首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

Cocos2d-x 實現精靈超出父節點範圍裁剪不顯示

     編輯:程式設計綜合問答

需求

精靈移動時,超出父節點矩形範圍的部分自動裁剪隱藏,類似 clippingEnabled 或 CSS overflow: hidden。

核心方案:重寫 visit() 啟用 Scissor Test

Cocos2d-x 繪製流程中,visit() 是節點渲染入口。通過 OpenGL GL_SCISSOR_TEST 可實現矩形裁剪區域。

實現代碼


class ClippingNode : public cocos2d::Node {
protected:
    // 重寫 visit 方法
    void visit(cocos2d::Renderer *renderer, const cocos2d::Mat4 &parentTransform, uint32_t parentFlags) override {
        // 1. 計算世界空間下的裁剪矩形 (父節點的包圍盒)
        cocos2d::Rect clippingRect = getClippingRect(); // 需自行實現獲取父節點世界座標下的 rect
        
        // 2. 啟用 Scissor Test
        glEnable(GL_SCISSOR_TEST);
        // glScissor 參數:左下角 x, y, 寬, 高 (像素,OpenGL 座標系,原點左下角)
        // 需將 cocos2d::Rect 轉換為 OpenGL 視口座標
        cocos2d::Point origin = this->convertToWorldSpace(clippingRect.origin);
        cocos2d::Size size = clippingRect.size;
        // 考慮縮放、旋轉等變換,實際項目中建議用 getBoundingBoxToWorld()
        glScissor((GLint)origin.x, (GLint)origin.y, (GLsizei)size.width, (GLsizei)size.height);
        
        // 3. 調用父類 visit 繪製子節點 (在裁剪區域內)
        Node::visit(renderer, parentTransform, parentFlags);
        
        // 4. 禁用 Scissor Test (恢復狀態)
        glDisable(GL_SCISSOR_TEST);
    }
    
    // 獲取裁剪區域 (示例:使用自身 contentSize 作為裁剪區)
    virtual cocos2d::Rect getClippingRect() {
        return cocos2d::Rect(0, 0, this->getContentSize().width, this->getContentSize().height);
    }
};

關鍵點詳解

步驟說明
glEnable(GL_SCISSOR_TEST)啟用 OpenGL 裁剪測試,後續繪製命令僅影響裁剪矩形內的像素
glScissor(x, y, w, h)設置裁剪矩形,**座標系為 OpenGL 視口座標 (左下角原點,像素單位)**,非 Cocos2d-x 節點座標
座標轉換必須將節點座標系下的矩形轉換為視口座標:
auto worldRect = node->getBoundingBoxToWorld();
再配合 Director::getInstance()->getOpenGLView()->getFrameSize() 等計算
Node::visit(...)在裁剪狀態下繪製自身及所有子節點
glDisable(GL_SCISSOR_TEST)**必須成對調用**,否則影響後續無關節點渲染

簡化版:使用內建 ClippingNode (Cocos2d-x 3.0+)

引擎已提供 cocos2d::ClippingNode (繼承自 Node),基於 Stencil Buffer 實現任意形狀裁剪,比 Scissor Test 更強大:


auto clippingNode = ClippingNode::create();
// 設置模板節點 (定義裁剪形狀,這裡用矩形)
auto stencil = DrawNode::create();
stencil->drawSolidRect(Vec2(0,0), Vec2(300,200), Color4F::WHITE);
clippingNode->setStencil(stencil);
// 反轉模板 (可選)
clippingNode->setInverted(false);
// 添加內容節點
clippingNode->addChild(sprite);
this->addChild(clippingNode);

優勢:支援非矩形裁剪 (圓形、多邊形、不規則形狀)、抗鋸齒、嵌套裁剪。

性能與注意事項

  • Scissor Test:GPU 級硬件裁剪,**性能極高**,但僅支援**軸對齊矩形**,不支援旋轉/縮放後的非軸對齊矩形。
  • ClippingNode (Stencil):支援任意形狀,但會增加 Draw Call 和 Stencil Buffer 操作,大量使用需注意性能。
  • **坐標轉換是難點**:務必在 visit 中使用最新的變換矩陣計算世界座標下的裁剪矩形。
  • 嵌套裁剪時,內層需結合外層裁剪區域取交集。

總結

**推薦使用內建 ClippingNode` + `DrawNode` 模板** 實現,代碼簡潔、功能強大、官方維護。僅在極度追求性能且裁剪區域為固定軸對齊矩形時,考慮手工 visit() + GL_SCISSOR_TEST。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved