unity场景初始化_【渲染流程】Cluster_Unity实现详解(一)预计算AABB

紧接上篇

未名客:【渲染流程】Cluster_Unity实现概述​zhuanlan.zhihu.com
6558a10a1c99b33624868f5ccfc6c713.png

上篇文章,是对Unity 实现Cluster 灯光裁剪的一个概述,从这篇文章开始,我们开始结合代码详细展开,实现每一个流程。强烈建议大家先看上篇文章,很多推导,总结都在上篇文章里,这里及以后的文章不重复相关内容。

用Unity 实现ClusterBasedLighting,一开始考虑的便是Unity 的Srp,不过一来,自己对SRP 不熟,目前也没有足够的时间学习相关的东西,其二,本文的重点是梳理Cluster的流程,想更纯粹一些。最后受MaxwellGeng 兄弟的启发,决定,决定从零开始,完全自己手写。未来某一天如果对SRP 比较熟,会移植一下~

其实这里所谓的完全自定义,是自己调用一些Unity 较底层的绘制函数,绘制到自己创建的RT上,最后使用一个Blit 操作,把我们自己创建的RT 拷贝到摄像机的RT 上,由Unity 提交,最后在屏幕上显示。

一、准备环境

这一步比较简单,首先在一个空场景中,新建脚本Script_ClusterBasedLighting.cs, 并把它挂在Camera 上面,当你的Scene 视图,背景被清空成灰色,环境准备完成~

6e0faa6f9b9a4e783288d68bb46293c5.png
clear rt: gray color
[ExecuteInEditMode]
#if UNITY_5_4_OR_NEWER
[ImageEffectAllowedInSceneView]
#endif
public class Script_ClusterBasedLighting : MonoBehaviour
{
    
    private RenderTexture _rtColor;
    private RenderTexture _rtDepth;

    void Start()
    {
    
        _rtColor = new RenderTexture(Screen.width, Screen.height, 24);
        _rtDepth = new RenderTexture(Screen.width, Screen.height, 24, RenderTextureFormat.Depth, RenderTextureReadWrite.Linear);
    }

    void OnRenderImage(RenderTexture sourceTexture, RenderTexture destTexture)
    {
    
        Graphics.SetRenderTarget(_rtColor.colorBuffer, _rtDepth.depthBuffer);
        GL.Clear(true, true, Color.gray);

        Graphics.Blit(_rtColor, destTexture);
    }
}

我们在_rtColor, _rtDepth 上面绘制内容,最后blit 到 camera 的rt 上。

使用OnRenderImage() 函数,配合【ExecuteInEditMode】,【ImageEffectAllowedInSceneView】 是为了能在Scene视图窗口 预览结果。

这部分内容MaxwellGeng 已经解释的很清楚了,这里不做赘述,有兴趣或者不太明白的小伙伴可以点一下链接过去学习一下。

二、预计算ClusterAABB, 绘制调试Cluster

从这一阶段开始,我们进入正题,如标题所言,我们将实现如下内容:

  1. 预计算Cluster AABB
  2. 绘制供调试的Cluster

完成以后,就能得到本篇文章标题的画面啦~

2.1 预计算Cluster AABB

主相机的视锥体被按照一定规则,切分成一定数量的小锥体,为了能更快的完成后面Cluster 与光源的求交,我们用AABB BoundBox 包围盒这种方式来表示Cluster,且此包围盒需要完整包含小锥体。这一步,我们的目标就是求出View空间下一系列Cluster AABB 的数组。

810db0b387b4ac95202bea4b777aa643.png

之前有提到我们最终实现的cluster, 是类似cube 的aabb,尽量做到均匀分布,实现方法就是在view 空间,做一种类似指数型的切分,具体推导过程见上篇文章,最终我们得到了如下公式:

(1)

(2)

这两个公式非常重要,是我们后面做各种变化的基础。简单解释一下:

第一个公式:根据View 空间下的z ,计算当前z 所处的 cluster z 方向的Index;

第二个公式:根据cluster z 方向的Index ,反推 View 空间下 z坐标。

设想,假设我们知道屏幕上的一个Tile(即,Cluster 的xy 坐标),配合相机近裁面的z,便可得出一个view 空间下的3d 坐标,这个坐标与 摄像机的位置,便可形成一条线。

同时我知道了view 空间下,第k 个 cluster 的z坐标,根据这个z 构建一个平行于相机近、远裁面的面,那么便可以求出 这条线与k 平面的交点。 这个交点其实 就是 小cluster 锥体的某个点啦~

e69049388771d025813bf94829196dab.png
屏幕上的Tile,对应Cluster,及AABB

有了这个思路就可以写代码了~

为了方便,我们构建如下结构体:

struct CD_DIM
{
    public float fieldOfViewY;
    public float zNear;
    public float zFar;

    public float sD;
    public float logDimY;
    public float logDepth;

    public int clusterDimX;
    public int clusterDimY;
    public int clusterDimZ;
    public int clusterDimXYZ;
};

用来表示cluster 和相机的一些信息。在相机视锥体发生改变时(初始化需要调用一次),计算这个结构:

    void CalculateMDim(Camera cam)
    {
        // The half-angle of the field of view in the Y-directio
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值