OpenGL:旋转网格时出现照明问题

OpenGL: Problem with lighting when rotating mesh

我正在绘制一些静态几何体(球体、立方体等)和一些动态几何体(旋转环面)。

我可以看到有一个问题,因为圆环上的镜面光照是静态的,当旋转角度改变时圆环变暗...

我的目标是 OpenGL 2.1(桌面)、OpenGL ES2(移动)和 WebGL1(网络)。这里有一个gist with the full code. There is also a WebGL demo.

使用的框架是chronotext-cross。它提供了高于 GL 的抽象级别。它应该很容易理解。无论如何我都可以给作者指点。

C++ 代码,删节:

void Sketch::setup()
{
    Box()
        .setFrontFace(CCW)
        .setColor(0.75f, 0.75f, 0.75f, 1)
        .setSize(300, 5, 300)
        .append(geometryBatch, Matrix().translate(-150, -5, -150));

    Sphere()
        .setFrontFace(CCW)
        .setColor(0.25f, 1.0f, 0.0f, 1)
        .setSectorCount(60)
        .setStackCount(30)
        .setRadius(40)
        .append(geometryBatch, Matrix().translate(-75, -40, 100));

    Torus()
        .setFrontFace(CCW)
        .setSliceCount(20)
        .setLoopCount(60)
        .setInnerRadius(12)
        .setOuterRadius(48)
        .append(torusBatch, Matrix());
}

void Sketch::resize()
{
    camera
        .setFov(45)
        .setClip(0.1f, 1000.0f)
        .setWindowSize(windowInfo.size);
}

void Sketch::draw()
{
    camera.getViewMatrix()
        .setIdentity()
        .scale(1, -1, 1)
        .translate(0, 0, -400)
        .rotateX(-30 * D2R)
        .rotateY(15 * D2R);

    State state;
    state
        .setShader(shader)
        .setShaderMatrix<MODEL>(Matrix())
        .setShaderMatrix<VIEW>(camera.getViewMatrix())
        .setShaderMatrix<PROJECTION>(camera.getProjectionMatrix())
        .setShaderMatrix<NORMAL>(camera.getNormalMatrix())
        .setShaderUniform("u_eye_position", camera.getEyePosition())
        .setShaderUniform("u_light_position", camera.getEyePosition())
        .setShaderUniform("u_shininess", 50.0f)
        .apply();

    geometryBatch.flush();

    Matrix modelMatrix;
    modelMatrix
        .translate(75, -60, 100)
        .rotateY(clock()->getTime());

    state
        .setShaderMatrix<MODEL>(modelMatrix)
        .apply();

    torusBatch.flush();
}

顶点着色器:

attribute vec4 a_position;
attribute vec3 a_normal;
attribute vec4 a_color;
attribute vec2 a_coord;

uniform mat4 u_model_matrix;
uniform mat4 u_view_matrix;
uniform mat4 u_projection_matrix;
uniform mat3 u_normal_matrix;
uniform vec3 u_eye_position;
uniform vec3 u_light_position;

varying vec3 v_normal;
varying vec4 v_color;
varying vec2 v_coord;
varying vec3 v_surface_to_light;
varying vec3 v_surface_to_view;

void main() {
  v_normal = u_normal_matrix * a_normal;
  v_color = a_color;
  v_coord = a_coord;

  v_surface_to_light = (u_view_matrix * (vec4(u_light_position, 1.0) - a_position)).xyz;
  v_surface_to_view = (u_view_matrix * (vec4(u_eye_position, 1.0) - a_position)).xyz;

  gl_Position = u_projection_matrix * u_view_matrix * u_model_matrix * a_position;
}

片段着色器:

#ifdef GL_ES
    precision highp float;
#endif

uniform sampler2D u_sampler;
uniform float u_shininess;

varying vec3 v_normal;
varying vec4 v_color;
varying vec2 v_coord;
varying vec3 v_surface_to_light;
varying vec3 v_surface_to_view;

void main() {
    vec3 normal = normalize(v_normal);

    vec3 surfaceToLightDirection = normalize(v_surface_to_light);
    vec3 surfaceToViewDirection = normalize(v_surface_to_view);
    vec3 halfVector = normalize(surfaceToLightDirection + surfaceToViewDirection);

    float specular = 0.0;
    float light = dot(normal, surfaceToLightDirection);
    if (light > 0.0) {
        specular = pow(dot(normal, halfVector), u_shininess);
    }

    vec4 color = v_color * texture2D(u_sampler, v_coord);
    gl_FragColor = vec4(color.rgb * light + specular, 1.0);
}

我找到了解决方案:在绘制动态网格时将一个新的法线矩阵(从模型视图矩阵中提取)传递给着色器。

    Matrix modelMatrix;
    modelMatrix
            .translate(75, -60, 100)
            .rotateY(clock()->getTime());

    Matrix modelViewMatrix = modelMatrix * camera.getViewMatrix();

    state
            .setShaderMatrix<MODEL>(modelMatrix)
            .setShaderMatrix<NORMAL>(modelViewMatrix.getNormalMatrix())
            .apply();