练习项目(七):几种简单的阴影实现

概述

再次说明一下,最近的几篇“练习项目”,都是在学习这个Github项目,使用URP重新实现一遍。对于本篇的内容,我也纠结了很久,纠结要不要写本篇博客。因为本篇的内容没有什么知识点,只是介绍了一些比较受限的阴影实现。最后还是决定要写下来,让这个“练习项目”完整一点。

一、用面片实现阴影

说起来也是缘分,几年前刚毕业进入一家游戏公司,那时候做的是横版2D游戏,游戏内角色的阴影就是用这种方式实现的。后来也有几款游戏延续了这种实现方式。

这种方式很简单,用一个圆形的面片代表阴影,放在要产生阴影的物体下方,跟随该物体。至于阴影面片的高度,当时的做法是:从产生阴影的物体往下面的地面发射射线,检测到地面,得到的高度就是阴影面片的高度。

这种方式比较受限,只适用于平整的地面。

也不需要写新的Shader,使用Sprite Renderer组件就能实现效果。

二、平面阴影

之前在听ILRuntime作者在Unity线上技术大会的演讲时,提到了平面阴影的概念(19:30开始)。

目前自己在做的游戏使用了Unity自带的Shadowmap实现的阴影。在Unity里面看起来效果还行,但是打包到手机上之后,效果很差,会有各种锯齿、抖动。后来按照上面的演讲,试着实现了一版平面阴影,发现阴影的质量真的非常高,在移动端也没有问题。但是发现平面阴影与场景烘焙出的阴影,在融合上有些问题,就暂时没有采用平面阴影。

下面简单介绍一下平面阴影的实现。主要参考了知乎上面的几篇博客,感谢博主的分享。

与上面的演讲的区别是,这里并没有使用Renderer Feature来实现平面阴影,而是使用了多Pass来实现平面阴影。

第一个Pass用来渲染物体的本身,第二个Pass用来渲染阴影。

渲染阴影的思路:考虑在二维平面系中,已知地面的高度 h h h,光线的方向 ( L x , L y ) (L_x,L_y) (Lx,Ly),顶点的世界坐标为 ( V x , V y ) (V_x,V_y) (Vx,Vy),那么要求的就是顶点在地面的投影点 ( P x , P y ) (P_x,P_y) (Px,Py)。由于投影点在地面上,所以 P y = h P_y = h Py=h。从顶点到投影点的向量为 ( P x − V x , P y − V y ) (P_x-V_x,P_y-V_y) (PxVx,PyVy),由于是光线经过顶点的投影,所以该向量和光线的方向平行,所以:
P y − V y P x − V x = L y L x \frac{P_y-V_y}{P_x -V_x} = \frac{L_y}{L_x} PxVxPyVy=LxLy

所以可以得到:
P x = L x ∗ ( P y − V y ) L y + V x P_x = \frac{L_x*(P_y-V_y)}{L_y} + V_x Px=LyLx(PyVy)+Vx

P y = h P_y = h Py=h

效果如下图:

代码如下

当然,如果想改成Renderer Feature实现平面阴影也很简单,只要把阴影Pass的LightMode改成自定义值,然后在ForwardRenderer里面添加新的Render Objects即可,然后在Filters设置合适的Layer Mask和Light Mode Tags即可。注意,本项目的URP版本是8.2.0,不用的版本可能有些名称不同。

三、球体阴影

不知道用“球体阴影”描述是否合适。这种实现方式主要适用于场景中只有球体产生阴影的情况。场景中其它的物体都“知道”球体的坐标和半径,从而可以判断是否在球体的阴影里面。

如下图所示,点L为光源位置,点A为场景中的物体的顶点,B为球形的圆心。点A到球形圆心的向量和点A到光源的向量之间的夹角为 α \alpha α;C点是垂直于AB向量的圆周上的一点,AB和AC之间的夹角为 β \beta β。那么,判断点A是否在球形的阴影里面,就是判断 α \alpha α是否小于 β \beta β

得到的效果如下:

代码如下

四、总结

上面介绍的几种阴影的实现方式,可能并不是很通用,但可能对于某种类型的游戏,或者某种情况下,上面的实现也会是一种比较优的方案。这里,只是简单介绍了一下实现的方式,有需要可以继续深入研究。

参考

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值