原文 http://www.cnblogs.com/CGDeveloper/archive/2008/07/03/1234206.html

如果物体表面细节很多,我们可以不断的精细化物体的几何数据,但是这样会产生大量的Lighting & Transformation等计算,
为了实现丰富真实的物体表面,除了贴上一般纹理之外,往往还使用Bump mapping(凹凸纹理)技术。
Bump mapping并没有增加物体的几何复杂度,它只是在计算物体的光照效果时作了“弊”,不使用物体本身的法向量,而是
使用了经过处理的法向量。如果这样的法向量使用normal map,我们可以使用GLSL实现凹凸效果。
首先,因为没有改变对象的几何形状,所以bump mapping的实现是在FS之中进行的,因此光照计算就必须在FS之中进行。
由于normal map之中的法向量是在SURFACE_LOCAL COORDINATE SPACE,所以用于光照计算的光源的方向和视向都
必须变换到同一空间进行光照计算。也就是说,必须使用所谓TBN矩阵的逆矩阵对光源的方向和视向进行变换,转换之后的值
作为varying传入到FS之中。
对于三角形mesh而言,TBN的一种计算方法如下:

void FindInvTBN(Vertor3f Vertices[3], Vector2f TexCoords[3], Vector3f & InvNormal,
                  Vector3f & InvBinormal, Vector3f & InvTangent) 
  {
                /* Calculate the vectors from the current vertex
                   to the two other vertices in the triangle */
  
                Vector3f v2v1 = Vertices[0] - Vertices[2];
                Vector3f v3v1 = Vertices[1] - Vertices[2];
  
                //Calculate the “direction” of the triangle based on texture coordinates.
  
                // Calculate c2c1_T and c2c1_B
                float c2c1_T = TexCoords[0].x() - TexCoords[2].x();
                float c2c1_B = TexCoords[0].y() - TexCoords[2].y();
  
                // Calculate c3c1_T and c3c1_B
                float c3c1_T = TexCoords[1].x() - TexCoords[2].x();
                float c3c1_B = TexCoords[1].y() - TexCoords[2].y();
  
                //Look at the references for more explanation for this one.
                float fDenominator = c2c1_T * c3c1_B - c3c1_T * c2c1_B;  
                /*ROUNDOFF here is a macro that sets a value to 0.0f if the value is a very small
                  value, such as > -0.001f and < 0.001. */
 
                /* EDIT by c programmer: you should NEVER perform an equality test against a floating point value, even if
                   your macro has set fDenominator to 0.0f.  The comparison can still fail.  The code needs fixed.
                   Instead you should check if fDenominator is within an epsilon value of 0.0f. */
 
                if (ROUNDOFF(fDenominator) == 0.0f) 
                {
                       /* We won't risk a divide by zero, so set the tangent matrix to the
                          identity matrix */
                        InvTangent = Vector3f(1.0f, 0.0f, 0.0f);
                        InvBinormal = Vector3f(0.0f, 1.0f, 0.0f);
                        InvNormal = Vector3f(0.0f, 0.0f, 1.0f);
                }
                else
                {            
                        // Calculate the reciprocal value once and for all (to achieve speed)
                        float fScale1 = 1.0f / fDenominator;
  
                        /* Time to calculate the tangent, binormal, and normal.
                           Look at Søren’s article for more information. */
                        Vector3f T, B, N;
                        T = Vector3f((c3c1_B * v2v1.x() - c2c1_B * v3v1.x()) * fscale1,
                                     (c3c1_B * v2v1.y() - c2c1_B * v3v1.y()) * fScale1,
                                     (c3c1_B * v2v1.z() - c2c1_B * v3v1.z()) * fScale1);
  
                        B = Vector3f((-c3c1_T * v2v1.x() + c2c1_T * v3v1.x()) * fScale1,                                     (-c3c1_T * v2v1.y() + c2c1_T * v3v1.y()) * fScale1,                                     (-c3c1_T * v2v1.z() + c2c1_T * v3v1.z()) * fScale1);                          N = T%B; //Cross product!  /*This is where programmers should break up the function to smooth the tangent, binormal and    normal values. */    //Look at “Derivation of the Tangent Space Matrix” for more information.                          float fScale2 = 1.0f / ((T.x() * B.y() * N.z() - T.z() * B.y() * N.x()) +                                                 (B.x() * N.y() * T.z() - B.z() * N.y() * T.x()) +                                                 (N.x() * T.y() * B.z() - N.z() * T.y() * B.x()));                        InvTangent.set((B%N).x() * fScale2,                                       ((-1.0f * N)%T).x() * fScale2,                                       (T%B).x() * fScale2);                        InvTangent.normalize();                          InvBinormal.set(((-1.0f *B)%N).y() * fScale2,                                        (N%T).y() * fScale2,                                        ((-1.0f * T)%B).y() * fScale2);                        InvBinormal.normalize();                          InvNormal.set((B%N).z() * fScale2,                                      ((-1.0f * N)%T).z() * fScale2,                                      (T%B).z() * fScale2);                        InvNormal.normalize();              }

上述计算中可以只计算T。
相应的VS如下:

varying vec3 LightDir;
varying vec3 EyeDir; attribute vec3 Tangent; void main()
{
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
    gl_TexCoord[0] = gl_MultiTexCoord0;     // 眼坐标系下的TBN
    vec3 n = normalize(gl_NormalMatrix * gl_Normal);
    vec3 t = normalize(gl_NormalMatrix * Tangent);
    vec3 b = cross(n, t);
    mat3 TBN = mat3(t, b, n);
    
    vec4 pos = gl_ModelViewMatrix * gl_Vertex;
    vec3 epos = vec3(pos)/pos.w;
    
    vec3 v = gl_LightSource[0].position.xyz - epos;
    v = v * TBN;
    LightDir = normalize(v);     v = -epos * TBN;
    EyeDir = normalize(v);
}

相应的FS如下:

uniform sampler2D BumpTex;
uniform sampler2D DecalTex; varying vec3 LightDir;
varying vec3 EyeDir; void main() 
{
    vec3 BumpNorm = vec3(texture2D(BumpTex, gl_TexCoord[0].xy));
    BumpNorm = (BumpNorm -0.5) * 2.0;
    
    vec4 DecalCol = texture2D(DecalTex, gl_TexCoord[0].xy);
    
    float NdotL = max(dot(BumpNorm, LightDir), 0.0);
    
    vec3 h = normalize(LightDir+EyeDir);
    float NdotH = max(dot(BumpNorm, h), 0.0);
    
    vec3 diffuse = vec3(NdotL * gl_LightSource[0].diffuse * DecalCol);
    vec3 specular = vec3(pow(NdotH, 6) * gl_LightSource[0].specular);
    
    gl_FragColor = vec4(diffuse + specular, 1.0);
}

Bump mapping的GLSL实现 [转]的更多相关文章

  1. 《The Cg Tutorial》阅读笔记——凹凸贴图 Bump Mapping

    本文为大便一箩筐的原创内容,转载请注明出处,谢谢:http://www.cnblogs.com/dbylk/p/5018103.html 凹凸贴图 Bump Mapping 一.简介 凹凸贴图用于在不 ...

  2. Directx11教程(42) 纹理映射(12)-简单的bump mapping

    原文:Directx11教程(42) 纹理映射(12)-简单的bump mapping        有时候,我们只有一个粗糙的模型,但是我们想渲染纹理细节,比如一个砖墙,我们如何在只有一个平面的时候 ...

  3. Parallax Occlusion Mapping in GLSL [转]

    http://www.sunandblackcat.com/tipFullView.php?topicid=28   This lesson shows how to implement differ ...

  4. 翻译:非常详细易懂的法线贴图(Normal Mapping)

    翻译:非常详细易懂的法线贴图(Normal Mapping) 本文翻译自: Shaders » Lesson 6: Normal Mapping 作者: Matt DesLauriers 译者: Fr ...

  5. Step deep into GLSL

    1 Lighting computation is handled in eye space(需要根据眼睛的位置来计算镜面发射值有多少进入眼睛), hence, when using GLSL (GP ...

  6. 翻译:GLSL的顶点位移贴图

    翻译:GLSL的顶点位移贴图 翻译自: Vertex Displacement Mapping using GLSL 译者: FreeBlues 说明: 之所以选择这篇文档, 是因为现在但凡提到位移贴 ...

  7. 在 OpenGL ES 2.0 上实现视差贴图(Parallax Mapping)

    在 OpenGL ES 2.0 上实现视差贴图(Parallax Mapping) 视差贴图 最近一直在研究如何在我的 iPad 2(只支持 OpenGL ES 2.0, 不支持 3.0) 上实现 视 ...

  8. 【ZZ】 移位贴图 Displacement Mapping

    http://blog.csdn.net/huazai434/article/details/5650629 说明:该技术需要VS3.0的支持!!! 一,移位贴图类似于地形渲染.不过由于移位纹理可以做 ...

  9. 3DShader之法线贴图(normal mapping)

    凹凸贴图(bump mapping)实现的技术有几种,normal mapping属于其中的一种,这里实现在物体的坐标系空间中实现的,国际惯例,上图先: 好了讲下原理 可以根据高度图生成法线量图,生成 ...

随机推荐

  1. Windows Phone 离主流系统还很远

    调查机构 Kantar Worldpanel 在本月发布全球智能手机份额报告.报告显示,五月份除德国和澳大利亚出现下滑,Windows Phone 的市场份额在不少国家都实现增长. 英国,4.1% 升 ...

  2. UVA 10047 The Monocycle

    大白图论第二题··· 题意:独轮车的轮子被均分成五块,每块一个颜色,每走过一个格子恰好转过一个颜色. 在一个迷宫中,只能向前走或者左转90度或右转90度(我曾天真的认为是向左走和向右走···),每个操 ...

  3. C# 委托总结

    总结 委托的本质: 委托是一种特殊的数据类型,它表示某种特定类型的函数,并且可以表示多个函数,将这些函数串联起来.使用委托就好像函数调用一样. 委托实质上是一个类,编译器会根据关键字delegate自 ...

  4. 程序破解之 API HOOK技术 z

    API HOOK,就是截获API调用的技术,在程序对一个API调用之前先执行你的函数,然后根据你的需要可以执行缺省的API调用或者进行其他处理,假设如果想截获一个进程对网络的访问,一般是几个socke ...

  5. SQL SERVER 实现分组合并实现列数据拼接

    需求场景: SQL SERVER 中组织的数据结构是一个层级关系,现在需要抓出每个组织节点以上的全部组织信息,数据示例如下: ADOrg_ID--------------ParentID------- ...

  6. selenium打开带有扩展的chrome

    每当用跑用例失败的时候,第一反应就是查看元素定位是不是正确,帮助定位的扩展是必不可少的,但是selenium一般打开的是不带扩展的干净的浏览器,如果操作步骤很长的话,就得手动去执行直到那一步去检查元素 ...

  7. 在这个年纪,打DOTA冲分有那么可笑么?

    大学四年,毕业两年,6年dota,总是在最无助的时候让心灵得到一丝安宁的东西,烟和dota. 我不知道dota对别人的意义是什么,一盘dota,在最多不超过1个半小时的时间里,仿佛经历了一个小人生,每 ...

  8. adb常用命令介绍

    adb connect 命令格式:adb connect <host>[:<port>] 作用:connect to a device via TCP/IP,Port 5555 ...

  9. HDFS分布式文件系统设计思想

    HDFS设计目标 1)硬件错误是常态,数据保存需要冗余. 2)数据批量读取,Hadoop擅长数据分析而不是事务处理. 3)大规模数据集. 4)简单一致醒模型,降低系统复杂度,文件一次写入多次读取, 5 ...

  10. POJ动态规划题目列表

    列表一:经典题目题号:容易: 1018, 1050, 1083, 1088, 1125, 1143, 1157, 1163, 1178, 1179, 1189, 1191,1208, 1276, 13 ...