找回密码
 立即注册
查看: 569|回复: 0

[简易教程] cocos2d-x 3.x ccUILayout里的裁剪bug

[复制链接]
发表于 2021-5-28 15:16 | 显示全部楼层 |阅读模式
我们项目有个需求,实行任意形状的遮罩,并且可能有多层叠加,嵌套,blendmode无法实现这么复杂的功能,而如果使用rendertexture呢,效率会变得很低,失帧严重,所以最终决定使用stencil这个opengl的功能。

这样的话跟UIListView里的stencil就有冲突了,然而,UIListView里的裁剪都是矩形,所以用stencil来实现未免大材小用,于是决定将UIListView里的裁剪修改为SCISSOR。

本以为直接将构造函数里的setClippingType改成ClippingType::SCISSOR就行了,可是,改完了发现两个问题,1位置不对,2,有时候多层嵌套,显示不对。

可能是官方默认用了stencil之后没有测试过SCISSOR的显示,其实修改Layout:getClippingRect()方法就行了,这里要考虑的是如果父节点或者更上层的节点也带了裁剪,那么计算时,这个rect就不能超出父节点的裁剪范围。

主要修改如下


const Rect& Layout::getClippingRect()
{
    if (_clippingRectDirty)
    {
        Vec2 worldPos = convertToWorldSpace(Vec2::ZERO);
        AffineTransform t = getNodeToWorldAffineTransform();
        float scissorWidth = _contentSize.width*t.a;
        float scissorHeight = _contentSize.height*t.d;
        Rect parentClippingRect;
        Node* parent = this;//这里的原来是Layout* parent,当然这么改之后,Node也要改,加一个isClippingEnabled()函数

        while (parent)
        {
//这里原来是转换为Layout,这样的问题是如果中间有一个节点不是Layout的话,嵌套关系就会中断,裁剪区域就会有问题
            parent = dynamic_cast<Node*>(parent->getParent());

            if(parent && parent->isClippingEnabled())
                        {
                                Layout * layoutP = dynamic_cast<Layout*>(parent);
                                if (layoutP != nullptr)
                                {
                                        _clippingParent = layoutP;
                                        break;
                                }
            }
        }
        
        if (_clippingParent)
        {
            parentClippingRect = _clippingParent->getClippingRect();
            //以下也是重写了的,原来的区域计算完全不对
                        float finalX = worldPos.x;
                        float finalY = worldPos.y;
                        float finalWidth = scissorWidth;
                        float finalHeight = scissorHeight;
                        if (finalX < parentClippingRect.origin.x) finalX = parentClippingRect.origin.x;
                        if (finalY < parentClippingRect.origin.y) finalY = parentClippingRect.origin.y;
                        if (worldPos.x + scissorWidth>parentClippingRect.origin.x + parentClippingRect.size.width)
                                finalWidth = parentClippingRect.origin.x + parentClippingRect.size.width - worldPos.x ;
                        if (worldPos.y+scissorHeight>parentClippingRect.origin.x+parentClippingRect.size.height)
                                finalHeight=parentClippingRect.origin.y+parentClippingRect.size.height-worldPos.y;

            _clippingRect.origin.x = finalX;
            _clippingRect.origin.y = finalY;
            _clippingRect.size.width = finalWidth;
            _clippingRect.size.height = finalHeight;
        }
        else
                {
                        _clippingRect.origin.x = worldPos.x;
                        _clippingRect.origin.y = worldPos.y;
            _clippingRect.size.width = scissorWidth;
            _clippingRect.size.height = scissorHeight;
        }
        _clippingRectDirty = false;
    }
    return _clippingRect;
}
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-11-23 17:17 , Processed in 0.098154 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表