unity2d 投影_Unity 2D Light (3) - 半影

半影方案

之前用来生成lightMesh的端点扫描的方案并不适合生成ShadowMesh,主要原因是光源体积边缘的点和光源中心点的端点顺序可能不同。虽然端点排序很快,但也不可能每个半影区域都排一次,即使有优化方案,代码的复杂度也会很高。

使用Shader绘制阴影(包括半影)比较简单,而且效率很高。个人觉得它不能完全替代生成lightMesh的方案。使用Shader实现的阴影仅仅是视觉效果,很难将受影或受光区域反馈给Unity。比如说角色在光照区域下有一些Buff之类的效果,优化好的lightMesh可以比用射线检测的效率高很多。

目前我所知的半影方案有两种:

绘制ShadowMesh(Mesh为所有阴影区域),明确区分出半影区域,然后使用半影贴图绘制半影区域。参考:dynamic 2d soft shadows

绘制ShadowMesh(Mesh为所有阴影区域),在片元着色器里计算遮挡值来绘制半影区域。参考:如何在unity实现足够快的2d动态光照

看了SF soft Shadow 2d的阴影实现源码,发现与方案2比较类似。它的ShadowMesh是在顶点作色器里用一个非常巧妙的方法计算的。遮挡值计算比较复杂,虽然搞明白了它怎么实现的,但是不清楚原理来源,属于知其然而不知其所以然。

采用方案:使用sf shadow中的方法来实现ShadowMesh,遮挡值计算使用方案2中方法,大部分计算都在着色器里。

ShadowMesh

单个线段投影区域计算方法

在顶点着色器里需要将模型空间顶点转化为裁剪空间顶点。

o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);

// unit 会自动转化为

o.vertex = UnityObjectToClipPos(v.vertex);

顶点和uv都为(0,0) (1,0) (0,1) (1,1)的正方形:

如果修改顶点的W值

// UnityObjectToClipPos会将W修改为1,所以替换成以下代码

o.vertex = mul(UNITY_MATRIX_VP, mul(unity_ObjectToWorld, float4(v.vertex.rgb, 0.5)));

结果是变大了。

实际变化是以原点到顶点的向量方向除以W的值。

仅uv.y=1的时候修改w值。

if(i.uv.y == 1){

o.vertex = mul(UNITY_MATRIX_VP, mul(unity_ObjectToWorld, float4(v.vertex.rgb, 0.5)));

} else {

o.vertex = UnityObjectToClipPos(v.vertex);

}

当AB与CD相同且w趋近于0,那么AB则无限远,结果ABCD形状就是原点对线段CD的投影。

// 简写,效率更高更合适。

// o.vertex = mul(UNITY_MATRIX_VP, mul(unity_ObjectToWorld, float4(v.vertex.rgb, 1 - uv.y)));

// 为了方便理解我都是用的条件语句

if(i.uv.y == 1){

// 让w趋近为0,直接为0会出错,应该是之后的齐次除法导致的。

o.vertex = mul(UNITY_MATRIX_VP, mul(unity_ObjectToWorld, float4(v.vertex.rgb, 0.0001)));

} else {

o.vertex = UnityObjectToClipPos(v.vertex);

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值