OpenGL.Shader: 8-Learning Light-Normal Matrix

OpenGL.Shader: 8-Learning Light-Normal Matrix

 

 El artículo anterior registró el conocimiento básico de los vectores normales de iluminación y principios simples de cálculo de iluminación. Se puede ver en las representaciones que la fuente de luz cambia con la posición de la cámara, y cada lado del cubo presenta diferentes efectos oscuros. ¿Qué pasa si el modelo cambia si la posición de la fuente de luz no cambia? De acuerdo con lo que hemos aprendido antes, la posición del modelo cambia y necesita ser multiplicada por la matriz mvp, entonces, ¿se puede multiplicar el vector normal por la matriz mvp?

Demostración de errores, use directamente mvp como matriz normal

#version 320 es
uniform mat4   _mvp;
uniform mat3   _normalMatrix;
uniform vec3   _lightDir;
uniform vec3   _lightColor;
uniform vec3   _lightDiffuse;
in      vec3   _position;
in      vec3   _normal;
in      vec2   _uv;
out     vec2   _outUV;
out     vec4   _outComposeColor;
void main()
{
    _outUV                =   _uv;
    vec3    normal        =   normalize(_normalMatrix * _normal); //输入法线*法线矩阵 再归一化
    float lightStrength   =   max(dot(normal, -_lightDir), 0.0);
    _outComposeColor =   vec4(_lightColor * lightStrength + _lightDiffuse, 1);
    gl_Position      =   _mvp * vec4(_position,1.0);
}

#version 320 es
precision mediump float;
in      vec4        _outComposeColor;
in      vec2        _outUV;
uniform sampler2D   _texture;
out     vec4        _fragColor;
void main()
{
    vec4    color   =   texture(_texture,_outUV);
    _fragColor      =   color * _outComposeColor;
}

Primero pegamos el grupo de programas de sombreado usado, introducimos uniform mat3 _normalMatrix; la matriz normal usada para cambiar el vector normal, normalizamos (_normalMatrix * _normal); obtenemos el vector normal cambiado y luego realizamos el cálculo de iluminación.

    void    render(Camera3D& camera)
    {
        sprogram.begin();
        static  float   angle = 0;
        angle += 0.3f;
        CELL::matrix4   matRot;
        matRot.rotateYXZ(angle, 0.0f, 0.0f);
        // 这里的模型矩阵只进行简单进行旋转操作。
        CELL::matrix4   model   =   mModelMatrix * matRot; //mModelMatrix只是一个简单的单位矩阵
        CELL::matrix4   vp = camera.getProject() * camera.getView();
        CELL::matrix4   mvp = (vp * model);
        glUniformMatrix4fv(sprogram._mvp, 1, GL_FALSE, mvp.data());
        // 设置法线矩阵 为 mvp
        glUniformMatrix3fv(sprogram._normalMatrix, 1, GL_FALSE, mat4_to_mat3(mvp).data());

        glActiveTexture(GL_TEXTURE0);
        glEnable(GL_TEXTURE_2D);
        glBindTexture(GL_TEXTURE_2D,  mCubeSurfaceTexId);
        glUniform1i(sprogram._texture, 0);

        glUniform3f(sprogram._lightDiffuse, 0.1f, 0.1f, 0.1f); // 漫反射 环境光
        glUniform3f(sprogram._lightColor, 1.0f, 1.0f, 1.0f); // 定向光源的颜色
        glUniform3f(sprogram._lightDir, // 定向光源的方向
                    static_cast<GLfloat>(camera._dir.x),
                    static_cast<GLfloat>(camera._dir.y),
                    static_cast<GLfloat>(camera._dir.z));

        glVertexAttribPointer(static_cast<GLuint>(sprogram._position), 3, GL_FLOAT, GL_FALSE,
                              sizeof(CubeIlluminate::V3N3T2), &_data[0].x);
        glVertexAttribPointer(static_cast<GLuint>(sprogram._normal),   3, GL_FLOAT, GL_FALSE,
                              sizeof(CubeIlluminate::V3N3T2), &_data[0].nx);
        glVertexAttribPointer(static_cast<GLuint>(sprogram._uv),       2, GL_FLOAT, GL_FALSE,
                              sizeof(CubeIlluminate::V3N3T2), &_data[0].u);
        glDrawArrays(GL_TRIANGLES, 0, 36);
        sprogram.end();
    }
//-------------------------------
    tmat3x3<T> mat4_to_mat3(const tmat4x4<T> & m)
    {
        return  tmat3x3<T>(
                tvec3<T>(m[0][0],m[0][1],m[0][2])
                ,tvec3<T>(m[1][0],m[1][1],m[1][2])
                ,tvec3<T>(m[2][0],m[2][1],m[2][2]));
    }

Luego pegue la configuración de los parámetros de renderizado y simplemente gire a lo largo del eje Y. Una cosa a tener en cuenta es que el vector normal es de tipo vec3, que solo representa la dirección y no tiene información de posición. mvp es una matriz de 4x4, por lo que los dos no se pueden multiplicar directamente Personalice el método mat4_to_mat3 para eliminar el componente w.

Se puede ver en el renderizado que el cálculo de iluminación es anormal después de la rotación automática. Deslice manualmente la lente para que la iluminación y el modelo parezcan normales nuevamente después de alcanzar el ángulo especificado. ¿Por qué esto es tan? Analicemos brevemente los principios matemáticos subyacentes:

En OpenGL ES 2.0, un vértice se convierte al sistema de coordenadas del ojo mediante:
                                             vertexEyeSpace = view_Matrix * model_Matrix * vértice;
entonces, ¿por qué no podemos hacer el mismo trabajo como un vector normal? Primero, el vector normal es un vector de 3 flotadores y la matriz modelView es una matriz de 4X4. Esto se puede lograr con el siguiente código:
                                            normalEyeSpace = vec3 (view_Matrix * model_Matrix * vec4 (normal, 0.0));
Hay un problema potencial arriba: el
       vértice es (x, y, z) que representa el vector predeterminado (x, y, z, 1); y el vector normal es un vector direccional sin un punto fijo. Porque el vector normal se puede obtener restando dos vértices fijos (x1, y1, z1,1) y (x2, y2, z2,1) sobre la normal. Por tanto, desde este punto se puede ver que el vértice es diferente del vector normal, lo que resulta en una transformación invisible. El vector normal solo puede garantizar la consistencia de la dirección, pero no la consistencia de la posición.

En la imagen de arriba vemos un triángulo con un vector normal y un vector plano tangente La siguiente imagen muestra la escena cuando se amplía una matriz de observación. Si todavía llamamos al código anterior:

Como se muestra arriba, la matriz de observación afecta a todos los vértices y normales, obviamente este resultado es incorrecto, las normales no son perpendiculares al plano tangente. Entonces ahora sabemos que la matriz de observación no se puede aplicar a todas las normales. Entonces, ¿qué matriz deberíamos usar para transformar el vector normal? Eche un vistazo a la solución en la siguiente tabla.

De la derivación en el cuadro de arriba, podemos ver que si queremos transformar el vector u correspondiente a la matriz A, si queremos asegurarnos de que el vector normal todavía es perpendicular al vector tangente correspondiente después de la transformación, entonces lo haremos Solo es necesario realizar una transformación de matriz inversa en el vector vertical, para que no tengamos que preocuparnos por la situación correspondiente a la imagen de arriba, y la transformación de matriz inversa es el resultado correcto que esperamos.

La conclusión final es matriz transpuesta = matriz inversa del modelo matriz transformada normal

    void        render(Camera3D& camera)
    {
        sprogram.begin();
        static  float   angle = 0;
        angle += 0.1f;
        CELL::matrix4   matRot;
        matRot.rotateYXZ(angle, 0.0f, 0.0f);
        // 这里的模型矩阵只进行简单进行旋转操作。
        CELL::matrix4   model   =   mModelMatrix * matRot;
        // 法线矩阵 = 模型矩阵的逆矩阵的转置
        CELL::matrix3   matNormal=   mat4_to_mat3(model)._inverse()._transpose();
        glUniformMatrix3fv(sprogram._normalMatrix, 1, GL_FALSE, matNormal.data());

        CELL::matrix4   vp = camera.getProject() * camera.getView();
        CELL::matrix4   mvp = (vp * model);
        glUniformMatrix4fv(sprogram._mvp, 1, GL_FALSE, mvp.data());

        glActiveTexture(GL_TEXTURE0);
        glEnable(GL_TEXTURE_2D);
        glBindTexture(GL_TEXTURE_2D,  mCubeSurfaceTexId);
        glUniform1i(sprogram._texture, 0);
        ... ...
    }

El efecto de actualización es el siguiente: Puede ver que el efecto de iluminación final es correcto ya sea girando el modelo o deslizando manualmente la cámara para cambiar la posición de la fuente de luz.

Enlace del proyecto de demostración https://github.com/MrZhaozhirong/NativeCppApp -> LightRenderer.cpp CubeIlluminate.hpp CubeIlluminateProgram.hpp 

Supongo que te gusta

Origin blog.csdn.net/a360940265a/article/details/93780849
Recomendado
Clasificación