WebGL draw through indices - javascript

I am new in WebGL, I am trying to draw a square using two triangles and indices. However I am not getting something right. I have been looking at codes and examples but missing something. I am trying to keep things really simple.
<html>
<head>
<meta charset="utf-8"/>
<script id="vertex" type="x-shader">
attribute vec2 aVertexPosition;
void main() {
gl_Position = vec4(aVertexPosition, 0.0, 1.0);
}
</script>
<script id="fragment" type="x-shader">
#ifdef GL_ES
precision highp float;
#endif
uniform vec4 uColor;
void main() {
gl_FragColor = uColor;
}
</script>
<script type="text/javascript">
function init(){
var canvas = document.getElementById("mycanvas");
var gl = canvas.getContext("experimental-webgl");
gl.viewport(0, 0, canvas.width, canvas.height);
gl.clearColor(0.5, 0.0, 0.2, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
var v = document.getElementById("vertex").firstChild.nodeValue;
var f = document.getElementById("fragment").firstChild.nodeValue;
var vs = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vs, v);
gl.compileShader(vs);
var fs = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fs, f);
gl.compileShader(fs);
var program = gl.createProgram();
gl.attachShader(program, vs);
gl.attachShader(program, fs);
gl.linkProgram(program);
var vertices = [ -0.5, -0.5, -0.5, 0.5, 0.5, 0.5, 0.5, -0.5];
var indices = [ 3, 2, 1, 3, 1, 0 ]
var vbuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vbuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
var ebuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ebuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
var itemSize = 2;
var numItems = vertices.length / itemSize;
gl.useProgram(program);
program.uColor = gl.getUniformLocation(program, "uColor");
gl.uniform4fv(program.uColor, [0.0, 0.3, 0.0, 1.0]);
program.aVertexPosition = gl.getAttribLocation(program, "aVertexPosition");
gl.enableVertexAttribArray(program.aVertexPosition);
gl.vertexAttribPointer(program.aVertexPosition, itemsize, gl.UNSIGNED_SHORT, false, 0, 0);
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
}
</script>
</head>
<body onload="init()">
<canvas id="mycanvas" width="800" height="500"></canvas>
</body>
The background appears, but the square does not.
The downloaded codes run so I know the error is in my code only.

Your gl.vertexAttribPointer is incorrect. You created a Float32Array but you are telling webGL to use unsigned shorts and you mispelled itemSize.
Change to gl.vertexAttribPointer(program.aVertexPosition, itemSize, gl.FLOAT, false, 0, 0); and it works for me.

Your vertices array was missing a coordinate for the last element. Always, arrays of vertices should have 3 coordinates for each vertices and be multiplo of 3.
Your indices array, points which vertices should be connected as triangles to make you geometry display. Give a try to this. This should work.
function init(){
var canvas = document.getElementById("mycanvas");
var gl = canvas.getContext("experimental-webgl");
gl.viewport(0, 0, canvas.width, canvas.height);
gl.clearColor(0.5, 0.0, 0.2, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
var v = document.getElementById("vertex").firstChild.nodeValue;
var f = document.getElementById("fragment").firstChild.nodeValue;
var vs = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vs, v);
gl.compileShader(vs);
var fs = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fs, f);
gl.compileShader(fs);
var program = gl.createProgram();
gl.attachShader(program, vs);
gl.attachShader(program, fs);
gl.linkProgram(program);
var vertices = [ -0.5, 0, 0, 0, 0.5, 0, 0.5, 0, 0];
var indices = [ 0, 1, 2 ]
var vbuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vbuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
var ebuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ebuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
var itemSize = 2;
var numItems = vertices.length / itemSize;
gl.useProgram(program);
program.uColor = gl.getUniformLocation(program, "uColor");
gl.uniform4fv(program.uColor, [0.0, 0.3, 0.0, 1.0]);
program.aVertexPosition = gl.getAttribLocation(program, "aVertexPosition");
gl.enableVertexAttribArray(program.aVertexPosition);
gl.vertexAttribPointer(program.aVertexPosition, itemsize, gl.UNSIGNED_SHORT, false, 0, 0);
gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_SHORT, 0);
}

Related

Why is the WebGL instancing extension only drawing one triangle instead of two?

I'm trying to use instancing with WebGL based on this guide. I've tried to create a simple example that draws a red triangle on the left and a blue triangle on the right. When I run it, it draws a blue triangle on the left and I don't understand why.
I've tried changing the arguments to drawArraysInstancedANGLE but that doesn't help. I've tried changing the order of lines for binding buffers and setting attribute pointers, etc. What am I doing wrong? Thanks
const canvas = document.getElementById("canvas");
const gl = canvas.getContext("webgl");
const ext = gl.getExtension("ANGLE_instanced_arrays");
const vert = gl.createShader(gl.VERTEX_SHADER);
const frag = gl.createShader(gl.FRAGMENT_SHADER);
const program = gl.createProgram();
gl.shaderSource(vert, `
attribute vec4 a_position;
attribute vec4 a_color;
varying vec4 v_color;
void main() {
gl_Position = a_position;
v_color = a_color;
}
`);
gl.shaderSource(frag, `
precision mediump float;
varying vec4 v_color;
void main() {
gl_FragColor = v_color;
}
`);
gl.compileShader(vert);
gl.compileShader(frag);
gl.attachShader(program, vert);
gl.attachShader(program, frag);
gl.linkProgram(program);
const a_position = gl.getAttribLocation(program, "a_position");
const buffer1 = gl.createBuffer();
const positions = [-0.5, 0, -0.5, 0.2, -0.3, 0, 0.5, 0, 0.5, 0.2, 0.3, 0];
gl.bindBuffer(gl.ARRAY_BUFFER, buffer1);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
const a_color = gl.getAttribLocation(program, "a_color");
const buffer2 = gl.createBuffer();
const colors = [1, 0, 0, 1, 0, 0, 1, 1];
gl.bindBuffer(gl.ARRAY_BUFFER, buffer2);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
gl.viewport(0, 0, 300, 300);
gl.useProgram(program);
gl.bindBuffer(gl.ARRAY_BUFFER, buffer1);
gl.enableVertexAttribArray(a_position);
gl.vertexAttribPointer(a_position, 2, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, buffer2);
gl.enableVertexAttribArray(a_color);
gl.vertexAttribPointer(a_color, 4, gl.FLOAT, false, 0, 0);
ext.vertexAttribDivisorANGLE(a_color, 1);
ext.drawArraysInstancedANGLE(gl.TRIANGLES, 0, 3, 2);
<canvas id="canvas" width="300" height="300"></canvas>
So I see you mostly already got an answer in the comments.
The code is drawing the first triangle twice, once in red, then once in blue.
But, ... you mentioned indexing a uniform array. That would be unusual
Normally you'd put per instance data in a buffer. The example on the site linked used a matrix just to be generic since a matrix well will let you do just about any math (translation, rotation, scale, 3d projection, ...) but just as an example, you could just pass in single x offset.
const canvas = document.getElementById("canvas");
const gl = canvas.getContext("webgl");
const ext = gl.getExtension("ANGLE_instanced_arrays");
const vert = gl.createShader(gl.VERTEX_SHADER);
const frag = gl.createShader(gl.FRAGMENT_SHADER);
const program = gl.createProgram();
gl.shaderSource(vert, `
attribute vec4 a_position;
attribute float a_xoffset;
attribute vec4 a_color;
varying vec4 v_color;
void main() {
gl_Position = a_position;
gl_Position.x += a_xoffset;
v_color = a_color;
}
`);
gl.shaderSource(frag, `
precision mediump float;
varying vec4 v_color;
void main() {
gl_FragColor = v_color;
}
`);
gl.compileShader(vert);
gl.compileShader(frag);
gl.attachShader(program, vert);
gl.attachShader(program, frag);
gl.linkProgram(program);
const a_position = gl.getAttribLocation(program, "a_position");
const buffer1 = gl.createBuffer();
const positions = [-0.5, 0, -0.5, 0.2, -0.3, 0];
gl.bindBuffer(gl.ARRAY_BUFFER, buffer1);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
const a_color = gl.getAttribLocation(program, "a_color");
const buffer2 = gl.createBuffer();
const colors = [1, 0, 0, 1, 0, 0, 1, 1];
gl.bindBuffer(gl.ARRAY_BUFFER, buffer2);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
const a_xoffset = gl.getAttribLocation(program, "a_xoffset");
const buffer3 = gl.createBuffer();
const xoffsets = [0, 1];
gl.bindBuffer(gl.ARRAY_BUFFER, buffer3);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(xoffsets), gl.STATIC_DRAW);
gl.viewport(0, 0, 300, 300);
gl.useProgram(program);
gl.bindBuffer(gl.ARRAY_BUFFER, buffer1);
gl.enableVertexAttribArray(a_position);
gl.vertexAttribPointer(a_position, 2, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, buffer2);
gl.enableVertexAttribArray(a_color);
gl.vertexAttribPointer(a_color, 4, gl.FLOAT, false, 0, 0);
ext.vertexAttribDivisorANGLE(a_color, 1);
gl.bindBuffer(gl.ARRAY_BUFFER, buffer3);
gl.enableVertexAttribArray(a_xoffset);
gl.vertexAttribPointer(a_xoffset, 1, gl.FLOAT, false, 0, 0);
ext.vertexAttribDivisorANGLE(a_xoffset, 1);
ext.drawArraysInstancedANGLE(gl.TRIANGLES, 0, 3, 2);
<canvas id="canvas" width="300" height="300"></canvas>
I'm just pointing that out because you have millions of values in a buffer but uniforms are far more limited so indexing a uniform for instancing is not common.
If you actually wanted different data per instance then yes you'd have to do something else.
One example is here

WebGL color buffer issue: [GL_INVALID_OPERATION : glDrawArrays]

I am trying to get starting learning WebGL; I got my proof of concept working without color, but as soon as I tried added color by adding
colorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
gl.bufferData (gl.ARRAY_BUFFER, new Float32Array(
1, 0, 0, 1,
0, 1, 0, 1,
0, 0, 1, 1,
), gl.STATIC_DRAW);
ColorAttribute = gl.getAttribLocation(program, 'color');
gl.enableVertexAttribArray(ColorAttribute);
gl.vertexAttribPointer(ColorAttribute, 4, gl.FLOAT, false, 0, 0);
where
gl is the WebGLRenderingContext,
program is the successfully compiled program with a vertex and a fragment shader attached
colorBuffer, ColorAttribute are null variables
in the main code, and changing
gl_FragColor = vec4(0.2, 0.4, 0.6, 1);
to
gl_FragColor = vcolor;
in the fragment shader source(commenting the shader body does not make the error go away); I got the following error:
[.Offscreen-For-WebGL-0000000005BB7940]GL ERROR :GL_INVALID_OPERATION : glDrawArrays: attempt to access out of range vertices in attribute 1
Which is strange because my color buffer has 3 colors in it, one for each vertex of the triangle:
gl.bufferData (gl.ARRAY_BUFFER, new Float32Array(
1, 0, 0, 1,
0, 1, 0, 1,
0, 0, 1, 1,
), gl.STATIC_DRAW);
and my vertex buffer has 3 vertices in it:
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
0, 0, 0,
0, 1, 0,
1, 1, 0
]), gl.STATIC_DRAW);
I made sure that i set the item size of color buffer to 4, and item size of vertex buffer to 3 in my calls to vertexAttribPointer, so I am not sure what could be out of range.
Below is a code that works, with the color changes commented out, followed by one that doesn't work with color changes in. Both samples work by pasting into browser developer console on any window, but the screenshots were taken in "about:blank".
Both snippets are self contained, but only tested in Chrome.
This is the working version:
(function() {
"use strict";
var hWnd;
var src_vertexShader;
var src_fragmentShader;
var canvas;
var gl;
var program;
var vertexShader;
var fragmentShader;
var vertexBuffer;
var colorBuffer;
var PositionAttribute;
var ColorAttribute;
// | canvas container.
hWnd = document.createElement("div");
hWnd.style.position = "fixed";
hWnd.style.top = "0px";
hWnd.style.left = "0px";
hWnd.style.border = "1px solid #000000";
hWnd.addEventListener("click", function() {
this.outerHTML = '';
});
// | vertex shader source.
src_vertexShader = `
attribute vec3 position;
attribute vec4 color;
varying vec4 vcolor;
void main() {
gl_Position = vec4(position, 1.0);
vcolor = color;
}`;
// | fragment shader source.
src_fragmentShader = `
varying lowp vec4 vcolor;
void main() {
gl_FragColor = vec4(0.2, 0.4, 0.6, 1);
//gl_FragColor = vcolor;
}`;
// | our WebGL canvas.
canvas = document.createElement('canvas');
canvas.width = 320;
canvas.height = 200;
// | our WebGLRenderingContext.
gl = canvas.getContext('webgl', {antialias: false});
// | setting up our program using a Vertex and a Fragment shader.
program = gl.createProgram();
vertexShader = gl.createShader(gl.VERTEX_SHADER);
fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(vertexShader, src_vertexShader);
gl.shaderSource(fragmentShader, src_fragmentShader);
gl.compileShader(vertexShader);
console.log('Shader compiled successfully: ' + gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS));
console.log('Shader compiler log: ' + gl.getShaderInfoLog(vertexShader));
gl.compileShader(fragmentShader);
console.log('Shader compiled successfully: ' + gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS));
console.log('Shader compiler log: ' + gl.getShaderInfoLog(fragmentShader));
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
gl.useProgram(program);
console.log(gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS));
// | create and attach a vertex buffer with data for one triangle.
vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
0, 0, 0,
0, 1, 0,
1, 1, 0
]), gl.STATIC_DRAW);
PositionAttribute = gl.getAttribLocation(program, 'position');
gl.enableVertexAttribArray(PositionAttribute);
gl.vertexAttribPointer(PositionAttribute, 3, gl.FLOAT, false, 0, 0);
/*
// | create and attach a color buffer with color data for our triangle.
colorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
gl.bufferData (gl.ARRAY_BUFFER, new Float32Array(
1, 0, 0, 1,
0, 1, 0, 1,
0, 0, 1, 1,
), gl.STATIC_DRAW);
ColorAttribute = gl.getAttribLocation(program, 'color');
gl.enableVertexAttribArray(ColorAttribute);
gl.vertexAttribPointer(ColorAttribute, 4, gl.FLOAT, false, 0, 0);
*/
// | clear the screen.
gl.clearColor(0.93, 0.93, 0.93, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
// | draw the triangle.
gl.drawArrays(gl.TRIANGLES, 0, 3);
hWnd.appendChild(canvas)
document.body.appendChild(hWnd);
})();
This is the version that complains:
(function() {
"use strict";
var hWnd;
var src_vertexShader;
var src_fragmentShader;
var canvas;
var gl;
var program;
var vertexShader;
var fragmentShader;
var vertexBuffer;
var colorBuffer;
var PositionAttribute;
var ColorAttribute;
// | canvas container.
hWnd = document.createElement("div");
hWnd.style.position = "fixed";
hWnd.style.top = "0px";
hWnd.style.left = "0px";
hWnd.style.border = "1px solid #000000";
hWnd.addEventListener("click", function() {
this.outerHTML = '';
});
// | vertex shader source.
src_vertexShader = `
attribute vec3 position;
attribute vec4 color;
varying vec4 vcolor;
void main() {
gl_Position = vec4(position, 1.0);
vcolor = color;
}`;
// | fragment shader source.
src_fragmentShader = `
varying lowp vec4 vcolor;
void main() {
gl_FragColor = vcolor;
}`;
// | our WebGL canvas.
canvas = document.createElement('canvas');
canvas.width = 320;
canvas.height = 200;
// | our WebGLRenderingContext.
gl = canvas.getContext('webgl', {antialias: false});
// | setting up our program using a Vertex and a Fragment shader.
program = gl.createProgram();
vertexShader = gl.createShader(gl.VERTEX_SHADER);
fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(vertexShader, src_vertexShader);
gl.shaderSource(fragmentShader, src_fragmentShader);
gl.compileShader(vertexShader);
console.log('Shader compiled successfully: ' + gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS));
console.log('Shader compiler log: ' + gl.getShaderInfoLog(vertexShader));
gl.compileShader(fragmentShader);
console.log('Shader compiled successfully: ' + gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS));
console.log('Shader compiler log: ' + gl.getShaderInfoLog(fragmentShader));
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
gl.useProgram(program);
console.log(gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS));
// | create and attach a vertex buffer with data for one triangle.
vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
0, 0, 0,
0, 1, 0,
1, 1, 0
]), gl.STATIC_DRAW);
PositionAttribute = gl.getAttribLocation(program, 'position');
gl.enableVertexAttribArray(PositionAttribute);
gl.vertexAttribPointer(PositionAttribute, 3, gl.FLOAT, false, 0, 0);
// | create and attach a color buffer with color data for our triangle.
colorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
gl.bufferData (gl.ARRAY_BUFFER, new Float32Array(
1, 0, 0, 1,
0, 1, 0, 1,
0, 0, 1, 1,
), gl.STATIC_DRAW);
ColorAttribute = gl.getAttribLocation(program, 'color');
gl.enableVertexAttribArray(ColorAttribute);
gl.vertexAttribPointer(ColorAttribute, 4, gl.FLOAT, false, 0, 0);
// | clear the screen.
gl.clearColor(0.93, 0.93, 0.93, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
// | draw the triangle.
gl.drawArrays(gl.TRIANGLES, 0, 3);
hWnd.appendChild(canvas)
document.body.appendChild(hWnd);
})();
Thanks ahead of time.
The issue is the code is missing square brackets when defining the colors
gl.bufferData (gl.ARRAY_BUFFER, new Float32Array(
1, 0, 0, 1,
0, 1, 0, 1,
0, 0, 1, 1,
), gl.STATIC_DRAW);
vs this
gl.bufferData (gl.ARRAY_BUFFER, new Float32Array([
1, 0, 0, 1,
0, 1, 0, 1,
0, 0, 1, 1,
]), gl.STATIC_DRAW);
(function() {
"use strict";
var hWnd;
var src_vertexShader;
var src_fragmentShader;
var canvas;
var gl;
var program;
var vertexShader;
var fragmentShader;
var vertexBuffer;
var colorBuffer;
var PositionAttribute;
var ColorAttribute;
// | canvas container.
hWnd = document.createElement("div");
hWnd.style.position = "fixed";
hWnd.style.top = "0px";
hWnd.style.left = "0px";
hWnd.style.border = "1px solid #000000";
hWnd.addEventListener("click", function() {
this.outerHTML = '';
});
// | vertex shader source.
src_vertexShader = `
attribute vec3 position;
attribute vec4 color;
varying vec4 vcolor;
void main() {
gl_Position = vec4(position, 1.0);
vcolor = color;
}`;
// | fragment shader source.
src_fragmentShader = `
varying lowp vec4 vcolor;
void main() {
gl_FragColor = vcolor;
}`;
// | our WebGL canvas.
canvas = document.createElement('canvas');
canvas.width = 320;
canvas.height = 200;
// | our WebGLRenderingContext.
gl = canvas.getContext('webgl', {antialias: false});
// | setting up our program using a Vertex and a Fragment shader.
program = gl.createProgram();
vertexShader = gl.createShader(gl.VERTEX_SHADER);
fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(vertexShader, src_vertexShader);
gl.shaderSource(fragmentShader, src_fragmentShader);
gl.compileShader(vertexShader);
console.log('Shader compiled successfully: ' + gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS));
console.log('Shader compiler log: ' + gl.getShaderInfoLog(vertexShader));
gl.compileShader(fragmentShader);
console.log('Shader compiled successfully: ' + gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS));
console.log('Shader compiler log: ' + gl.getShaderInfoLog(fragmentShader));
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
gl.useProgram(program);
console.log(gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS));
// | create and attach a vertex buffer with data for one triangle.
vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
0, 0, 0,
0, 1, 0,
1, 1, 0
]), gl.STATIC_DRAW);
PositionAttribute = gl.getAttribLocation(program, 'position');
gl.enableVertexAttribArray(PositionAttribute);
gl.vertexAttribPointer(PositionAttribute, 3, gl.FLOAT, false, 0, 0);
// | create and attach a color buffer with color data for our triangle.
colorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
gl.bufferData (gl.ARRAY_BUFFER, new Float32Array([
1, 0, 0, 1,
0, 1, 0, 1,
0, 0, 1, 1,
]), gl.STATIC_DRAW);
ColorAttribute = gl.getAttribLocation(program, 'color');
gl.enableVertexAttribArray(ColorAttribute);
gl.vertexAttribPointer(ColorAttribute, 4, gl.FLOAT, false, 0, 0);
// | clear the screen.
gl.clearColor(0.93, 0.93, 0.93, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
// | draw the triangle.
gl.drawArrays(gl.TRIANGLES, 0, 3);
hWnd.appendChild(canvas)
document.body.appendChild(hWnd);
})();

webGL - vertexAttribPointer: Bad `type`: NONE

I can't seem to figure out why my code isn't working. When I run it I get these errors:
Error: WebGL warning: vertexAttribPointer: Bad type: NONE
Error: WebGL warning: drawArrays: no VBO bound to enabled vertex attrib index 1u!
I followed this example: Link
EDIT: now the code works, it should show a colored triangle
MyCode:
var gl;
var shaderProgram;
var triangleVertices =
[ // X, Y, R, G, B
0.0, 0.5, 1.0, 1.0, 0.0,
-0.5, -0.5, 0.7, 0.0, 1.0,
0.5, -0.5, 0.1, 1.0, 0.6
];
var triangleVertexBufferObject;
var positionAttribLocation;
var colorAttribLocation;
var vertShaderCode = 'precision mediump float;'+
'attribute vec2 vertPosition;'+
'attribute vec3 vertColor;'+
'varying vec3 fragColor;'+
'void main()'+
'{'+
' fragColor = vertColor;'+
' gl_Position = vec4(vertPosition, 0.0, 1.0);'+
'}';
var fragShaderCode =
'precision mediump float;'+
'varying vec3 fragColor;'+
'void main()'+
'{'+
' gl_FragColor = vec4(fragColor, 1.0);'+
'}';
function initGL(canvas) {
try {
gl = canvas.getContext("webgl");
gl.viewportWidth = canvas.width;
gl.viewportHeight = canvas.height;
} catch (e) {
}
if (!gl) {
alert("Could not initialise WebGL, sorry :-(");
}
}
function initShaders() {
var fragmentShader = getShader(fragShaderCode, gl.FRAGMENT_SHADER);
var vertexShader = getShader(vertShaderCode, gl.VERTEX_SHADER);
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");
}
}
function initBuffers() {
triangleVertexBufferObject = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexBufferObject);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(triangleVertices), gl.STATIC_DRAW);
positionAttribLocation = gl.getAttribLocation(shaderProgram, "vertPosition");
colorAttribLocation = gl.getAttribLocation(shaderProgram, "vertColor");
gl.vertexAttribPointer(
positionAttribLocation, // attribute location
2, //number of elements per attribute
gl.FLOAT, // type of element
gl.FALSE,
5 * Float32Array.BYTES_PER_ELEMENT,//size of induvidual vertex
0//offset from the beginning of a single vertex to this attribute
);
gl.vertexAttribPointer(
colorAttribLocation,
3,
gl.FLOAT,
gl.FALSE,
5 * Float32Array.BYTES_PER_ELEMENT,
2 * Float32Array.BYTES_PER_ELEMENT
);
gl.enableVertexAttribArray(positionAttribLocation);
gl.enableVertexAttribArray(colorAttribLocation);
}
function drawScene() {
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0/*verts to skip*/, 3/*verts to draw*/);
}
function getShader(code, type){
var shader = gl.createShader(type);
gl.shaderSource(shader, code);
gl.compileShader(shader);
return shader;
}
this.start = function(spritesCompiledDone, scriptsCompiledDone, roomsCompiledDone, customObjectsCompiledDone, soundsCompiledDone, currentIdGen){
document.body.style.cursor = "auto";
var canvas = document.createElement("canvas");
canvas.width = 640;
canvas.height = 480;
canvas.style.position = "fixed";
canvas.style.top = "0px";
canvas.style.left = "0px";
document.body.appendChild(canvas);
initGL(canvas);
initShaders();
initBuffers();
gl.useProgram(shaderProgram);
gl.clearColor(0.2, 0.1, 0.7, 1.0);
drawScene();
}
It looks like I have done all the steps to get the attribute locations and pointers but it doesn't work. I don't understand how no VBO can be bound as I use gl.bindBuffer which should still be active in the draw phase.
You should change the following things:
function initBuffers() {
triangleVertexBufferObject = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexBufferObject);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(triangleVertices), gl.STATIC_DRAW);
positionAttribLocation = gl.getAttribLocation(shaderProgram, "vertPosition");
colorAttribLocation = gl.getAttribLocation(shaderProgram, "vertColor");
gl.vertexAttribPointer(
positionAttribLocation, // attribute location
2, //number of elements per attribute
gl.FLOAT, // type of element
gl.FALSE, // to => false,
5 * Float32Array.BYTES_PER_ELEMENT,//size of induvidual vertex
0//offset from the beginning of a single vertex to this attribute
);
gl.vertexAttribPointer(
colorAttribLocation,
3,
gl.Float, //to => gl.FLOAT,
gl.False, //to => false,
5 * Float32Array.BYTES_PER_ELEMENT,
5 * Float32Array.BYTES_PER_ELEMENT //to => 2 * Float32Array.BYTES_PER_ELEMENT
);
gl.enableVertexAttribArray(positionAttribLocation);
gl.enableVertexAttribArray(colorAttribLocation);
}

WebGl Code "object does not exist or has been deleted"

I keep getting the following error when I run my code: "INVALID_VALUE: getAttribLocation: no object or object deleted"
I am brand new to webGL and any help will be greatly appreciated! Sorry if this question is too broad.
HTML
<html>
<head>
<script type="text/javascript" src = "prog1.js"></script>
<script type="text/javascript" src = "webgl-utils.js"></script>
<script type="text/javascript" src = "webgl-debug.js"></script>
<script type="text/javascript" src = "cuon-utils.js"></script>
<script type="text/javascript" src = "cuon-matrix.js"></script>
</head>
<body onload="init()">
<script id ="vertexShader" type="x-shader/x-vertex">
precision mediump float;
attribute vec4 vertexPosition;
void main(){
gl_position = vertexPosition;
}
</script>
<script id ="fragmentShader" type ="x-shader/x-fragment">
void main(){
gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0);
}
</script>
<canvas id = "webgl" width = "300" height = "300"></canvas>
</body>
</html>
JAVASCRIPT
function flatten(a) {
return a.reduce(function(b, v) {
b.push.apply(b, v);
return b
}, [])
}
function init() {
var positions = [
[-0.25, 0.5, 0],
[-0.5, 0.0, 0],
[0.0, 0.0, 0.0]
];
var triangles = [
[0, 1, 2]
];
// initialize the GL context
canvas = document.getElementById("webgl");
gl = getWebGLContext(canvas, false);
// initialize the program object
var vertexSource = document.getElementById("vertexShader").text;
var fragmentSource = document.getElementById("fragmentShader").text;
program = createProgram(gl, vertexSource, fragmentSource);
gl.useProgram(program);
// initialize the buffer objects
positionBuffer = gl.createBuffer();
triangleBuffer = gl.createBuffer();
// copy vertex data to the gpu
positionArray = new Float32Array(flatten(positions));
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, positionArray, gl.STATIC_DRAW);
// copy triangle data to the gpu
triangleArray = new Uint16Array(flatten(triangles));
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, triangleBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, triangleArray, gl.STATIC_DRAW);
requestAnimationFrame(draw);
}
function draw() {
var vertexSource = document.getElementById("vertexShader").text;
var fragmentSource = document.getElementById("fragmentShader").text;
gl.clearColor(0.0, 0.8, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
var vertexPositionLocation = gl.getAttribLocation(program, "vertexPosition");
gl.vertexAttribPointer(vertexPositionLocation, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(vertexPositionLocation);
gl.drawElements(gl.TRIANGLES, triangleArray.length, gl.UNSIGNED_SHORT, 0);
}
Your shader program probably didn't compile/link and your createProgram function returned null. The error explains it directly
INVALID_VALUE: getAttribLocation: no object or object deleted"
Since getAttribLocation takes only 2 values. The first is a WebGLProgram and get second a string. Since your string is a constant then there must be something wrong with your program argument. "no object" probably means "is null" or "undefined"
When I run your code with my substitution for createProgram I get
*** Error compiling shader: ERROR: 0:4: 'gl_position' : undeclared identifier
ERROR: 0:4: 'assign' : cannot convert from 'attribute mediump 4-component vector of float' to 'float'
function flatten(a) {
return a.reduce(function(b, v) {
b.push.apply(b, v);
return b
}, [])
}
function init() {
var positions = [
[-0.25, 0.5, 0],
[-0.5, 0.0, 0],
[0.0, 0.0, 0.0]
];
var triangles = [
[0, 1, 2]
];
// initialize the GL context
canvas = document.getElementById("webgl");
gl = canvas.getContext("webgl");
// initialize the program object
var vertexSource = document.getElementById("vertexShader").text;
var fragmentSource = document.getElementById("fragmentShader").text;
program = createProgram(gl, vertexSource, fragmentSource);
gl.useProgram(program);
// initialize the buffer objects
positionBuffer = gl.createBuffer();
triangleBuffer = gl.createBuffer();
// copy vertex data to the gpu
positionArray = new Float32Array(flatten(positions));
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, positionArray, gl.STATIC_DRAW);
// copy triangle data to the gpu
triangleArray = new Uint16Array(flatten(triangles));
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, triangleBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, triangleArray, gl.STATIC_DRAW);
requestAnimationFrame(draw);
}
function draw() {
var vertexSource = document.getElementById("vertexShader").text;
var fragmentSource = document.getElementById("fragmentShader").text;
gl.clearColor(0.0, 0.8, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
var vertexPositionLocation = gl.getAttribLocation(program, "vertexPosition");
gl.vertexAttribPointer(vertexPositionLocation, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(vertexPositionLocation);
gl.drawElements(gl.TRIANGLES, triangleArray.length, gl.UNSIGNED_SHORT, 0);
}
function createProgram(gl, vs, fs) {
return twgl.createProgramFromSources(gl, [vs, fs]);
}
init();
<script id ="vertexShader" type="x-shader/x-vertex">
precision mediump float;
attribute vec4 vertexPosition;
void main(){
gl_position = vertexPosition;
}
</script>
<script id ="fragmentShader" type ="x-shader/x-fragment">
void main(){
gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0);
}
</script>
<canvas id = "webgl" width = "300" height = "300"></canvas>
<script src="https://twgljs.org/dist/twgl.min.js"></script>
The bug is it's gl_Position not gl_position. It's case sensitive.
You should probably print your shader compilation and linking errors using standard boilerplate WebGL code and make sure to check the JavaScript console for error messages or use an alert or throw an exception if they fail to compile.
PS: please use running snippets when you can. It's less work for the rest of us.

Draw points on click in webGL

I am a newbie, I am trying to draw a point of size 10, in WebGL, every time on MouseClick. At the point where I click. But Due to some logical error, it behaves a bit differently, it draws two points on click. Also I pass the colour black. It sometimes draws point of different colour(like green).
<html>
<head>
<meta charset="utf-8">
<script id="vertex" type="x-shader">
attribute vec2 aVertexPosition;
attribute vec4 vColor;
varying vec4 fColor;
void main() {
gl_Position = vec4(aVertexPosition, 0.0, 1.0);
gl_PointSize = 10.0;
fColor = vColor;
}
</script>
<script id="fragment" type="x-shader">
#ifdef GL_ES
precision highp float;
#endif
varying vec4 fColor;
void main() {
gl_FragColor = fColor;
}
</script>
<script type="text/javascript">
var points = [];
var index = 0;
function init1(){
var canvas = document.getElementById("mycanvas");
gl = canvas.getContext("experimental-webgl");
gl.viewport(0, 0, canvas.width, canvas.height);
gl.clearColor(1.0, 1.0, 1.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
var v = document.getElementById("vertex").firstChild.nodeValue;
var f = document.getElementById("fragment").firstChild.nodeValue;
var vs = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vs, v);
gl.compileShader(vs);
var fs = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fs, f);
gl.compileShader(fs);
var program = gl.createProgram();
gl.attachShader(program, vs);
gl.attachShader(program, fs);
gl.linkProgram(program);
gl.useProgram(program);
color= [0.0, 0.0, 0.0, 1.0];
var vbuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vbuffer);
gl.bufferData(gl.ARRAY_BUFFER, 8*200, gl.STATIC_DRAW);
program.aVertexPosition = gl.getAttribLocation(program, "aVertexPosition");
gl.enableVertexAttribArray(program.aVertexPosition);
gl.vertexAttribPointer(program.aVertexPosition, 2, gl.FLOAT, false, 0, 0);
var cBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, cBuffer);
gl.bufferData(gl.ARRAY_BUFFER, 16*200, gl.STATIC_DRAW);
program.vColor = gl.getAttribLocation(program, "vColor");
gl.enableVertexAttribArray(program.vColor);
gl.vertexAttribPointer(program.vColor, 3, gl.FLOAT, false, 0, 0);
var flattenedVertices = [];
var idx = 0;
canvas.addEventListener("mousedown", function(event){
x=2*event.clientX/canvas.width-1;
y=2*(canvas.height-event.clientY)/canvas.height-1;
var pts = [x, y];
points.push(pts);
gl.bindBuffer(gl.ARRAY_BUFFER, vbuffer);
gl.bufferSubData(gl.ARRAY_BUFFER, 8*index++, new Float32Array(pts));
gl.bindBuffer(gl.ARRAY_BUFFER, cBuffer);
gl.bufferSubData(gl.ARRAY_BUFFER, 16*index++, new Float32Array(color));
});
render();
}
function render(){
gl.clear( gl.COLOR_BUFFER_BIT );
gl.drawArrays(gl.POINTS, 0, index);
window.requestAnimationFrame(render);
}
</script>
</head>
<body onload="init1()">
<canvas id="mycanvas" width="800" height="500"></canvas>
</body>
Above is my code, if anybody can help me fine tune it to work exactly what I want. There are a few problems I face,
1)I suspect that it draws two points on every click.
2)If I change the number 3 to 4 in line gl.vertexAttribPointer(program.vColor, 3, gl.FLOAT, false, 0, 0);
it only draws one point, the initial one and does not draws any point on successive clicks.
Kindly help.
You are incrementing index twice with 2 index++ calls. Do it like this instead:
var i = index;
gl.bindBuffer(gl.ARRAY_BUFFER, vbuffer);
gl.bufferSubData(gl.ARRAY_BUFFER, 8*i, new Float32Array(pts));
gl.bindBuffer(gl.ARRAY_BUFFER, cBuffer);
gl.bufferSubData(gl.ARRAY_BUFFER, 16*i, new Float32Array(color));
index ++;
And I suspect you meant gl.vertexAttribPointer(program.vColor, 4, gl.FLOAT, false, 0, 0); rather than gl.vertexAttribPointer(program.vColor, 3, gl.FLOAT, false, 0, 0); Since your color is 4 elems: var color= [0.0, 0.0, 0.0, 1.0];
Also, use appropriate hint when allocating a new BufferData. If your data is not static (like how you are changing the buffer when "drawing" a new point) use gl.STREAM_DRAW or gl.DYNAMIC_DRAW. Using wrong hint can have a 5-10x performance loss.

Categories