我正在尝试为我的硕士学位(以及我的技能)制作一个小型3D引擎。我对镜面反射有问题。 (我很抱歉插图图片的链接,但我还没有足够的声誉)。我的GitHub上提供了所有来源:DWRenderer
就在这里,我们正在拍摄物体,但相机在前面也是灯光。我们可以看到,对象背后有一个反映。
为了描述实际参数,所有计算都是在世界空间中进行的(通常......有了这个问题,我有点怀疑)。我把相机放在vec3(0,0,3)的位置进行测试,光线只是vec3(1.2,1,2)的一个点,用立方体表示。我在Ubuntu下使用Qt 5.4和OpenGL 4.1和Nvidia驱动程序。
这是我的顶点着色器:
#version 410 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 normal;
out vec3 Normal;
out vec3 FragPos;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
uniform mat3 normalMatrix;
void main()
{
gl_Position = projection * view * model * vec4(position, 1.0f);
FragPos = vec3(model * vec4(position, 1.0f));
Normal = normalMatrix * normal;
}
我的片段着色器:
#version 410 core
out vec4 color;
in vec3 Normal;
in vec3 FragPos;
struct Material {
vec3 ambient;
vec3 diffuse;
vec3 specular;
float shininess;
};
struct Light {
vec3 position;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
uniform Material material;
uniform Light light;
uniform vec3 viewPos;
void main()
{
// Vectors
vec3 norm = normalize(Normal);
vec3 lightDir = normalize(light.position - FragPos);
vec3 viewDir = normalize(viewPos - FragPos);
vec3 reflectDir = reflect(-lightDir, norm);
// Ambient
vec3 ambient = material.ambient * light.ambient;
// Diffuse
float diff = clamp(dot(lightDir, norm), 0.0, 1.0);
vec3 diffuse = diff * material.diffuse * light.diffuse;
// Specular - The bug seems only here
float spec = pow(clamp(dot(viewDir, reflectDir), 0.0, 1.0), material.shininess);
vec3 specular = spec * material.specular * light.specular;
vec3 result = (diffuse + specular + ambient);
color = vec4(result, 1.0f);
// For test vectors
//color = vec4(specular, 1.0f);
}
游戏循环中的代码(paintGL的实时间隔为16ms)用于初始化统一变量(着色器的摄像机位置是固定的,我可以转动我的立方体进行检查错误。灯光的位置在“initializeGL”中并且也是固定的):
// Draw cube
m_cubeShader->useShaderProgram();
GLint lightPosLoc = glGetUniformLocation(m_cubeShader->getId(), "light.position");
GLint viewPosLoc = glGetUniformLocation(m_cubeShader->getId(), "viewPos");
GLint matAmbientLoc = glGetUniformLocation(m_cubeShader->getId(), "material.ambient");
GLint matDiffuseLoc = glGetUniformLocation(m_cubeShader->getId(), "material.diffuse");
GLint matSpecularLoc = glGetUniformLocation(m_cubeShader->getId(), "material.specular");
GLint matShineLoc = glGetUniformLocation(m_cubeShader->getId(), "material.shininess");
GLint lightAmbientLoc = glGetUniformLocation(m_cubeShader->getId(), "light.ambient");
GLint lightDiffuseLoc = glGetUniformLocation(m_cubeShader->getId(), "light.diffuse");
GLint lightSpecularLoc = glGetUniformLocation(m_cubeShader->getId(), "light.specular");
glUniform3f(lightAmbientLoc, 0.2f, 0.2f, 0.2f);
glUniform3f(lightDiffuseLoc, 0.5f, 0.5f, 0.5f);
glUniform3f(lightSpecularLoc, 1.0f, 1.0f, 1.0f);
glUniform3f(matAmbientLoc, 1.0f, 0.5f, 0.31f);
glUniform3f(matDiffuseLoc, 1.0f, 0.5f, 0.31f);
glUniform3f(matSpecularLoc, 0.5f, 0.5f, 0.5f);
glUniform1f(matShineLoc, 32.0f);
glUniform3f(viewPosLoc, 0.0f, 0.0f, 3.0f); // For testing a bug - Unresolved
//glUniform3f(viewPosLoc, m_camera->getPosition().x, m_camera->getPosition().y, m_camera->getPosition().z);
glUniform3f(lightPosLoc, m_lightPos.x, m_lightPos.y, m_lightPos.z);
glm::mat4 model;
glm::mat4 view;
glm::mat4 projection;
glm::mat3 normalMatrix;
normalMatrix = glm::mat3(glm::transpose(glm::inverse(model)));
view = m_camera->getViewMatrix();
projection = glm::perspective(glm::radians(m_camera->getFov()), (GLfloat)m_screenWidth / (GLfloat)m_screenHeight, 0.1f, 100.0f);
GLint normalMatrixLoc = glGetUniformLocation(m_cubeShader->getId(), "normalMatrix");
GLint modelLoc = glGetUniformLocation(m_cubeShader->getId(), "model");
GLint viewLoc = glGetUniformLocation(m_cubeShader->getId(), "view");
GLint projectionLoc = glGetUniformLocation(m_cubeShader->getId(), "projection");
glUniformMatrix3fv(normalMatrixLoc, 1, GL_FALSE, glm::value_ptr(normalMatrix));
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projection));
glBindVertexArray(m_cubeVAO);
glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(0);
// Draw light
m_lightShader->useShaderProgram();
model = glm::mat4();
model = glm::translate(model, m_lightPos);
model = glm::scale(model, glm::vec3(0.2f));
modelLoc = glGetUniformLocation(m_lightShader->getId(), "model");
viewLoc = glGetUniformLocation(m_lightShader->getId(), "view");
projectionLoc = glGetUniformLocation(m_lightShader->getId(), "projection");
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projection));
glBindVertexArray(m_lightVAO);
glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(0);
我试过在视图空间上进行计算,但它不起作用。我已经尝试修改/规范化/使用max()而不是clamp(),但问题几个小时后。我没有任何想法。
答案 0 :(得分:1)
如果lightDir
(从片段到光的方向)在norm
方向(片段的法线向量),则只有漫反射光和镜面反射光。如果他们针对你,你可以做没有漫反射和镜面光。换句话说,如果不是任何漫射光(因为diff
是0.0
),那么也没有任何镜面反射光。像这样调整你的代码:
void main()
{
// Vectors
vec3 norm = normalize(Normal);
vec3 lightDir = normalize(light.position - FragPos);
vec3 viewDir = normalize(viewPos - FragPos);
vec3 reflectDir = reflect(-lightDir, norm);
// Ambient
vec3 ambient = material.ambient * light.ambient;
vec3 result = ambient;
float dotNvLd = dot( norm, lightDir );
if ( dotNvLd > 0.0 ) // test if normal vector not directed against vector to light position
{
// Diffuse
float diff = min( dotNvLd, 1.0 );
vec3 diffuse = diff * material.diffuse * light.diffuse;
// Specular - The bug seems only here
float spec = pow(clamp(dot(viewDir, reflectDir), 0.0, 1.0), material.shininess);
vec3 specular = spec * material.specular * light.specular;
result = (diffuse + specular + ambient);
}
color = vec4(result, 1.0f);
// For test vectors
//color = vec4(specular, 1.0f);
}