- ParallaxMapping是传统BumpMapping的一个变种,其原理是根据表面高度纹理和当前视点朝向对纹理坐标进行偏
- 移,以为凹凸表面添加视差效果.
- 优点:相对于更为复杂而开销巨大的技术(Relief Mapping和Displacement Mapping),Parallax Mapping以较少的
开销完全对视差效果的良好近似.避免了RelefMapping庞大计算量和DisplacementMapping多边形自镶嵌的开销. - 缺点:由于ParallaxMapping本身只是一种近似,所以必然存在对准确效果的许多近似计算.例如:在处理高度变化
- 频率太多的表面上会出现严重走样;并未考虑真实凹凸表面自身遮挡;并未对真实凹凸表面由于视差导致的轮廓进
- 行仿真.
- 实现细节:为了屏蔽由于不同表面方面所导致的不一致性,切空间变换矩阵的TBN各向量必须先变换到照相机空间,
- 并且使视向量和光向量同处于一个坐标系统,然后再进行切空间的变换.
- 以下为着色器代码:
Vertex Shader:
// 切空间变换矩阵各列
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);- // 世界空间视点坐标
uniform vec3 g_vec3ViewCoord;
// 世界空间光源坐标
uniform vec3 g_vec3LightCoord; - // 纹理坐标
varying vec2 g_vec2TexCoord;
// 切空间光向量
varying vec3 g_vec3LightDirection;
// 切空间视向量
varying vec3 g_vec3ViewDirection; - // 入口函数
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;
} - Fragment Shader:
// 材质属性
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;- // ParallaxMapping缩放和偏移值
const float g_fScale = 0.04;
const float g_fBias = g_fScale*0.5; - uniform bool g_bOffset; // 是否进行偏移的标志
- uniform sampler2D g_ColorTexture; // 墙颜色纹理
uniform sampler2D g_NormalTexture; // 墙法线纹理
uniform sampler2D g_HeightTexture; // 墙高度纹理 - // 纹理坐标
varying vec2 g_vec2TexCoord;
// 切空间光向量
varying vec3 g_vec3LightDirection;
// 切空间视向量
varying vec3 g_vec3ViewDirection; - 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 ); - // 规范化光向量
vec3 vec3LightDirection = normalize(g_vec3LightDirection); - // 计算散射因子
float fDiffuseGene = max(dot(vec3LightDirection, vec3Normal), 0.0); - // 计算镜面因子
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);
} - 效果截图:
- exe文件:http://www.fileden.com/files/2009/4/12/2401496/ParallaxMapping.rar
- 参考文献:ShaderX3:Parallax Mapping
ParallaxMapping
最新推荐文章于 2022-06-12 15:28:17 发布