Draw points on click in webGL - javascript

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.

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 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.

WebGL error - "glDrawArrays: attempt to access out of range vertices in attribute 0"

Edit:
After grueling reviewal of the code I happened to make the right alteration to have this triangle render. In the code posted here, the vertices and colors Arrays are declared before initBuffers. In my actual code, they are declared somewhat after. Because javascript (in sublime text) was auto-completing these variables no matter where I defined them (like methods in a java class, say..) and because chrome was throwing no errors, I assumed this could not be the problem. Yet simply shifting these array initializations from after initShaders, initBuffers to before those calls was the crux of my problem. I'm sorry for posting a fundamental unanswerable question but hopefully this will serve as a helpful warning to future people that declaration time matters with regards to webGL buffers. More rigorous checking of shader compilation/linking may yield better information here.
///////////////////
I'm taking some WebGL code I found in a tutorial and trying to refactor it to use code-specified color values for each vertex. Unfortunately, after working this code it, I receive the aforementioned "out of range" error.
node - any not seen declarations are global vars
I have the following setup code, initializing buffers:
The vertex information is specified like so:
var vertices = [
0.0, 1.0,
-1.0, -1.0,
1.0, -1.0
];
var colors = [
1, 0, 0,
1, 0, 0,
1, 0, 0
];
var gl;
var shaderProgram;
var triangleVertexPositionBuffer;
var triangleVertexColorBuffer;
var canvas = document.getElementById("ABID");
gl = canvas.getContext("experimental-webgl");
gl.viewportWidth = canvas.width;
gl.viewportHeight = canvas.height;
function initBuffers() {
triangleVertexPositionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexPositionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
triangleVertexPositionBuffer.itemSize = 2;
triangleVertexColorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexColorBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
triangleVertexColorBuffer.itemSize = 3;
}
initBuffers();
Then creating my shaders/program where I try to get attribute locations and set them on the global variable, '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");
shaderProgram.vertexColorAttrib = gl.getAttribLocation(shaderProgram, "aVertexColor");
gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);
gl.enableVertexAttribArray(shaderProgram.vertexColorAttrib);
}
It depends on a getShader function which works perfectly. The shaders are as follows:
<script id="shader-fs" type="x-shader/x-fragment">
precision mediump float;
varying vec3 color;
void main(void) {
gl_FragColor = vec4(1,0,0, 1);
}
</script>
<script id="shader-vs" type="x-shader/x-vertex">
attribute vec2 aVertexPosition;
attribute vec3 aVertexColor;
varying vec3 color;
void main(void) {
gl_Position = vec4(aVertexPosition, 1.0,1.0);
color = aVertexColor;
}
</script>
And finally, the error occurs somehow when drawing these 3 vertices:
draw();
function draw() {
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
gl.clearColor(0, 0, 0, 1);
gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexPositionBuffer);
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, triangleVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexColorBuffer);
gl.vertexAttribPointer(shaderProgram.vertexColorAttrib, triangleVertexColorBuffer.itemSize, gl.FLOAT, false, 0, 0);
gl.drawArrays(gl.TRIANGLES, 0, 3);
}
I'm sure there is some offset, or size or magic number typed incorrectly but I've been over this many times and cannot spot the error. Being an openGL beginner and a lack of debugging insights compounds the frustrations. Any help would be greatly appreciated.

Setting gl_PointSize dynamically as shader attribute not working in WebGL

I'm trying to change gl_PointSize within my vertex-shader depending on an input. So, whenever I set ie. gl_PointSize = 10.0 explicitly, everything is working out fine. After adding
attribute vec4 vPosition;
attribute vec4 vColor;
attribute float vSize;
varying vec4 fColor;
void main()
{
fColor = vColor;
gl_PointSize = vSize;
gl_Position = vPosition;
}
and calling
var size = new Float32Array([10.0]);
.
.
.
var sizeBufferId = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, sizeBufferId);
gl.bufferData(gl.ARRAY_BUFFER, size, gl.STATIC_DRAW);
var vSize = gl.getAttribLocation(program, "vSize");
gl.vertexAttribPointer(vSize, 1, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(vSize);
vSize is 2 after this so the buffer is created and bound correctly. WebGL Inspector also verified, that its content is 10.0.
Still, when calling my draw-code
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.POINTS, 0, 2);
I only receive a blank canvas... Where am I wrong?
The rest of my code:
var canvas = document.getElementById("gl-canvas");
gl = WebGLUtils.setupWebGL(canvas);
if (!gl) { alert("WebGL isn't available"); }
var colors = new Float32Array([ 1, 0, 0, 1,
0, 0, 1, 1]);
var vertices = new Float32Array([-0.5, 0,
0.5, 0]);
var size = new Float32Array([10.0]);
// Configure viewport
gl.viewport(0,0,canvas.width,canvas.height);
gl.clearColor(1.0,1.0,1.0,1.0);
// Init shader program and bind it (invoked from another JS-file)
var program = initShaders(gl, "vertex-shader", "fragment-shader");
gl.useProgram(program);
// Load colors into the GPU and associate shader variables
var cBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, cBuffer);
gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW);
var vColor = gl.getAttribLocation(program, "vColor");
gl.vertexAttribPointer(vColor, 4, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(vColor);
// Load positions into the GPU and associate shader variables
var bufferId = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, bufferId);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
var vPosition = gl.getAttribLocation(program, "vPosition");
gl.vertexAttribPointer(vPosition, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(vPosition);
// Load squares' size into the GPU and associate shader variables
var sizeBufferId = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, sizeBufferId);
gl.bufferData(gl.ARRAY_BUFFER, size, gl.STATIC_DRAW);
var vSize = gl.getAttribLocation(program, "vSize");
gl.vertexAttribPointer(vSize, 1, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(vSize);
alert("Color var: " + vColor + " | Pos var: " + vPosition + " | Size var: " + vSize);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.POINTS, 0, 2);
I already figured it out myself. A silly and naive mistake, yet easy to overlook:
By calling gl.drawArrays(gl.POINTS, 0, 2) it is specified, that WebGL has to draw two independent points - each with its own coordinates, color AND PointSize.
So by altering var size = new Float32Array([10.0, 10.0]) WebGL may now get two independent PointSize values out of size. Otherwise there would be some kind of NullPointerException within the WebGL state-machine.

WebGL draw through indices

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);
}

Categories