Я пытаюсь сделать небольшой 3D-движок для моей степени магистра (и для моего мастерства). У меня проблема с зеркальным отражением. (Прошу прощения за ссылку для иллюстрации, но у меня пока недостаточно репутации). Все источники доступны на моем GitHub: DWRenderer
Прямо здесь, мы видим объект, но камера на передней панели и свет. Как мы видим, позади объекта есть отражение.
Для описания реальных параметров все вычисления выполняются в мировом пространстве (обычно … с этой проблемой, я сомневаюсь). Я поставил камеру в положение vec3 (0, 0, 3) для теста, и свет — это просто точка в vec3 (1.2, 1, 2), представленная кубом. Я использую Qt 5.4 и OpenGL 4.1 под Ubuntu с драйверами 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 со временем с интервалом 16 мс для реального времени) для инициализации единой переменной (положение камеры для шейдера фиксировано, я могу повернуть свой куб для проверки ошибки. Положение источника света находится в «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 () вместо зажима (), но через несколько часов по этой проблеме. У меня нет идей.
У вас есть только рассеянный и зеркальный свет, если 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);
}
Других решений пока нет …