我正在创建一个程序,通过创建许多三角形来使用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);
}
这是最终图片:
那么,我该怎样做才能使三角形变得平滑,以至于你再也看不到这些硬边了呢?
答案 0 :(得分:4)
您对每个三角形的所有3个顶点使用相同的法线。这基本上会产生平面着色,这意味着每个三角形的颜色是不变的。
您需要的是更接近曲面实际法线的法线,而不是分别计算每个三角形的法线。要获得平滑的表面,您需要为每个顶点设置一个法线,然后在为所有指定共享顶点的三角形的顶点时使用该法线。
最有效的方法是,您只需将网格的每个顶点/法线存储在VBO中一次。然后,您可以在定义三角形时使用索引缓冲区来引用顶点。这意味着您有一个包含索引的GL_ELEMENT_ARRAY_BUFFER
类型的附加缓冲区,然后使用glDrawElements()
进行绘制。您应该能够找到有关如何执行此操作的参考信息和教程。
要实际获得法线,一种常见方法是平均所有相邻三角形的三角法线以计算顶点的法线。