【问题标题】:Diffuse lighting for a moving object移动物体的漫射照明
【发布时间】:2020-07-18 09:03:35
【问题描述】:

在计算移动物体的漫反射光照时,我必须将光源与物体本身一起移动:

@Override
public void draw() { // draw frame
  ...
  // Move object
  GLES20.glVertexAttribPointer(aPositionLink, 3, GLES30.GL_FLOAT,
                    false, 0, object3D.getVertices());
  // The luminous source moves nearby the object, so the 
  // object is always illuminated from one side
  GLES20.glUniform3f(lightPositionLink, object3D.getX(),
        object3D.getY(), object3D.getZ() + 2.0f);
  ...
}

顶点着色器片段:

#version 300 es
uniform mat4 u_mvMatrix; // model-view matrix of object
uniform vec3 u_lightPosition; // position of the luminous source
in vec4 a_position; // vertex data is loaded here
in vec3 a_normal; // normal data is loaded here
struct DiffuseLight { 
  vec3 color; 
  float intensity; 
};
uniform DiffuseLight u_diffuseLight;
...
void main() {
  ...
  vec3 modelViewNormal = vec3(u_mvMatrix * vec4(a_normal, 0.0));
  vec3 modelViewVertex = vec3(u_mvMatrix * a_position);
  // calculate the light vector by subtracting the
  // position of the object from the light position
  vec3 lightVector = normalize(u_lightPosition - modelViewVertex);
  float diffuse = max(dot(modelViewNormal, lightVector), 0.1);
  float distance = length(u_lightPosition - modelViewVertex);
  diffuse = diffuse * (1.0 / (1.0 + pow(distance, 2.0)));
  // calculate the final color for diffuse lighting
  lowp vec3 diffuseColor = diffuse * u_diffuseLight.color * u_diffuseLight.intensity;
  v_commonLight = vec4((ambientColor + diffuseColor), 1.0);
  ...
}

这是正确的方法吗?或者是否有另一种使用固定光源的合理选择,以免在每帧计算光源的位置上花费资源?注意:增加距离没有帮助。提前致谢。

解决方案:

根据 Rabbid76 的建议,我按照here 的描述应用了定向光。

【问题讨论】:

    标签: java android opengl glsl shader


    【解决方案1】:

    我必须将光源连同物体本身一起移动

    为什么光源会随着物体移动?

    如果光是世界中的点光源,并且物体移动,那么物体的照明会发生变化(在“真实”世界中)。

    在您的情况下,照明是在视图空间中计算的。如果光源是世界上的一个点,那么你必须通过视图矩阵变换位置(视图矩阵从世界空间变换到视图空间)。例如:

    uniform mat4 u_viewMatrix;
    
    void main()
    {
        // [...]
    
        vec3 lightPosView = vec3(u_viewMatrix * vec4(u_lightPosition.xyz, 1.0)); 
        vec3 lightVector  = normalize(u_lightPosition - modelViewVertex);
    
        // [...]
    }
    

    无论如何,如果对象移动并且光源以某种方式锚定到对象,则您必须将应用于对象顶点的变换也应用于光源。
    在这种情况下,u_lightPosition 必须是对象模型空间中的一个位置,这意味着它相对于对象 (u_lightModelPosition)。然后你可以这样做:

    uniform vec3 u_lightModelPosition; 
    
    void main()
    {
        mat3 normalMat       = inverse(transpose(mat3(u_mvMatrix)));
        vec3 modelViewNormal = normalMat * a_normal;
        vec3 modelViewVertex = vec3(u_mvMatrix * a_position);
        vec3 modelViewLight  = vec3(u_mvMatrix * vec4(u_lightModelPosition, 1.0));
    
        vec3 lightVector = normalize(modelViewLight - modelViewVertex);
    
        // [...]
    }
    

    如果你想要一个不依赖于位置的灯,你必须使用定向灯。在那种情况下,光源不是世界上的一个点,它只是一个方向。例如:

    vec3 lightVector = -u_lightRayDirection;
    

    u_lightRayDirection 必须在光计算空间中。由于光照是在视图空间中计算的,u_lightRayDirection 也必须是视图空间中的一个方向。如果u_lightRayDirection是世界空间中的一个向量,那么它必须被mat3(u_viewMatrix)转换。
    定向光没有距离(或恒定距离)。


    如果光源固定在相机上,则根本不需要任何变换(因为您在视图空间中进行光照计算)。

    【讨论】:

    • 非常感谢您的详细解答!在我的例子中,一个移动的光源模拟了定向光(由于对理论的无知)。现在,根据您的建议,我应用了定向光并将其添加到解决方案中。
    猜你喜欢
    • 1970-01-01
    • 2017-09-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多