打开GL ES透明纹理不混合

时间:2015-12-16 16:01:42

标签: ios objective-c opengl-es textures opengl-es-2.0

我正在尝试将透明度的纹理绘制到背景渐变上,由顶点着色器创建,该顶点着色器在顶点之间插入颜色。但是,只绘制纹理的不透明部分。

我正在使用混合功能:

glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

渲染代码:

struct vertex {
    float position[3];
    float color[4];
    float texCoord[2];
};

typedef struct vertex vertex;

const vertex vertices[] = {
    {{1, -1, 0}, {0, 167.0/255.0, 253.0/255.0, 1}, {1, 0}}, // BR (0)
    {{1, 1, 0}, {0, 222.0/255.0, 1.0, 1}, {1, 1}}, // TR (1)
    {{-1, 1, 0}, {0, 222.0/255.0, 1.0, 1}, {0, 1}}, // TL (2)
    {{-1, -1, 0}, {0, 167.0/255.0, 253.0/255.0, 1}, {0, 0}}, // BL (3)
};

const GLubyte indicies[] = {
    3, 2, 0, 1
};

-(void) render {

    glViewport(0, 0, self.frame.size.width, self.frame.size.height);

    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);

    glVertexAttribPointer(positionSlot, 3, GL_FLOAT, GL_FALSE, sizeof(vertex), 0);
    glVertexAttribPointer(colorSlot, 4, GL_FLOAT, GL_FALSE, sizeof(vertex), (GLvoid*)(sizeof(float)*3));
    glVertexAttribPointer(textureCoordSlot, 2, GL_FLOAT, GL_FALSE, sizeof(vertex), (GLvoid*)(sizeof(float)*7));

    glDrawElements(GL_TRIANGLE_STRIP, sizeof(indicies)/sizeof(indicies[0]), GL_UNSIGNED_BYTE, 0);

    // Not sure if required for blending to work..
    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texture);
    glUniform1i(textureUniform, 0);

    glVertexAttribPointer(positionSlot, 3, GL_FLOAT, GL_FALSE, sizeof(vertex), 0);
    glVertexAttribPointer(colorSlot, 4, GL_FLOAT, GL_FALSE, sizeof(vertex), (GLvoid*)(sizeof(float)*3));
    glVertexAttribPointer(textureCoordSlot, 2, GL_FLOAT, GL_FALSE, sizeof(vertex), (GLvoid*)(sizeof(float)*7));


    glDrawElements(GL_TRIANGLE_STRIP, sizeof(indicies)/sizeof(indicies[0]), GL_UNSIGNED_BYTE, 0);


    [context presentRenderbuffer:GL_RENDERBUFFER];
}

我不确定是否需要对渲染缓冲区进行两次绘制才能使混合函数正常工作,所以目前我绘制时没有纹理绑定,然后将其绑定。

片段着色器:

varying lowp vec4 destinationColor;

varying lowp vec2 texCoordOut;
uniform sampler2D tex;

void main() {
    lowp vec4 tex2D = texture2D(tex, texCoordOut);
    gl_FragColor = vec4(tex2D.rgb+destinationColor.rgb, tex2D.a*destinationColor.a);
}

顶点着色器:

attribute vec4 position;

attribute vec4 sourceColor;
varying vec4 destinationColor;

attribute vec2 texCoordIn;
varying vec2 texCoordOut;


void main() {
    destinationColor = sourceColor;
    gl_Position = position;
    texCoordOut = texCoordIn;
}

纹理加载代码:

-(GLuint) loadTextureFromImage:(UIImage*)image {

    CGImageRef textureImage = image.CGImage;

    size_t width = CGImageGetWidth(textureImage);
    size_t height = CGImageGetHeight(textureImage);

    GLubyte* spriteData = (GLubyte*) malloc(width*height*4);

    CGColorSpaceRef cs = CGImageGetColorSpace(textureImage);
    CGContextRef c = CGBitmapContextCreate(spriteData, width, height, 8, width*4, cs, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
    CGColorSpaceRelease(cs);

    CGContextScaleCTM(c, 1, -1);
    CGContextTranslateCTM(c, 0, -CGContextGetClipBoundingBox(c).size.height);

    CGContextDrawImage(c, (CGRect){CGPointZero, {width, height}}, textureImage);
    CGContextRelease(c);

    GLuint glTex;
    glGenTextures(1, &glTex);
    glBindTexture(GL_TEXTURE_2D, glTex);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (int)width, (int)height, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData);

    glBindTexture(GL_TEXTURE_2D, 0);

    free(spriteData);

    return glTex;
}

任何想法我做错了什么?

2 个答案:

答案 0 :(得分:1)

你给自己的答案可能足以满足你的特殊情况,但我认为这不是一个很好的解决方案。当您想要渲染两个以上的对象时,可能会遇到很多问题。

您绘制两次相同的对象。首先没有纹理绑定,然后纹理绑定 - 在着色器中完成混合。但是你如何用第三个对象做到这一点?

我建议为两个对象使用不同的顶点集。像这样:

const vertex gradient_background[] = {
    {{1, -1, 0}, {0, 167.0/255.0, 253.0/255.0, 1}, {1, 0}},
    {{1, 1, 0}, {0, 222.0/255.0, 1.0, 1}, {1, 1}}, 
    {{-1, 1, 0}, {0, 222.0/255.0, 1.0, 1}, {0, 1}}, 
    {{-1, -1, 0}, {0, 167.0/255.0, 253.0/255.0, 1}, {0, 0}}
};

const vertex textured_object[] = {
    {{1, -1, 0}, {0, 0, 0, 0}, {1, 0}},
    {{1, 1, 0}, {0, 0, 0, 0}, {1, 1}},
    {{-1, 1, 0}, {0, 0, 0, 0}, {0, 1}}, 
    {{-1, -1, 0}, {0, 0, 0, 0}, {0, 0}}
};

适当调整渲染功能,绘制后也将纹理解除绑定为0。

-(void) render {

    ...

    glVertexAttribPointer(positionSlot, 3, GL_FLOAT, GL_FALSE, sizeof(gradient_background), 0);
    glVertexAttribPointer(colorSlot, 4, GL_FLOAT, GL_FALSE, sizeof(gradient_background), (GLvoid*)(sizeof(float)*3));
    glVertexAttribPointer(textureCoordSlot, 2, GL_FLOAT, GL_FALSE, sizeof(gradient_background), (GLvoid*)(sizeof(float)*7));

    glDrawElements(GL_TRIANGLE_STRIP, sizeof(indicies)/sizeof(indicies[0]), GL_UNSIGNED_BYTE, 0);

    ...

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texture);
    glUniform1i(textureUniform, 0);

    glVertexAttribPointer(positionSlot, 3, GL_FLOAT, GL_FALSE, sizeof(textured_object), 0);
    glVertexAttribPointer(colorSlot, 4, GL_FLOAT, GL_FALSE, sizeof(textured_object), (GLvoid*)(sizeof(float)*3));
    glVertexAttribPointer(textureCoordSlot, 2, GL_FLOAT, GL_FALSE, sizeof(textured_object), (GLvoid*)(sizeof(float)*7));


    glDrawElements(GL_TRIANGLE_STRIP, sizeof(indicies)/sizeof(indicies[0]), GL_UNSIGNED_BYTE, 0);

    // Don't forget to unbind texture for next draw
    glBindTexture(GL_TEXTURE_2D, 0);

    ...
}

片段着色器

varying lowp vec4 destinationColor;

varying lowp vec2 texCoordOut;
uniform sampler2D tex;

void main() {
    lowp vec4 tex2D = texture2D(tex, texCoordOut); // Returns (0, 0, 0, 1) when texture 0 is bound
    gl_FragColor = destinationColor + tex2D;
}

然后使用

glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

或您希望的任何其他混合功能。

答案 1 :(得分:0)

好吧,我觉得很傻。尝试在片段着色器外部使用混合函数并没有做任何事情,因为已经绘制了纹理。我只需要在片段着色器中使用等效的东西:

varying lowp vec4 destinationColor;

varying lowp vec2 texCoordOut;
uniform sampler2D tex;

void main() {
    lowp vec4 tex2D = texture2D(tex, texCoordOut);    
    lowp vec4 result = tex2D + vec4(1.0 - tex2D.a) * destinationColor;

    gl_FragColor = result;
}