美文网首页
Cocos 3.x camera

Cocos 3.x camera

作者: 合肥黑 | 来源:发表于2021-05-19 09:32 被阅读0次

    参考
    Unity3D Camera设置结合OpenGL详细解读
    Unity 对Camera 属性Clear Flags 的SkyBox/Solid Color/Depth Only深度解析

    一、Unity3D Camera属性
    1.Clear Flags

    每帧绘制完后,都需要清空各种缓冲区,最主要的是color和depth,一个负责画面最终呈现的颜色,一个负责景深。重要的是,在当前Camera范围内color和depth会有被覆盖的可能性。在范围外的color和depth有被其它Camera使用的可能性。这里的清除很多时候是为了处理,在当前Camera范围外的区域。

    • Skybox, 可以理解为Camera范围外的区域,使用SkyBox来填充。
    • Solid color,可以理解为Camera范围外的区域,使用一个纯色来填充。
    • Depth only,可以理解为Camera范围外的区域,只清空depth,而不清除color。这就保留了其它Camera范围绘制的画面,但丢失了所有景深信息。这就是为什么,当一个Camera选择Depth only的时候,其它Camera的渲染画面可以保留。没有了景深,多个Camera之间的渲染层级就依赖Camera的Depth来设置。
    • Don’t clear, 就是不清除color和depth,每次绘制都会叠加在一起。
    2.Background:

    就是用来填充,当前Camera范围内没有被绘制的区域。

    3.Culling Mask:

    没被选中的Layer会被当前Camera给剔除,不会渲染。过滤非选中层的方法有很多,可能都不会调用渲染函数,没必要使用OpenGL的剪裁功能。

    4.Projection:

    正交ortho和透视perspective,以及剪裁平面,就是生成一个矩阵数据。

    参考正交相机与透视相机的区别
    正交相机,三只羊一样大。

    image.png
    透视相机,三只羊大小不一样,缩小视距可以减轻这种影响。
    image.png
    5.Viewport Rect:

    直接对应了,OpenGL的 glViewport 调用。

    6.Depth:

    当有多个Camera的时候,每个Camera有自己的绘制空间区域和屏幕视口。所包含的物体会通过Camera的范围渲染出来。多个Camera的层级,决定了所包含物体的渲染顺序。这个数字从小到大,越来越靠近屏幕。

    7.Rendering Path:

    通用的几个shader选择,主要处理光照的。

    8.Target Texture:

    可以把Camera渲染的画面,绘制到一个纹理上,而不是设备的显示缓冲区里。

    二、Unity3D Clear Flags详解
    1.内部环境裁剪(Clipped inside the environment)

    这个说的是Camera的另一个属性Clipping Planes,这个属性包含两个值Near/Far。举个简单的例子,比如人眼睛,距离人眼睛太近的物体看不清、距离人眼睛太远的物体看不到,这就是Near、Far了。看下图


    image.png

    你看,这个观赏树的近端可以看完整,远景也OK。这个时候Clipping Planes Near == 0.3 Far == 1000


    image.png
    再看,近端丢了一块,远景也丢了。这个时候Near == 3 Far == 6

    也就是说距Camera小于Near距离的物体被裁剪掉、距Camera大于Far距离的物体被裁剪掉。

    将Far的默认值从1000改到18

    那么,怎么能避免物体被裁剪掉,而且还能离摄像头Near>=3呢?那就是,把这个景观树单独用另一个摄像头来显示。具体,看下一个知识点。

    2.Depth

    这个深度,顾名思义,就是摄像机的深度了。当只有一个摄像机时,这个属性没有意义。当有大于两个摄像机时,就牵扯到多个摄像机的前后层叠问题了。

    Depth值越大,越靠上,也就是越靠外,也就是可以遮挡值较小的摄像机的画面。比如MainCamera就默认为-1,然后新建摄像机就是0,在上边。

    那么回到刚才景观树这个问题,如果想用一个摄像机专门展示景观树,而且还在主摄像机中可以看到,那么Depth必然要大一些,在主摄像机的上面喽。接下来,我们就来讨论Clear Flags 的Depth Only啦:

    我们先试着把显示景观树的摄像机的Clear Flags设置为SkyBox或者Solid Color,我们会发现主摄像机镜头被天空盒或者纯色挡住了。然后将ClearFlags改为Depth only,我们会发现,景观树成功的嵌入了主摄像机的其他景色中,浑然天成。根据Depth only字面意思来讨论,也就是说,这个时候摄像机的未渲染部分的显示内容取决于深度,未渲染部分显示什么由深度小于本摄像机的内容来决定。

    3.Depth only应用实例

    现在回到枪的话题。我做了一个小例子,如图就是场景,其中有三个Enemy,一个Player(蓝色),一个Gun(绿色):


    image.png

    然后先是只有一个Camera,我们看看效果:


    image.png
    看,由于枪离人物太近,导致从人物的视角观察时,最近的一部分被裁剪掉了。那怎么办?我总不能把枪再朝外吧?再朝外就不自然了呢。

    那么我把枪的Layer设置成GunLayer,然后在MainCamera中CullingMask中取消对GunLayer的显示。然后新建Camera,把深度设置为0(因为MainCamera的深度为-1),Clear Flags设置成Depth only,把CullingMask中只勾选GunLayer,那么这个新的Camera就只显示Gun了。调整Camera的位置到适合位置。看效果:


    image.png

    人物举枪的姿势,很自然吧?

    接下来,我将专门解析这段话的含义,觉得上面的翻译有些不好,我自己尝试翻译了下

    This will keep the graphical display of the environment on the screen, but discard all information about where each object exists in 3-D space. When the gun is drawn, the opaque parts will completely cover anything drawn, regardless of how close the gun is to the wall.(设置深度的这个操作)将会保持环境中的图形显示的完整,但是,会丢弃所有其他物体在3D空间中存放位置的信息。当枪被绘制时,它的透明部分会完整的覆盖其他任何绘制,不管这把枪到底离墙有多近。

    那么我理解的意思就是设置成Depth only的Camera中的物体,将会凌驾在其他任何物体上,当然,只能凌驾在Depth比他小的物体上。不受3D位置的前后影响。能够完整的呈现在观察者面前。

    我做实验如下:

    我先将一个Enemy顶进了枪里:


    image.png

    再来观察效果:


    image.png

    枪还在外面,没有顶进去。很明显,其他物体的3D位置信息没有体现出来,不然就不是这个效果了。

    至此,这个Depth Only,的含义已经很传神了。

    三、cocos3.0 camera

    参考
    cocos3.0官方文档 camera
    cocos3.0官方文档 渲染排序说明

    1.相机分组渲染

    Visibility 属性用于设置哪些层级(Layer)的节点应该被相机观察到,可同时选择多个 Layer。注意:从 Cocos Creator 3.0 开始,2D 元素(例如 Sprite)的渲染也遵从 Layer 与 Visibility 的判断,开发者可以根据需要自行调整 Layer 与 Visibility。

    当开发者在 Visibility 属性中勾选了多个 Layer 时,Visibility 属性值便是通过将多个 Layer 的属性值执行 | 操作计算得出。

    2.Clear Flags
    image.png
    • DONT_CLEAR:不清空;
    • DEPTH_ONLY:只清空深度;
    • SOLID_COLOR:清空颜色、深度与模板缓冲;
    • SKYBOX:启用天空盒,只清空深度

    排序是一个很简单的功能,但是最终的呈现却是根据不同平台提供的渲染能力来的。因此,在这里说明一下,如果遇到了 UI 渲染出错,花屏,闪屏等现象,首先要检查的就是场景里所有相机(Camera 和 Canvas)的 ClearFlag,确保场景里必须有一个相机要执行 Solid_Color 清屏操作。

    具体如何设置 ClearFlag,可参考以下几种情况:

    如果场景中只有一个 UI Canvas 或者 3D Camera,那么 ClearFlag 属性设置为 Solid_Color。
    如果场景中包含 UI 背景层、3D 场景层、 UI 操作层,则:

    • 2D 背景层:ClearFlag 属性设置为 Solid_Color。
    • 3D 场景层:ClearFlag 属性设置为 Depth_Only。
    • 2D UI 层:若有模型,ClearFlag 属性设置为 Depth_Only 以避免出现模型闪屏或者穿透的情况。若没有模型,ClearFlag 属性可设置为 Dont_Clear 或 Depth_Only。
    image.png
    3.canvas自带的摄像机属性
    image.png
    image.png

    如图,设计分辨率1080*2000时,默认canvas的camera属性。其中orthoHeight是高度2000的一半。如果设计分辨率是1080*1920,则orthoHeight就是960了。

    上图摄像机盒子的厚度是由far来控制的,默认摄像机位置Z是1000,默认Far是2000。如果将far改为1000,则刚好看到canvas的内容。

    默认的正交摄像机,改fov没影响。在透视摄像机中,改Fov和摄像机的坐标以及旋转角度,就能得到合适的画面。


    image.png
    3.测试实例
    image.png

    新建一个Scene,以下操作全部使用默认配置:

    • 添加一个胶囊,默认LAYER是DEFAULT
    • scene中默认的相机ClearFlag使用SOLID_COLOR,visibility设置为IGNORE_RAYCAST|UI_3D|DEFAULT,注意为透视投影
    • 添加一个Button,会自动生成CANVAS父节点和相应的CAMERA,CANVAS和BUTTON的LAYER全是UI_2D
    • CANVAS下的CAMERA,其visibility设置为UI_3D|UI_2D,ClearFlag使用DEPTH_ONLY,注意为正交投影
    • Priority 相机的渲染优先级,值越小越优先渲染。所以这里CANVAS下的CAMERA的Priority值非常大(1073741824),而SCENE中的CAMERA的Priority为0(简单记忆为,值大的盖在上面)

    分析:
    BUTTON以及CANVAS的LAYER全是UI_2D,其相应的CAMERA,设置的VISIBILITY确保只看到这些,然后使用的DEPTH_ONLY会叠加到场景中的主摄像机上。

    场景里所有相机(Camera 和 Canvas)的 ClearFlag,确保 场景里必须有一个相机要执行 Solid_Color 清屏操作。

    根据官方文档所说,场景中的Camera 设置为Solid_Color即可。

    4.【Cocos Creator3.0教程】小地图的实现方式
    • TargetTexture 指定相机的渲染输出目标贴图,默认为空,直接渲染到屏幕,本例将副摄像机看到的内容动态输出到一个sprite中
    • ClearColor 指定清空颜色,本例中将颜色值和透明度全部清0
    //MiniMap.ts:
    import { _decorator, Component, Node, Camera, Sprite, RenderTexture, UITransform, SpriteFrame } from 'cc';
    const { ccclass, property } = _decorator;
    
    @ccclass('Minimap')
    export class Minimap extends Component {
        @property(Camera)
        private minimapCamera: Camera = null!;
        @property(Sprite)
        private contentSprite: Sprite = null!;
    
        start() {
            //新建一个和当前contentSprite大小一样的rendertexture
            const size = this.contentSprite.getComponent(UITransform)!.contentSize;
            const renderTexture = new RenderTexture();
            renderTexture.reset(size);
            //把摄像机看到的内容输出到这个rendertexture
            this.minimapCamera.targetTexture = renderTexture;
    
            //把这个rendertexture包装到SpriteFrame中,然后呈现给当前contentSprite
            const spriteFrame = new SpriteFrame();
            spriteFrame.texture = renderTexture;
            this.contentSprite.spriteFrame = spriteFrame;
        }
    
    }
    
    5.near
    image.png

    如上图,当把模型的scale调大后,会出现面部贴图糊掉。此时改一下camera的near属性即可。

    6.固定角度的3D场景适配

    参考
    各位大佬,3D模型怎么做适配呀
    急!creator3d的适配问题
    Creator 3D Camera按宽度适配的解决方案

    import { _decorator, Component, Node, CameraComponent, view, SystemEventType, systemEvent } from "cc";
    const { ccclass, property, requireComponent } = _decorator;
    
    @ccclass
    @requireComponent(CameraComponent)
    export class FitWidthCamerats extends Component {
    
        private _camera!: CameraComponent;
        private _defaultTanHalfFov!: number;
    
        onLoad() {
            this._camera = this.getComponent(CameraComponent)!;
            this._defaultTanHalfFov = Math.tan(this._camera.fov * 0.5 / 180 * Math.PI);
            this.updateFov();
            window.addEventListener('resize', this.updateFov);
        }
    
        updateFov = () => {
            console.log(view.getVisibleSize().height, view.getDesignResolutionSize().height)
            let tanHalfFov2 = view.getVisibleSize().height / view.getDesignResolutionSize().height * this._defaultTanHalfFov;
            this._camera.fov = Math.atan(tanHalfFov2) / Math.PI * 180 * 2;
        }
    
        onDestroy() {
            window.removeEventListener('resize', this.updateFov);
        }
    
    }
    

    这里要注意,增加fov会导致屏幕宽高的可视区域都会加大。在特别瘦长的手机屏幕上,为了保证屏幕宽度范围内看到所有模型,就会导致额外看到屏幕顶部和底部更多内容。

    相关文章

      网友评论

          本文标题:Cocos 3.x camera

          本文链接:https://www.haomeiwen.com/subject/gatbrltx.html