1. 程式人生 > >解決了一個cocos2dx 在部分 android手機上模板測試錯誤的問題

解決了一個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();
    }
}