使许多亮三角形看起来光滑

时间:2015-03-07 17:46:08

标签: c++ opengl smooth perlin-noise

我正在创建一个程序,通过创建许多三角形来使用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

那么,我该怎样做才能使三角形变得平滑,以至于你再也看不到这些硬边了呢?

1 个答案:

答案 0 :(得分:4)

您对每个三角形的所有3个顶点使用相同的法线。这基本上会产生平面着色,这意味着每个三角形的颜色是不变的。

您需要的是更接近曲面实际法线的法线,而不是分别计算每个三角形的法线。要获得平滑的表面,您需要为每个顶点设置一个法线,然后在为所有指定共享顶点的三角形的顶点时使用该法线。

最有效的方法是,您只需将网格的每个顶点/法线存储在VBO中一次。然后,您可以在定义三角形时使用索引缓冲区来引用顶点。这意味着您有一个包含索引的GL_ELEMENT_ARRAY_BUFFER类型的附加缓冲区,然后使用glDrawElements()进行绘制。您应该能够找到有关如何执行此操作的参考信息和教程。

要实际获得法线,一种常见方法是平均所有相邻三角形的三角法线以计算顶点的法线。