Я написал базовую программу, которая загружает модель и отображает ее на экране. Я использую GLSL для правильной трансформации модели, но нормали всегда кажутся неправильными после их вращения с каждой комбинацией матриц модели, матрицы просмотра, обратной, транспозиции и т. Д., О которых я мог думать. Матричная модель только вращение вокруг оси у, используя GLM:Нормальное вращение в GLSL
angle += deltaTime;
modelMat = glm::rotate(glm::mat4(), angle, glm::vec3(0.f, 1.f, 0.f));
Мой текущий код вершинного шейдера (я изменил нормаль много много раз):
#version 150 core
uniform mat4 projMat;
uniform mat4 viewMat;
uniform mat4 modelMat;
in vec3 inPosition;
in vec3 inNormal;
out vec3 passColor;
void main()
{
gl_Position = projMat * viewMat * modelMat * vec4(inPosition, 1.0);
vec3 normal = normalize(mat3(inverse(modelMat)) * inNormal);
passColor = normal;
}
И мой фрагмент шейдер:
#version 150 core
in vec3 passColor;
out vec4 outColor;
void main()
{
outColor = vec4(passColor, 1.0);
}
Я знаю точно, что унифицированные переменные передается в шейдер правильно, так как модель сама преобразуется должным образом, и начальные нормали правильно, если я делаю расчеты су ch как направленное освещение.
Я создал GIF вращающейся модели, жаль низкого качества: http://i.imgur.com/LgLKHCb.gif?1
Что меня смущает больше всего, как нормалей вращаться по оси на нескольких, которые я не думаю, что должно происходят при умножении на одну матрицу вращения на одну ось.
Edit:
Я добавил еще немного кода клиента ниже.
Это где буферы получить связаны для модели, в Mesh
классе (vao
является GLuint
, определенный в классе):
GLuint vbo[3];
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(normals? (uvcoords? 3 : 2) : (uvcoords? 2 : 1), vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glBufferData(GL_ARRAY_BUFFER, vcount * 3 * sizeof(GLfloat), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
if(normals)
{
glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
glBufferData(GL_ARRAY_BUFFER, vcount * 3 * sizeof(GLfloat), normals, GL_STATIC_DRAW);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_TRUE, 0, 0);
glEnableVertexAttribArray(1);
}
if(uvcoords)
{
glBindBuffer(GL_ARRAY_BUFFER, vbo[2]);
glBufferData(GL_ARRAY_BUFFER, vcount * 2 * sizeof(GLfloat), uvcoords, GL_STATIC_DRAW);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(2);
}
glBindVertexArray(0);
glGenBuffers(1, &ib);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ib);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, icount * sizeof(GLushort), indices, GL_STATIC_DRAW);
Это где шейдеры компилируются после загрузки в память с простой readf(), в классе Material
:
u32 vertexShader = glCreateShader(GL_VERTEX_SHADER);
u32 fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(vertexShader, 1, (const GLchar**)&vsContent, 0);
glCompileShader(vertexShader);
if(!validateShader(vertexShader)) return false;
glShaderSource(fragmentShader, 1, (const GLchar**)&fsContent, 0);
glCompileShader(fragmentShader);
if(!validateShader(fragmentShader)) return false;
programHandle = glCreateProgram();
glAttachShader(programHandle, vertexShader);
glAttachShader(programHandle, fragmentShader);
glBindAttribLocation(programHandle, 0, "inPosition");
glBindAttribLocation(programHandle, 1, "inNormal");
//glBindAttribLocation(programHandle, 2, "inUVCoords");
glLinkProgram(programHandle);
if(!validateProgram()) return false;
и validateShader(GLuint)
и validateProgram()
функции:
bool Material::validateShader(GLuint shaderHandle)
{
char buffer[2048];
memset(buffer, 0, 2048);
GLsizei len = 0;
glGetShaderInfoLog(shaderHandle, 2048, &len, buffer);
if(len > 0)
{
Logger::log("ve::Material::validateShader: Failed to compile shader - %s", buffer);
return false;
}
return true;
}
bool Material::validateProgram()
{
char buffer[2048];
memset(buffer, 0, 2048);
GLsizei len = 0;
glGetProgramInfoLog(programHandle, 2048, &len, buffer);
if(len > 0)
{
Logger::log("ve::Material::validateProgram: Failed to link program - %s", buffer);
return false;
}
glValidateProgram(programHandle);
GLint status;
glGetProgramiv(programHandle, GL_VALIDATE_STATUS, &status);
if(status == GL_FALSE)
{
Logger::log("ve::Material::validateProgram: Failed to validate program");
return false;
}
return true;
}
Каждый Material
экземпляр имеет std::map
из Mesh
с, и получить визуализируется как так:
void Material::render()
{
if(loaded)
{
glUseProgram(programHandle);
for(auto it = mmd->uniforms.begin(); it != mmd->uniforms.end(); ++it)
{
GLint loc = glGetUniformLocation(programHandle, (const GLchar*)it->first);
switch(it->second.type)
{
case E_UT_FLOAT3: glUniform3fv(loc, 1, it->second.f32ptr); break;
case E_UT_MAT4: glUniformMatrix4fv(loc, 1, GL_FALSE, it->second.f32ptr); break;
default: break;
}
}
for(Mesh* m : mmd->objects)
{
GLint loc = glGetUniformLocation(programHandle, "modelMat");
glUniformMatrix4fv(loc, 1, GL_FALSE, &m->getTransform()->getTransformMatrix()[0][0]);
m->render();
}
}
}
it->second.f32ptr
будет float
указатель на &some_vec3[0]
или &some_mat4[0][0]
. Я вручную загружаю матрицу преобразования модели перед рендерингом, однако (которая является только матрицей вращения, класс Transform
(возвращаемый Mesh :: getTransform()) будет выполнять только glm :: rotation(), поскольку я пытался выяснить проблема).
Наконец, Mesh
делают код:
if(loaded)
{
glBindVertexArray(vao);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ib);
glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_SHORT, 0);
}
Я думаю, что это все необходимый код, но я могу разместить больше, если это необходимо.
Благодарим за ответы, но я все еще в недоумении. Я изменил нормальную линию на 'vec3 normal = normalize (transpose (inverse (mat3 (modelMat))) * inNormal);' , но все же имеют похожие результаты с неправильными нормалями – user3764686
@ user3764686: Ну, какое пространство вы хотите, чтобы ваши нормали в? Это не совсем понятно из вашего вопроса. Также неясно, правильны ли ваши нормали ввода. И вы также должны перенормировать их в FS, поскольку линейная интерполяция не сохраняет длину. – derhass
Извините за неясность, я установил выходной цвет, равный нормалям, чтобы определить, правильно ли они вращаются, но анимированное изображение в главном вопросе иллюстрирует, что происходит. Я не знаю, правильно ли это, но я думаю, что цвета (нормальные значения) не должны перемещаться вертикально вокруг сферы, несмотря на то, что я использую пространство модели или пространство просмотра. – user3764686