正常的映射消失了可怕的错误

我试图在我的opengl应用程序中实现正常的映射,但我无法得到它的工作。

这是漫reflection地图(我添加了一个棕色), 这是正常的地图。

为了得到切线和苦行(在其他地方叫binormals?)向量,我运行这个函数为我的网格中的每个三angular形:

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; } 

我得到的图像是完全不正确的。 (灯光定位在相机上) 可怕的结果

我在这里做错了什么?

我敢打赌,片段着色器中的颜色设置/混合…

  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. 首先尝试正常/凹凸阴影

    忽略环境,reflection,镜面reflection…然后如果有效的话,逐个添加其余的。 总是检查着色器的编译日志

懒得进一步分析你的代码,所以这里是我如何做到这一点:

凹凸映射的例子

左尺寸是固定function呈现的太空飞船物体(类似于ZXS Elite的Viper)。 右侧是相同的(有点不同的对象旋转)与GLSL着色器的地方和这个正常/凹凸贴图

在这里输入图像描述

[顶点]

 //------------------------------------------------------------------ #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; pw=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; pw=1.0; pixel_TBN[0]=normalize((tm_l2g_dir*p).xyz); p.xyz=bin.xyz; pw=1.0; pixel_TBN[1]=normalize((tm_l2g_dir*p).xyz); p.xyz=nor.xyz; pw=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; } //------------------------------------------------------------------ 

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

所以只提取你需要的东西。 如果你对variables名称感到困惑,那么评论我…

  • tm_代表变换matrix
  • l2g代表局部坐标系对全局坐标系的变换
  • dir表示变换正好变向(偏移量为0,0,0)
  • g2s代表全球屏幕…
  • perangular度转换…

GLSL编译日志

在编译你的着色器(不是应用程序!!!)之后,你必须获得它的内容programaticaly。 我这样做,调用函数glGetShaderInfoLog为每个着色器,我使用的程序…

[笔记]

一些驱动程序优化“未使用”的variables。 正如你可以在图像中看到txr_texture1即使片段着色器在代码中没有find,但混合没有在这个应用程序中使用,所以驱动程序删除它自己…

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

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

GLSL IDE

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

TBN创build可能也有问题

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

法线

我会尽量让你的代码工作。 你有移动相机试过吗?

我看不到任何你已经用转换,视图和模型matrix转换TBNMatrix地方。 你有没有尝试vec3 normal = TBNMatrix[2]; 原来的法线? (片段着色器)

以下可能会有所帮助。 在顶点着色器中有:

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

但是在这里,只有这三个matrix应该使用:

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

计算CPU上这些matrix的乘积会更有效率(因为matrix乘法是相关的,所以产生相同的结果)。 那么这个产品,PCM可以用来计算每个顶点有一个乘法的新位置:

 gl_Position = PCM * vec4(vertex, 1.0); 

MIT是模型matrix的逆转置,你必须在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)); 

我不确定切线和苦行会发生什么事情,但这样正常情况下会保持垂直。 这很容易certificate。 这里我使用a°b作为a和b向量的标量积。 所以设n是一个正规的,而a是表面上的某个vektor(例如,三angular形的{bi}切线,边),并且设A是任意的变换。 然后:

0 = an = A ^( – 1)A a°n = A a°A ^( – T)n = 0

我在哪里使用了等式A xy y = x°A ^ T y。 因此,如果a垂直于n,则A a垂直于A ^( – T)n,所以我们必须用matrix的逆转置来转换它。 但是,正常的长度应该是1,所以在转换之后,应该正常化。

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

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

如果交叉(a,b)是计算a和b交叉积的函数,则女巫总是垂直于a和b。

对不起我的英语不好 :)