在SKEffectNode中设置自定义CIColorCube过滤器

时间:2014-02-23 23:16:46

标签: ios sprite-kit cifilter skeffectnode

我正在尝试创建一个SKEffectNode,它将在黑色背景上变为透明的任何绿色像素。出于测试目的,我想出这个东西,我想确保以下代码不会在SKEffectNode的子树内变得透明。以下代码实际上阻止了孩子被绘制,并且它吐出以下错误:

CIColorCube inputCubeData is not of the expected length.

这是创建SKEffectNode

的方法
- (SKEffectNode *) newVeil
{
    SKEffectNode *node = [[SKEffectNode alloc] init];

    node.shouldEnableEffects = YES;
    node.filter = [self createFilter];

    SKSpriteNode *darkness = [SKSpriteNode spriteNodeWithColor:[UIColor blackColor] size:self.view.frame.size];
    node.position = self.view.center;
    [node addChild:darkness];

    return node;
}

这就是我设置过滤器的方式(大多数,或者我敢说所有这些代码都在Apple's dev documents中)。

- (CIFilter *) createFilter
{
    // Allocate memory
    const unsigned int size = 64;
    float *cubeData = (float *)malloc (size * size * size * sizeof (float) * 4);
    float *c = cubeData;
    rgb rgbInput;
    hsv hsvOutput;

    // Populate cube with a simple gradient going from 0 to 1
    for (int z = 0; z < size; z++){
        rgbInput.b = ((double)z)/(size-1); // Blue value
        for (int y = 0; y < size; y++){
            rgbInput.g = ((double)y)/(size-1); // Green value
            for (int x = 0; x < size; x ++){
                rgbInput.r = ((double)x)/(size-1); // Red value
                // Convert RGB to HSV
                // You can find publicly available rgbToHSV functions on the Internet
                hsvOutput = rgb2hsv(rgbInput);
                // Use the hue value to determine which to make transparent
                // The minimum and maximum hue angle depends on
                // the color you want to remove
                float alpha = (hsvOutput.h > 120 && hsvOutput.h < 100) ? 0.0f: 1.0f;
                // Calculate premultiplied alpha values for the cube
                c[0] = rgbInput.b * alpha;
                c[1] = rgbInput.g * alpha;
                c[2] = rgbInput.r * alpha;
                c[3] = alpha;
                c += 4; // advance our pointer into memory for the next color value
            }
        }
    }
    // Create memory with the cube data
    NSData *data = [NSData dataWithBytesNoCopy:cubeData
                                        length:size
                                  freeWhenDone:YES];

    CIFilter *colorCube = [CIFilter filterWithName:@"CIColorCube"];
    [colorCube setValue:@(size) forKey:@"inputCubeDimension"];
    // Set data for cube
    [colorCube setValue:data forKey:@"inputCubeData"];

    return colorCube;
}

我无法发现问题。 CoreImage并没有很多经验。任何人吗?

更新1

我尝试将整个CIFilter导出到它自己的类中。

//  PMColorCube.h

#import <CoreImage/CoreImage.h>

@interface PMColorCube : CIFilter{
    CIImage *inputImage;
}
@property (retain, nonatomic) CIImage *inputImage;
@end



//  PMColorCube.m

#import "PMColorCube.h"

typedef struct {
    double r;       // percent
    double g;       // percent
    double b;       // percent
} rgb;

typedef struct {
    double h;       // angle in degrees
    double s;       // percent
    double v;       // percent
} hsv;

static hsv      rgb2hsv(rgb in);

@implementation PMColorCube
@synthesize inputImage;

hsv rgb2hsv(rgb in)
{
    hsv         out;
    double      min, max, delta;

    min = in.r < in.g ? in.r : in.g;
    min = min  < in.b ? min  : in.b;

    max = in.r > in.g ? in.r : in.g;
    max = max  > in.b ? max  : in.b;

    out.v = max;                                // v
    delta = max - min;
    if( max > 0.0 ) {
        out.s = (delta / max);                  // s
    } else {
        // r = g = b = 0                        // s = 0, v is undefined
        out.s = 0.0;
        out.h = NAN;                            // its now undefined
        return out;
    }
    if( in.r >= max )                           // > is bogus, just keeps compilor happy
        out.h = ( in.g - in.b ) / delta;        // between yellow & magenta
    else
        if( in.g >= max )
            out.h = 2.0 + ( in.b - in.r ) / delta;  // between cyan & yellow
        else
            out.h = 4.0 + ( in.r - in.g ) / delta;  // between magenta & cyan

    out.h *= 60.0;                              // degrees

    if( out.h < 0.0 )
        out.h += 360.0;

    return out;
}

- (CIImage *) outputImage
{
    const unsigned int size = 64;
    float *cubeData = (float *)malloc (size * size * size * sizeof (float) * 4);
    float *c = cubeData;
    rgb rgbInput;
    hsv hsvOutput;

    // Populate cube with a simple gradient going from 0 to 1
    for (int z = 0; z < size; z++){
        rgbInput.b = ((double)z)/(size-1); // Blue value
        for (int y = 0; y < size; y++){
            rgbInput.g = ((double)y)/(size-1); // Green value
            for (int x = 0; x < size; x ++){
                rgbInput.r = ((double)x)/(size-1); // Red value
                // Convert RGB to HSV
                // You can find publicly available rgbToHSV functions on the Internet
                hsvOutput = rgb2hsv(rgbInput);
                // Use the hue value to determine which to make transparent
                // The minimum and maximum hue angle depends on
                // the color you want to remove
                float alpha = (hsvOutput.h > 120 && hsvOutput.h < 100) ? 0.0f: 1.0f;
                // Calculate premultiplied alpha values for the cube
                c[0] = rgbInput.b * alpha;
                c[1] = rgbInput.g * alpha;
                c[2] = rgbInput.r * alpha;
                c[3] = alpha;
                c += 4; // advance our pointer into memory for the next color value
            }
        }
    }
    // Create memory with the cube data
    NSData *data = [NSData dataWithBytesNoCopy:cubeData
                                        length:size
                                  freeWhenDone:YES];

    CIFilter *colorCube = [CIFilter filterWithName:@"CIColorCube"];
    [colorCube setValue:@(size) forKey:@"inputCubeDimension"];
    // Set data for cube
    [colorCube setValue:data forKey:@"inputCubeData"];

    [colorCube setValue:self.inputImage forKey:kCIInputImageKey];
    CIImage *result = [colorCube valueForKey:kCIOutputImageKey];

    return result;
}
@end

我在运行时仍然遇到同样的错误

1 个答案:

答案 0 :(得分:2)

听起来很尴尬。我在创建NSData时在类方法中传递的大小与实际大小不对应。修正如下:

    // Create memory with the cube data
    NSData *data = [NSData dataWithBytesNoCopy:cubeData
                                        length:size * size * size * sizeof (float) * 4
                                  freeWhenDone:YES];