加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

cocos2d-x – Cocos2dx:Sprite3D不会渲染到纹理

发布时间:2020-12-14 18:58:41 所属栏目:百科 来源:网络整理
导读:我使用RenderTexture将包含其所有节点的图层渲染到纹理,然后在该纹理上应用OpenGL着色器以创建后期处理效果.除Sprite3D和Billboard节点外,它的工作正常.它已在他们的论坛上被问过几次而没有任何回应.我想知道是否有人让这个工作. 这是一个例子: Layer* game
我使用RenderTexture将包含其所有节点的图层渲染到纹理,然后在该纹理上应用OpenGL着色器以创建后期处理效果.除Sprite3D和Billboard节点外,它的工作正常.它已在他们的论坛上被问过几次而没有任何回应.我想知道是否有人让这个工作.

这是一个例子:

Layer* gameLayer = Layer::create();
this->addChild(gameLayer,0);

auto dir = Director::getInstance()->getWinSize();
Camera *camera = Camera::createPerspective(60,(GLfloat)dir.width / dir.height,1,1000);
camera->setPosition3D(Vec3(0,100,100));
camera->lookAt(Vec3(0,0),Vec3(0,0));
gameLayer->addChild(camera); //add camera to the scene

// You'll get a NULL camera inside BillBoard::calculateBillbaordTransform() function
// if you call visit()
/*auto billboard = BillBoard::create("cocos2d-x.png",BillBoard::Mode::VIEW_POINT_ORIENTED);
billboard->setPosition(Vec2(VisibleRect::center().x,VisibleRect::center().y));
gameLayer->addChild(billboard,100);*/

// This one won't render into the texture
Sprite3D* sprite3D = Sprite3D::create("blend_test/character_3_animations_test.c3b");
sprite3D->setScale(5.0f); //sets the object scale in float
sprite3D->setRotation3D(Vec3(0.0f,0.0f,0.0f));
//sprite3D->setPosition3D(Vec3(VisibleRect::center().x,VisibleRect::center().y,0.0f)); //sets sprite position
sprite3D->setPosition(Vec2(VisibleRect::center().x,VisibleRect::center().y));
gameLayer->addChild(sprite3D,1); //adds sprite to scene,z-index: 1

// This one works just fine and appears black and white as expected
// in the resulting texture
Sprite* sprite2D = Sprite::create("cocos2d-x.png");
sprite2D->setPosition(Vec2(VisibleRect::center().x,VisibleRect::center().y));
gameLayer->addChild(sprite2D);

// Black and white OpenGL shader
GLProgram* glProgram = GLProgram::createWithFilenames("shaders/gray.vert","shaders/gray.frag");
glProgram->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_COLOR,GLProgram::VERTEX_ATTRIB_POSITION);
glProgram->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_POSITION,GLProgram::VERTEX_ATTRIB_COLOR);
glProgram->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_TEX_COORD,GLProgram::VERTEX_ATTRIB_TEX_COORD);
glProgram->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_TEX_COORD1,GLProgram::VERTEX_ATTRIB_TEX_COORD1);
glProgram->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_TEX_COORD2,GLProgram::VERTEX_ATTRIB_TEX_COORD2);
glProgram->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_TEX_COORD3,GLProgram::VERTEX_ATTRIB_TEX_COORD3);
glProgram->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_NORMAL,GLProgram::VERTEX_ATTRIB_NORMAL);
glProgram->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_BLEND_WEIGHT,GLProgram::VERTEX_ATTRIB_BLEND_WEIGHT);
glProgram->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_BLEND_INDEX,GLProgram::VERTEX_ATTRIB_BLEND_INDEX);
glProgram->link();
glProgram->updateUniforms();

RenderTexture* renderTexture = RenderTexture::create(VisibleRect::width(),VisibleRect::height());
renderTexture->retain();

Sprite* ppSprite = Sprite::createWithTexture(renderTexture->getSprite()->getTexture());
ppSprite->setTextureRect(Rect(0,ppSprite->getTexture()->getContentSize().width,ppSprite->getTexture()->getContentSize().height));
ppSprite->setAnchorPoint(Point::ZERO);
ppSprite->setPosition(Point::ZERO);
ppSprite->setFlippedY(true);
ppSprite->setGLProgram(glProgram);
this->addChild(ppSprite,100);

renderTexture->beginWithClear(0.0f,0.0f);
auto renderer = _director->getRenderer();
auto& parentTransform = _director->getMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
gameLayer->visit(renderer,parentTransform,true);
//gameLayer->visit();
renderTexture->end();

ppSprite->setTexture(renderTexture->getSprite()->getTexture());

解决方法

Cocos2d-x v3.11.1(本文截至本文)及以下版本不能正确支持带Sprite3D的RenderTextures,因为有明显的深度缓冲区错误.

这个bug有一个GitHub issue.但现在存在一种解决方法:

...
sprite3D->setForce2DQueue(true); // puts your Sprite3D on same render queue as the RenderTexture. More info below.
...
auto rt = RenderTexture::create(1280,720,Texture2D::PixelFormat::RGBA8888,GL_DEPTH24_STENCIL8); // By default a depth buffer isn't created
rt->setKeepMatrix(true); // required
...
...
rt->beginWithClear(0,1); // required,clears the depth buffer

此外,需要对RenderTexture.cpp进行更改.这修复了Cocos2d-x中的清除深度缓冲区错误.

void RenderTexture::onClear()
{
    // save clear color
    GLfloat oldClearColor[4] = {0.0f};
    GLfloat oldDepthClearValue = 0.0f;
    GLint oldStencilClearValue = 0;
    GLboolean oldDepthWrite = GL_FALSE;

    // backup and set
    if (_clearFlags & GL_COLOR_BUFFER_BIT)
    {
        glGetFloatv(GL_COLOR_CLEAR_VALUE,oldClearColor);
        glClearColor(_clearColor.r,_clearColor.g,_clearColor.b,_clearColor.a);
    }

    if (_clearFlags & GL_DEPTH_BUFFER_BIT)
    {
        glGetFloatv(GL_DEPTH_CLEAR_VALUE,&oldDepthClearValue);
        glClearDepth(_clearDepth);

        glGetBooleanv(GL_DEPTH_WRITEMASK,&oldDepthWrite);
        glDepthMask(true);
    }

    if (_clearFlags & GL_STENCIL_BUFFER_BIT)
    {
        glGetIntegerv(GL_STENCIL_CLEAR_VALUE,&oldStencilClearValue);
        glClearStencil(_clearStencil);
    }

    // clear
    glClear(_clearFlags);

    // restore
    if (_clearFlags & GL_COLOR_BUFFER_BIT)
    {
        glClearColor(oldClearColor[0],oldClearColor[1],oldClearColor[2],oldClearColor[3]);
    }
    if (_clearFlags & GL_DEPTH_BUFFER_BIT)
    {
        glClearDepth(oldDepthClearValue);
        glDepthMask(oldDepthWrite);
    }
    if (_clearFlags & GL_STENCIL_BUFFER_BIT)
    {
        glClearStencil(oldStencilClearValue);
    }
}

有关详细信息,请参见the issue.我还做了一个example gist的解决方法.截图如下.

我不确定广告牌,但这种解决方法也可能解决它.

Example gist screenshot

有关Cocos2d-x渲染队列的信息:

Sprite3D需要与RenderTexture位于同一渲染队列中. Cocos2d-x(截至v3.7左右)现在有5个渲染队列:

>全球Z订单< 0
> 3D不透明
> 3D透明
>全球Z订单== 0(2D默认)
>全球Z订单> 0

您可以使用setGlobalZOrder(1)将Sprite3D和RenderTexture放在最后一个队列中,或者只使用sprite3D-> setForce2DQueue(true)将Sprite3D放入2D队列中.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读