视差贴图的拓展

视差映射技术

在我的上一篇文章里,有提到过基本的高度图的使用。具体的原理这里也不多解释,具体可以看回 基于物理的渲染PBR(三):视差贴图。而上一篇文章里介绍的,只是最基本的视差映射,其实它得到的采样点并不是百分百正确的。虽然Unity自带的视差处理是基础的近似值,但是通过查阅资料,我们可以更加精确的得到采样点,下面一一介绍几种视差映射算法。

陡峭视差映射

该方法的核心是把表面深度切分成等距的若干层,然后通过以视角方向为参考,比较自己定义的表面深度和实际的高度图。当表面深度大于高度图时,证明还没到实际的视角点,继续叠加纹理坐标直到找到第一个小于高度图的点,那一个点便取做真正的纹理坐标,具体的可以参考下图:
在这里插入图片描述
从上图得知,T3就是我们要求的纹理坐标,但我们不难看出,它离实际的视角接触到的高度图坐标还是有不小差距。所以,如果我们想要得到更加精确的结果,我们需要把层数增加,叠加的数值尽量的小,这样可以得到更加精确的结果。但是相应的,会增加性能上的开销,毕竟每次都需要采样得到高度图的值。下面列举核心代码:

float2 SteepParallax(float2 uv,float3 viewparallax)
            {
                //把切线空间的视角方向归一
                float3 v = normalize(viewparallax);
                //该操作是为了防止当视角方向和法线夹角过大时的意外情况
                v.z += 0.42;
                Layernum = 10;
                v.xy *= _ParallaxScale;
                //每层深度的增量
                float everyheight = 1.0 / Layernum;
                //当前的深度
                float currentheight = 0.0;
                //当前的纹理坐标
                float2 currenttex = uv;
                //纹理坐标的增量
                float2 dtex = v.xy / v.z / Layernum;
                //需要比较的高度图的值
                float currentheightmap = tex2Dlod(_ParallaxMap,float4(currenttex,0,0)).a;
                while(currentheightmap > currentheight)
                {
                    currentheight += everyheight;
                    currenttex += dtex;
                    currentheightmap = tex2Dlod(_ParallaxMap,float4(currenttex,0,0)).a;
                }
                return currenttex;
            }

基本就是先定义每层的深度,在计算层数深度、纹理坐标等的增量,然后通过循环去计算,需要注意的是在CG语言里,我们不能在for循环或者while循环里用tex2D,可以使用tex2Dlod代替。
下面是用陡峭视差映射的效果图。
在这里插入图片描述
我们可以看到它的锯齿非常的严重,那是因为我们的层数只设置了较为低的层数,得到的结果很多都是重复或者不是特别精确的,所以下面引入一个更加精确的方法,浮雕视差映射

浮雕视差映射

浮雕视差映射其实前半段方法跟陡峭视差映射相差不多,它的核心是在做完陡峭视差技术后,通过二分法进一步得到更精确的纹理坐标,每一次的搜索迭代都可以让精确度提升许多。我们先看下面的图。
在这里插入图片描述
通过上图,我们得到T3纹理坐标后,把一开始得到的高度增量和纹理坐标增量除以2,然后往反方向按陡峭视差计算下一个坐标点。同理,如果得到的结果深度是大于高度图的数值,那么继续按反方向计算,反之则往正方向,即图中的左边方向计算。每次计算时都把增量除以2,而计算的次数也是由我们决定,当然还是那句话,次数越多,纹理坐标越精确,但相应性能损耗也很高。下面是核心代码:

                ******//与陡峭视差映射一样,此处省略了
                //二分次数
                float numsearch = 5;
                for(int i = 0; i < numsearch; i ++)
                {
                    //把增量除以2
                    everyheight *= 0.5;
                    dtex *= 0.5;
                    currentheightmap = tex2Dlod(_ParallaxMap,float4(currenttex,0,0)).a;
                    //比较
                    if(currentheightmap < currentheight)
                    {
                        currenttex -= dtex;
                        currentheight -= everyheight;
                    }
                    else
                    {
                        currenttex += dtex;
                        currentheight += everyheight;
                    }
                }
                return currenttex;

下面是效果图:
在这里插入图片描述
可以很明显看到,锯齿少了非常多,但是该方法比陡峭映射更消耗性能,因此,我们又推出了另一种映射方法,视差遮蔽映射

视差遮蔽映射

该方法属于陡峭视差映射的另一种改进方法,它不使用二分法找精确点,因为在渲染里,循环操作是非常耗性能的,该方法使用的是对所得的两个近似结果进行插值,虽然它效果不如浮雕视差映射,但是性能比它好一点。

在这里插入图片描述
从上图,我们在陡峭视差映射里得到最后的结果和上一个结果,即H(T3)H(T2)进行插值,得到的结果Tp也可以近似的看作纹理坐标结果。下面列举核心代码:

                ******//与陡峭视差映射一样,此处省略了
                //得到上一个计算出的纹理坐标
                float2 prevtex = currenttex - dtex;
                //线性插值
                float afterHeight = currentheightmap - currentheight;
                float beforeHeight = tex2D(_ParallaxMap,prevtex).a - currentheight + everyheight;
                float weight = afterHeight / (afterHeight - beforeHeight);
                float2 finaltex = lerp(currenttex,prevtex,weight);
                return finaltex;

下面上结果图:

在这里插入图片描述
我们可以看到还是有轻微的锯齿的,但是比起陡峭会好很多,性能上也比浮雕好,如果想要得到更加精确的结果,只能在层数上进行增加。

最后在层数上的数据,在阅读其他文章中也有提到一个优化方法,就是设定一个最小层和最大层,而它的层数由视角和法线的角度作为一个基准,做两个数的一个线性插值,下面是具体代码:

                float minLayernum = 5;
                float maxlayernum = 15;
                float Layernum = lerp(minLayernum,maxlayernum,abs(dot(float3(0,0,1),v)));

最后再对比上一章给的,用基础的视差映射近似法得到的结果图:

在这里插入图片描述
咦,怎么回事。。。怎么效果这么好,其实这里我是不太懂的,如果有懂的老哥麻烦指导一下,我自己是觉得这个近似法的效果是最好的。。。可能跟贴图和高度图的复杂度也有关系吧

参考:

(译) GLSL 中的视差遮蔽映射(Parallax Occlusion Mapping in GLSL

Parallax Mapping需要翻墙

视差贴图(Parallax Mapping)

Parallax Mapping视差映射:模拟冰块

视差贴图(parallax mapping)学习笔记

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值