【问题标题】:OpenGL - How to rotate light source without rotating object at the same time?OpenGL - 如何在不旋转物体的同时旋转光源?
【发布时间】:2018-08-17 08:05:43
【问题描述】:

我正在学习 learnopengl 教程,并且正在尝试基本照明教程中的练习之一 -

尝试随着时间的推移在场景中移动光源 罪或因。

虽然就我而言,我使用的是 SDL,这意味着我不能使用以下方程式来旋转我的光源:

lightPos.x = 1.0f + sin(glfwGetTime()) * 2.0f;
lightPos.y = sin(glfwGetTime() / 2.0f) * 1.0f;

现在,当我旋转我的对象时,我的光源会随之旋转,但是我希望我的光源与我的对象分开旋转。这是我在渲染循环中处理灯光和对象旋转的内容:

void OpenGLWindow::render()
{

    lightPos.x = 1.0f + sin(SDL_GetTicks()/1000.0f) * 2.0f;
    lightPos.y = sin((SDL_GetTicks()/1000.0f) / 2.0f) * 1.0f;

    glm::mat4 model(1.0f);
    //model = glm::translate(model, lightPos);
    model = glm::rotate(model, lightPos.z, glm::vec3(0.0f, 0.0f, 1.0f));
    //model = glm::rotate(model, lightPos.y, glm::vec3(0.0f, 1.0f, 0.0f));
    model = glm::rotate(model, lightPos.x, glm::vec3(1.0f, 0.0f, 0.0f));
    int modelMatLocation = glGetUniformLocation(shader, "lightMatrix");
    glUniformMatrix4fv(modelMatLocation, 1, false, &model[0][0]);

    // NOTE: glm::translate/rotate/scale apply the transformation by right-multiplying by the
    //       corresponding transformation matrix (T). IE glm::translate(M, v) = M * T, not T*M
    //       This means that the transformation you apply last, will effectively occur first
    glm::mat4 modelMat(1.0f);
    modelMat = glm::translate(modelMat, parentEntity.position);
    modelMat = glm::rotate(modelMat, parentEntity.rotation.z, glm::vec3(0.0f, 0.0f, 1.0f));
    modelMat = glm::rotate(modelMat, parentEntity.rotation.y, glm::vec3(0.0f, 1.0f, 0.0f));
    modelMat = glm::rotate(modelMat, parentEntity.rotation.x, glm::vec3(1.0f, 0.0f, 0.0f));
    modelMat = glm::scale(modelMat, parentEntity.scale);
    int modelMatrixLoc = glGetUniformLocation(shader, "modelMatrix");
    glUniformMatrix4fv(modelMatrixLoc, 1, false, &modelMat[0][0]);
}

这就是我的顶点着色器中的内容:

in vec3 position;
out vec3 FragPos;
out vec3 Normal;

uniform mat4 projectionMatrix;
uniform mat4 viewingMatrix;
uniform mat4 modelMatrix;
uniform mat4 lightMatrix;

void main()
{
    vec4 transformedPosition = projectionMatrix * viewingMatrix * modelMatrix * lightMatrix * vec4(position, 1.0f);

    gl_Position = transformedPosition;
    FragPos = vec3(modelMatrix * vec4(position, 1.0));
    Normal = mat3(transpose(inverse(modelMatrix))) * position;
}

片段着色器:

out vec4 outColor;
in vec3 Normal;
in vec3 FragPos;

uniform vec3 lightPos;
uniform vec3 objectColor;
uniform vec3 lightColor;
uniform vec3 viewPos;

void main()
{
    float ambientStrength = 0.06;
    vec3 ambient = ambientStrength * lightColor;

    vec3 norm = normalize(Normal);
    vec3 lightDir = normalize(lightPos - FragPos);
    float diff = max(dot(norm, lightDir), 0.0);
    vec3 diffuse = diff * lightColor;

    float specularStrength = 0.6;
    vec3 viewDir = normalize(viewPos - FragPos);
    vec3 reflectDir = reflect(-lightDir, norm);
    float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32);
    vec3 specular = specularStrength * spec * lightColor;
    vec3 result = (ambient + diffuse + specular) * objectColor;
    outColor = vec4(result, 1.0);
}

如何只旋转光源而不旋转物体?

【问题讨论】:

  • 你设置了两次模型矩阵,这是故意的吗? lightMatrix 是做什么的?它似乎没有以任何方式修改照明计算。 lightPos 在哪个空间给出?从代码中可以看出,当在世界空间中给出lightPosviewPos 时,灯光应该保持在同一位置。
  • 没有。我只试过这个,我看到光会随着物体旋转。否则我不确定如何让它旋转,我应该删除与“lightMatrix”相关的部分代码吗?
  • 目前 lightMatrix 不影响光照。你需要做的是在设置这个统一之前用这个矩阵转换lightPos。并完全离开顶点着色器中的 lightMatrix。我会写一个答案。

标签: opengl graphics sdl sdl-2 opengl-3


【解决方案1】:

如果要旋转光源,则必须变换lightPos 而不是旋转模型。这也更有效,因为它每帧只需要一个矩阵变换(而不是每个顶点一个)。代码应如下所示:

// C++
glm::vec4 lightPos(...) // <-- The light position you currently use

glm::mat4 lightM(1.0f);
lightM = glm::rotate(lightM, lightRotation.z, glm::vec3(0.0f, 0.0f, 1.0f));
lightM = glm::rotate(lightM, lightRotation.y, glm::vec3(0.0f, 1.0f, 0.0f));
lightM = glm::rotate(lightM, lightRotation.x, glm::vec3(1.0f, 0.0f, 0.0f));

glm::vec4 rotatedLightPos = lightM * lightPos;

glUniform3f(lightPosLocation, rotatedLightPos.x, rotatedLightPos.y, rotatedLightPos.z);

顶点着色器:

// GLSL
in vec3 position;
out vec3 FragPos;
out vec3 Normal;

uniform mat4 projectionMatrix;
uniform mat4 viewingMatrix;
uniform mat4 modelMatrix;

void main()
{
    vec4 transformedPosition = projectionMatrix * viewingMatrix * modelMatrix * vec4(position, 1.0f);

    gl_Position = transformedPosition;
    FragPos = vec3(modelMatrix * vec4(position, 1.0));
    Normal = mat3(transpose(inverse(modelMatrix))) * position;
}

片段着色器保持原样。

【讨论】:

  • 很抱歉,您在哪里定义您在lightM = glm::rotate(lightM, lightRotation.z, glm::vec3(0.0f, 0.0f, 1.0f)); 中使用的lightRotation
  • 这定义了你想要旋转多少光源。我猜你已经在某个地方有了它。
  • 我正在使用这些来旋转:lightPos.x = 1.0f + sin(glfwGetTime()) * 2.0f;lightPos.y = sin(glfwGetTime() / 2.0f) * 1.0f;
  • 哦,对不起,我错过了。那完全是我的错。在这种情况下,您只需从顶点着色器中删除 lightMatrix,一切都应该正常工作。
  • 这里出现错误:glm::vec4 rotatedLightPos = lightM * lightPos;error: no match for ‘operator*’ (operand types are ‘glm::mat4 {aka glm::tmat4x4&lt;float, (glm::precision)0&gt;}’ and ‘glm::vec3 {aka glm::tvec3&lt;float, (glm::precision)0&gt;}’)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-15
相关资源
最近更新 更多