元宇宙主要有以下几项核心技术:一是扩展现实技术,包括VR和AR。扩展现实技术可以提供沉浸式的体验,可以解决手机解决不了的问题;二是数字孪生,能够把现实世界镜像到虚拟世界里面去。这也意味着在元宇宙里面,我们可以看到很多自己的虚拟分身;三是用区块链来搭建经济体系。
而forward light是以这种方式绘制的:
对每一个场景中的Mesh,对每一个灯光,将其绘制到屏幕上
最直接的差别是,对于数量为M的Mesh,数量为L的光源而言,deferred light的draw call次数为O(M+L),而forward light为O(ML)。
在2d光照中也可以用同样的概念去理解,可以用deferred及forward两种不同的方式去实现。
我最终选择了deferred的方式去实现,像这样:
对每一个光源,如果没有被剔除(在摄像机外),则将其光照绘制到一个等同屏幕比例的光照贴图上。
在绘制场景完中每一个精灵(Sprite)/粒子/骨骼动画以后,将光照贴图以一个quad mesh的方式绘制到屏幕上,使用相乘的blend方式。
这样可以保证我可以方便地在任意一个已开发到一定复杂度的游戏中加入这个光照系统,而无需改动场景中原来任意Renderer的绘制Shader。
同时为了光照能够让场景中的物体呈现不同的细节,我们可以很方便地加入法线贴图,具体可以参考这篇文章。
因为光源的强度会随距离衰减,我们为光照Mesh中不同的顶点赋值不同的颜色值使之中心最亮,边缘最暗(2d中的光源,线性衰减效果已经足够好)。
其中获取周围遮挡点的实现可以参考:
public class CircleHitPoint{
public float radius;
public LayerMask colliderLayer;
public float binaryMaxDegree=5;
public int rayCount;
public Vector2 center;
public struct HitInfo{
public RaycastHit2D hit2D;
public float angle;
public HitInfo(RaycastHit2D hit2D,float angle)
{
this.hit2D=hit2D;
this.angle=angle;
}
public Vector2 Position(Vector2 center,float radius){
if(hit2D){
return hit2D.point;
}
else{
return center+CircleHitPoint.Degree2Dir(angle)*radius;
}
}
}
private static Vector2 Degree2Dir(float degree){
float rayRad=Mathf.Deg2Rad*degree;
Vector2 dir=new Vector2(Mathf.Cos(rayRad),Mathf.Sin(rayRad));
return dir;
}
private RaycastHit2D AngleRayCast(float angle){
var rayDir=Degree2Dir(angle);
var hit=Physics2D.Raycast(center,rayDir,radius,colliderLayer);
return hit;
}