渲染6——凹凸

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wodownload2/article/details/82227310

扰乱法线模拟凹凸
用高度图计算法线
采样和混合高度图
切线空间转世界空间

本节是渲染得第六节课程。之前的一节介绍了多盏灯的使用,本节主要介绍给物体表面增加更多细节。

本节课程使用unity的版本为 5.4.0f3.
这里写图片描述

1 凹凸映射
我们可以使用漫反射贴图丰富物体表面的颜色形式。我们也可以利用法线增加表面的弯曲。这两种方法,可以产生各种各样的表面。但是,如果表面只有一个三角形,这势必造成这个三角面是很平的。因为这个三角面只有三个法线,它不能用来描述一个粗糙的或者多变的表面。

下面创建一个平面,来看下如何在这个平面上进行一些凹凸处理。
创建一个平面,如下图示:
这里写图片描述

是全白的,我们可以把环境光关闭掉。
这里写图片描述
然后此时的平面只有主光源的颜色了。
这里写图片描述

如何把这个平面弄得高低起伏呢?有一种方法时增加网格,网格多了,自然法线多了,然后就可以有凹凸的感觉了。但是效率很低。

1.1 高度图
一个粗糙的表面有不同的高低起伏信息,如果把这些高低起伏的信息记录在一个贴图上——高度图,我们就可以逐个像素的计算法线,而不是逐顶点。这个思想就是凹凸映射。发明人是James Blinn。

下面是一张高度图,它的RGB三个通道都是相同值:
这里写图片描述

下面就是使用这个贴图了,我们的高度图和主纹理使用的是同一个uv坐标,所以不需要缩放以及偏移信息,声明的属性中可以加入一个关键字:[NoScaleOffset]
这里写图片描述

这里写图片描述

扫描二维码关注公众号,回复: 2983834 查看本文章

这样效果为:
这里写图片描述

到这里我们先看下平面的旋转信息:
这里写图片描述

这个平面的法线都是(0,1,0)
所以计算法线的第一版是这样的:

void InitializeFragmentNormal(inout Interpolators i) {
    i.normal = float3(0, 1, 0);
    i.normal = normalize(i.normal);
}

然后我们想从高度图上后去高度作为法线:

void InitializeFragmentNormal(inout Interpolators i) {
    float h = tex2D(_HeightMap, i.uv);
    i.normal = float3(0, h, 0);
    i.normal = normalize(i.normal);
}

你觉得这个对吗?是不对的,因为所有的高度又被归一化到(0,1,0)了。

1.3 高度差——求变化率
因为我们使用的是贴图,所有它是个二维的数据,对应常说的uv二维。我们可以根据uv获得第三维度,即高度。h=f(u,v)。
第一种求高度的方法是,利用一维求高度,这里利用的是u,此时函数变为h=f(u)。

如果我们知道每个u对应的坡度,那么我们就可以求得每个点的法线。这里的法线被定义为高度的变化率,于是需要求高度的导数:h’=f’(u)。

但是事实上,我们不知道这个函数。
但是我们可以模拟他们,我们可以比较高度上两个点的对应的高度信息。比如我们采样u=0,对应的高度;以及u=1,对应的高度,其高度差为f(1)-f(0)。
我们可以构建一个tangent向量:
(1, f(1)-f(0), 0)

这里写图片描述

0 和1 是u坐标的两个端点,这个距离有点大了,我们可以再小一点,比如取0和0.5
那么此时的向量为:
(0.5, f(0.5)-f(0), 0)

我们关心的是变化率,对于下面的求导数的公式,不会很陌生:
这里写图片描述

这个δ,在unity中存储在高度图变量对应的以_TexelSize为后缀的同名变量中,类似于_ST变量。
类似如下的函数:

sampler2D _HeightMap;
float4 _HeightMap_TexelSize;

float2 delta = float2(_HeightMap_TexelSize.x, 0);
float h1 = tex2D(_HeightMap, i.uv);
float h2 = tex2D(_HeightMap, i.uv + delta);
i.normal = float3(1, (h2 - h1) / delta.x, 0);

i.normal = normalize(i.normal);

由于需要标准化,所以我们在计算的时候,可以用乘法把这个除以δ变为乘法处理,如下:

i.normal = float3(delta.x, h2 - h1, 0);

使用这种求导数的方式之后,效果为:

这里写图片描述

看看这个:

i.normal = float3(1, (h2 - h1) / delta.x, 0);

delta.x=_HeightMap_TexelSize.x,当如果,delta.x特别小,(h2-h1)/delta.x,则得到一个很大的值,高度也就特别高。
上图平面凹凸太明显了,如果把这个值直接定为1,看看其效果为:
这里写图片描述

平坦了好多,然后我们知道这个向量是水平向右的,所以我们要把他绕z轴旋转90度,得到:

i.normal = float3(h1-h2, 1, 0);

这里写图片描述

1.5 中心点采样——求高度变化率
这里写图片描述

其效果改变的不多。

1.6 使用uv两个维度
上面只利用u一维求得了一个导数,那么我们也可以利用v求得另外一个导数,于是有了:
f’(u)
f’(v)
如果使用v求导数的话,那么这个对应的切向量为:
(0,f’(v),1)
对应的法线也要绕x轴旋转一下:
(0,1,-f’(v))

为啥要绕x轴旋转90度,因为这里的利用v,就相当于利用了笛卡尔坐标系的z,那么法线要朝上,所以要绕x轴旋转90度。
二维向量的旋转,参考之前的旋转章节。

float2 dv = float2(0, _HeightMap_TexelSize.y * 0.5);
float v1 = tex2D(_HeightMap, i.uv - dv);
float v2 = tex2D(_HeightMap, i.uv + dv);
i.normal = float3(0, 1, v1 - v2);

i.normal = normalize(i.normal);

效果和使用u推导变化率差不多。

现在我们有了u和v两个切向量,如果做下叉乘,那么将得到一个垂直于u和v构成平面的向量。

float2 du = float2(_HeightMap_TexelSize.x * 0.5, 0);
float u1 = tex2D(_HeightMap, i.uv - du);
float u2 = tex2D(_HeightMap, i.uv + du);
float3 tu = float3(1, u2 - u1, 0);

float2 dv = float2(0, _HeightMap_TexelSize.y * 0.5);
float v1 = tex2D(_HeightMap, i.uv - dv);
float v2 = tex2D(_HeightMap, i.uv + dv);
float3 tv = float3(0, v2 - v1, 1);

i.normal = cross(tv, tu);
i.normal = normalize(i.normal);

2 法线映射
尽管凹凸映射可以很好的工作了,但是从计算效率上,要u和v两次采样,计算一次叉乘,而且是对每个像素进行计算,所以效率不高。所以能不能把计算出来的结果保存起来,然后直接使用。于是unity为我们提供了直接由高度图生成法线图的方法,我们可以把上面的高度图重新设置类型为:Normal Map即可得到法线图:
这里写图片描述

这里写图片描述

unity为了把法线可视化,采取如下的处理,因为我们知道法线是向量,单位向量的某个分量是从-1到1的,而为了变为颜色显示,那么需要做的是(N+1)/2,映射到0到1,区间。那么对应的在解法线的时候要做相反的处理。
2.1 法线贴图采样
法线贴图和高度图是不同的两种图,所以改下属性名:

Properties 
{

    [NoScaleOffset] _NormalMap ("Normals", 2D) = "bump" {}
    //[NoScaleOffset] _HeightMap ("Heights", 2D) = "gray" {}
}

然后是法线直接从法线贴图取出即可:

sampler2D _NormalMap;
…

void InitializeFragmentNormal(inout Interpolators i) {
    i.normal = tex2D(_NormalMap, i.uv).rgb;
    i.normal = normalize(i.normal);
}

法线采完需要做颜色反推向量的操作:2N-1

i.normal = tex2D(_NormalMap, i.uv).xyz * 2 - 1;

这里有个不明白的地方就是为什么还需要做y和z轴的互换。

i.normal = tex2D(_NormalMap, i.uv).xyz * 2 - 1;
i.normal = i.normal.xzy;

有知道的告诉我哦!!!

猜你喜欢

转载自blog.csdn.net/wodownload2/article/details/82227310