2015-12-16 131 views
0

我想繪製一個帶透明度的紋理到背景漸變上,由頂點着色器創建,該頂點着色器在頂點之間插入顏色。但是,只有紋理的不透明部分正在繪製。Open GL ES透明紋理不混合

我現在用的是混合功能:

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; 
} 

的Ÿ想法我做錯了什麼?

+0

你的片段着色器不能爲我編譯。你不是指'gl_FragColor = destinationColor + texture2D(tex,texCoordOut);' – Reigertje

+0

oops,是的,我的意思是。我已更新OP – Hamish

+0

您預計何時發生混合? – Reigertje

回答

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); 

或任何其他混合功能你的願望。

+0

同意,你的方法更靈活。謝謝 – Hamish

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; 
}