2016-01-07 9 views
2

В настоящее время я работаю над проектом OpenGL (JOGL) в java. Целью является создание ландшафта с текстурами и затенением.Окантовка текстуры ландшафта

Я создаю случайный симплекс-шум, используя эти значения в качестве карты высот. Высота сопоставляется с 1D текстурой для имитации окраски по высоте. Затем для имитации затенения используется материал (окружающий/рассеянный/зеркальный/блеск).

Однако; после добавления затенения к рельефу, «полосы» появляются на каждом «столбце» (направление Y) местности.

Следующий материал затем применяется:

TERRAIN(
     new float[]{0.5f, 0.5f, 0.5f, 1.0f}, 
     new float[]{0.7f, 0.7f, 0.7f, 1.0f}, 
     new float[]{0.2f, 0.2f, 0.2f, 1.0f}, 
     new float[]{100f}) 

Материал конструктора перечисления:

Material(float[] ambient, float[] diffuse, float[] specular, float[] shininess) { 
    this.ambient = ambient; 
    this.diffuse = diffuse; 
    this.specular = specular; 
    this.shininess = shininess; 
} 

я применить материал, используя следующий метод:

public void use(GL2 gl) { 
    // set the material properties 
    gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GLLightingFunc.GL_AMBIENT, ambient, 0); 
    gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GLLightingFunc.GL_DIFFUSE, diffuse, 0); 
    gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GLLightingFunc.GL_SPECULAR, specular, 0); 
    gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GLLightingFunc.GL_SHININESS, shininess, 0); 
} 

После создания 2D «noisearray», совпадающий с значениями 0-1, создается 2D-векторный символ, содержащий X * Y vec tors, где каждый вектор представляет собой точку в плоскости/местности.

Вот метод, который рисует треугольники между теми точками, где вы можете увидеть, я рисую плоскость для каждого столбца (Y-направление):

public void draw(GL2 gl, GLU glu, GLUT glut, Drawer drawer) { 
    Material.TERRAIN.use(gl); 
    texture.bind(gl); 
    if (showGrid) 
     gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_LINE); 
    ArrayList<Vector[]> normals = new ArrayList<>(); 
    for(int i=1;i<vectors.length;i++) { 
     gl.glBegin(gl.GL_TRIANGLE_STRIP); 
     for (int j = 0; j < vectors[i].length; j++) { 
      Vector normalTopRight, normalBottomLeft; 

      //Calculate normals top right 
      Vector v1, v2, triangleCenterTR; 
      if (j < vectors[i].length - 1) 
      { 
       v1 = vectors[i-1][j].subtract(vectors[i][j]); 
       v2 = vectors[i][j+1].subtract(vectors[i][j]); 
       normalTopRight = v2.cross(v1).normalized(); 
       // Get center (a+b+c)*(1/3) 
       triangleCenterTR = (vectors[i][j].add(vectors[i - 1][j]).add(vectors[i][j + 1])).scale(1.0/3); 
      } else { 
       v1 = vectors[i-1][j].subtract(vectors[i][j]); 
       v2 = vectors[i][j-1].subtract(vectors[i][j]); 
       normalTopRight = v1.cross(v2).normalized(); 
       // Get center (a+b+c)*(1/3) 
       triangleCenterTR = (vectors[i][j].add(vectors[i-1][j]).add(vectors[i][j-1])).scale(1.0/3); 
      } 
      normals.add(new Vector[] {triangleCenterTR, triangleCenterTR.add(normalTopRight)}); 

      if (j != 0) 
      { 
       v1 = vectors[i][j].subtract(vectors[i-1][j]); 
       v2 = vectors[i-1][j-1].subtract(vectors[i-1][j]); 
       normalBottomLeft = v2.cross(v1).normalized(); 
       // Get center (a+b+c)*(1/3) 
       Vector triangleCenterBL = (vectors[i - 1][j].add(vectors[i][j]).add(vectors[i - 1][j - 1])).scale(1.0/3); 
       normals.add(new Vector[]{triangleCenterBL, triangleCenterBL.add(normalBottomLeft)}); 
      } else { 
       normalBottomLeft = null; // If j==0, there is no bottom left triangle above 
      } 

      /** 
      * We have everything to start drawing 
      */ 
      // Set some color 
      if (j == 0) { 
       // Initialization vector 
       gl.glTexCoord1d(mapTextureToHeight(vectors[i][j].z)); 
       drawer.glVertexV(vectors[i][j]); 
      } else { 
       drawer.glNormalV(normalBottomLeft); 
      } 

      // Shift left 
      gl.glTexCoord1d(mapTextureToHeight(vectors[i - 1][j].z)); 
      drawer.glVertexV(vectors[i - 1][j]); 

      // Right down diagonally 
      if (j < vectors[i].length - 1) { // Skip if we are reached the end 
       gl.glTexCoord1d(mapTextureToHeight(vectors[i][j + 1].z)); 
       drawer.glNormalV(normalTopRight); 
       drawer.glVertexV(vectors[i][j + 1]); 
      } 
     } 
     gl.glEnd(); 
    } 
    if (showGrid) 
     gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_FILL); 
    if (drawNormals) { 
     for (Vector[] arrow : normals) { 
      if (yellowNormals) 
       Material.YELLOW.use(gl); 
      else 
       gl.glTexCoord1d(mapTextureToHeight(arrow[0].z)); 
      drawer.drawArrow(arrow[0], arrow[1], 0.05); 
     } 
    } 

    texture.unbind(gl); 
} 

Наиболее очевидной причиной полос является тот факт, я рисую треугольники на столбец, в результате чего OpenGL не сможет сгладить затенение на многоугольниках (GL_SMOOTH). Есть ли способ исправить это?

Image of stripes appearing on terrain

Using a higher resolution (more polygons)

[Edit1] скопированные с комментарием по Spektre

Я только что закончил вычисления средних нормалей, я действительно имеют гладкую местность в настоящее время, но освещение выглядит вид (глубина)

example

Вот новый код, который рисует рельеф местности:

public void draw() { 
    if (showGrid) 
     gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_LINE); 
    texture.bind(gl); 
    Material.TERRAIN.use(gl); 
    for(int i=1;i<vectors.length;i++) { 
     gl.glBegin(gl.GL_TRIANGLE_STRIP); 
     for (int j = 0; j < vectors[i].length; j++) { 
      // Initialization vector 
      gl.glTexCoord1d(mapTextureToHeight(vectors[i][j].z)); 
      drawer.glNormalV(normals.get(vectors[i][j])); 
      drawer.glVertexV(vectors[i][j]); 

      // Shift left 
      gl.glTexCoord1d(mapTextureToHeight(vectors[i - 1][j].z)); 
      drawer.glNormalV(normals.get(vectors[i - 1][j])); 
      drawer.glVertexV(vectors[i - 1][j]); 
     } 
     gl.glEnd(); 
    } 
    if (showGrid) 
     gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_FILL); 
    if (drawNormals) 
     drawFaceNormals(); 
    texture.unbind(gl); 
} 

Я очистил его, я уверен, что нормалей указывает правильный путь, используя функцию drawnormals и убедились, что OpenGL видит в верхней части местности, как FRONT использует (gl.GL_FRONT -> рисует только над рельефом, а не ниже).

Вот полный класс: PasteBin

+1

вам нужно пересчитать нормали на вершину, чтобы они соответствовали [Как достичь гладких касательных пространственных нормалей?] (http://stackoverflow.com/a/21930058/2521214) – Spektre

+0

@Spektre Спасибо за ваш комментарий, я только что закончил вычислять средние нормали, у меня действительно есть гладкая местность сейчас, но освещение выглядит вроде скучно (без глубины) [image] (http://i.imgur.com/EbtqLAK.png) Любые предложения? –

+1

Моя ставка заключается в том, что ваши нормали указывают на другой способ попытаться свести их на нет «normal = -normal» или не нормализуются или ошибочно вычисляются – Spektre

ответ

0

Благодаря @Spektre за помощь мне.

После правильного вычисления средней нормы всех окружающих поверхностей на вершине и использования этого нормального значения для glNormal, затенение было правильным.

Смежные вопросы