Reputation: 40719
I'm learning WebGL, and I would like to make a program, where there are colored, and textured objects also. I tried to modify a bit the fragment shader: If the object don't have texture, then it will be colored.
precision mediump float;
varying vec4 vColor;
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
void main(void) {
gl_FragColor = vColor;
gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
}
It doesn't works. I get an error: Could not initialize shaders.
Upvotes: 4
Views: 7500
Reputation:
This may or may not make sense but whether you have a texture or not requires different shaders. To get around this many people use a single pixel white texture when they don't want textures. That way they only need 1 shader to cover both cases. The shader might look something like this
uniform vec4 u_color;
uniform sampler2D u_texture;
varying vec2 v_texCoord;
void main(void) {
gl_FragColor = texture2D(u_texture, v_texCoord) * u_color;
}
Now, in your code you can draw textured like this
// at init time.
var whiteColor = new Float32Array([1, 1, 1, 1]);
// at draw time
gl.uniform4fv(u_colorLocation, whiteColor); // use white color
gl.bindTexture(gl.TEXTURE_2D, someTexture); // and some texture
... draw ...
And to draw un-textured you do this
// at init time.
var whiteTexture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, whiteTexture);
var whitePixel = new Uint8Array([255, 255, 255, 255]);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0,
gl.RGBA, gl.UNSIGNED_BYTE, whitePixel);
// at draw time
gl.uniform4fv(u_colorLocation, someColor); // use the color I want
gl.bindTexture(gl.TEXTURE_2D, whiteTexture); // use the white texture
... draw ...
That also gives you the ability to tint your textures by using a non white color and a texture together.
Upvotes: 10
Reputation: 34498
I think we may need to see some more code before we can hel you figure out the exact issue. For example, what does your vertex shader look like, and how are you linking them?
In the meantime there are a couple of pointers I can give you about the shader you posted. For one, it will not give you the effect that you described. What will actually happen is that it will always show the texture color or, if no texture is given, display black. The vertex color will never be shown. This is because you are assigning to the final fragment color twice, with the second assignment always overriding the first.
What you might want to try is blending the two values together by either adding or multiplying the color and texture values. Try something like so:
gl_FragColor = vColor + texture2D(uSampler, vTextureCoord);
The only problem there is that if the texture is empty you'll still get black (anything multiplied by 0 is still 0). To avoid that, always use a solid white texture if you don't have an actual texture available.
If you want the exact effect you described (vertex color only if no texture) you may need to use a conditional statement. Those are typically best avoided but I doubt your usage will be anything terribly heavy.
Also, as a style tip, The following lines are equivalent:
vec2(vTextureCoord.s, vTextureCoord.t)
vTextureCoord.st
The second may be faster, however, and should be preferred. Beyond that, however, you could just pass in vTextureCoord
directly (like I showed) because it already is a vec2.
Upvotes: 3