正常的映射非常错误

时间:2015-02-15 10:52:17

标签: opengl graphics glsl lighting

我试图在我的opengl应用程序中实现普通映射,但我无法让它工作。

This是漫反射贴图(我将其添加为棕色),this是法线贴图。

为了获得切线和bitangent(在其他地方称为binormals?)向量,我为网格中的每个三角形运行此函数:

void getTangent(const glm::vec3 &v0, const glm::vec3 &v1, const glm::vec3 &v2,
const glm::vec2 &uv0, const glm::vec2 &uv1, const glm::vec2 &uv2,
std::vector<glm::vec3> &vTangents, std::vector<glm::vec3> &vBiangents)
{
    // Edges of the triangle : postion delta
    glm::vec3 deltaPos1 = v1-v0;
    glm::vec3 deltaPos2 = v2-v0;

    // UV delta
    glm::vec2 deltaUV1 = uv1-uv0;
    glm::vec2 deltaUV2 = uv2-uv0;

    float r = 1.0f / (deltaUV1.x * deltaUV2.y - deltaUV1.y * deltaUV2.x);
    glm::vec3 tangent = (deltaPos1 * deltaUV2.y   - deltaPos2 * deltaUV1.y)*r;
    glm::vec3 bitangent = (deltaPos2 * deltaUV1.x   - deltaPos1 * deltaUV2.x)*r;

    for(int i = 0; i < 3; i++) {
        vTangents.push_back(tangent);
        vBiangents.push_back(bitangent);
    }
}

之后,我调用glBufferData将顶点,法线,uvs,切线和bitangents上传到GPU。 顶点着色器:

#version 430

uniform mat4 ProjectionMatrix;
uniform mat4 CameraMatrix;
uniform mat4 ModelMatrix;

in vec3 vertex;
in vec3 normal;
in vec2 uv;
in vec3 tangent;
in vec3 bitangent;

out vec2 fsCoords;
out vec3 fsVertex;
out mat3 TBNMatrix;

void main()
{
    gl_Position = ProjectionMatrix * CameraMatrix * ModelMatrix * vec4(vertex, 1.0);

    fsCoords = uv;
    fsVertex = vertex;

    TBNMatrix = mat3(tangent, bitangent, normal);
}

片段着色器:

#version 430

uniform sampler2D diffuseMap;
uniform sampler2D normalMap;
uniform mat4 ModelMatrix;
uniform vec3 CameraPosition;

uniform struct Light {
    float ambient;
    vec3 position;
} light;
uniform float shininess;

in vec2 fsCoords;
in vec3 fsVertex;
in mat3 TBNMatrix;

out vec4 color;

void main()
{
    //base color
    const vec3 brownColor = vec3(153.0 / 255.0, 102.0 / 255.0, 51.0 / 255.0);
    color = vec4(brownColor * (texture(diffuseMap, fsCoords).rgb + 0.25), 1.0);//add a fixed base color (0.25), because its dark as hell

    //general vars
    vec3 normal = texture(normalMap, fsCoords).rgb * 2.0 - 1.0;
    vec3 surfacePos = vec3(ModelMatrix * vec4(fsVertex, 1.0));
    vec3 surfaceToLight = normalize(TBNMatrix * (light.position - surfacePos)); //unit vector
    vec3 eyePos = TBNMatrix * CameraPosition;

    //diffuse
    float diffuse = max(0.0, dot(normal, surfaceToLight));

    //specular
    float specular;
    vec3 incidentVector = -surfaceToLight; //unit
    vec3 reflectionVector = reflect(incidentVector, normal); //unit vector
    vec3 surfaceToCamera = normalize(eyePos - surfacePos); //unit vector
    float cosAngle = max(0.0, dot(surfaceToCamera, reflectionVector));
    if(diffuse > 0.0)
        specular = pow(cosAngle, shininess);

    //add lighting to the fragment color (no attenuation for now)
    color.rgb *= light.ambient;
    color.rgb += diffuse + specular;
}

我得到的图像完全不正确。 (光线位于相机上) horrible results

我在这里做错了什么?

2 个答案:

答案 0 :(得分:7)

我的赌注是片段着色器中的颜色设置/混合......

  1. 您将输出颜色设置为多次

    如果我在某些gfx驱动程序上正确记得那些存在大问题的驱动程序,例如行之后的所有内容

    color = vec4(brownColor * (texture(diffuseMap, fsCoords).rgb + 0.25), 1.0);//add a fixed base color (0.25), because its dark as hell
    

    可以被驱动程序删除...

  2. 您要添加colorintensities而不是color*intensity

    但我可以忽略一些。

  3. 首先尝试正常/凹凸着色

    忽略环境,反射,镜面反射......然后如果有效则将其余部分逐一添加。始终检查着色器的编译日志

  4. 懒得进一步分析您的代码,所以我就是这样做的:

    bump mapping example

    左侧大小是具有固定功能的太空船对象(类似于ZXS Elite的Viper)。右侧相同(对象的旋转稍有不同), GLSL着色器就位,此正常/凹凸贴图

    enter image description here

    <强> [顶点]

    //------------------------------------------------------------------
    #version 420 core
    //------------------------------------------------------------------
    // texture units:
    // 0 - texture0 map 2D rgba
    // 1 - texture1 map 2D rgba
    // 2 - normal map 2D xyz
    // 3 - specular map 2D i
    // 4 - light map 2D rgb rgb
    // 5 - enviroment/skybox cube map 3D rgb
    
    uniform mat4x4 tm_l2g;
    uniform mat4x4 tm_l2g_dir;
    uniform mat4x4 tm_g2s;
    
    uniform mat4x4 tm_l2s_per;
    uniform mat4x4 tm_per;
    
    layout(location=0) in vec3 pos;
    layout(location=1) in vec4 col;
    layout(location=2) in vec2 txr;
    layout(location=3) in vec3 tan;
    layout(location=4) in vec3 bin;
    layout(location=5) in vec3 nor;
    
    out smooth vec3 pixel_pos;
    out smooth vec4 pixel_col;
    out smooth vec2 pixel_txr;
    //out flat   mat3 pixel_TBN;
    out smooth mat3 pixel_TBN;
    //------------------------------------------------------------------
    void main(void)
        {
        vec4 p;
        p.xyz=pos;
        p.w=1.0;
        p=tm_l2g*p;
        pixel_pos=p.xyz;
        p=tm_g2s*p;
        gl_Position=p;
        pixel_col=col;
        pixel_txr=txr;
        p.xyz=tan.xyz; p.w=1.0; pixel_TBN[0]=normalize((tm_l2g_dir*p).xyz);
        p.xyz=bin.xyz; p.w=1.0; pixel_TBN[1]=normalize((tm_l2g_dir*p).xyz);
        p.xyz=nor.xyz; p.w=1.0; pixel_TBN[2]=normalize((tm_l2g_dir*p).xyz);
        }
    //------------------------------------------------------------------
    

    <强> [片段]

    //------------------------------------------------------------------
    #version 420 core
    //------------------------------------------------------------------
    in smooth vec3 pixel_pos;
    in smooth vec4 pixel_col;
    in smooth vec2 pixel_txr;
    //in flat   mat3 pixel_TBN;
    in smooth mat3 pixel_TBN;
    
    uniform sampler2D   txr_texture0;
    uniform sampler2D   txr_texture1;
    uniform sampler2D   txr_normal;
    uniform sampler2D   txr_specular;
    uniform sampler2D   txr_light;
    uniform samplerCube txr_skybox;
    
    const int _lights=3;
    uniform vec3 light_col0=vec3(0.1,0.1,0.1);
    uniform vec3 light_dir[_lights]=         // direction to local star in ellipsoid space
        {
        vec3(0.0,0.0,+1.0),
        vec3(0.0,0.0,+1.0),
        vec3(0.0,0.0,+1.0),
        };
    uniform vec3 light_col[_lights]=         // local star color * visual intensity
        {
        vec3(1.0,0.0,0.0),
        vec3(0.0,1.0,0.0),
        vec3(0.0,0.0,1.0),
        };
    
    out layout(location=0) vec4 frag_col;
    
    const vec4 v05=vec4(0.5,0.5,0.5,0.5);
    const bool _blend=false;
    const bool _reflect=true;
    //------------------------------------------------------------------
    void main(void)
        {
        float a=0.0,b,li;
        vec4 col,blend0,blend1,specul,skybox;
        vec3 normal;
        col=(texture2D(txr_normal,pixel_txr.st)-v05)*2.0;       // normal/bump maping
    //  normal=pixel_TBN*col.xyz;
        normal=pixel_TBN[0];
        blend0=texture(txr_texture0,pixel_txr.st);
        blend1=texture(txr_texture1,pixel_txr.st);
        specul=texture(txr_specular,pixel_txr.st);
        skybox=texture(txr_skybox,normal);
    
        if (_blend)
            {
            a=blend1.a;
            blend0*=1.0-a;
            blend1*=a;
            blend0+=blend1;
            blend0.a=a;
            }
    
        col.xyz=light_col0; col.a=0.0; li=0.0;                          // normal shading (aj s bump mapingom)
        for (int i=0;i<_lights;i++)
                {
                b=dot(light_dir[i],normal.xyz);
                if (b<0.0) b=0.0;
    //          b*=specul.r;
                li+=b;
                col.xyz+=light_col[i]*b;
                }
        col*=blend0;
        if (li<=0.1)
            {
            blend0=texture2D(txr_light,pixel_txr.st);
            blend0*=1.0-a;
            blend0.a=a;
            col+=blend0;
            }
        if (_reflect) col+=skybox*specul.r;
            col*=pixel_col;
        if (col.r<0.0) col.r=0.0;
        if (col.g<0.0) col.g=0.0;
        if (col.b<0.0) col.b=0.0;
        a=0.0;
        if (a<col.r) a=col.r;
        if (a<col.g) a=col.g;
        if (a<col.b) a=col.b;
        if (a>1.0)
            {
            a=1.0/a;
            col.r*=a;
            col.g*=a;
            col.b*=a;
            }
        frag_col=col;
        }
    //------------------------------------------------------------------
    

    这些源代码有点旧,并且针对特定应用程序混合了不同的东西

    因此,只提取您需要的东西。如果您对变量名称感到困惑,那么请评论我......

    • tm_代表转换矩阵
    • l2g代表局部坐标系到全局坐标系变换
    • dir表示转换只改变方向(偏移量为0,0,0)
    • g2s代表全球屏幕......
    • per是透视变换......

    GLSL编译日志

    在编辑着色器之后,你必须以编程方式获取其内容(不是应用!!!)。我这样做是为每个着色器调用函数glGetShaderInfoLog,我使用的程序......

    <强> [注释]

    某些驱动程序会优化“未使用”的变量。正如您在图像txr_texture1中看到的那样,即使片段着色器在代码中有它,但在此App中没有使用混合,因此驱动程序也没有找到它,因此驱动程序自行删除它...

    着色器日志可以显示很多(语法错误,警告......)

    很少有GLSL IDE可以让着色器变得简单,但我更喜欢自己的,因为我可以直接在其中使用目标应用程序代码。我看起来像这样:

    GLSL IDE

    每个txt窗口都是着色器源(顶点,片段......),右下角是剪贴板,左上角是最后一次编译后的着色器日志,左下角是预览。我设法编写它像Borland样式IDE(键也和语法高亮)其他IDE看起来相似(不同颜色的粗:))无论如何你想玩着色器的下载这样的应用程序或自己做它会有很多帮助...

    TBN创建也可能存在问题

    通过在每个顶点位置绘制彩色线,您应目视检查 TBN 矢量(正切,正常,法线)是否与物体表面相对应。只是为了确定......这样的事情:

    normals

答案 1 :(得分:0)

我会尝试让你的代码工作。你用移动相机试过吗?

我无法看到你用变换,视图和模型矩阵转换TBNMatrix的任何地方。您尝试使用vec3 normal = TBNMatrix[2];原始法线吗? (片段着色器)

以下内容可能有所帮助。在Vertex着色器中,您有:

uniform mat4 ProjectionMatrix;
uniform mat4 CameraMatrix;
uniform mat4 ModelMatrix;

但是,这里只应使用这3个矩阵:

uniform mat4 PCM;
uniform mat4 MIT;         //could be mat3
uniform mat4 ModelMatrix; //could be mat3

在CPU上计算这些矩阵的乘积更有效(并且因为矩阵乘法是关联的,所以产生相同的结果)。然后这个产品,PCM可以用来计算每个顶点一次乘法的新位置:

gl_Position = PCM * vec4(vertex, 1.0);

MITModelMatrix的逆转置,你必须在CPU上计算它。这可以用于变换法线:

vec4 tang = ModelMatrix*vec4(tangent,0);
vec4 bita= ModelMatrix*vec4(bitangent,0);
vec4 norm= PCMIT*vec4(tangent,0);   
TBNMatrix = mat3(normalize(tang.xyz), normalize(bita.xyz), normalize(normal.xyz));

我不确定切线和切线会发生什么,但这样法线将保持垂直于它们。这很容易证明。这里我用a b作为a和b向量的skalar乘积。所以让n是正常的,a是表面上的一些vektor(例如,{bi}正切,三角形的边缘),并且让A成为任何变换。然后:

0 = a n = A ^( - 1)A a°n = A a°A ^( - T)n = 0

我使用等式A x°y = x°A ^ T y。因此,如果a垂直于n,则A a垂直于A ^( - T)n,因此我们必须使用矩阵的逆转置对其进行变换。 但是,法线的长度应为1,所以在转换之后,它应该被标准化。

通过这样做,你也可以得到垂直正常:

vec3 normal = normalize(cross(tangent, bitangent));

当cross(a,b)是计算a和b的叉积的函数时,巫婆总是垂直于a和b。

对不起我的英文:)