cocos2dv2.1で追加されたCCClippingNodeを試す
この記事は、cocos2dv2.1で追加されたCCDrawNodeを試す - taoru's memo の続きです。
今回はCCClippingNodeを試す。これを使うといわゆるmask効果を得られる。
が、適当に試しててもなかなか思い通りにできなかったので、練習する。
CCClippingNode.h についてるコメント
/** CCClippingNode is a subclass of CCNode.
It draws its content (childs) clipped using a stencil.
The stencil is an other CCNode that will not be drawn.
The clipping is done using the alpha part of the stencil (adjusted with an alphaThreshold).
*/stencilによって、clippingNodeにaddChildされたCCNodeをクリッピングする。
そのstencilは(clippingNodeとは別の?)CCNodeで、描画されることがない。
stencilの透過部分がクリッピングに使われる
setできるparameter
/** The CCNode to use as a stencil to do the clipping. The stencil node will be retained. This default to nil. */ @property (nonatomic, retain) CCNode *stencil; /** The alpha threshold. The content is drawn only where the stencil have pixel with alpha greater than the alphaThreshold. Should be a float between 0 and 1. This default to 1 (so alpha test is disabled). */ @property (nonatomic) GLfloat alphaThreshold; /** Inverted. If this is set to YES, the stencil is inverted, so the content is drawn where the stencil is NOT drawn. This default to NO. */ @property (nonatomic) BOOL inverted;以下は私の解釈
- stencil
- stencilTestに使用されるCCNode, このNodeによってマスクされる
- alphaThreshold
- 直訳でalpha値のしきい値。
- stencilのうちalphaThresholdより大きいalpha値を持つpixelのみコンテンツが描画される。
- inverted
- これがYESだとstencilTestの結果が逆転して、stencilが描画されない領域だけが描画されるようになる。
英語が弱すぎてかなりあやふやですが、そこはTry&Errorでカバーしましょう…
が、いっこうにうまくいかない
まずAppDelegate.m のCCGLViewを定義している箇所を書き換えて、stencil bufferを有効にする(たぶん)
// Create an CCGLView with a RGB565 color buffer, and a depth buffer of 0-bits CCGLView *glView = [CCGLView viewWithFrame:[window_ bounds] pixelFormat:kEAGLColorFormatRGB565 depthFormat:GL_DEPTH24_STENCIL8_OES //GL_DEPTH_COMPONENT24_OES preserveBackbuffer:NO sharegroup:nil multiSampling:NO numberOfSamples:0];サンプルを元に、ClippingNodeを試す(NGコード)
- (id)init { if (self = [super init]) { CGPoint square[] = { {-100,-100}, {100,-100}, {100,100}, {-100,100} }; CGPoint triangle[] = { {-50,-50}, {50,-50}, {0,50}}; ccColor4F green = ccc4FFromccc3B(ccGREEN); ccColor4F red = ccc4FFromccc3B(ccRED); // contents部分 これを表示させたい CCDrawNode *content = [CCDrawNode node]; [content drawPolyWithVerts:square count:4 fillColor:green borderWidth:0 borderColor:green]; content.position = ccp(50, 50); // stencil これでマスクする CCDrawNode *stencil = [CCDrawNode node]; [stencil drawPolyWithVerts:triangle count:3 fillColor:red borderWidth:0 borderColor:red]; stencil.position = ccp(50, 50); [stencil runAction:[CCRepeatForever actionWithAction:[CCRotateBy actionWithDuration:1 angle:90]]]; CCClippingNode *clippingNode = [CCClippingNode clippingNode]; clippingNode.anchorPoint = ccp(0.5f, 0.5f); clippingNode.alphaThreshold = 0.05f; clippingNode.stencil = stencil; // clippingしたいnodeを、clippingNodeにaddChildする [clippingNode addChild:content]; clippingNode.position = ccp(self.contentSize.width/2 -50, self.contentSize.height/2 - 50); [self addChild:clippingNode]; } return self; }
サンプルとほぼ同じなのに、できない。何がいけないんだろう。
追記1
alphaThresholdの指定を外したらできた!(defaultでは1になってる)
alphaThresholdについての理解ができていない。まだまだマスターには遠いな。
上記からalphaThresholdを外して、contentにCCSpriteを使ってみた。
- (id)init { if (self = [super init]) { CGPoint triangle[] = { {-100,-100}, {100,-100}, {0,100}}; ccColor4F red = ccc4FFromccc3B(ccRED); // contents部分 これを表示させたい CCSprite *content = [CCSprite spriteWithFile:@"Default@2x.png"]; content.position = ccp(50, 50); // stencil これでマスクする CCDrawNode *stencil = [CCDrawNode node]; [stencil drawPolyWithVerts:triangle count:3 fillColor:red borderWidth:0 borderColor:red]; stencil.position = ccp(50, 50); [stencil runAction:[CCRepeatForever actionWithAction:[CCRotateBy actionWithDuration:1 angle:90]]]; CCClippingNode *clippingNode = [CCClippingNode clippingNode]; clippingNode.anchorPoint = ccp(0.5f, 0.5f); clippingNode.stencil = stencil; [clippingNode addChild:content]; clippingNode.position = ccp(self.contentSize.width/2 -50, self.contentSize.height/2 - 50); [self addChild:clippingNode]; } return self; }
こいつは面白い。
次にstencil部分に CCSpriteを使ってみた。
- (id)init { if (self = [super init]) { // CGPoint triangle[] = { {-100,-100}, {100,-100}, {0,100}}; // ccColor4F red = ccc4FFromccc3B(ccRED); // contents部分 これを表示させたい CCSprite *content = [CCSprite spriteWithFile:@"Default@2x.png"]; content.position = ccp(50, 50); // stencil これでマスクする // CCDrawNode *stencil = [CCDrawNode node]; // [stencil drawPolyWithVerts:triangle count:3 fillColor:red borderWidth:0 borderColor:red]; CCSprite *stencil = [CCSprite spriteWithFile:@"star.png"]; stencil.position = ccp(50, 50); stencil.scale = 1.5f; [stencil runAction:[CCRepeatForever actionWithAction:[CCRotateBy actionWithDuration:1 angle:90]]]; CCClippingNode *clippingNode = [CCClippingNode clippingNode]; clippingNode.anchorPoint = ccp(0.5f, 0.5f); clippingNode.stencil = stencil; clippingNode.alphaThreshold = 0.01; [clippingNode addChild:content]; clippingNode.position = ccp(self.contentSize.width/2 -50, self.contentSize.height/2 - 50); [self addChild:clippingNode]; } return self; }
CCSpriteをstencilに用いるときは、alphaThresholdを設定する必要があった。
default(1.0f)だと何も表示されなかったので、0より大きい0.01をセットした。
-
- 2013/03/06
childやstencilにCCNodeを使い、更にactionがつく場合の制御が意外と難しい。
CCNodeのcontentSizeが関係しているかも?