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

GLSL实现Ambient Occlusion 【转】

http://blog.csdn.net/a3070173/archive/2008/11/04/3221181.aspx

 

 

 相信使用OpenGl或DirectX3D的朋友都知道到固定功能管线在光照处理主要由环境光,散射光和镜面光构成,这样一个光照处理模型在被光 的地方将以统一的环境光进行着色,导致一种不自然的不真实效果.本文介绍的Ambient Occlusion方法将使用不当预计算的方式离线的生成模型的AO图,并在片元着色器中将对此AO图进行采样的结果与环境光和散射光效果进行相乘以适当 削弱环境光和散射光的强度,以增加模型的真实感.

那么什么是AO图呢?AO图其实是Ambient Occlusion纹理图的简称,其包含了模型各顶点的AO因子(即削弱因子).关于此削弱因子是如何计算的请参考http://www.ozone3d.net/tutorials/ambient_occlusion.php.这里只介绍效果的具体实现.

 由于这个效果主要在GLSL着色器上进行实现所以以下贴出的Ambient Occlusion着色器代码.
 顶点着色器:
uniform float g_fScale;

varying vec2 g_vec2TexCoord0;
varying vec3 g_vec3Normal;
varying vec3 g_vec3Vertex;

void main()
{
 g_vec2TexCoord0 = vec2(gl_MultiTexCoord0.s, 1.0 - gl_MultiTexCoord0.t);
 g_vec3Normal = vec3(gl_Normal);

    g_vec3Vertex = vec3(gl_Vertex);
    gl_Position = ftransform();
}

 片元着色器:
const vec3 g_vec3AmbientResult = vec3(0.2, 0.2, 0.2);
const vec3 g_vec3DiffuseResult = vec3(0.64, 0.64, 0.64);
const vec3 g_vec3SpecularResult = vec3(1.0, 1.0, 1.0);
const float g_fShininess = 100.0;

uniform vec3 g_vec3CameraPositinInModel; // 模型空间照相机位置
uniform vec3 g_vec3LightPositionInModel; // 模型空间光源位置

uniform sampler2D g_AmbientOcclusion;

uniform bool g_bUseAmbientGene; // 是否使用Ambient Occlusion的标志

varying vec2 g_vec2TexCoord0;
varying vec3 g_vec3Normal;
varying vec3 g_vec3Vertex;

void main()
{
 // 采样Ambient Occlusion因子
 float fAmbientGene = texture2D(g_AmbientOcclusion, g_vec2TexCoord0).r;

 // 计算散射因子
 vec3 L = normalize(g_vec3LightPositionInModel - g_vec3Vertex);
 vec3 N = normalize(g_vec3Normal);
 float fDiffuseGene = max(dot(N, L), 0.0);

 // 计算镜面光因子
 float fSpecularGene = 0.0;
 if (fDiffuseGene > 0.0)
 {
  vec3 V = normalize(g_vec3CameraPositinInModel - g_vec3Vertex);
  vec3 H = normalize(L + V);
  fSpecularGene = pow(max(dot(N, H), 0.0), g_fShininess);
 }

 // 计算最终颜色     
 if (g_bUseAmbientGene)
 {
  // Ambient Occlusion只影响环境和散射选项
  gl_FragColor = vec4(fAmbientGene*(g_vec3AmbientResult + 
      fDiffuseGene*g_vec3DiffuseResult) +
      fSpecularGene*g_vec3SpecularResult,
      1.0);
 }
 else
 {
  gl_FragColor = vec4(g_vec3AmbientResult + 
      fDiffuseGene*g_vec3DiffuseResult +
      fSpecularGene*g_vec3SpecularResult,
      1.0);
 }
}

 在整个着色过程中唯一需要注意的是由于AO图是上下颠倒的,所以带计算纹理坐标时需要将t坐标被1.0f相减.
 Demo效果图:
 不启动Ambient Occlusion:

 


 
 启动Ambient Occlusion:

 

posted on   3D入魔  阅读(1121)  评论(1编辑  收藏  举报
编辑推荐:
· 记一次.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

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