ParallaxMapping

  1. ParallaxMapping是传统BumpMapping的一个变种,其原理是根据表面高度纹理和当前视点朝向对纹理坐标进行偏
  2. 移,以为凹凸表面添加视差效果.
  3. 优点:相对于更为复杂而开销巨大的技术(Relief Mapping和Displacement Mapping),Parallax Mapping以较少的
    开销完全对视差效果的良好近似.避免了RelefMapping庞大计算量和DisplacementMapping多边形自镶嵌的开销.
  4. 缺点:由于ParallaxMapping本身只是一种近似,所以必然存在对准确效果的许多近似计算.例如:在处理高度变化
  5. 频率太多的表面上会出现严重走样;并未考虑真实凹凸表面自身遮挡;并未对真实凹凸表面由于视差导致的轮廓进
  6. 行仿真.
  7. 实现细节:为了屏蔽由于不同表面方面所导致的不一致性,切空间变换矩阵的TBN各向量必须先变换到照相机空间,
  8. 并且使视向量和光向量同处于一个坐标系统,然后再进行切空间的变换.
  9. 以下为着色器代码:
    Vertex Shader:

  10. // 切空间变换矩阵各列
    const vec3 g_vec3Tangment = vec3(1.0, 0.0, 0.0);
    const vec3 g_vec3Binormal = vec3(0.0, 1.0, 0.0);
    const vec3 g_vec3Normal = vec3(0.0, 0.0, 1.0);
  11. // 世界空间视点坐标
    uniform vec3 g_vec3ViewCoord;
    // 世界空间光源坐标
    uniform vec3 g_vec3LightCoord;
  12. // 纹理坐标
    varying vec2 g_vec2TexCoord;
    // 切空间光向量
    varying vec3 g_vec3LightDirection;
    // 切空间视向量
    varying vec3 g_vec3ViewDirection;
  13. // 入口函数
    void main()
    {
     // 计算照相机空间切变换矩阵各列
        vec3 vec3Tangment = vec3(gl_NormalMatrix*g_vec3Tangment);
        vec3 vec3Binormal = vec3(gl_NormalMatrix*g_vec3Binormal);
        vec3 vec3Normal = vec3(gl_NormalMatrix*g_vec3Normal);
       
        // 计算切空间光向量
     vec3 vec3Temp = gl_NormalMatrix*(g_vec3LightCoord - gl_Vertex.xyz);
        g_vec3LightDirection.x = dot(vec3Tangment, vec3Temp);
        g_vec3LightDirection.y = dot(vec3Binormal, vec3Temp);
        g_vec3LightDirection.z = dot(vec3Normal, vec3Temp);
       
        // 计算切空间视向量
        vec3Temp = -vec3(gl_ModelViewMatrix*gl_Vertex);
        g_vec3ViewDirection.x = dot(vec3Tangment, vec3Temp);
        g_vec3ViewDirection.y = dot(vec3Binormal, vec3Temp);
        g_vec3ViewDirection.z = dot(vec3Normal, vec3Temp);
       
     // 传递纹理坐标
     g_vec2TexCoord = gl_MultiTexCoord0.st;
     
     // 计算裁剪空间坐标
        gl_Position = gl_ModelViewProjectionMatrix*gl_Vertex;
    }
  14.  
  15. Fragment Shader:

  16. // 材质属性
    const vec3 g_vec3AmbientResult = vec3(0.2, 0.2, 0.2);
    const vec3 g_vec3DiffuseResult = vec3(0.8, 0.8, 0.8);
    const vec3 g_vec3SpecularResult = vec3(1.0, 1.0, 1.0);
    const float g_fShininess = 128.0;
  17. // ParallaxMapping缩放和偏移值
    const float g_fScale = 0.04;
    const float g_fBias = g_fScale*0.5;
  18. uniform bool g_bOffset; // 是否进行偏移的标志
  19. uniform sampler2D g_ColorTexture; // 墙颜色纹理
    uniform sampler2D g_NormalTexture; // 墙法线纹理
    uniform sampler2D g_HeightTexture; // 墙高度纹理
  20. // 纹理坐标
    varying vec2 g_vec2TexCoord;
    // 切空间光向量
    varying vec3 g_vec3LightDirection;
    // 切空间视向量
    varying vec3 g_vec3ViewDirection;
  21. void main()
    {
     // 采样高度纹理
     float fHeight = texture2D(g_HeightTexture, g_vec2TexCoord).x;
     
     // 规范化视向量
     vec3 vec3ViewDirection = normalize(g_vec3ViewDirection);
     
     // 计算经过缩放和偏移后的纹理坐标
     vec2 vec2TexCoord = !g_bOffset ? g_vec2TexCoord :
          ( (fHeight*g_fScale - g_fBias)*vec3ViewDirection.xy + g_vec2TexCoord );
     
     // 采样墙颜色纹理
     vec4 vec4SurfaceColor = texture2D(g_ColorTexture, vec2TexCoord);
     
     // 采样法线纹理
     vec3 vec3Normal = normalize( (texture2D(g_NormalTexture, vec2TexCoord).xyz - 0.5)*2.0 );
  22.  // 规范化光向量
     vec3 vec3LightDirection = normalize(g_vec3LightDirection);
  23.  // 计算散射因子
     float fDiffuseGene = max(dot(vec3LightDirection, vec3Normal), 0.0);
  24.  // 计算镜面因子
     float fSpecularGene = 0.0;
     if (fDiffuseGene > 0.0)
     {
      vec3 vec3HalfAngle = normalize(vec3ViewDirection + vec3LightDirection);
      fSpecularGene = pow(max(dot(vec3HalfAngle, vec3Normal), 0.0), g_fShininess);
     }
     
     // 计算最终颜色
        gl_FragColor = vec4((g_vec3AmbientResult + fDiffuseGene*g_vec3DiffuseResult)*vec4SurfaceColor.xyz
           + fSpecularGene*g_vec3SpecularResult, 1.0);
    }
  25.  
  26. 效果截图:
  27. parallaxmapping
  28. exe文件:http://www.fileden.com/files/2009/4/12/2401496/ParallaxMapping.rar
  29. 参考文献:ShaderX3:Parallax Mapping
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值