• cocos2dx深度检测与Zorder


    cocos2dx里面有两个渲染队列,RenderQueue和TransparentRenderQueue。我们可以从Renderer::render()的代码看到:

    void Renderer::render()
    {
        //Uncomment this once everything is rendered by new renderer
        //glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
        //TODO: setup camera or MVP
        _isRendering = true;
        
        if (_glViewAssigned)
        {
            //Process render commands
            //1. Sort render commands based on ID
            for (auto &renderqueue : _renderGroups)
            {
                renderqueue.sort();
            }
            visitRenderQueue(_renderGroups[0]);
            flush();
            
            //Process render commands
            //draw transparent objects here, do not batch for transparent objects
            if (0 < _transparentRenderGroups.size())
            {
                _transparentRenderGroups.sort();
                glEnable(GL_DEPTH_TEST);
                visitTransparentRenderQueue(_transparentRenderGroups);
                glDisable(GL_DEPTH_TEST);
            }
        }
        clean();
        _isRendering = false;
    }

    先绘制的是RenderQueue,没有启用深度检测,之后绘制的TransparentRenderQueue才会启用深度检测。

    一般情况下我们使用的是RenderQueue,它有如下性质:

    1. RenderQueue里面的东西完全是按Zorder来决定渲染的先后顺序的,Zorder越小越靠前。

    2. 若Zorder相等,则按chlid队列中的顺序决定,先加入到队列的靠前。

    3. 可以使用glBlendFunc做颜色混合以及使用2D shader(因为颜色混合需要禁用深度缓存或者把深度缓存设为只读)

    若要启用深度检测,我们则需要把绘制物体放入TransparentRenderQueue中,方法就是设置onDraw回调的时候,设置command的tansparent为ture,如:

    _customCommand.init(1);
    _customCommand.func = CC_CALLBACK_0(CCGSpell::onDraw, this, transform, flags);
    _customCommand.setTransparent(true);
    renderer->addCommand(&_customCommand);

    若要将Sprite放入TransparentRenderQueue,则要像上面那样修改Sprite::draw(),或者在子类中override它。

    由于TransparentRenderQueue无法使用颜色混合(虽然修改Render模块可以做到,但一般情况下最好是不要修改cocos2dx的代码),我们主要使用的还是RenderQueue。

    只是使用RenderQueue绘制3D场景的时候经常会遇到如下问题,先贴代码:

    auto marisa = CCGSprite::create("textures/marisa.png");
    marisa->setAnchorPoint(Vec2(0.5, 0));
    marisa->setPosition3D(Vec3(origin.x, origin.y - 200, 0));
    addChild(marisa, 0);
    
    auto mare = CCGSprite::create("textures/mare.png");
    mare->setAnchorPoint(Vec2(0.5, 0));
    mare->setPosition3D(Vec3(origin.x, origin.y - 200, -1000));
    addChild(mare, 0);
    
    auto spr3D = Sprite3D::create("Sprite3DTest/boss1.obj");
    spr3D->setScale(20.f);
    spr3D->setTexture("Sprite3DTest/boss.png");
    spr3D->setPosition3D(Vec3(origin.x, origin.y, -500));
    spr3D->runAction(RepeatForever::create(RotateBy::create(3, 360)));
    addChild(spr3D);
    
    auto ground = CCGSprite::create("textures/grassHR.jpg");
    ground->setPosition3D(Vec3(origin.x, origin.y - 200, 0));
    ground->setRotation3D(Vec3(-90, 0, 0));
    addChild(ground, 0);

    场景中除动画人物外有4个精灵,其中有一个3D精灵spr3D,以及一个绕x轴旋转90度的ground。若按上面的代码会得到如下效果:

    与xy平面平行部分都OK,但是与xy平面垂直的ground却压在所有精灵上面,这就是没有深度检测造成的。

    说到这里就不得不说下Zorder与positionZ的关系。

    在调用setPosition3D,setPositionZ的时候,其实是做了两件事:

    1. 根据positionZ设置transform,也就是实际渲染在场景中的位置。

    2. 用positionZ设置GlobalZOrder的值,而GlobalZOrder则决定了渲染顺序。

    那么上面问题的原因就是ground的Zorder最大(依次是0, -1000, -500, 0),而且addchild是在Zorder同样大的marisa之后。

    因此是最后渲染出来的。

    那么,如果我们不想移动ground的位置,又想把ground移到最后,那么单独设置一下ground的Zorder便可:

    auto ground = CCGSprite::create("textures/grassHR.jpg");
    ground->setPosition3D(Vec3(origin.x, origin.y - 200, 0));
    ground->setRotation3D(Vec3(-90, 0, 0));
    ground->setGlobalZOrder(-2000);
    addChild(ground, 0);

    修改后的效果如下:

    而对于GlobalZOrder和LocalZOrder的区别是,GlobalZOrder改变的是物体在整个Scene中的渲染顺序,而LocalZOrder改变的只是物体在其父节点下的渲染顺序。

    由于本例的父节点就是Scene,因此GlobalZOrder和LocalZOrder的效果是相同的。

  • 相关阅读:
    将读取的.raw文件转换为tensor张量送入网络
    批量解压zip文件到指定位置
    三维医学图像深度学习,数据增强方法(monai):RandHistogramShiftD, Flipd, Rotate90d
    springboot的starter原理探究 + 如何自定义自己的starter
    构建一个可执行的 JAR 并运行
    git:当远程仓库迁移后,需要更改远程仓库指向
    正则表达式验证版本号
    HbuilderX 更改内置终端为 gitBash
    不用 Typescript 的理由
    用户协议和隐私政策的实现方式调查研究
  • 原文地址:https://www.cnblogs.com/marisa/p/4130551.html
Copyright © 2020-2023  润新知