我该如何在iPhone上使用遮罩裁剪图像并将其与另一张图像(背景)合并?(首选OpenGL ES 1.1)

7
我需要将三张图片合并成如附图所示的方式:
1)一张图片是背景。它在实质上是“实心”的,没有alpha通道。
2)另一张是精灵。精灵位于背景之上。精灵可能有自己的alpha通道,在精灵透明的地方,背景必须可见。
3)有许多掩码:我每一帧都会对精灵应用新的掩码。掩码不是矩形的。
换句话说,如果裁剪掩码对应的颜色为白色或精灵透明,则可见像素=背景像素;否则,可见像素=精灵像素(例如,相应掩码的像素为黑色)。
我正在使用cocos2d-iphone。我能用cocos2d-iphone或OpenGL ES 1.1做出这样的组合吗?如果任何一个答案是YES,则赠送工作代码。如果两个答案都是否定的,那么在iOS上有另一种技术可以实现我的愿望吗(也许是Quartz2d或OpenGL ES 2.0)?
掩码格式不一定是精灵为黑色,背景为白色。如果需要,我可以制作所需格式的掩码,例如背景透明和精灵为白色。
P.S. 还有一个未回答的同类问题:Possible to change the alpha value of certain pixels on iPhone?

对于阅读此问题的任何人来说,认识到有一种日常技术可完全地、彻底地实现这一点,而不需要以任何方式使用OpenGL是很好的...http://developer.apple.com/library/mac/#documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_images/dq_images.html - Fattie
1个回答

9
这是关于OpenGL的答案。对于Quartz过程将非常不同。 实际的代码很简单,但要确保完全正确就比较棘手。我正在使用一个具有1024X1024大小和原点在左下角的GL上下文。我不会发布我的代码,因为它使用了OpenGL|ES中不可用的即时模式。如果您需要我的绘图代码,请让我知道,我会更新我的答案。
1. 使用禁用混合的方法绘制蒙版。 2. 启用混合,设置GLBlendFunc(GL_DST_COLOR, GL_ZERO),并绘制渗透纹理。我的蒙版在应该渗透的地方是白色的。在你的问题中,它是黑色的。 3. 现在要绘制背景,将混合函数设置为glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_DST_COLOR),并绘制背景纹理。 编辑 这里是我上面描述的代码。请注意,这不会在iOS上工作,因为那里没有即时模式,但您应该能够在Macintosh项目中使其正常工作。一旦这样做正常,您可以将其转换为在iOS项目中兼容的代码,并将该代码移动到您的iOS项目中。
renderMask()调用是最有趣的部分。renderTextures()在顶行绘制示例纹理。
static GLuint color_texture;
static GLuint mask_texture;
static GLuint background_texture;

static float window_size[2];

void renderMask()
{
float texture_x=0, texture_y=0;
float x=0, y=0;

{
    glBindTexture(GL_TEXTURE_2D, mask_texture);
    
    glDisable(GL_BLEND);
    glBegin(GL_QUADS);
        glTexCoord2f(texture_x,texture_y);
        glVertex2f(x,y);
        
        glTexCoord2f(texture_x+1.0,texture_y);
        glVertex2f(x+512.0,y);
        
        glTexCoord2f(texture_x+1.0,texture_y+1.0);
        glVertex2f(x+512.0,y+512.0);
        
        glTexCoord2f(texture_x,texture_y+1.0);
        glVertex2f(x,y+512.0);
    glEnd();
}

{
    glBindTexture(GL_TEXTURE_2D, color_texture);
    glEnable(GL_BLEND);
    glBlendFunc(GL_DST_COLOR, GL_ZERO);
    glBegin(GL_QUADS);
        glTexCoord2f(texture_x,texture_y);
        glVertex2f(x,y);
        
        glTexCoord2f(texture_x+1.0,texture_y);
        glVertex2f(x+512.0,y);
        
        glTexCoord2f(texture_x+1.0,texture_y+1.0);
        glVertex2f(x+512.0,y+512.0);
        
        glTexCoord2f(texture_x,texture_y+1.0);
        glVertex2f(x,y+512.0);
    glEnd();
}

{   
    glBindTexture(GL_TEXTURE_2D, background_texture);
    glEnable(GL_BLEND);
    glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_DST_COLOR);
    glBegin(GL_QUADS);
        glTexCoord2f(texture_x,texture_y);
        glVertex2f(x,y);
        
        glTexCoord2f(texture_x+1.0,texture_y);
        glVertex2f(x+512.0,y);
        
        glTexCoord2f(texture_x+1.0,texture_y+1.0);
        glVertex2f(x+512.0,y+512.0);
        
        glTexCoord2f(texture_x,texture_y+1.0);
        glVertex2f(x,y+512.0);
    glEnd();
}
}

// Draw small versions of the textures.
void renderTextures()
{
float texture_x=0, texture_y=0;
float x=0, y=532.0;
float size = 128;

{
    glBindTexture(GL_TEXTURE_2D, mask_texture);
    
    glDisable(GL_BLEND);
    glBegin(GL_QUADS);
        glTexCoord2f(texture_x,texture_y);
        glVertex2f(x,y);
        
        glTexCoord2f(texture_x+1.0,texture_y);
        glVertex2f(x+size,y);
        
        glTexCoord2f(texture_x+1.0,texture_y+1.0);
        glVertex2f(x+size,y+size);
        
        glTexCoord2f(texture_x,texture_y+1.0);
        glVertex2f(x,y+size);
    glEnd();
}

{
    glBindTexture(GL_TEXTURE_2D, color_texture);
    x = size + 16;

    glBegin(GL_QUADS);
        glTexCoord2f(texture_x,texture_y);
        glVertex2f(x,y);
        
        glTexCoord2f(texture_x+1.0,texture_y);
        glVertex2f(x+size,y);
        
        glTexCoord2f(texture_x+1.0,texture_y+1.0);
        glVertex2f(x+size,y+size);
        
        glTexCoord2f(texture_x,texture_y+1.0);
        glVertex2f(x,y+size);
    glEnd();
}

{
    glBindTexture(GL_TEXTURE_2D, background_texture);
    x = size*2 + 16*2;
    glBegin(GL_QUADS);
        glTexCoord2f(texture_x,texture_y);
        glVertex2f(x,y);
        
        glTexCoord2f(texture_x+1.0,texture_y);
        glVertex2f(x+size,y);
        
        glTexCoord2f(texture_x+1.0,texture_y+1.0);
        glVertex2f(x+size,y+size);
        
        glTexCoord2f(texture_x,texture_y+1.0);
        glVertex2f(x,y+size);
    glEnd();
}
}

void init()
{
GLdouble bounds[4];

glGetDoublev(GL_VIEWPORT, bounds);

window_size[0] = bounds[2];
window_size[1] = bounds[3];

glClearColor(0.0, 0.0, 0.0, 1.0);

glShadeModel(GL_SMOOTH);

// Load our textures...
color_texture = [[NSImage imageNamed:@"colors"] texture];
mask_texture = [[NSImage imageNamed:@"mask"] texture];
background_texture = [[NSImage imageNamed:@"background"] texture];

    
// Enable alpha blending.  We'll learn more about this later
glEnable(GL_BLEND);

glEnable(GL_TEXTURE_2D);
}

void draw()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glColor3f(1.0, 1.0, 1.0);

renderMask();
renderTextures();
}

void reshape(int width, int height)
{
glViewport(0, 0, width, height);

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0, width, 0.0, height);
glMatrixMode(GL_MODELVIEW);

window_size[0] = width;
window_size[1] = height;
}

这里展示了我正常绘制的三个纹理(裁剪、透出和背景),然后在下方组合在一起。

image


似乎不起作用 :( 想象一下Sprite上的黑点:在2)之后,我们会得到两种黑色 - Sprite上的黑点的黑色和未掩蔽区域的黑色。在3)中,无论何处DST_COLOR为BLACK,背景都将出现。 - Oleg Trakhman
我指的是精灵的黑色像素,如果它们在掩码内,则应保持为黑色,而不是背景。 - Oleg Trakhman
遮罩需要在渗透处为白色。第二步中的混合将遮罩颜色值乘以渗透纹理的值。如果遮罩是黑色(0,0,0),则乘法的结果为零。因此,你的cropping_mask.png需要在五边形内为白色,在五边形外为透明。 - Mark
好的。在第二步之后,您应该已经用透视模式填满了您的遮罩。 - Mark
1
请原谅,如果Sprite有一个被遮罩覆盖的黑色像素,那么在2)之后,我会裁剪Sprite,在黑色背景上,对吗?在3)之后,我在所有黑色像素上都有背景,对吗?之后,我的精灵的黑色像素变成了彩色。它就是不起作用,我尝试了很多混合方案,但它们似乎都不适合我的情况。问题是glBlend总是组合两个纹理,但我需要三个。除了混合之外还有其他东西吗? - Oleg Trakhman
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接