WebGL rendering a texture for a 2d sprite. Not showing up - javascript

Previously had a color vertex for rendering this small square, now i want to use an image. Im using an image sprite i had lying around that sits at 64x128 wide.
I'm not getting any errors, but nothing is showing up either. First the shaders:
<script id="shader-fs" type="x-shader/x-fragment">
precision mediump float;
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
void main(void) {
gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
}
</script>
<script id="shader-vs" type="x-shader/x-vertex">
attribute vec3 aVertexPosition;
attribute vec2 aTextureCoord;
uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;
varying vec2 vTextureCoord;
void main(void) {
gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
vTextureCoord = aTextureCoord;
}
</script>
For the buffers:
initBuffers: function () {
this.planePositionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, this.planePositionBuffer);
var vertices = [
1.0, 1.0, 0.0,
-1.0, 1.0, 0.0,
1.0, -1.0, 0.0,
-1.0, -1.0, 0.0
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
this.planePositionBuffer.itemSize = 3;
this.planePositionBuffer.numItems = 4;
this.textureBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, this.textureBuffer);
var textureCoords = [
0.0, 1.0,
0.0, 0.0,
1.0, 1.0,
1.0, 0.0
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureCoords), gl.STATIC_DRAW);
this.textureBuffer.itemSize = 2;
this.textureBuffer.numItems = 4;
}
Initializing the shaders:
initShaders: function () {
this.shader = new Shader("shader");
var shaderProgram = this.shader.shaderProgram;
shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);
shaderProgram.textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord");
gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute);
shaderProgram.pMatrixUniform = gl.getUniformLocation(shaderProgram, "uPMatrix");
shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix");
shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler");
}
And the draw call.
draw: function () {
this.resize();
var delta = this.getDeltaTime();
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
mat4.identity(this.mvMatrix);
mat4.identity(this.pMatrix);
mat4.perspective(this.pMatrix, 45 * Math.PI / 180, gl.canvas.clientWidth / gl.canvas.clientHeight, 0.1, 100.0);
mat4.translate(this.pMatrix, this.pMatrix, [0.0, 0.0, -50.0]);
var shaderProgram = this.shader.shaderProgram;
for (var i = 0; i < this.objects.length; i++) {
this.objects[i].update(delta, this.mvMatrix);
}
gl.bindBuffer(gl.ARRAY_BUFFER, this.planePositionBuffer);
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, this.planePositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, this.textureBuffer);
gl.vertexAttribPointer(shaderProgram.textureCoordAttribute, this.textureBuffer.itemSize, gl.FLOAT, false, 0, 0);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, me.loader.getImage('test'));
gl.uniform1i(shaderProgram.samplerUniform, 0);
this.setMatrixUniforms();
gl.drawArrays(gl.TRIANGLE_STRIP, 0, this.planePositionBuffer.numItems);
requestAnimationFrame(this.draw.bind(this));
},
I based the texture coords off of an article i found on opengles drawing on android. The idea was the coords should be in order of bottom left -> top left -> bottom right -> top right.
Full source code for its broken state can be found here in addition to the snippets above: https://github.com/agmcleod/webgl-2dexperiment/tree/13f31f70037fdd4515c1336423337a1e82ab4e89

Looks as if the WebGL code was all correct. However, I was never invoking the function bindAllTextures to actually set up the texture with webgl for rendering.

Related

webgl2 3D object translation

I try to transform two 3D objects separately and I failed, it seems each translation is apply to both objects . They are translating together. And what really confusing is t1,which is scaling,it applys to only one object successfully , but its translation ,t2 affects itself and also the another object ,and so do the translation t1 .Any help is appreciated.
The important codes :
gl.bindVertexArray(vao2);
var t1 = mat4(2.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 2.0, 0.0,
0.0, 0.0, 0.0, 1.0);
var t2 = translate( 0.0, -0.5, 0.0 );
let changedmodelMatrix1 = mat4(1.0)
changedmodelMatrix1 =mult(t2,mult(t1,modelMatrix));
let changedMvpmodelMatrix1 = mult(mult(projectionMatrix, viewMatrix), changedmodelMatrix1);
gl.uniformMatrix4fv(
gl.getUniformLocation(program, "u_mvp1"),
gl.FALSE,
flatten(changedMvpmodelMatrix1));
gl.drawArrays(gl.TRIANGLES, 0, 18);
gl.bindVertexArray(vao1);
var t3 = translate(0.0, 0.3, 0.0);
let changedmodelMatrix2 = mat4(1.0);
changedmodelMatrix2 = mult(t3,modelMatrix);
let changedMvpmodelMatrix2 = mult(mult(projectionMatrix, viewMatrix), changedmodelMatrix2);
gl.uniformMatrix4fv(
gl.getUniformLocation(program, "u_mvp2"),
gl.FALSE,
flatten(changedMvpmodelMatrix2));
gl.drawArrays(gl.TRIANGLES, 0, vertexCounter);
html:
layout(location = 0) in vec3 a_position;
layout(location = 1) in vec4 a_teapotposition;
uniform mat4 u_mvp1;
uniform mat4 u_mvp2;
void main() {
gl_Position = u_mvp2 *
a_teapotposition
+
u_mvp1 *
vec4(a_position, 1.0)
;
You don't need 2 attributes and 2 matrix uniform variables.
Create a simple shader program:
layout(location = 0) in vec3 a_position;
uniform mat4 u_mvp;
void main()
{
gl_Position = u_mvp * a_position;
}
Bind the Vertex Array Object and set the uniform before drawing the object:
gl.bindVertexArray(vao2);
gl.uniformMatrix4fv(
gl.getUniformLocation(program, "u_mvp"),
gl.FALSE,
flatten(changedMvpmodelMatrix1));
gl.drawArrays(gl.TRIANGLES, 0, 18);
gl.bindVertexArray(vao1);
gl.uniformMatrix4fv(
gl.getUniformLocation(program, "u_mvp"),
gl.FALSE,
flatten(changedMvpmodelMatrix2));
gl.drawArrays(gl.TRIANGLES, 0, vertexCounter);

webgl trying to draw a triangle

I have been trying to draw a triangle but it is not showing up on the canvas
here is my draw function code:
function draw() {
gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight)gl.clear(gl.COLOR_BUFFER_BIT)
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute,
buffer.itemSize, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute)
  
//Draw the triangle
gl.drawArrays(gl.TRIANGLES, 0, buffer.numberOfItems)
}
here is the whole work:
const vertexShaderText = [
'attribute vec3 vertexPos;',
'',
'void main() {',
' gl_Position = vec4(vertexPos, 1.0);',
'}'
].join('\n')
const fragmentShaderText = [
'precision mediump float;',
'',
'void main() {',
' gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);',
'}'
].join('\n')
let gl, shaderProgram, buffer
function startup() {
const canvas = document.getElementById('myCanvas')
gl = canvas.getContext('webgl')
initShader()
initBuffer()
gl.clearColor(0.0, 0.0, 0.0, 1.0)
draw()
}
function initShader() {
// VERTEX SHADER
let vertexShader = gl.createShader(gl.VERTEX_SHADER)
gl.shaderSource(vertexShader, vertexShaderText)
gl.compileShader(vertexShader)
if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
alert('vertex', gl.getShaderInfoLog(vertexShader))
return
}
let fragmentShader = gl.createShader(gl.FRAGMENT_SHADER)
gl.shaderSource(fragmentShader, fragmentShaderText)
gl.compileShader(fragmentShader)
if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
alert('fragment', gl.getShaderInfoLog(fragmentShader))
return
}
shaderProgram = gl.createProgram()
gl.attachShader(shaderProgram, vertexShader)
gl.attachShader(shaderProgram, fragmentShader)
gl.linkProgram(shaderProgram)
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
alert('Failed to setup shaders')
}
gl.useProgram(shaderProgram)
shaderProgram.vertextPositionAttribute = gl.getAttribLocation(shaderProgram, 'vertexPos')
//gl.enableVertexAttribArray(shaderProgram.vertextPositionAttribute)
}
function initBuffer() {
buffer = gl.createBuffer()
gl.bindBuffer(gl.ARRAY_BUFFER, buffer)
const triangleVertices = [
0.0, 0, 5, 0.0, -0.5, -0.5, 0.0,
0.5, -0.5, 0.0
]
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(triangleVertices), gl.STATIC_DRAW)
buffer.itemSize = 3
buffer.numberOfItems = 3
console.log(shaderProgram)
}
function draw() {
gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight) 
gl.clear(gl.COLOR_BUFFER_BIT)
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute,
buffer.itemSize, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute)  
//Draw the triangle
gl.drawArrays(gl.TRIANGLES, 0, buffer.numberOfItems)
}
startup()
<canvas id="myCanvas" width="500" height="500"></canvas>
There are some issues:
The properties gl.viewportWidth and gl.viewportHeight are never set:
gl = canvas.getContext('webgl')
gl.viewportWidth = canvas.clientWidth;
gl.viewportHeight = canvas.clientHeight;
In the array of vertex coordinates is a , instead of a .
const triangleVertices = [
0.0, 0,5, 0.0, // <---- this line
-0.5, -0.5, 0.0,
0.5, -0.5, 0.0
]
And there is a typo , you wrote vertextPositionAttribute instead of vertexPositionAttribute, when you get the attribute index:
shaderProgram.vertextPositionAttribute = // <--- typo
gl.getAttribLocation(shaderProgram, 'vertexPos')
But in general your code works:
const vertexShaderText = [
'attribute vec3 vertexPos;',
'',
'void main() {',
' gl_Position = vec4(vertexPos, 1.0);',
'}'
].join('\n')
const fragmentShaderText = [
'precision mediump float;',
'',
'void main() {',
' gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);',
'}'
].join('\n')
let gl, shaderProgram, buffer
function startup() {
const canvas = document.getElementById('myCanvas')
gl = canvas.getContext('webgl')
gl.viewportWidth = canvas.clientWidth;
gl.viewportHeight = canvas.clientHeight;
initShader()
initBuffer()
gl.clearColor(0.0, 0.0, 0.0, 1.0)
draw()
}
function initShader() {
// VERTEX SHADER
let vertexShader = gl.createShader(gl.VERTEX_SHADER)
gl.shaderSource(vertexShader, vertexShaderText)
gl.compileShader(vertexShader)
if(!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
alert('vertex', gl.getShaderInfoLog(vertexShader))
return
}
let fragmentShader = gl.createShader(gl.FRAGMENT_SHADER)
gl.shaderSource(fragmentShader, fragmentShaderText)
gl.compileShader(fragmentShader)
if(!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
alert('fragment', gl.getShaderInfoLog(fragmentShader))
return
}
shaderProgram = gl.createProgram()
gl.attachShader(shaderProgram, vertexShader )
gl.attachShader(shaderProgram, fragmentShader)
gl.linkProgram(shaderProgram)
if(!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
alert('Failed to setup shaders')
}
gl.useProgram(shaderProgram)
shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, 'vertexPos')
//gl.enableVertexAttribArray(shaderProgram.vertextPositionAttribute)
}
function initBuffer() {
buffer = gl.createBuffer()
gl.bindBuffer(gl.ARRAY_BUFFER, buffer)
const triangleVertices = [
0.0, 0.5, 0.0,
-0.5, -0.5, 0.0,
0.5, -0.5, 0.0
]
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(triangleVertices), gl.STATIC_DRAW)
buffer.itemSize = 3
buffer.numberOfItems = 3
console.log(shaderProgram)
}
function draw() {
gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight)
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute,
buffer.itemSize, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);
//Draw the triangle
gl.drawArrays(gl.TRIANGLES, 0, buffer.numberOfItems)
requestAnimationFrame(draw);
}
startup()
<canvas id="myCanvas" width="500" height="500"></canvas>
Some issues
There is no such thing as gl.viewportWidth and gl.viewportHeight
Use gl.canvas.width and gl.canvas.height.
There's a site out there that teaches using gl.viewportWidth and gl.viewportHeight. It is arguably an anti-pattern. Those variables are not part of WebGL. They are user variables being added by the example onto the WebGL context. There is absolutely zero reason to do that as they will always have to be manually updated and the actual width and height are always available.
Typo in triangleVertices
The second comma below should be a period
bad
const triangleVertices = [
0.0, 0, 5, 0.0, -0.5, -0.5, 0.0,
0.5, -0.5, 0.0
]
good
const triangleVertices = [
0.0, 0.5, 0.0, -0.5, -0.5, 0.0,
0.5, -0.5, 0.0
]
With that it runs but here's another typo
vertextPositionAttribute should be vertexPositionAttribute
shaderProgram.vertextPositionAttribute = gl.getAttribLocation(shaderProgram, 'vertexPos')
//gl.enableVertexAttribArray(shaderProgram.vertextPositionAttribute)
That said here's a bunch of suggestions.
Use multiline template literals for shaders
Instead of
const vertexShaderText = [
'attribute vec3 vertexPos;',
'',
'void main() {',
' gl_Position = vec4(vertexPos, 1.0);',
'}'
].join('\n')
do this
const vertexShaderText = `
attribute vec3 vertexPos;
void main() {
gl_Position = vec4(vertexPos, 1.0);
}
`;
So much easier! Use backticks instead of quotes for multi-line strings
Make initShader return a shader rather than assign a global
It's not common to have a single shader in WebGL so it's much more useful to have a function that creates shaders
Don't call gl.useProgram in initShader
Again it's not common to have a single shader. Calling gl.useProgram generally belongs in draw
Don't add attributes to browser objects, especially WebGL objects
bad
shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, 'vertexPos');
good (one of many ways)
const shaderProgramInfo = {}
shaderProgramInfo.program = initShader(...)
shaderProgramInfo.vertexPositionAttribute =
gl.getAttribLocation(shaderProgramInfo.program, 'vertexPos');
This is because if initShader fails (for example the context is lost) your gl.createProgram will be null and trying to assign a property to null will cause your page to fail. The same issue with buffer
bad
const buffer = gl.createBuffer();
...
buffer.itemSize = 3
buffer.numberOfItems = 3
good (one of many ways)
const bufferInfo = {
buffer: gl.createBuffer(),
}
...
bufferInfo.itemSize = 3
bufferInfo.numberOfItems = 3
Call gl.bindBuffer before calling gl.vertexAttribPointer
Your code works because there is only one buffer. If there are 2 buffers it would likely stop working because gl.vertexAttribPointer references the currently bound buffer
Consider Reading better tutorials.
I'd recommend https://webglfundamentals.org
const vertexShaderText = `
attribute vec3 vertexPos;
void main() {
gl_Position = vec4(vertexPos, 1.0);
}
`;
const fragmentShaderText = `
precision mediump float;
void main() {
gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
}
`;
let gl, shaderProgramInfo, bufferInfo
function startup() {
const canvas = document.getElementById('myCanvas')
gl = canvas.getContext('webgl')
shaderProgramInfo = {
program: initShader(gl, vertexShaderText, fragmentShaderText),
};
shaderProgramInfo.vertexPositionAttribute = gl.getAttribLocation(shaderProgramInfo.program, 'vertexPos');
bufferInfo = initBuffer()
gl.clearColor(0.0, 0.0, 0.0, 1.0)
draw()
}
function initShader(gl, vertexShaderText, fragmentShaderText) {
// VERTEX SHADER
let vertexShader = gl.createShader(gl.VERTEX_SHADER)
gl.shaderSource(vertexShader, vertexShaderText)
gl.compileShader(vertexShader)
if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
alert('vertex', gl.getShaderInfoLog(vertexShader))
return
}
let fragmentShader = gl.createShader(gl.FRAGMENT_SHADER)
gl.shaderSource(fragmentShader, fragmentShaderText)
gl.compileShader(fragmentShader)
if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
alert('fragment', gl.getShaderInfoLog(fragmentShader))
return
}
const shaderProgram = gl.createProgram()
gl.attachShader(shaderProgram, vertexShader)
gl.attachShader(shaderProgram, fragmentShader)
gl.linkProgram(shaderProgram)
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
alert('Failed to setup shaders')
}
return shaderProgram;
}
function initBuffer() {
buffer = gl.createBuffer()
gl.bindBuffer(gl.ARRAY_BUFFER, buffer)
const triangleVertices = [
0.0, 0.5, 0.0, -0.5, -0.5, 0.0,
0.5, -0.5, 0.0
]
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(triangleVertices), gl.STATIC_DRAW)
return {
buffer,
itemSize: 3,
numberOfItems: 3,
};
}
function draw() {
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height); 
gl.clear(gl.COLOR_BUFFER_BIT)
gl.useProgram(shaderProgramInfo.program)
gl.bindBuffer(gl.ARRAY_BUFFER, bufferInfo.buffer);
gl.vertexAttribPointer(shaderProgramInfo.vertexPositionAttribute,
bufferInfo.itemSize, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(shaderProgramInfo.vertexPositionAttribute)  
//Draw the triangle
gl.drawArrays(gl.TRIANGLES, 0, bufferInfo.numberOfItems)
}
startup()
<canvas id="myCanvas" width="500" height="500"></canvas>

Adding background image to WebGL 3D scene

I wrote a code that tried to draw only the background image in a WebGL 3D scene. Here are the relevant parts of the code:
<script id="shader-fs" type="x-shader/x-fragment">
varying highp vec2 vTexCoord;
uniform sampler2D uSampler;
void main(void) {
gl_FragColor = texture2D(uSampler, vec2(vTexCoord.s, vTexCoord.t));
}
</script>
<script id="shader-vs" type="x-shader/x-vertex">
attribute vec3 aVertexPosition;
attribute vec2 aTextureCoord;
uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;
varying highp vec2 vTexCoord;
void main(void) {
gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
vTexCoord = aTextureCoord;
}
</script>
<script>
var VBack = [
-24.0, 0.0, 0.0,
24.0, 0.0, 0.0,
24.0, 48.0, 0.0,
-24.0, 48.0, 0.0
];
var vTBack = [
0.0, 0.0,
1.0, 0.0,
1.0, 1.0,
0.0, 1.0
];
var VBuffer;
var vTBuffer;
function initMatrix() {
orthoMatrix = makeOrtho(-24.0, 24.0, 0.0, 48.0, 20.0, -20.0); // From glUtils.js
mvMatrix = Matrix.I(4);
...
}
function handleBkTex(tex) {
GL.bindTexture(GL.TEXTURE_2D, tex);
GL.pixelStorei(GL.UNPACK_FLIP_Y_WEBGL, true);
GL.texImage2D(GL.TEXTURE_2D, 0, GL.RGBA, GL.RGBA, GL.UNSIGNED_BYTE, tex.Img);
GL.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MAG_FILTER, GL.NEAREST);
GL.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MIN_FILTER, GL.NEAREST);
GL.bindTexture(GL.TEXTURE_2D, null);
}
function initBkgnd() {
backTex = GL.createTexture();
backTex.Img = new Image();
backTex.Img.onload = function() {
handleBkTex(backTex);
}
backTex.Img.src = "Bkgnd.jpg";
}
function drawBkgnd() {
GL.bindBuffer(GL.ARRAY_BUFFER, VBuffer);
GL.vertexAttribPointer(vertexPositionAttribute, 3, GL.FLOAT, false, 0, 0);
GL.bindBuffer(GL.ARRAY_BUFFER, vTBuffer);
GL.vertexAttribPointer(texCoordAttribute, 2, GL.FLOAT, false, 0, 0);
GL.activeTexture(GL.TEXTURE0);
GL.bindTexture(GL.TEXTURE_2D, backTex);
GL.uniform1i(GL.getUniformLocation(shaderProgram, "uSampler"), 0);
GL.drawArrays(GL.TRIANGLE_STRIP, 0, 4);
}
function start() {
var canvas = document.getElementById("glcanvas");
initWebGL(canvas);
if (GL) {
initShaders();
initBuffers();
initMatrix();
initBkgnd();
drawBkgnd();
}
}
The canvas size is 512 x 512, the same as the image size. But I don't get the correct image on the canvas. How to do this correctly?
Do you want the answer to be how to setup a 3D matrix to draw a 2D image or do you want the answer to be how to do this efficiently?
Here's the efficient answer. There's no reason to use 3D to draw 2D. Change your vertices to
var VBack = [
-1, -1,
1, -1,
1, 1,
-1, 1,
];
Change your call to vertexAttribPointer to
GL.vertexAttribPointer(vertexPositionAttribute, 2, GL.FLOAT, false, 0, 0);
Change your vertex shader to
attribute vec4 aVertexPosition;
attribute vec2 aTextureCoord;
varying highp vec2 vTexCoord;
void main(void) {
gl_Position = aVertexPosition;
vTexCoord = aTextureCoord;
}
And it should work.
See this set of articles for more about 2D in WebGL for more.
I found some small errors in my code. Here are they:
WebGL scene must always be redrawn. So the function drawBkgnd() must be called repeatedly, using setInterval() or requestAnimationFrame().
To use drawArrays() with GL_TRIANGLE_STRIP to draw a rectangle correctly, the order of the vertices must be:
*2 *3
*0 *1
or any equivalent order, but not:
*3 *2
*0 *1
So the order of the vertices in VBack must be changed to:
var VBack = [
-24.0, 0.0, 0.0,
24.0, 0.0, 0.0,
-24.0, 48.0, 0.0
24.0, 48.0, 0.0,
];
and the order of vertices in vTBack must also be changed accordingly.

WebGL using gl-matrix library mat4.translate not running

I have this segment of code:
function setupWebGL() {
gl.clearColor(0.1, 0.5, 0.1, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.viewport(0,0,400,300);
mat4.perspective(45, 400 / 300, 0.1, 100.0, pMatrix);
mat4.identity(mvMatrix);
mat4.translate(mvMatrix, [0, 0, -2.0]);
}
And everything in the code runs except the very last line
mat4.translate(mvMatrix, [0, 0, -2.0]);
I know this because I put alert functions after every line until they failed to run (I need a better way of debugging in chrome, any suggestions?)
I'm using the gl-Matrix library found here https://github.com/toji/gl-matrix/blob/master/dist/gl-matrix-min.js
Any ideas on why that line is stopping the code execution?
Here is the full code:
<!doctype html>
<html>
<head>
<title>WebGL - Chapter One - Lol</title>
<style>
body{ background-color: grey; }
canvas{ background-color: white; }
</style>
<script src = "gl-matrix-min.js"></script>
<script src = "raf_polyfill.js"></script>
<script id="shader-vs" type="x-shader/x-vertex">
attribute vec3 aVertexPosition;
attribute vec3 aVertexColor;
uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;
varying highp vec4 vColor;
void main(void){
gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
vColor = vec4(aVertexColor, 1.0);
}
</script>
<script id="shader-fs" type="x-shader/x-fragment">
varying highp vec4 vColor;
void main(void){
gl_FragColor = vColor;
}
</script>
<script>
var gl = null,
canvas = null,
glProgram = null,
fragmentShader = null,
vertexShader = null;
var vertexPositionAttribute = null,
trianglesVerticeBuffer = null,
vertexColorAttribute = null,
trianglesColorBuffer = null;
var angle = 0.0;
var mvMatrix = mat4.create(),
pMatrix = mat4.create();
function initWebGL(){
var canvas = document.getElementById("my-canvas");
try{
gl = canvas.getContext("experimental-webgl");
}catch(e){}
if(gl){
initShaders();
setupBuffers();
getMatrixUniforms();
animLoop();
}else{
alert("Error: Your browser does not appear to support WebGL.");
}
}
function animLoop(){
setupWebGL();
setupDynamicBuffers();
setMatrixUniforms();
drawScene();
requestAnimationFrame(animLoop,canvas);
}
function setupWebGL() {
//sets the clear color to red lol
gl.clearColor(0.1, 0.5, 0.1, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.viewport(0,0,400,300);
mat4.perspective(45, 400 / 300, 0.1, 100.0, pMatrix);
mat4.identity(mvMatrix);
mat4.translate(mvMatrix, [0, 0, -2.0]);
}
function initShaders(){
var fs_source = document.getElementById("shader-fs").innerHTML;
var vs_source = document.getElementById("shader-vs").innerHTML;
//compile shaders
vertexShader = makeShader(vs_source, gl.VERTEX_SHADER);
fragmentShader = makeShader(fs_source, gl.FRAGMENT_SHADER);
//create program
glProgram = gl.createProgram();
//attach and link shaders to the program
gl.attachShader(glProgram, vertexShader);
gl.attachShader(glProgram, fragmentShader);
gl.linkProgram(glProgram);
if (!gl.getProgramParameter(glProgram, gl.LINK_STATUS)) {
alert("Unable to initialize the shader program.");
}
//use program
gl.useProgram(glProgram);
}
function makeShader(src, type) {
//compile the vertex shader
var shader = gl.createShader(type);
gl.shaderSource(shader, src);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert("Error compiling shader: " + gl.getShaderInfoLog(shader));
}
return shader;
}
function getMatrixUniforms(){
glProgram.pMatrixUniform = gl.getUniformLocation(glProgram, "uPMatrix");
glProgram.mvMatrixUniform = gl.getUniformLocation(glProgram, "uMVMatrix");
}
function setMatrixUniforms(){
gl.unifromMatrix4fv(glProgram.pMatrixUniform, false, pMatrix);
gl.unifromMatrix4fv(glProgram.mvMatrixUniform, false, mvMatrix);
}
function setupBuffers() {
var triangleVerticeColors = [
1.0, 0.0, 0.0,
1.0, 1.0, 1.0,
1.0, 0.0, 0.0,
0.0, 0.0, 1.0,
1.0, 1.0, 1.0,
0.0, 0.0, 1.0
];
trianglesColorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, trianglesColorBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(triangleVerticeColors), gl.STATIC_DRAW);
}
function setupDynamicBuffers(){
var xTran = Math.sin(angle)/2.0;
var triangleVertices = [
-0.5 + xTran, 0.5, -0.5,
0.0 + xTran, 0.0, -0.5,
-0.5 + xTran, -0.5, -0.5,
0.5 + xTran, 0.5, -0.5,
0.0 + xTran, 0.0, -0.5,
0.5 + xTran, -0.5, -0.5
];
angle += 0.05;
trianglesVerticeBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, trianglesVerticeBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(triangleVertices), gl.DYNAMIC_DRAW);
}
function drawScene() {
vertexPositionAttribute = gl.getAttribLocation(glProgram, "aVertexPosition");
gl.enableVertexAttribArray(vertexPositionAttribute);
gl.bindBuffer(gl.ARRAY_BUFFER, trianglesVerticeBuffer);
gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0);
vertexColorAttribute = gl.getAttribLocation(glProgram, "aVertexColor");
gl.enableVertexAttribArray(vertexColorAttribute);
gl.bindBuffer(gl.ARRAY_BUFFER, trianglesColorBuffer);
gl.vertexAttribPointer(vertexColorAttribute, 3, gl.FLOAT, false, 0, 0);
gl.drawArrays(gl.TRIANGLES, 0, 6);
}
</script>
</head>
<body onload="initWebGL()">
<canvas id="my-canvas" width="400" height="300">
Your browser does not support the HTML5 canvas element.
</canvas>
</body>
</html>
Use the new API:
Old API
mat4.translate(mvMatrix, [0, 0, -2.0]);
New API
var translation = vec3.create();
vec3.set (translation, 0, 0, -2.0);
mat4.translate (mvMatrix, mvMatrix, translation);
You have a typo:
unifromMatrix4fv should be uniformMatrix4fv in function setMatrixUniforms.
I'm not sure if this fixes your problem or not, or why you thought your problem was with mat4.translate. You can always open the JavaScript console (F12 if you're running Chrome in Windows) and it'll tell you what the error is.

Multiple Programs in WebGL doesn't work

I'm trying to use multiple shader programs in webgl but continue to get issues.
It seems that if i have a different number of vertex shader attributes in programs then i get nothing rendered with no errors. Is there some constraint that means that programs have to have the same number of attributes? Do i need to disable/enable attribute locations when changing programs?
It seems that just creating multiple programs causes the issue ( i dont even have to use the second shader, just the fact that it is created causes the issue).
To create the attributes i'm using the following snippet (works fine when number of attributes in all programs is the same):
for ( var i=0 ; i<vertexAttributes.length ; i++ )
{
shaderProgram[vertexAttributes[i].name] = gl.getAttribLocation(shaderProgram,vertexAttributes[i].name);
gl.enableVertexAttribArray(shaderProgram[vertexAttributes[i].name]);
}
Sorry for posting such a large chunk of code, but this best illustrates the issue. this is code from one of the learningwebgl.com tutorials, all that i have done is add a second pair of shaders ("shader2-fs" and "shader2-vs") and a new function called initShaders2. if initShaders2 is called in webGLStart() (as it is in the code) then nothing is drawn??? i'm baffled!
<script type="text/javascript" src="two_files/glMatrix-0.js"></script>
<script type="text/javascript" src="two_files/webgl-utils.js"></script>
<script id="shader-fs" type="x-shader/x-fragment">
precision mediump float;
varying vec4 vColor;
void main(void) {
gl_FragColor = vColor;
}
</script>
<script id="shader-vs" type="x-shader/x-vertex">
attribute vec3 aVertexPosition;
attribute vec4 aVertexColor;
uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;
varying vec4 vColor;
void main(void) {
gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
vColor = aVertexColor;
}
</script>
<script id="shader2-fs" type="x-shader/x-fragment">
precision mediump float;
varying vec2 vTextureCoord;
varying vec3 vLightWeighting;
uniform sampler2D uSampler;
void main(void) {
vec4 textureColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
gl_FragColor = vec4(textureColor.rgb * vLightWeighting, textureColor.a);
}
</script>
<script id="shader2-vs" type="x-shader/x-vertex">
attribute vec3 aVertexPosition;
attribute vec3 aVertexNormal;
attribute vec2 aTextureCoord;
uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;
uniform mat3 uNMatrix;
uniform vec3 uAmbientColor;
uniform vec3 uLightingDirection;
uniform vec3 uDirectionalColor;
uniform bool uUseLighting;
varying vec2 vTextureCoord;
varying vec3 vLightWeighting;
void main(void) {
gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
vTextureCoord = aTextureCoord;
if (!uUseLighting) {
vLightWeighting = vec3(1.0, 1.0, 1.0);
} else {
vec3 transformedNormal = uNMatrix * aVertexNormal;
float directionalLightWeighting = max(dot(transformedNormal, uLightingDirection), 0.0);
vLightWeighting = uAmbientColor + uDirectionalColor * directionalLightWeighting;
}
}
</script>
<script type="text/javascript">
var gl;
function initGL(canvas) {
try {
gl = canvas.getContext("experimental-webgl");
gl.viewportWidth = canvas.width;
gl.viewportHeight = canvas.height;
} catch (e) {
}
if (!gl) {
alert("Could not initialise WebGL, sorry :-(");
}
}
function getShader(gl, id) {
var shaderScript = document.getElementById(id);
if (!shaderScript) {
return null;
}
var str = "";
var k = shaderScript.firstChild;
while (k) {
if (k.nodeType == 3) {
str += k.textContent;
}
k = k.nextSibling;
}
var shader;
if (shaderScript.type == "x-shader/x-fragment") {
shader = gl.createShader(gl.FRAGMENT_SHADER);
} else if (shaderScript.type == "x-shader/x-vertex") {
shader = gl.createShader(gl.VERTEX_SHADER);
} else {
return null;
}
gl.shaderSource(shader, str);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert(gl.getShaderInfoLog(shader));
return null;
}
return shader;
}
var shaderProgram;
function initShaders() {
var fragmentShader = getShader(gl, "shader-fs");
var vertexShader = getShader(gl, "shader-vs");
shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
alert("Could not initialise shaders");
}
gl.useProgram(shaderProgram);
shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);
shaderProgram.vertexColorAttribute = gl.getAttribLocation(shaderProgram, "aVertexColor");
gl.enableVertexAttribArray(shaderProgram.vertexColorAttribute);
shaderProgram.pMatrixUniform = gl.getUniformLocation(shaderProgram, "uPMatrix");
shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix");
}
var shaderProgram2;
function initShaders2() {
var fragmentShader = getShader(gl, "shader2-fs");
var vertexShader = getShader(gl, "shader2-vs");
shaderProgram2 = gl.createProgram();
gl.attachShader(shaderProgram2, vertexShader);
gl.attachShader(shaderProgram2, fragmentShader);
gl.linkProgram(shaderProgram2);
if (!gl.getProgramParameter(shaderProgram2, gl.LINK_STATUS)) {
alert("Could not initialise shaders");
}
gl.useProgram(shaderProgram2);
shaderProgram2.vertexPositionAttribute = gl.getAttribLocation(shaderProgram2, "aVertexPosition");
gl.enableVertexAttribArray(shaderProgram2.vertexPositionAttribute);
shaderProgram2.vertexNormalAttribute = gl.getAttribLocation(shaderProgram2, "aVertexNormal");
gl.enableVertexAttribArray(shaderProgram2.vertexNormalAttribute);
shaderProgram2.textureCoordAttribute = gl.getAttribLocation(shaderProgram2, "aTextureCoord");
gl.enableVertexAttribArray(shaderProgram2.textureCoordAttribute);
shaderProgram2.pMatrixUniform = gl.getUniformLocation(shaderProgram2, "uPMatrix");
shaderProgram2.mvMatrixUniform = gl.getUniformLocation(shaderProgram2, "uMVMatrix");
shaderProgram2.nMatrixUniform = gl.getUniformLocation(shaderProgram2, "uNMatrix");
shaderProgram2.samplerUniform = gl.getUniformLocation(shaderProgram2, "uSampler");
shaderProgram2.useLightingUniform = gl.getUniformLocation(shaderProgram2, "uUseLighting");
shaderProgram2.ambientColorUniform = gl.getUniformLocation(shaderProgram2, "uAmbientColor");
shaderProgram2.lightingDirectionUniform = gl.getUniformLocation(shaderProgram2, "uLightingDirection");
shaderProgram2.directionalColorUniform = gl.getUniformLocation(shaderProgram2, "uDirectionalColor");
}
var mvMatrix = mat4.create();
var mvMatrixStack = [];
var pMatrix = mat4.create();
function mvPushMatrix() {
var copy = mat4.create();
mat4.set(mvMatrix, copy);
mvMatrixStack.push(copy);
}
function mvPopMatrix() {
if (mvMatrixStack.length == 0) {
throw "Invalid popMatrix!";
}
mvMatrix = mvMatrixStack.pop();
}
function setMatrixUniforms() {
gl.uniformMatrix4fv(shaderProgram.pMatrixUniform, false, pMatrix);
gl.uniformMatrix4fv(shaderProgram.mvMatrixUniform, false, mvMatrix);
}
function degToRad(degrees) {
return degrees * Math.PI / 180;
}
var pyramidVertexPositionBuffer;
var pyramidVertexColorBuffer;
var cubeVertexPositionBuffer;
var cubeVertexColorBuffer;
var cubeVertexIndexBuffer;
function initBuffers() {
pyramidVertexPositionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, pyramidVertexPositionBuffer);
var vertices = [
// Front face
0.0, 1.0, 0.0,
-1.0, -1.0, 1.0,
1.0, -1.0, 1.0,
// Right face
0.0, 1.0, 0.0,
1.0, -1.0, 1.0,
1.0, -1.0, -1.0,
// Back face
0.0, 1.0, 0.0,
1.0, -1.0, -1.0,
-1.0, -1.0, -1.0,
// Left face
0.0, 1.0, 0.0,
-1.0, -1.0, -1.0,
-1.0, -1.0, 1.0
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
pyramidVertexPositionBuffer.itemSize = 3;
pyramidVertexPositionBuffer.numItems = 12;
pyramidVertexColorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, pyramidVertexColorBuffer);
var colors = [
// Front face
1.0, 0.0, 0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
0.0, 0.0, 1.0, 1.0,
// Right face
1.0, 0.0, 0.0, 1.0,
0.0, 0.0, 1.0, 1.0,
0.0, 1.0, 0.0, 1.0,
// Back face
1.0, 0.0, 0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
0.0, 0.0, 1.0, 1.0,
// Left face
1.0, 0.0, 0.0, 1.0,
0.0, 0.0, 1.0, 1.0,
0.0, 1.0, 0.0, 1.0
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
pyramidVertexColorBuffer.itemSize = 4;
pyramidVertexColorBuffer.numItems = 12;
cubeVertexPositionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer);
vertices = [
// Front face
-1.0, -1.0, 1.0,
1.0, -1.0, 1.0,
1.0, 1.0, 1.0,
-1.0, 1.0, 1.0,
// Back face
-1.0, -1.0, -1.0,
-1.0, 1.0, -1.0,
1.0, 1.0, -1.0,
1.0, -1.0, -1.0,
// Top face
-1.0, 1.0, -1.0,
-1.0, 1.0, 1.0,
1.0, 1.0, 1.0,
1.0, 1.0, -1.0,
// Bottom face
-1.0, -1.0, -1.0,
1.0, -1.0, -1.0,
1.0, -1.0, 1.0,
-1.0, -1.0, 1.0,
// Right face
1.0, -1.0, -1.0,
1.0, 1.0, -1.0,
1.0, 1.0, 1.0,
1.0, -1.0, 1.0,
// Left face
-1.0, -1.0, -1.0,
-1.0, -1.0, 1.0,
-1.0, 1.0, 1.0,
-1.0, 1.0, -1.0
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
cubeVertexPositionBuffer.itemSize = 3;
cubeVertexPositionBuffer.numItems = 24;
cubeVertexColorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexColorBuffer);
colors = [
[1.0, 0.0, 0.0, 1.0], // Front face
[1.0, 1.0, 0.0, 1.0], // Back face
[0.0, 1.0, 0.0, 1.0], // Top face
[1.0, 0.5, 0.5, 1.0], // Bottom face
[1.0, 0.0, 1.0, 1.0], // Right face
[0.0, 0.0, 1.0, 1.0] // Left face
];
var unpackedColors = [];
for (var i in colors) {
var color = colors[i];
for (var j=0; j < 4; j++) {
unpackedColors = unpackedColors.concat(color);
}
}
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(unpackedColors), gl.STATIC_DRAW);
cubeVertexColorBuffer.itemSize = 4;
cubeVertexColorBuffer.numItems = 24;
cubeVertexIndexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer);
var cubeVertexIndices = [
0, 1, 2, 0, 2, 3, // Front face
4, 5, 6, 4, 6, 7, // Back face
8, 9, 10, 8, 10, 11, // Top face
12, 13, 14, 12, 14, 15, // Bottom face
16, 17, 18, 16, 18, 19, // Right face
20, 21, 22, 20, 22, 23 // Left face
];
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(cubeVertexIndices), gl.STATIC_DRAW);
cubeVertexIndexBuffer.itemSize = 1;
cubeVertexIndexBuffer.numItems = 36;
}
var rPyramid = 0;
var rCube = 0;
function drawScene() {
gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
mat4.perspective(45, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0, pMatrix);
mat4.identity(mvMatrix);
mat4.translate(mvMatrix, [-1.5, 0.0, -8.0]);
mvPushMatrix();
mat4.rotate(mvMatrix, degToRad(rPyramid), [0, 1, 0]);
gl.bindBuffer(gl.ARRAY_BUFFER, pyramidVertexPositionBuffer);
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, pyramidVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, pyramidVertexColorBuffer);
gl.vertexAttribPointer(shaderProgram.vertexColorAttribute, pyramidVertexColorBuffer.itemSize, gl.FLOAT, false, 0, 0);
setMatrixUniforms();
gl.drawArrays(gl.TRIANGLES, 0, pyramidVertexPositionBuffer.numItems);
mvPopMatrix();
mat4.translate(mvMatrix, [3.0, 0.0, 0.0]);
mvPushMatrix();
mat4.rotate(mvMatrix, degToRad(rCube), [1, 1, 1]);
gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer);
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, cubeVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexColorBuffer);
gl.vertexAttribPointer(shaderProgram.vertexColorAttribute, cubeVertexColorBuffer.itemSize, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer);
setMatrixUniforms();
gl.drawElements(gl.TRIANGLES, cubeVertexIndexBuffer.numItems, gl.UNSIGNED_SHORT, 0);
mvPopMatrix();
}
var lastTime = 0;
function animate() {
var timeNow = new Date().getTime();
if (lastTime != 0) {
var elapsed = timeNow - lastTime;
rPyramid += (90 * elapsed) / 1000.0;
rCube -= (75 * elapsed) / 1000.0;
}
lastTime = timeNow;
}
function tick() {
requestAnimFrame(tick);
drawScene();
animate();
}
function webGLStart() {
var canvas = document.getElementById("lesson04-canvas");
initGL(canvas);
initShaders2(); // !!!!!!!!!!!!!!!!!!!!!!!!!
initShaders();
initBuffers();
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.enable(gl.DEPTH_TEST);
tick();
}
</script>
</head>
<body onload="webGLStart();">
<< Back to Lesson 4<br>
<canvas id="lesson04-canvas" style="border: none;" width="500" height="500"></canvas>
<br>
<< Back to Lesson 4<br>
</body></html>
You'll probably need to give us a little bit more information, but to get you started here's a quick checklist. Any time you change programs, you'll want to:
Enable the appropriate vertex attribute arrays
Bind the vertex attribute pointers, even if they were already bound to the right buffers
Bind any uniforms needed, like texture samplers.
Basically, you want to treat every time you change programs as if it's the first time you're setting up a draw call.

Categories