cocos2dx之ClippingNode

源码注释

/** ClippingNode is a subclass of Node.
 * It draws its content (children) clipped using a stencil.
 * The stencil is an other Node that will not be drawn.
 * The clipping is done using the alpha part of the stencil (adjusted with an alphaThreshold).
 */
  • 翻译注释:

    • ClippingNode是Node的子类。

    • 它通过一个模板节点去裁剪添加到它的子节点们。

    • 模板节点不会被渲染出来。

    • 裁剪是通过Alpha通道来实现的。

  • 补充说明:

    • 模板可以是一张图(即一个Sprite),也可以是一个DrawNode,甚至可以是一个Node(这个Node再添加如Sprite一类的子节点)。

    • setInverted(true或者false)裁剪成模板里面还是外面。

    • setAlphaThreshold(GLfloat n)。n的取值范围是0到1,模板图片会被n给分割成大于n和小于n的,从而形成丢弃和保留的部分。

      如果一张图有三种alpha通道值,那么可以通过修改n值,来裁剪出不同的形状。

Alpha通道

关于Alpha通道,可以参考这篇文章:什么是Alpha通道?

  • 摘录其中几句话:

    • 一个使用每个像素16比特存储的位图,对于图形中的每一个像素而言,可能以5个比特表示红色,5个比特表示绿色,5个比特表示蓝色,最后一个比特是阿尔法。在这种情况下,它表示透明或者不透明,因为阿尔法比特只有0或1两种不同表示的可能性。又如一个使用32个比特存储的位图,每8个比特表示红绿蓝,和阿尔法通道。在这种情况下,就不光可以表示透明还是不透明,阿尔法通道还可以表示256级的半透明度,因为阿尔法通道有8个比特可以有256种不同的数据表示可能性。

    • Alpha通道储存一个值,其外在表现是透明度,Alpha通道和透明度没啥关系。

    • 真正让图片变透明的不是Alpha,而是Alpha所代表的数值和其他数值做了一次运算。比如你有一张图片你想抠出图片中间的一部分,在PS里你会建立一个蒙板,然后在蒙板里把不需要的地方填充成黑色,需要的留成白色,这个时候实际上是是做了一次乘法。用黑色所代表的数值0去乘以你所填充的地方,那么这个地方就变透明了。

典型用法

//第一种方法:通过Sprite去裁剪
//这张图的路径cocos2d-x-3.17/tests/cpp-tests/Resources/Images/hole_effect.png
auto stencil = Sprite::create("res/hole_effect.png");
auto clip = ClippingNode::create(stencil);
clip->setPosition(Vec2(visibleSize.width / 2, visibleSize.height / 2));
clip->setAlphaThreshold(0.05);
clip->setInverted(true);
this->addChild(clip);
//这张图的路径cocos2d-x-3.17/tests/cpp-tests/Resources/Images/MagentaSquare.png
auto content = Sprite::create("res/MagentaSquare.png");
clip->addChild(content);
//第二种方法:通过DrawNode(多边形)去裁剪,这种方法不需要setAlphaThreshold
auto stencil = DrawNode::create();
const int cnt = 720;//用多少个点来画一个圆
int r = 10;//圆的半径
Vec2 arr[cnt];//组成圆的每个点的横纵坐标
for (int i = 0; i < cnt; i++)
{
    arr[i].x = r * cos( (360.0f/cnt) * i * (M_PI/180) );
    arr[i].y = r * sin( (360.0f/cnt) * i * (M_PI/180) );
}//不要写成360/cnt,脸一黑
stencil->drawPolygon(arr, cnt, Color4F::BLUE, 0, Color4F::ORANGE);
auto clip = ClippingNode::create(stencil);
clip->setPosition(Vec2(visibleSize.width / 2, visibleSize.height / 2));
clip->setInverted(true);
this->addChild(clip);
auto content = Sprite::create("res/MagentaSquare.png");
clip->addChild(content);
//第三种方法:通过DrawNode(点)去裁剪,这种方法需要setAlphaThreshold
auto stencil = DrawNode::create();
//DrawNode还有drawDot()和drawCircle()两个方法。
stencil->drawDot(Vec2(0, 0), 10, Color4F::BLUE);
auto clip = ClippingNode::create(stencil);
clip->setPosition(Vec2(visibleSize.width / 2, visibleSize.height / 2));
//如果不调用setAlphaThreshold(0.1)的话,裁剪出来是方的😂
clip->setAlphaThreshold(0.1);
clip->setInverted(true);
this->addChild(clip);
auto content = Sprite::create("res/MagentaSquare.png");
clip->addChild(content);
//第四种方法:模板节点可以是Node类型,下边再添加Sprite,这样也是可以的。
auto stencil = Node::create();
auto spr1 = Sprite::create("res/hole_effect.png");
stencil->addChild(spr1);
//同理,content也可以是空的Sprite,下边再添加Sprite。