经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » 游戏设计 » 查看文章
Unity 2D Light (4) - 平行光
来源:cnblogs  作者:Lain_vv  时间:2020/11/23 11:52:32  对本文有异议

image

平行光

2D这里主要是指有高度的光,即限定了影子的长度。

Shadow Mesh

限定影子长度生成的Mesh有很多种,可以根据实际情况,选择不同的方案。

  • 平移Sprite顶点(自动生成的Sprite Vertex 或者 Custome Physics Shape 顶点),然后使用凸包形成新的影子外形。
  • 使用相同的Sprite Renderer渲染影子,在Shader里进行旋转拉伸等操作。
  • 其他:直接复制平移Sprite然后颜色置黑(如浮空物体);加一个单独的影子贴图(如一个椭圆的影子贴图放在物体下面);等等。

平移Sprite顶点

在c#脚本里遍历Sprite生成Mesh数据。生成一个Mesh绘制影子,只有一个Draw Call。

  1. 根据选择获取Sprite顶点(默认或Custome Physics Shape)
  2. 按照光方向平移顶点

image
3. 使用凸包算法获取凸点,保存为Mesh的数据

image
4. 软阴影可以在Mesh外面包一个Mesh,使用一张渐变纹理绘制软阴影。用UV或Tangent等通道保存渐变贴图的UV,内围点为0,外围点为1。

imageimage

  1. 合并所有数据生成一个Shadow Mesh

使用Custome Physics Shape和默认顶点的结果:

image

Shader里进行旋转拉伸贴图

遍历Srpite使用Sprite原来的Sprite Renderer加上阴影的Shader绘制阴影。每个Sprite都需要一个Draw Call。这样做主要是因为需要使用Sprite贴图的Alpha通道绘制影子外形。

如果合并使用一个Draw Call绘制,阴影的外形不好控制(使用默认Sprite顶点基本上效果会很差)。可以使用cutom outline或者cutom physics shape生成相对细致的外形,属于空间换时间的做法。

  1. C#脚本中指定Sprite Renderer(主要是需要主贴图),旋转所用的根顶点,旋转弧度,拉伸长度
  2. 在顶点着色器里进行顶点旋转拉伸,按任意方向拉伸算法参考Scaling along the cardinal axes
  1. // c#
  2. // 旋转所用的根顶点,取中间接近底部的顶点
  3. // 兼容旋转缩放
  4. var matrix = Matrix4x4.TRS(caster.transform.position, caster.transform.rotation, caster.transform.localScale);
  5. var rootPos = (Vector2)(matrix * new Vector4(0f, -0.45f, 0, 1));
  6. rootPos = caster.transform.InverseTransformPoint(rootPos);
  7. // shader
  8. // 二维按任意方向拉伸
  9. float2 scaleByDir(float2 p, float radian, float k){
  10. float2 dir = float2(cos(radian), sin(radian));
  11. float2 r1 = float2(1 + (k - 1) * dir.x * dir.x, (k - 1) * dir.x * dir.y);
  12. float2 r2 = float2((k - 1) * dir.x * dir.y, 1 + (k - 1) * dir.y * dir.y);
  13. return float2(r1.x * p.x + r1.y * p.y, r2.x * p.x + r2.y * p.y);
  14. }

image

旋转根部的瑕疵

image

解决方法可以是使用一张底部是圆形的Mask贴图,这样旋转的时候就看不出来瑕疵。我觉得是一种比较好的方法,Mask贴图还可用来做软阴影(未验证)。

另一种是底部uv.y比较小的时候不进行旋转拉伸。

大于180°时,下面会消失。是因为底部不旋转,其他地方旋转大于180°时导致三角面片反了。大于180°将底部x坐标置反即可。

image

但是旋转角度接近与0°和180°时底部过小处理起来比较麻烦,除了手动加一个圆形阴影想不出来什么好的处理方法。相对来说还是使用一个阴影Mask贴图比较方便。

image

image

阴影覆盖贴图处理

阴影会将Sprite本身覆盖掉。

image

因为覆盖地方完全贴合Sprite,所以除了每个Sprite在渲染阴影后再渲一遍将覆盖地方去除,目前想不其他好的方法。

  1. // 将alpha置反,混合时取最小即可
  2. BlendOp Min
  3. Blend One OneMinusDstColor
  4. frag {
  5. fixed alpha = tex2D(_MainTex, i.uv).a;
  6. fixed4 col = 1 - alpha;
  7. col.a = 1;
  8. return col;
  9. }

image

阴影衰减

简单点计算顶点与之前旋转用的点的距离然后使用1.0 - saturate(distance * _ShadowFalloff)求出衰减即可。

image

源码

link

参考

拉伸矩阵:https://www.mauriciopoppe.com/notes/computer-graphics/transformation-matrices/scale/

原文链接:http://www.cnblogs.com/lain-vv/p/14019449.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号