c++ - 片段着色器输出不受旋转影响

标签 c++ opengl fragment-shader vertex-shader

我正在编写一个应该实现 Phong 照明模型的着色器。问题是我没有使用 glRotatef 和这些函数,而是将缩放和平移 vector 和旋转矩阵传递给着色器。我在屏幕上画了一个茶壶,看起来不错,除了我旋转它的时候。灯似乎没有移动,就好像灯被连接到茶壶上并随之旋转一样。

顶点着色器:

#version 120

varying vec3 normal, position;
uniform vec3 scale, translation;
uniform mat4 rotation;

void main()
{
    vec4 vertex= (gl_Vertex * rotation) * vec4(scale,1.0) + vec4(translation,0.0);
    gl_Position= gl_ProjectionMatrix * gl_ModelViewMatrix *vertex ;
    normal= normalize(gl_NormalMatrix * gl_Normal);
    position= vec3(gl_ModelViewMatrix * gl_Vertex);
}

片段着色器:

#version 120

#pragma optionNV( unroll none)

uniform int model;
// 1: phong, 2: blinn-phong
varying vec3 normal, position;
// 1: directional, 2:point, 3:spot
uniform int lightType;
uniform float spotExponent;


vec4 phong(vec3 L, vec3 N, vec3 V, int light) {
    float LdotN= max(dot(L,N),0.0);
    vec3 R= 2.0 * LdotN * N - L;
    vec4 color= gl_FrontMaterial.ambient * gl_LightSource[light].ambient;
    color+= gl_FrontMaterial.diffuse * gl_LightSource[light].diffuse * LdotN;
    color+= gl_FrontMaterial.specular * gl_LightSource[light].specular * pow(max(dot(R,V),0.0),gl_FrontMaterial.shininess);
    return color;
}

vec4 blinnPhong(vec3 L, vec3 N, vec3 V, int light) {
    float LdotN= max(dot(L,N),0.0);
    vec3 H= normalize(L+V);
    vec4 color= gl_FrontMaterial.ambient * gl_LightSource[light].ambient;
    color+= gl_FrontMaterial.diffuse * gl_LightSource[light].diffuse * LdotN;
    color+= gl_FrontMaterial.specular * gl_LightSource[light].specular * pow(max(dot(H,N),0.0),gl_FrontMaterial.shininess);
    return color;
}

float norm(vec3 v) {
    return sqrt(v.x*v.x + v.y*v.y + v.z*v.z);
}

float pointLightAttenuation(float range, int light) {
    float distance= norm(gl_LightSource[light].position.xyz - position);
    if(distance > range)
        return 0.0;
    else
        return max(1.0,1.0/(gl_LightSource[light].quadraticAttenuation*distance*distance+gl_LightSource[light].linearAttenuation*distance+gl_LightSource[light].constantAttenuation));
}

float spotLightAttenuation(vec3 L, int light)  
{
    //return pow(max(dot(normalize(gl_LightSource[light].spotDirection),-L),0.0),spotExponent);
    return max(dot(normalize(gl_LightSource[light].spotDirection),-L),0.0);
}


void main()
{
    vec3 N= normalize(normal);
    vec3 L;
    float attenuation= 1.0;
    if(lightType== 1) { 
        // If light is directional
        L= normalize(- position);
    }
    else {
        L= normalize(gl_LightSource[0].position.xyz - position);
        attenuation= pointLightAttenuation(90.0,0);
        if(lightType== 3)
            attenuation*= spotLightAttenuation(L,0);
    }
    vec3 V= -normalize(position);
    if(model==1)
        gl_FragColor= attenuation * phong(L,N,V,0);
    else
        gl_FragColor= attenuation * blinnPhong(L,N,V,0);
}

我已经调试了着色器,我认为输出计算没有问题,除了它没有考虑对象旋转之外。所以我建议不要过分关注Phong方程的计算。

这是旋转前绘制的茶壶截图:

enter image description here

这是绕 Y 轴旋转后的:

enter image description here

就像你看到的那样,如果光随着茶壶一起移动,但是光在一个固定的位置:总是 (0,0,-15) !

最佳答案

The problem is that I am not using glRotatef and these functions, instead I am passing a scale and translate vector, and a rotation matrix to the shader.

是的,但是您只能使用它们来计算顶点的裁剪空间位置。您用于计算光照的值(将它们放入 varyings 并在片段着色器中获取插值后)仍然仅使用旧的内置矩阵进行计算,因此您的光照计算不会以与几何体相同的方式进行转换.

所以只是改变

normal= normalize(gl_NormalMatrix * gl_Normal);
position= vec3(gl_ModelViewMatrix * gl_Vertex);

normal = normalize(gl_NormalMatrix * ((gl_Normal * mat3(rotation)) / scale));
position = vec3(gl_ModelViewMatrix * vertex);

但老实说,在绘制任何内容之前,只需根据三个参数计算出一个合适的矩阵并将其乘以 CPU 上的模型 View 矩阵,效果会好得多,因为您仍在使用 gl_ModelViewMatrix 无论如何计算顶点位置(考虑到您似乎没有将其设置为任何值是否有必要是一个不同的问题,尽管如此)。我现在也将忽略您与 rotation 矩阵的乘法实际上与 OpenGL 通常使用的顺序相反(并且您将自己与其他矩阵一起使用),假设您知道这一点并且知道自己在做什么。

关于c++ - 片段着色器输出不受旋转影响,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20070511/

相关文章:

c++ - 推断可变模板参数包元素的类型

c++ - 如何分割白板区域?

c++ - 将 std::vector 作为参数传递给函数时出现 EXC_BAD_ACCESS

ios - 来自 MTLBuffer 问题的 MTLTexture

shader - AGAL seq 操作码适用于硬件,但不适用于软件仿真(两者的 float 比较不同?)

C++11 智能指针 Make 可变大小对象函数

c++ - 使用自动引用类在 C++ 中创建堆栈时出现问题

c++ - 使用 GlDrawElements() 绘制立方体?

c++ - 高斯模糊永远无法正常工作

c++ - 如何在渲染全屏四边形时在片段着色器中获取查看方向