解決了一個cocos2dx 在部分 android手機上模板測試錯誤的問題
在android 手機上,大部分的機器模板測試都沒問題。但是有一個奇葩的手機,小米2S, 當只有一層需要模板測試的時候 ,在cocos2dx 裡具體地說就是 使用 CCClippingNode 的時候 ,是沒問題的 。但是當一個 CCClippingNode 巢狀另外一個 CCClippingNode 時,就會出現各種顯示不出來的問題。cocostudio 製作 GUI 裡面許多面板,當開啟剪裁功能後 ,比如 UIPageView UIScrollView 也都是靠 CCClippingNode 開啟模板快取來渲染的 。
原因沒有具體弄明白,但是我用另外一個手段避開了這個問題。
因為是 模板測試 巢狀 模板測試 時,才會有問題 ,並且這種問題很多出現 在 GUI上 ,GUI 的大背景通常是一個長方形 ,所以就把 GUI 的 renderer ,也就是 RectClippingNode 剪裁時的渲染方式,從使用 模板測試,修改為 使用 剪裁測試,並根據剪裁區域設定 opengl 的剪裁區域, 渲染時從渲染 clipping node ,變為正常地渲染 普通 node .這樣 就比較完美地避開了了這個問題。
渲染前儲存好 scissor 相關的 引數,渲染後恢復即可。 cocos2dx 渲染其他 opengl 特性的 node 的做法,通常也就是這樣子的。具體可以參考 cocos2dx CCClippingNode 的 visit() 方法。
剪裁測試相關的關鍵字主要是 GL_SCISSOR_TEST glScissor() 之類的 ,具體api 可以自行查閱 OpenGL 資料。
通過此問題,我進一步地瞭解了 opengl 渲染管線 幾個測試的 的意義 和 順序關係 ,也進一步知道了 這幾個測試 都是發生在 fragment shader 之後。
並且還了解到了 Android SDK 的一個 分析渲染效能和渲染錯誤的工具 Tracer for OpenGL es, eclipse 如果安裝了外掛,就可以在eclipse裡開啟它了。 雖然最後解決問題沒用到它,但是感覺這是一個不錯的工具 。
具體的用法 官方文件有介紹 。可是山炮 的 小米 2S 上也跑步起來這個工具。
解決了這個問題挺高興,特此記錄。
void RectClippingNode::visit() { if (!m_bEnabled) { return; } if (m_bClippingEnabled) { #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) // some android device , such as "mi 2s" do not support stencil test node in stencil test node // so when load cocostudio GUI, do not use stencil test ,but use scissor test replace it. bool bEnabledScissorBefore = CCEGLView::sharedOpenGLView()->isScissorEnabled(); CCRect scissorRectBefore = CCEGLView::sharedOpenGLView()->getScissorRect(); // try to use Scissor Test replace Stencil Test glEnable(GL_SCISSOR_TEST); CCPoint worldPos = m_pParent->convertToWorldSpace(getPosition()); CCPoint anchor = getAnchorPoint(); CCPoint leftDownPos = ccp(worldPos.x - anchor.x * m_clippingSize.width ,worldPos.y - anchor.y * m_clippingSize.height); CCEGLView::sharedOpenGLView()->setScissorInPoints(leftDownPos.x,leftDownPos.y,m_clippingSize.width,m_clippingSize.height); // @temp 0,0 CCNode::visit(); // restore opengl states bEnabledScissorBefore ? glEnable(GL_SCISSOR_TEST) : glDisable(GL_SCISSOR_TEST); CCEGLView::sharedOpenGLView()->setScissorInPoints(scissorRectBefore.origin.x,scissorRectBefore.origin.y,scissorRectBefore.size.width,scissorRectBefore.size.height); #else CCClippingNode::visit(); #endif } else { CCNode::visit(); } }