我使用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, 0), Vec3(0, 1, 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, 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, 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, 0, 0, 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的解决方法.截图如下.
我不确定广告牌,但这种解决方法也可能解决它.
有关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队列中.