2015-03-07 3 views
0

Я пытаюсь создать программу, которая показывает волнообразную анимацию, используя Perlin Noise, создавая много треугольников.Сделать много светлых треугольников выглядят гладкими

Это важная часть моей программы:

class OGLT9_NOISE 
{ 
    //class for Perlin Noise (noise3d()) and Fractional Brownian Motion (fmb()) generaion 
}; 

glm::vec3 OGLT9_GRAPHICS::getNormal(glm::vec3 a, glm::vec3 b, glm::vec3 c) 
{ 
    return glm::normalize(glm::cross(c-a, b-a)); 
} 

void generateTerrain(OGLT9_SHADER *oglt9Shader) 
{ 
    static OGLT9_NOISE noise; 
    static float yValue = 0; 
    int terrainRes = 7;    //terrain's resolution 
    float terrainSpacing = 10.0f; 
    vector<glm::vec3> vertexData; 
    vector<glm::vec3> normalData; 
    multi_array<float, 2> terrain; 

    terrain.resize(extents[1<<terrainRes][1<<terrainRes]); 

    for(long z=-(1<<(terrainRes-1)); z<(1<<(terrainRes-1)); z++) 
     for(long x=-(1<<(terrainRes-1)); x<(1<<(terrainRes-1)); x++) 
      terrain[z+(1<<(terrainRes-1))][x+(1<<(terrainRes-1))] = (noise.fbm((double)x/16.0, yValue, (double)z/16.0, 2, 0.4, 1.2, 2.9, 1.1)/2.0+0.5)*100.0; 

    for(long z=0; z<(1<<terrainRes)-1; z++) 
    { 
     for(long x=0; x<(1<<terrainRes)-1; x++) 
     { 
      vertexData.push_back(glm::vec3((float)x*terrainSpacing, terrain[z][x], (float)z*terrainSpacing)); 
      vertexData.push_back(glm::vec3(((float)x+1.0f)*terrainSpacing, terrain[z+1][x+1], ((float)z+1.0f)*terrainSpacing)); 
      vertexData.push_back(glm::vec3(((float)x+1.0f)*terrainSpacing, terrain[z][x+1], (float)z*terrainSpacing)); 
      vertexData.push_back(glm::vec3((float)x*terrainSpacing, terrain[z][x], (float)z*terrainSpacing)); 
      vertexData.push_back(glm::vec3((float)x*terrainSpacing, terrain[z+1][x], ((float)z+1.0f)*terrainSpacing)); 
      vertexData.push_back(glm::vec3(((float)x+1.0f)*terrainSpacing, terrain[z+1][x+1], ((float)z+1.0f)*terrainSpacing)); 

      normalData.push_back(getNormal(vertexData[vertexData.size()-6], vertexData[vertexData.size()-5], vertexData[vertexData.size()-4])); 
      normalData.push_back(normalData[normalData.size()-1]); 
      normalData.push_back(normalData[normalData.size()-2]); 
      normalData.push_back(getNormal(vertexData[vertexData.size()-3], vertexData[vertexData.size()-2], vertexData[vertexData.size()-1])); 
      normalData.push_back(normalData[normalData.size()-1]); 
      normalData.push_back(normalData[normalData.size()-2]); 
     } 
    } 

    glUseProgram(oglt9Shader->program); 
    glGenBuffers(1, &vbo); 
    glBindBuffer(GL_ARRAY_BUFFER, vbo); 
    glBufferData(GL_ARRAY_BUFFER, vertexData.size()*3*sizeof(float), vertexData.data(), GL_STATIC_DRAW); 
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL); 
    glEnableVertexAttribArray(0); 

    glGenBuffers(1, &nbo); 
    glBindBuffer(GL_ARRAY_BUFFER, nbo); 
    glBufferData(GL_ARRAY_BUFFER, normalData.size()*3*sizeof(float), normalData.data(), GL_STATIC_DRAW); 
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, NULL); 
    glEnableVertexAttribArray(1); 
    glBindBuffer(GL_ARRAY_BUFFER, 0); 

    numVertices = vertexData.size()*3; 
    yValue += 0.01f; 
} 

void render() 
{ 
    //Clear screen and enable depth buffer 
    //Create and transmit matrices and light direction to shaders 

    generateTerrain(oglt9Shader); 

    glDrawArrays(GL_TRIANGLES, 0, numVertices); 

    glDeleteBuffers(1, &vbo); 
    glDeleteBuffers(1, &nbo); 

    //Swap buffers to window 
} 

И моя вершинный шейдер ...

#version 430 core 

layout (location = 0) in vec3 vPosition; 
layout (location = 1) in vec3 vNormal; 

uniform mat4 mMatrix; 
uniform mat4 vMatrix; 
uniform mat4 pMatrix; 

out vec3 fPosition; 
out vec3 fNormal; 

void main(void) 
{ 
    gl_Position = pMatrix * vMatrix * mMatrix * vec4(vPosition, 1.0); 
    fPosition = vPosition; 
    fNormal = normalize(transpose(inverse(mat3(mMatrix))) * vNormal); 
} 

#version 430 core 

in vec3 fPosition; 
in vec3 fNormal; 
out vec4 outColor; 
uniform vec3 lightDirection; 

... и пиксельный шейдер.

void main(void) 
{ 
    vec3 rawColor = vec3(1.0); 
    vec3 ambientColor = vec3(1.0, 1.0, 1.0); 
    float diffuseIntensity = max(0.0, dot(fNormal, lightDirection)); 
    vec3 diffuseColor = diffuseIntensity * vec3(0.9, 0.9, 0.9); 

    outColor = vec4(rawColor*ambientColor*diffuseColor, 1.0); 
} 

Это окончательное изображение:

The not so smooth image

Итак, что я могу сделать, чтобы сделать треугольники гладкой, так что вы не можете увидеть эти жесткие края больше?

ответ

4

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

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

Самый эффективный способ сделать это состоит в том, что вы действительно храните каждую вершину/нормальную сетку в VBO только один раз. Затем вы можете использовать индексный буфер для ссылки на вершины при определении треугольников. Это означает, что у вас есть дополнительный буфер типа GL_ELEMENT_ARRAY_BUFFER, содержащий индексы, а затем нарисуйте glDrawElements(). Вы должны найти справочную информацию и учебные пособия о том, как это сделать.

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