随笔 - 833  文章 - 1  评论 - 106  阅读 - 200万

Bump mapping的GLSL实现 [转]

原文 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.0f0.0f0.0f);
                        InvBinormal = Vector3f(0.0f1.0f0.0f);
                        InvNormal = Vector3f(0.0f0.0f1.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);
}
复制代码
posted on   3D入魔  阅读(1117)  评论(0编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
历史上的今天:
2011-06-24 std::set用法(转)
2011-06-24 STL中map用法详解(转)
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

点击右上角即可分享
微信分享提示