计算现代OpenGL中光的每片段法线

时间:2015-03-01 11:55:41

标签: c++ opengl fragment-shader geometry-shader

我想知道如何计算每片段法线以便能够为场景添加光线!

我读了一个从libnoise库生成的纹理 - http://libnoise.sourceforge.net并通过计算几何着色器中的东西创建一个地形,如下所示

地形看起来很好但不是闪电......

Want to calculate normals for light

我的代码如下所示:

const int TOTAL = (TERRAIN_WIDTH*TERRAIN_DEPTH);
const int TOTAL_INDICES = TOTAL*3*3;
glm::vec3 vertices[TOTAL];
GLuint indices[TOTAL_INDICES];

//...

int count = 0;
GLuint* id=&indices[0];
// Set up Geometry for terrain
for(int j = 0; j < TERRAIN_DEPTH; j++) {
    for(int i = 0; i < TERRAIN_WIDTH; i++) {

    //So I want to calculate position and normal here <-----
    vertices[count] = glm::vec3((float(i)/(TERRAIN_WIDTH-1)), 1.0,(float(j)/(TERRAIN_DEPTH-1)));
    count++;
    }
}

for (int i = 0; i < TERRAIN_DEPTH-1; i++) {
    for (int j = 0; j < TERRAIN_WIDTH-1; j++) {
        int i0 = j+ i*TERRAIN_WIDTH;
        int i1 = i0+1;
        int i2 = i0+TERRAIN_WIDTH;
        int i3 = i2+1;

        *id++ = i0; 
        *id++ = i2; 
        *id++ = i1; 
        *id++ = i1; 
        *id++ = i2; 
        *id++ = i3; 
    }    
}

...

GLubyte *pData = SOIL_load_image(filename, &textureWidth, 
                            &textureHeight, &channels, SOIL_LOAD_L);

glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices) , &vertices[0], GL_STATIC_DRAW);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementArrayObject);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), &indices[0], GL_STATIC_DRAW);

glGenTextures(1, &heightMapTextureID);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, heightMapTextureID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, textureWidth, textureHeight, 0, GL_RED, GL_UNSIGNED_BYTE, pData);

几何着色器:

layout (triangles) in;
layout (triangle_strip, max_vertices=9) out; 

uniform sampler2D heightMapTexture;
uniform mat4 projection;
uniform mat4 model;
uniform mat4 view;


void main()
{
    for(int i=0;i<gl_in.length(); i++) {
        vec4 position = gl_in[i].gl_Position;

        float height = texture(heightMapTexture, position.xz).r;
        vec2 xz = (position.xz*50); // the multiplication will decide how big the terrain will be
        gl_Position =  (projection * view * model) * vec4(xz.x,height*5,xz.y , 1.0);            
        EmitVertex();
    }
    EndPrimitive();
}

我的顶点和片段着色器是最基本的。

#version 330 core
layout(location = 0) out vec4 finalColor;

void main()
{   
    finalColor = vec4(vec3(1,1,1), 1.0f);
}

顶点:

#version 330 core
//inputs
layout(location = 0)in vec3 position;

void main()
{
    gl_Position =  vec4(position, 1.0f);
}

有人能帮助我吗?

1 个答案:

答案 0 :(得分:0)

在将几何体传递到地形之前,应计算几何体的法线。我现在说它会付出更多的努力,但最好为您的地形CPU端生成所有数据,然后将其传递给您的显卡。问题是一个片段没有关于下一个片段或前一个片段的信息。

您应该传递正常的顶点数据,以及法线和颜色(或纹理,或两者都没有),然后使用它来在GPU上进行计算。

问题是,是的,您可以在GeometryShader中生成几何体,但是您无法获得平滑的光照,因为您只能计算面部的一个法线。

总结如下:

1。)在CPU上生成几何体并将其存储在那里。

2。)迭代每个顶点并计算其法线。要计算它的法线,你将取所有相邻面或法向量的法线,然后求它们并取均值。

3.)将此数据传递到着色器管道。

4.。)根据您的所有输入计算您的照明模型(大概是phong)。

这也意味着你不必为每一帧生成几何体,如果你的地形或世界变得更大,这可能变得相当昂贵。