OpenGL的漫射照明问题
Posted
技术标签:
【中文标题】OpenGL的漫射照明问题【英文标题】:Problem with diffuse lighting with OpenGL 【发布时间】:2021-06-03 03:35:52 【问题描述】:我的漫射照明似乎无法正常工作。
片段着色器:
#version 330 core
out vec4 gl_FragColor;
in vec4 vertexColor;
in vec2 texelCoord;
in vec3 Normal;
struct DirectionalLight
vec3 color;
float ambientIntensity;
vec3 direction;
float diffuseIntensity;
;
uniform sampler2D textureSampler;
uniform DirectionalLight directionalLight;
void main()
vec4 ambientColor = vec4(directionalLight.color, 1.0f) * directionalLight.ambientIntensity;
float diffuseFactor = max(dot(normalize(Normal), normalize(directionalLight.direction)), 0.0f);
vec4 diffuseColor = vec4(directionalLight.color, 1.0f) * directionalLight.diffuseIntensity * diffuseFactor;
gl_FragColor = texture(textureSampler, texelCoord) * (ambientColor + diffuseColor);
顶点着色器:
#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec2 texCoord;
layout (location = 2) in vec3 normal;
out vec4 vertexColor;
out vec2 texelCoord;
out vec3 Normal;
uniform mat4 transformation;
uniform mat4 projection;
uniform mat4 view;
void main()
gl_Position = projection * view * transformation * vec4( position, 1.0f );
vertexColor = vec4(clamp(position, 0.0f, 1.0f), 1.0f);
texelCoord = texCoord;
Normal = mat3(transpose(inverse(transformation))) * normal;
我如何创建网格:
void CalcAverageNormals( unsigned int* indices , unsigned int indicesCount , float* vertices , unsigned int verticesCount , unsigned int vertexLength , unsigned int normalOffset )
for ( int i = 0; i < indicesCount; i += 3 )
unsigned int v1 = indices[i] * vertexLength;
unsigned int v2 = indices[ i + 1 ] * vertexLength;
unsigned int v3 = indices[ i + 2 ] * vertexLength;
glm::vec3 line1( vertices[ v2 ] - vertices[ v1 ] , vertices[ v2 + 1 ] - vertices[ v1 + 1 ] , vertices[ v2 + 2 ] - vertices[ v1 + 2 ] );
glm::vec3 line2( vertices[ v3 ] - vertices[ v1 ] , vertices[ v3 + 1 ] - vertices[ v1 + 1 ] , vertices[ v3 + 2 ] - vertices[ v1 + 2 ] );
glm::vec3 normal = glm::normalize( glm::cross( line1 , line2 ) );
v1 += normalOffset;
v2 += normalOffset;
v3 += normalOffset;
vertices[ v1 ] += normal.x; vertices[ v1 + 1 ] += normal.y; vertices[ v1 + 2 ] += normal.z;
vertices[ v2 ] += normal.x; vertices[ v2 + 1 ] += normal.y; vertices[ v2 + 2 ] += normal.z;
vertices[ v3 ] += normal.x; vertices[ v3 + 1 ] += normal.y; vertices[ v3 + 2 ] += normal.z;
for ( int j = 0; j < verticesCount / vertexLength; j++ )
unsigned int offset = j * vertexLength + normalOffset;
glm::vec3 normalVertex( vertices[ offset ] , vertices[ offset + 1 ] , vertices[ offset + 2 ] );
normalVertex = glm::normalize( normalVertex );
vertices[ offset ] = normalVertex.x;
vertices[ offset + 1 ] = normalVertex.y;
vertices[ offset + 2 ] = normalVertex.z;
void CreateTriangle()
float vertices[]
-0.5f,-0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, // Left
0.5f,-0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, // Right
0.0f, 0.5f, 0.0f, 0.5f, 1.0f, 0.0f, 0.0f, 0.0f, // Top
0.0f,-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f // Back Z
;
unsigned int indices[]
0, 1, 2, // Front
3, 2, 1, // Right
3, 2, 0, // Left
3, 0, 1 // Bottom
;
CalcAverageNormals( indices , 12 , vertices , 32 , 8 , 5 );
for ( int i = 0; i < 1; i++ )
Mesh* obj = new Mesh();
obj->CreateMesh( vertices , 32 , indices , 12 );
meshlist.push_back( obj );
创建网格()
void Mesh::CreateMesh( float* vertices , unsigned int numVertices , unsigned int* indices , unsigned int numIndices )
uIndices = numIndices;
glGenVertexArrays( 1 , &vao );
glBindVertexArray( vao );
/*Create Buffers*/
glGenBuffers( 1 , &ibo );
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER , ibo );
glBufferData( GL_ELEMENT_ARRAY_BUFFER , numIndices * sizeof(unsigned) , indices , GL_STATIC_DRAW );
glGenBuffers( 1 , &vbo );
glBindBuffer( GL_ARRAY_BUFFER , vbo );
glBufferData( GL_ARRAY_BUFFER , numVertices * sizeof(float) , vertices , GL_STATIC_DRAW );
glVertexAttribPointer( 0 , 3 , GL_FLOAT , GL_FALSE , sizeof( vertices[ 0 ] ) * 8 , 0 );
glEnableVertexAttribArray( 0 );
glVertexAttribPointer( 1 , 2 , GL_FLOAT , GL_FALSE , sizeof( vertices[ 0 ] ) * 8 , ( void* )( sizeof( vertices[ 0 ] ) * 3 ) );
glEnableVertexAttribArray( 1 );
glVertexAttribPointer( 2 , 3 , GL_FLOAT , GL_FALSE , sizeof( vertices[ 0 ] ) * 8 , ( void* )( sizeof( vertices[ 0 ] ) * 5 ) );
glEnableVertexAttribArray( 2 );
/*Unbind Objects*/
glBindBuffer( GL_ARRAY_BUFFER , 0 );
glBindVertexArray( 0 );
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER , 0 );
如果我旋转网格,我只会得到某种光照:
正常(无照明):
这几天我一直在尝试解决这个问题,但我不确定我做错了什么。如果你能帮助我,那就太好了。
【问题讨论】:
您正在操作顶点 (vertices[ v1 ] += normal.x;
...),同时迭代面部并计算面部法线向量。这会影响所有后续面的法线向量,这些面由操纵的顶点定义。
【参考方案1】:
原来是我的索引顺序有三角形缠绕问题。由于我的漫反射因子的计算方式,我通过按逆时针顺序绘制索引来解决此问题。
unsigned int indices[]
0, 1, 2, // Front
3, 1, 2, // Right
3, 0, 2, // Left
3, 1, 0 // Bottom
;
转置和逆计算是为了纠正非均匀尺度矩阵。
【讨论】:
【参考方案2】:这个:
Normal = mat3(transpose(inverse(transformation))) * normal;
看起来很可疑,法线本身应该转换到与光方向矢量所在的坐标系相同的坐标系中。由于法线是矢量,w
应该为零,所以我希望要么
Normal = view * transformation * vec4( normal, 0.0f );
如果光线方向在相机坐标中或:
Normal = transformation * vec4( normal, 0.0f );
如果光线方向在全球世界坐标中(这种情况更可能发生)...
另外,设置着色器输出变量(如 gl_Position
)应该是着色器的最后一行,否则您将面临 GL 实现在某些实现上优化其余代码的风险。
顺便说一句。 IIRC mat3(transpose(inverse(transformation)))
与 mat3(transformation)
相同,以防 transformation
但正如 Rabbid76 指出的那样......
我能想到的最后一件事是错误的法线方向(相反或不一致),在这种情况下我会尝试交换:
max(dot(normalize(Normal), normalize(directionalLight.direction)), 0.0f);
与:
abs(dot(normalize(Normal), normalize(directionalLight.direction));
如果有帮助,您必须检查法线或只是否定点结果...
更多信息见:
OpenGL - vertex normals in OBJ ...但是我使用w=1
,因为使用的矩阵没有偏移量,所以没关系
Understanding 4x4 homogenous transform matrices
【讨论】:
如果transformation
包含不对称刻度,则需要使用mat3(transpose(inverse(transformation))
。
@Rabbid76 嗯,好点我总是使用对称和单位的,所以我没有想到......所以它会做某种纵横比逆校正?但是在这种情况下,代码应该首先工作......所以那里肯定有其他可疑的东西
当然可以。我不是故意责备它,这只是一个便条。
@Rabbid76 别担心,我马上就把它拿走了只是好奇我理解它的正确作用......也许你可以在答案中编辑它......
有 2 个很好的问题可以解释“inverse/transpose”:Why is the transposed inverse of the model view matrix used to transform the normal vectors? 和 Why transforming normals with the transpose of the inverse of the modelview matrix?以上是关于OpenGL的漫射照明问题的主要内容,如果未能解决你的问题,请参考以下文章