This is the code I have for vs/fs and a simple cube that I want to put on to my canvas. some of the part is omitted for the sake of lengthiness.
<script id="cube-vs" type="notjs">
precision highhp float;
attribute vec3 vpos;
attribute vec3 vnormal;
attribute vec2 vtex;
varying vec3 fColor;
varying vec3 fNormal;
varying vec2 fTexCoord;
uniform mat4 view;
uniform mat4 proj;
uniform mat4 model;
uniform vec3 lightdir;
uniform vec3 cubecolor;
void main(void) {
gl_Position = proj * view * model * vec4(vpos, 1.0);
vec4 normal = normalize(model * vec4(vnormal,0.0));
float diffuse = .2 + abs(dot(normal, vec4(lightdir,0.0)));
fColor = (cubecolor * diffuse);
fTexCoord = vtex;
}
</script>
<script id="cube-fs" type="notjs">
precision highhp float;
varying vec3 fColor;
varying vec3 fNormal;
varying vec2 fTexCoord;
uniform sampler2D texSampler;
void main(void) {
vec4 texColor = texture2d(texSampler, fTexCoord);
gl_FragColor = vec4(fColor*texColor.xyz,1.0);
}
</script>
the cube
...
Cube.prototype.init = function(drawingState) {
var gl=drawingState.gl;
// create the shaders once - for all cubes
if (!shaderProgram) {
shaderProgram = twgl.createProgramInfo(gl, ["tree-vs", "tree-fs"]);
}
if (!buffers) {
var arrays = {
vpos : { numComponents: 3, data: [...] },
vnormal : {numComponents:3, data: [...]},
vtex : {numComponents:2, data: [
1,0,0,0,0,1,1,1,
1,0,0,0,0,1,1,1,
1,0,0,0,0,1,1,1,
1,0,0,0,0,1,1,1,
1,0,0,0,0,1,1,1,
1,0,0,0,0,1,1,1,
]},
indices : {[...]}
};
buffers = twgl.createBufferInfoFromArrays(gl,arrays);
}
if (!texture) {
texture = twgl.createTexture(gl, {src:textures/tree.jpg});
}
};
Cube.prototype.draw = function(drawingState) {
var modelM = twgl.m4.scaling([this.size*1.4,this.size*1.4,this.size*1.4]);
twgl.m4.setTranslation(modelM,this.position,modelM);
var gl = drawingState.gl;
gl.useProgram(shaderProgram.program);
twgl.setBuffersAndAttributes(gl,shaderProgram,buffers);
twgl.setUniforms(shaderProgram,{
view:drawingState.view, proj:drawingState.proj, lightdir:drawingState.sunDirection,
cubecolor:this.color, model: modelM, texSampler: texture);
twgl.drawBufferInfo(gl, gl.TRIANGLES, buffers);
};
the cube worked fine without texture but when I tried to put texture on, it never works I tried almost everything and I still can't figure out how to put texture on. so, how can i put texture on?
any hints would be very much appreciated.
*********edit I have managed to successfully upload the texture coordinates and uniforms but the image does not show up and the cube is colored light blue. any suggestions would be very much appreciated.
It would be nice if you could provide a working example instead of just parts of the code. There's several typos in the code above. For example in the setUniforms
part there's no closing }
. In the createTexture
part there's no quotes on the url. You spelled highp
as highhp
and texture2D
as texture2d
. I assume if you say it's running though without textures those are just transcription errors because if not you should see very clear errors in the JavaScript console.
It's not clear what's wrong but when debugging WebGL the first I'd do is check the JavaScript console. Are there any messages about un-renderable textures?
No? Then the next thing i'd do is change the fragment shader to a solid color
<script id="cube-fs" type="notjs">
precision highhp float;
varying vec3 fColor;
varying vec3 fNormal;
varying vec2 fTexCoord;
uniform sampler2D texSampler;
void main(void) {
vec4 texColor = texture2d(texSampler, fTexCoord);
gl_FragColor = vec4(fColor*texColor.xyz,1.0);
gl_FragColor = vec4(1,0,0,1); // -------ADDED-------------------------
}
</script>
If you see your cube then yes, the issue is related to the texture. If not the issue is somewhere else.
Let's assume you see a red cube. Ok, next thing is to check the texture coordinates. I'd change the fragment shader to this
<script id="cube-fs" type="notjs">
precision highhp float;
varying vec3 fColor;
varying vec3 fNormal;
varying vec2 fTexCoord;
uniform sampler2D texSampler;
void main(void) {
vec4 texColor = texture2d(texSampler, fTexCoord);
gl_FragColor = vec4(fColor*texColor.xyz,1.0);
gl_FragColor = vec4(fTexCoord,0,1); // -------CHANGED-------------------------
}
</script>
You should see the cube now with red->green shading. If not you've got bad texture coordinates.
If that looks correct the next thing I might try is put the shader back the way it was originally then check if the variable texture
is actually set.
There's a bunch of ways I could check this.
Use the WebGL Inspector
Use the standard JavaScript debugger. Put a breakpoint on the setUniforms
part. Inspect the variables
Do something like this
var uniforms = {
view:drawingState.view,
proj:drawingState.proj,
lightdir:drawingState.sunDirection,
cubecolor:this.color,
model: modelM,
texSampler: texture,
};
window.u = uniforms;
twgl.setUniforms(shaderProgram, uniforms);
Now open the JavaScript console and type u.texSampler
. It should print something like
WebGLTexture {}
If it doesn't then probably texture
is not the variable you think it is
One other question is are you rendering constantly using requestAnimationFrame as in
function render() {
// draw stuff like maybe call someCube.draw(drawingState)
...
requestAnimationFrame(render);
}
requestAnimationFrame(render);
I ask because textures are loaded asynchronously so if you are only rendering once then you won't see any textures because they have not yet been loaded.
You have a few options.
Render constantly (like the example above)
twgl will default to a 1x1 pixel texture so rendering should work. Then the image is finally loaded it will update the texture
Wait for the texture to load.
If you don't want to render until the texture is ready then you can add a callback to twgl.createTexture
and it will call you back when the texture is ready.
The other thing to do is to start with a working sample
var m4 = twgl.m4; // <!------------ ADDED
var v3 = twgl.v3; // <!------------ ADDED
// not sure why these are globals?!???!
var shaderProgram; // <!------------ ADDED
var texture; // <!------------ ADDED
var buffers; // <!------------ ADDED
var canvas = document.querySelector("canvas"); // <!------------ ADDED
var drawingState = { // <!------------ ADDED
gl: canvas.getContext("webgl"), // <!------------ ADDED
view: m4.inverse(m4.lookAt([3,3,6], [0, 0, 0], [0, 1, 0])), // <!------------ ADDED
proj: m4.perspective( // <!------------ ADDED
Math.PI * 0.3, // <!------------ ADDED
canvas.clientWidth / canvas.clientHeight, // <!------------ ADDED
0.1, 10), // <!------------ ADDED
sunDirection: v3.normalize([2,3,-2]), // <!------------ ADDED
}; // <!------------ ADDED
function Cube() { // <!-------------------------------------- ADDED
this.size = 1; // <!-------------------------------------- ADDED
this.position = [0, 0, 0]; // <!-------------------------------------- ADDED
this.color = [1, 1, 1]; // <!-------------------------------------- ADDED
} // <!-------------------------------------- ADDED
Cube.prototype.init = function(drawingState) {
var gl=drawingState.gl;
// create the shaders once - for all cubes
if (!shaderProgram) {
shaderProgram = twgl.createProgramInfo(gl, ["cube-vs", "cube-fs"]); // <!---- CHANGED
}
if (!buffers) {
var arrays = {
vpos: { numComponents: 3, data: [1, 1, -1, 1, 1, 1, 1, -1, 1, 1, -1, -1, -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, -1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, -1, -1, -1], },
vnormal: { numComponents: 3, data: [1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1], },
vtex: { numComponents: 2, data: [1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1], },
indices: [0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, 8, 9, 10, 8, 10, 11, 12, 13, 14, 12, 14, 15, 16, 17, 18, 16, 18, 19, 20, 21, 22, 20, 22, 23],
};
buffers = twgl.createBufferInfoFromArrays(gl,arrays);
}
if (!texture) {
texture = twgl.createTexture(gl, {
src: "https://farm6.staticflickr.com/5795/21506301808_efb27ed699_q_d.jpg",
crossOrigin: "", // <!--------- not needed if on same server which "texture/tree.jpg" is
});
}
};
Cube.prototype.draw = function(drawingState) {
var modelM = twgl.m4.scaling([this.size*1.4,this.size*1.4,this.size*1.4]);
twgl.m4.setTranslation(modelM,this.position,modelM);
var gl = drawingState.gl;
gl.useProgram(shaderProgram.program);
twgl.setBuffersAndAttributes(gl,shaderProgram,buffers);
twgl.setUniforms(shaderProgram,{
view:drawingState.view, proj:drawingState.proj, lightdir:drawingState.sunDirection,
cubecolor:this.color, model: modelM, texSampler: texture});
twgl.drawBufferInfo(gl, gl.TRIANGLES, buffers);
};
var cube = new Cube(); // <!------------ ADDED
cube.init(drawingState); // <!------------ ADDED
function render() { // <!------------ ADDED
var gl = drawingState.gl // <!------------ ADDED
gl.enable(gl.DEPTH_TEST); // <!------------ ADDED
cube.draw(drawingState); // <!------------ ADDED
requestAnimationFrame(render); // <!------------ ADDED
} // <!------------ ADDED
requestAnimationFrame(render); // <!------------ ADDED
canvas { border: 1px solid black; }
<script id="cube-vs" type="notjs">
//precision highp float; <!---------------- CHANGED
attribute vec3 vpos;
attribute vec3 vnormal;
attribute vec2 vtex;
varying vec3 fColor;
varying vec3 fNormal;
varying vec2 fTexCoord;
uniform mat4 view;
uniform mat4 proj;
uniform mat4 model;
uniform vec3 lightdir;
uniform vec3 cubecolor;
void main(void) {
gl_Position = proj * view * model * vec4(vpos, 1.0);
vec4 normal = normalize(model * vec4(vnormal,0.0));
float diffuse = .2 + abs(dot(normal, vec4(lightdir,0.0)));
fColor = (cubecolor * diffuse);
fTexCoord = vtex;
}
</script>
<script id="cube-fs" type="notjs">
precision highp float; // <!--------- CHANGED (should probably use mediump though)
varying vec3 fColor;
varying vec3 fNormal;
varying vec2 fTexCoord;
uniform sampler2D texSampler;
void main(void) {
vec4 texColor = texture2D(texSampler, fTexCoord); // < !-------- CHANGED
gl_FragColor = vec4(fColor*texColor.xyz,1.0);
}
</script>
<canvas></canvas>
<script src="https://twgljs.org/dist/twgl-full.min.js"></script>
One more question, are you running a webserver? WebGL requires a web server to read textures. Note, running a web server is trival. A really good one is here. Just download the version for your OS then
path/to/devd-download/devd path/to/project
Then go to http://localhost:8000/nameOfYourHtmlFile.html
I'm assuming this was not the issue because if it was you'd have seen a clear error in the JavaScript console about not being able to load the texture but you haven't mentioned errors in the JavaScript console