交互
观察荒野之息可以看到,在林克走在草地上的时候,几何草向四周倒下:
那么只需要向shader传入物体当前的位置,和影响范围内的点,计算出倒伏的方向:
// 传入交互的物体的位置
public void SetTargetPos()
{
Vector3 pos = TargetBall.transform.position;
// Vector2 uvPos = new Vector2(pos.x / 200f, pos.y / 200f);
GrassMat.SetVector("_TargetPos", pos);
FlowerMat.SetVector("_TargetPos", pos);
}
[maxvertexcount(24)]
void geom(point vertIn p[1], inout TriangleStream<geomOut> triStream)
{
...
// 和移动物体交互
// 计算和物体的距离
float dis = distance(_TargetPos, p[0].vertex);
//float fall = step(dis, _FallRange);
float fall = smoothstep(_FallRange * 0.5, _FallRange, dis);
// 修改校正后的方向
float3 dir = normalize((height * up + windVec * _WindScale + randomDir * _RandomDirScale) * fall + (p[0].vertex - _TargetPos) * float3(1,0,1) * (1 - fall));
...
}
阴影
阴影有两部分,接受阴影和投影。需要在Shader中分成两个Pass来做。
第一个Pass设置 LigntMode
为 ForwardBase
,在计算顶点的时候加入o._ShadowCoord = ComputeScreenPos(o.pos);
,计算点在屏幕空间的位置,这样可以在片元着色器中使用 SHADOW_ATTENUATION
来计算阴影强度。
另一个Pass设置 LightMode
为 ShadowCaster
,在片元着色器中只执行 SHADOW_CASTER_FRAGMENT(i)
。
原理可以在 Catlike Coding 关于渲染阴影的章节找到详细内容(参考资料2)。
中间有一个情况是绘制的物体接受阴影的时候可能会接受到自己的阴影,导致物体表面上出现条纹阴影,这个问题可以通过对阴影做一个偏移来规避。具体是在计算顶点时,在 ForwardBase Pass
中计算 ComputeScreenPos
,而在 ShadowCaster Pass
中对顶点执行 UnityApplyLinearShadowBias
,然后在场景光中设置动态阴影的 Bias
设置为合适的值(在我的项目中设置到最大值2才消除)。
设置偏移会带来阴影的位置不正确(放置在平面上的物体会比较明显),所以这个值的设置还是要具体情况来看。
具体代码可以看下Github中的项目,就不在这里贴出来了。
LOD(划掉)
之前已经提到过,既然每个草只有四个点,在单个草上减点做LOD就没有必要了。而且根据对荒野之息的研究(见参考资料5),这种草只会在玩家的周围出现,远一点的地方就是包含很多的草(或者花)的面片。荒野之息的过渡做的非常自然,本来草的颜色和地面就非常接近,不仔细看不太容易发现近景草和中景草的分界。
那么这种LOD就要结合大地形来做了,不过那就是另一个故事了。
小结
至此几何着色器草甸篇章就结束了,也没有什么新的内容,主要是对学习几何着色器过程的一个记录。当然据说几何着色器的性能并不好,不能在移动端使用,不过这就是另外的问题了。