视差计算一直都被我认为是难度比较高的计算,但是实际研究过后,其实还是比较简单的,相信经过这篇文章的简单介绍,各位会有个比较入门的认识。
首先什么是视差贴图,下面这个就是视差贴图:

当然这并不标准,正常的视差贴图应该是一张纹理的高度图,这是我用BaseColor转的,并且加强了对比度,也是为了让最终效果更加的明显。
那么接下来解释下视差的原理,请看图:
首先我们假设一个场景,场景内有有一个面片A,
然后这个面片A采样了一张视差贴图(单纯的采样,暂时不作视差计算),而渲染出来的灰度(高度)B

接下来我们进行多次的视差偏移,假设我们以某个高度偏移了2次,这时候我们得到了3层高度:

然后我们因为我们的贴图渲染时层层覆盖的关系,所以我们得讨巧下:使用上一次的深度,取反,假如比下一次要低,就继续往下覆盖
去改变我们的计算方法,那么这三条曲线就会变成这样:
B和B1的红叉并不是去掉的意思,而是在【红点】处被【截断】。

所以这样就能得出我们的计算过程了,放代码。
先看下这个最简单的,没有经过任何处理的,基于切线空间(贴图空间)的【视差代码公式】,没有它也不会有多种多样的视差变化:
相机世界空间坐标转切线空间,实际计算过程如下:
#define ParallaxStep 6
half3 TangentView.xyz = TransformWorldToTangent(WorldView.xyz);
ParallaxOffset.xy = TangentView.xy / TangentView.z;
half SampleEnd = 0;
//判断建议固定用常量,根据不同档位变化循环次数,实测5次以下也够用
for( int i=0 ; i < ParallaxStep; i++)
{
//每一次循环都增强视差的深度,并且获取上一次结果,取反,混合判断是否会被覆盖
uv += ParallaxOffset * ParallaxStrength*0.01 *(1-SampleEnd);
//再次采样
SampleEnd = tParallaxMap.SampleBias(sParallaxMapSampler,uv.xy,-2).r;
//最后这是一个优化手段,一旦发现不会被覆盖我们可以选择跳出循环了,不用再浪费时间计算了,阈值可以再低一点
//非uniform判断的动态分支,优化力度不会很高。
if( SampleEnd >=0.999)
break;
}
最后使用得到的最终uv去采样我们的贴图,输出颜色(法线、粗糙度同理)half3 BaseColor = tBaseMap.SampleBias(sBaseSampler,uv.xy,cBaseMapBias).rgb;
以下是效果截图:半透明渲染

地砖渲染,包含了法线,效果还是非常棒的
