使用自定义形状的孔创建图层蒙版

时间:2011-04-19 18:52:32

标签: iphone ios cocos2d-iphone

我花了太多时间试图解决这个问题,但却找不到可行的解决方案。

情况: 1.手机上会显示“某事”的图片。 2.将半透明(例如蓝色)层放置在图像的顶部,完全覆盖它。 3.该层中的“洞”存在于该层的该部分完全透明且可移动的位置。

一个示例可能是缩放效果,您可以在图像周围移动此“洞”。在孔内,您可以正常看到图像,而在外面则被半透明层覆盖。注意:我在cocos2d层中实现它,其中图像由CCSprite表示。但是,如果没有使用cocos,那应该没关系。

问题: 我已经尝试使用CAShapeLayer和位图作为掩码,但没有任何工作(请参阅下面的代码片段)。使用CAShapeLayer,我为'hole'创建一个UIBezierPath并将其应用于彩色层。但是,只有孔显示颜色,而其余部分是透明的。使用图像,掩码根本不起作用(我不知道为什么)。我甚至尝试过掩盖面具,看看是否可行。我也试过交换颜色......从白色到黑色,以清除填充和背景。

一个简单的解决方案,如果它存在,将是反转UIBezierPath的区域。我也尝试使用路径剪辑......但没有运气。

我希望这简直是愚蠢的,我只是在俯视。也许你们其中一个人会看到这个。我不关心的那个动人的部分。我需要先让实际的面具工作。示例代码忽略了iPhone SDK和openGL之间的y轴差异。

CAShapeLayer示例:

CGSize winSize = [[CCDirector sharedDirector] winSize];
UIImage* img = [UIImage imageNamed:@"zebra.png"];
CCSprite* spr = [CCSprite spriteWithCGImage:img.CGImage key:@"img"];
spr.position = ccp( winSize.width / 2, winSize.width / 2 );
[self addSprite:spr];

UIBezierPath* path = [UIBezierPath bezierPathWithRect:rectHole];
CAShapeLayer* maskLayer = [CAShapeLayer layer];
maskLayer.bounds = [spr boundingBox];
maskLayer.position = spr.position;
maskLayer.fillColor = [UIColor whiteColor].CGColor;
maskLayer.backgroundColor = [UIColor clearColor].CGColor;
maskLayer.path = path.CGPath;

CALayer* colorLayer = [CALayer layer];
colorLayer.bounds = [spr boundingBox];
colorLayer.position = maskLayer.position;
[colorLayer setMask:maskLayer];

[[[[CCDirector sharedDirector] openGLView] layer] addSublayer:colorLayer];

多层模板示例:

CGSize winSize = [[CCDirector sharedDirector] winSize];
UIImage* img = [UIImage imageNamed:@"zebra.png"];
CCSprite* spr = [CCSprite spriteWithCGImage:img.CGImage key:@"img"];
spr.position = ccp( winSize.width / 2, winSize.width / 2 );
[self addSprite:spr];

UIBezierPath* path = [UIBezierPath bezierPathWithRect:rectHole];
CAShapeLayer* maskLayer = [CAShapeLayer layer];
maskLayer.bounds = [spr boundingBox];
maskLayer.position = spr.position;
maskLayer.fillColor = [UIColor whiteColor].CGColor;
maskLayer.backgroundColor = [UIColor clearColor].CGColor;
maskLayer.path = path.CGPath;

UIBezierPath* pathOuter = [UIBezierPath bezierPathWithRect:img.frame];
CAShapeLayer* outerLayer = [CAShapeLayer layer];
outerLayer.bounds = [spr boundingBox];
outerLayer.position = spr.position;
outerLayer.fillColor = [UIColor blackColor].CGColor;
outerLayer.backgroundColor = [UIColor whiteColor].CGColor;
outerLayer = pathOuter.CGPath;
[outerLayer setMask:maskLayer];

CALayer* colorLayer = [CALayer layer];
colorLayer.bounds = [spr boundingBox];
colorLayer.position = outerLayer.position;
[colorLayer setMask:outerLayer];

[[[[CCDirector sharedDirector] openGLView] layer] addSublayer:colorLayer];

图片掩码示例:

CGSize winSize = [[CCDirector sharedDirector] winSize];
UIImage* img = [UIImage imageNamed:@"zebra.png"];
CCSprite* spr = [CCSprite spriteWithCGImage:img.CGImage key:@"img"];
spr.position = ccp( winSize.width / 2, winSize.width / 2 );
[self addSprite:spr];

CGRect r = [spr boundingBox];
CGSize sz = CGSizeMake( r.size.width, r.size.height );
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
CGContextRef context = CGBitmapContextCreate( NULL, w, h, 8, 0, colorSpace, kCGBitmapByteOrderDefault | kCGImageAlphaNone );
CGColorSpaceRelease( colorSpace );
CGContextSetFillColorWithColor( context, [UIColor whiteColor].CGColor );
CGContextFillRect( context, r );
CGContextSetFillColorWithColor( context, [UIColor blackColor].CGColor );
CGContextFillRect( context, rectHole );
CGImageRef ref = CGBitmapContextCreateImage( context );
CGContextRelease( context );

CALayer* maskLayer = [CALayer layer];
maskLayer.bounds = [spr boundingBox];
maskLayer.position = spr.position;
[maskLayer setContents:(id)ref];

CALayer* colorLayer = [CALayer layer];
colorLayer.bounds = [spr boundingBox];
colorLayer.position = maskLayer.position;
[colorLayer setMask:maskLayer];

[[[[CCDirector sharedDirector] openGLView] layer] addSublayer:colorLayer];
CGImageRelease( ref );

1 个答案:

答案 0 :(得分:13)

我在学习了其他核心图形技术之后又回到了这里。 该解决方案最接近上面的多层掩码示例。 但是,您需要将两个路径组合成一个相反方向的单个UIBezierPath,而不是创建内层和外层。

因此,例如,创建要裁剪的内部区域的路径(CW)。注意:x,y,w,h指的是“洞”的起源和大小。

      [path moveToPoint:ccp(x,y)];
      [path addLineToPoint:ccp(x+w,y)];
      [path addLineToPoint:ccp(x+w,y+h)];
      [path addLineToPoint:ccp(x,y+h)];
      [path addLineToPoint:ccp(x,y)];

然后,将相反方向的外部区域(CCW)添加到相同的路径。注意:x,y,w,h是指外直肠的原点和大小。

      [path moveToPoint:ccp(x,y)];
      [path addLineToPoint:ccp(x,y+h)];
      [path addLineToPoint:ccp(x+w,y+h)];
      [path addLineToPoint:ccp(x+w,y)];
      [path addLineToPoint:ccp(x,y)];

然后将此路径应用于图层(maskLayer),该图层用作最终图层(colorLayer)上的蒙版。不需要“outerLayer”。