cocos2dx 3.x中的renderTexture缺陷

个人认为存在这样一个缺陷,求官方确认/证否/解决。

设spriteX使用customCommand进行了自定义绘制
class CspriteX:public Sprite{
public:
float m_XXX;
void draw(Renderer *renderer, const Mat4 &transform, uint32_t flags){
_customCommand.init(_globalZOrder);
_customCommand.func = CC_CALLBACK_0(Cc3dSubMesh::onDraw,this, transform, flags);
renderer->addCommand(&_customCommand);
}
void onDraw(const Mat4& modelMat, uint32_t flags){
//依赖m_XXX属性的绘制代码
}

};

假设有下面一段代码:

CspriteX*spriteX=CspriteX::create();
spriteX->init(…);
spriteX->m_XXX=0;
scene->addChild(spriteX);

float oldXXX=spriteX->m_XXX;//备份m_XXX
spriteX->m_XXX=100;//修改m_XXX
renderTexture->begin();
scene->visit();
renderTexture->end();
spriteX->m_XXX=oldXXX;//恢复m_XXX

问:最后渲染到renderTexture的是spriteX(m_XXX==0)还是spriteX(m_XXX==100)?
显然,写上面代码的人希望的结果是spriteX(m_XXX==100),但是在3.x的command机制下得到的结果却是spriteX(m_XXX==0)。

一般性地说就是:
在当前3.x的command渲染机制下,如果用户scene中含有使用customCommand自定义绘图的节点,则用户就没办法在render to texture时临改变和恢复节点的属性。
这相对于2.x的立即模式是一个很大的缺陷。

补充:
造成这个问题有的根源是:3.x使用的command机制是一种延迟渲染,但是延迟渲染基本要求是一定要把渲染数据完整地保存到渲染队列里,这样才能保证最后执行command的时候的数据与当初添加command的时候的数据是完全一致的。但是customCommand没有做到“完整保存数据”这一条,它只保存了一个onDraw函数指针,而等到执行customCommand时onDraw函数里的数据可能已经改变了(比如用户主动修改),于是就产生customCommand执行结果非用户预期的问题。

兄弟,我也遇到类似的问题。我是在场景中继承了很多layerColor类绘制了很多自定义的UI控件,看着不错,可是当用renderTexture实现截屏功能时,总是发现只能截屏一小部分的node截屏,深入看了下和你发现的问题一致,node->visit只会调用layerColor的draw,这里只会添加绘图回调命令,真正的绘图需要等到OnDraw之后。 正在想解决方案,看了下底层render类有强制执行所有队列的接口,不过没有暴露,准备利用这货吧renderTexture改掉加个sync接口试试。

— Begin quote from ____

引用第1楼独孤崖于2014-12-07 21:47发表的 :
兄弟,我也遇到类似的问题。我是在场景中继承了很多layerColor类绘制了很多自定义的UI控件,看着不错,可是当用renderTexture实现截屏功能时,总是发现只能截屏一小部分的node截屏,深入看了下和你发现的问题一致,node->visit只会调用layerColor的draw,这里只会添加绘图回调命令,真正的绘图需要等到OnDraw之后。 正在想解决方案,看了下底层render类有强制执行所有队列的接口,不过没有暴露,准备利用这货吧renderTexture改掉加个sync接口试试。 http://www.cocoachina.com/bbs/job.php?action=topost&tid=273967&pid=1192194

— End quote

恩,如果提供一个手动接口充许提前执行当前command就好了。且render to texture是一个groupCommand,提前执行仍然是batch优化的。这样既实现了延迟和立即两种模式的自由选择,又不损失性能。

我往前走了一小步,但还没成功。我发现renderer->render()可以强行执行的命令队列,我在visit()之后做了这样的修改:
render_text = RenderTexture::create(visible_size.width, visible_size.height);
render_text->retain();
render_text->beginWithClear(0.0f, 0.0f, 0.0f, 0.0f);
this->visit();
auto renderer = Director::getInstance()->getRenderer();
renderer->render();
render_text->end();

单步跟踪了下,确实我几个对象父类(layerColor)的onDraw在end前都调用了,但renderer获取出来的图片还是没有这些layerColor对象,非常奇怪,兄弟不知道你有没有什么思路?

从逻辑上来看确实是这样,主要原因是场景树遍历和渲染分离了(和2.x最大的区别)导致的。

手动去调用void Renderer::render()我不确定建不建议,会不会有bug。

问题已经反馈引擎组~待会会有高手来解答~

忘说了,这个问题我昨晚解决了,看了下3.2 utils下加了一个copyScreen的接口,可以看出来官方已经不建议再用visit方式来进行截图,而是增加command回调的方式。不过话说回来3.x的资料真少,你可以参考下。

嗯,这个我知道。只是@wantnon想了解的是有没有接口可以直接执行当前renderQ的command。而不用等引擎来调用。对吗?

— Begin quote from ____

引用第6楼偶尔e网事于2014-12-09 10:02发表的 回 5楼(独孤崖) 的帖子 :
嗯,这个我知道。只是@wantnon想了解的是有没有接口可以直接执行当前renderQ的command。而不用等引擎来调用。对吗? http://www.cocoachina.com/bbs/job.php?action=topost&tid=273967&pid=1193565

— End quote

对,因为很多时间用renderTextue并不是为了截屏,而是为了动态生成纹理。所以如果能提前执行一个command比较灵活些。

倒是想到一个办法:
把前面例子中的
float oldXXX=spriteX->m_XXX;//备份m_XXX
spriteX->m_XXX=100;//修改m_XXX

spriteX->m_XXX=oldXXX;//恢复m_XXX
也都做成command。

不过这样写程序体验好差啊。

补充:
不过想了一下,在command渲染机制下好像也只能这样了。。。

火钳刘明:2:

render->render() after renderTexture->end()

这个问题有下文吗? 解决了吗

大神
float oldXXX=spriteX->m_XXX;//备份m_XXX
spriteX->m_XXX=100;//修改m_XXX
这个m_XXX是什么啊?求解感谢

就没有下文了吗?

lua里面怎么用这句?

又是一个太监贴。。。

:2:mark…

:14: 僵尸贴