我使用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的解决方法.截图如下.
我不确定广告牌,但这种解决方法也可能解决它.
有关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队列中.
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。