Unity Occlusion Culling 遮挡剔除研究

48 篇文章 2 订阅
33 篇文章 26 订阅

本文章由cartzhang编写,转载请注明出处。 所有权利保留。
文章链接:http://blog.csdn.net/cartzhang/article/details/52684127
作者:cartzhang

一、unity裁剪包括,视锥裁剪和遮挡裁剪。

什么是视锥体裁剪?
我们来直接看下官方的图解,看图说话。
场景中的对象:
https://docs.unity3d.com/uploads/Main/OcclusionNoCulling.png
这里写图片描述
视锥体的裁剪:
https://docs.unity3d.com/uploads/Main/OcclusionFrustumCulling.png
这里写图片描述

那什么是遮挡裁剪呢?
https://docs.unity3d.com/uploads/Main/OcclusionFullCulling.png
这里写图片描述
一图胜千言,这就是遮挡裁剪。
要说的是,之前的此功能必须是pro版本才有的,现在使用的5.4.0f3版本是有的
遮挡裁剪的原理:通过在场景中使用一个虚拟的摄像机来创建一个物体潜在可视性状态(set)的层级. 这些数据可以让每个运行时间内的摄像机来确定什么能看见什么看不见。通过这些数据, Unity 将确定只把可以看见的物体送去渲染.
使用二叉树进行处理,通过判断是否在相机中可以看到来,把看到的送去渲染。
当然还可以通过划定一个盒子来确定裁剪空间,更多细节请自行参考官方。
要说的是:当你使用遮挡剔除时你依然使用视锥体剔除,他们是并行不悖的。

本来有同事,是关于怎么判断对象是否在相机内渲染。
这个想来简单,找到对象的render,然后判断Renderer.isvisiable即可。
这时候发现,他说这个没有卵用。那我就自己试试了。
先写了个扩展方法:

public static class RendererExtensions
{
    public static bool IsVisibleFrom(this Renderer renderer, Camera camera)
    {
        Plane[] planes = GeometryUtility.CalculateFrustumPlanes(camera);
        return GeometryUtility.TestPlanesAABB(planes, renderer.bounds);
    }
}


但是这个方法很明显只判断是否在视锥平头体内,不判断是否可见。
那问题就在于遮挡裁剪啊,那看官方也琢磨了很久,一开始总是做不好。下面就是个记录历程,希望对看本文的你有所帮助。
来吧,实践是检验真理的唯一标准啊。

二、首先搭建一个简单场景。

这里写图片描述
注意:要把所有的cube转换为静态的,static.
其中有个小红色块是有代码的。
脚本如下:


public class IsRenderByCamera : MonoBehaviour
{
    private Renderer rend;
    // Use this for initialization
    void Start ()
    {
        rend = this.GetComponent<Renderer>();
    }

    // Update is called once per frame
    void Update ()
    {
        //if (rend.IsVisibleFrom(Camera.main))
        //{
        //    Debug.Log("visible by main camera");
        //}
        //else
        //{
        //    Debug.Log("not visible by any camera");
        //}

        //if (rend.IsVisibleFrom(Camera.main)) Debug.Log("Visible");
        //else Debug.Log("Not visible");

        if (rend.isVisible)
        {
            Debug.LogError("red cube is Visible");
        }
        else
        {
            Debug.LogError("red cube not Visible"); ;
        }

        if (Camera.main.useOcclusionCulling)
        {
            Debug.Log("currrent occluson is using");
        }    
    }

    void OnWillRenderObject()
    {
        //Debug.Log("will render ");
    }


    void OnBecameVisible()
    {
        //Debug.Log("became Visible");
    }

    void OnBecameInvisible()
    {
        //Debug.Log("became InVisible");
    }


}


直接构建操作如下:
这里写图片描述
下面就不多说了,直接构建啊。
构建完毕,看到如下结果:
这里写图片描述
发现没有,坐标轴位置就是相机位置,注意有什么特点。
在场景中直接拽动相机到大的遮挡版之前,发现没有发生任何所想的,所有对象依旧在渲染啊。
这里写图片描述

三、这是怎么回事。

查找了各种资料和尝试,相机在大遮挡板之前,遮挡在其后的小块没有一个消失不渲染的。而相机进入到蓝色盒子里面的时候,就可以发现有小块依次的不渲染。
这里写图片描述
这个就简单了、
所以,在相机的后面添加了一个cube,记得也修改为静态的。构建后如下图:
这里写图片描述

结果呢:
这里写图片描述
真的可以,大功告成啊。

四、是不是全部都需要为静态的呢?

怎么办,继续测试实验啊。

实验一、

就把相机背后点,还有做边界的小块做为静态,其他都非静态。
这里写图片描述

当然结果很明显了。没有遮挡版,无法实现遮挡裁剪。

实验二、

将大白板该为静态。
这里写图片描述
可以实现对大白板后面对象的遮挡裁剪。
这里写图片描述
而超越之后就没有效果了。
这里写图片描述

五、注意:

1.若在unity编辑器中没有选中Occlusion,在场景中拖拽相机,并不会出现效果。这个很怀疑是bug.
顺便说下,测试版本为5.4.0f3。
2.还有就是必须在Visulize模型下才可以正常使用。
这里写图片描述
而在Edit模式下,不进行遮挡裁剪。
这里写图片描述
所以,怀疑Unity的版本只在编辑器下才有效果。写代码就是为打包测试、

六、打包测试

这里写图片描述

这里写图片描述

结果是打包后遮挡裁剪是正常的。可以使用。哈哈,嫌疑排除,自己想多了。
但是怀疑精神还要有的。对吧?
本来是判断对象是否在相机内渲染做处理的,误入歧途,做了这些工作,分享出来,自己做个记录,以飨读者。

七、工程地址:

Github:https://github.com/cartzhang/OcclusionCullingTest

参考:

https://docs.unity3d.com/Manual/OcclusionCulling.html
http://bbs.9ria.com/thread-216913-1-1.html

八、—————–2017-03-09更新—–

**当前使用遮罩的时候,需要把它作为主场景,还必须有相机才可以。
若用其他场景来加载此场景,则遮罩不起作用。**

——————THE————————————————END——————–

若有问题,请随时联系!!!
非常感谢!!!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值