Overlaying a transparent color over a Texture with GLSL

3.1k views Asked by At

I have an image that I am loading using the Slick library, and the image renders fine without my shader active. When I use my shader to overlay a transparent color over the image the entire image is replaced by the transparent color.

without the shader

With the shader

Vertex Shader

varying vec4 vertColor;

void main(){
    vec4 posMat = gl_Vertex;
    gl_Position = gl_ModelViewProjectionMatrix * posMat;
    vertColor = vec4(0.5, 1.0, 1.0, 0.2);
}

Fragment Shader

varying vec4 vertColor;

void main(){
    gl_FragColor = vertColor;
}

Sprite Rendering Code

Color.white.bind();
GL11.glBindTexture(GL11.GL_TEXTURE, image.getTextureID());
GL11.glBegin(GL11.GL_QUADS);
GL11.glTexCoord2f(0, 0);
GL11.glVertex2f(this.x, this.y);
GL11.glTexCoord2f(1, 0);
GL11.glVertex2f(x + w, y);
GL11.glTexCoord2f(1, 1);
GL11.glVertex2f(x + w, y + h);
GL11.glTexCoord2f(0, 1);
GL11.glVertex2f(x, y + h);
GL11.glEnd();
GL11.glBindTexture(GL11.GL_TEXTURE, 0);

}

OpenGL Initialization

GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glLoadIdentity();
GL11.glOrtho(0, Screen.getW(), Screen.getH(), 0, -1, 1);
GL11.glMatrixMode(GL11.GL_MODELVIEW);
GL11.glEnable(GL11.GL_TEXTURE_2D);
GL11.glEnable(GL11.GL_BLEND);
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
1

There are 1 answers

1
AudioBubble On BEST ANSWER

a) vertColor = vec4(0.5, 1.0, 1.0, 0.2); b) gl_FragColor = vertColor;

the shader does exactly what you asked of it - it sets the color of all fragments to that color. If you want to blend colors, you should add/multiply them in the shader in some fashion (e.g. have a color attribute and/or texture sampler, and then, after exporting the attribute from vertex shader to fragment shader, use gl_FragColor = vertexColor * textureColor * blendColor; etc).

also note: you're mixing fixed-function pipeline with immediate mode (glBegin/glEnd) with shaders... that's not a good idea. Also, I don't see where your uniforms are set; using shaders without uniforms == asking for trouble.

IMO the best solution would be to either use regular OpenGL >= 3.1 with proper, compliant shaders etc. or only use fixed-function pipeline and no shaders with legacy OpenGL.


As to how to load a texture with GLSL: (see https://www.opengl.org/sdk/docs/tutorials/ClockworkCoders/texturing.php for more info if needed)

a) you feed the data to GPU by creating a texture & binding it to GPU texture unit by calling

int id = glGenTexture();
glBindTexture( GL_TEXTURE_2D, id );
glTexImage2D( ... );
// see https://www.opengl.org/sdk/docs/man/html/glTexImage2D.xhtml for details

(what I suppose you've already done, since you're using glBindTexture with image param already)

b) you provide UV texture coordinates for your geometry; you're already doing it by supplying glTexCoord2f, which will probably allow you to use legacy attribute names as in https://www.opengl.org/sdk/docs/tutorials/ClockworkCoders/attributes.php, but the proper way way would be to pass it as a part of packed attribute structure,

c) you use the bound texture by sampling the texture in the shader, e.g. (legacy GLSL follows)

// vertex shader
varying vec2 vTexCoord;

void main() {
   vTexCoord = gl_MultiTexCoord0;
   gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}

// fragment shader
uniform sampler2D texture;
varying vec2 vTexCoord;

void main() {
   vec4 colorMultiplier = vec4(0.5, 1.0, 1.0, 0.2);
   gl_FragColor = texture2D(texture, vTexCoord) * colorMultiplier;
}

still, if you intend on changing it at runtime, it'd be best to pass the colorMultiplier as a uniform.