drawElements with multiple attributes - javascript

I am trying to render multiple attribute buffers with drawElements:
var verteces = [1,1, 0,-1, -1,0];
var vBuffer = gl.createBuffer(gl.ARRAY_BUFFER);
gl.bindBuffer(gl.ARRAY_BUFFER, vBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(verteces), gl.DYNAMIC_DRAW);
gl.enableVertexAttribArray(0);
gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
var colors = [1,0,0,1, 0,1,0,1, 0,0,1,1];
var cBuffer = gl.createBuffer(gl.ARRAY_BUFFER);
gl.bindBuffer(gl.ARRAY_BUFFER, cBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.DYNAMIC_DRAW);
gl.enableVertexAttribArray(1);
gl.vertexAttribPointer(1, 4, gl.FLOAT, false, 0, 0);
var indices = [0,3,2];
var elBuffer = gl.createBuffer(gl.ELEMENT_ARRAY_BUFFER);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint8Array(indices), gl.STATIC_DRAW);
If I run this code with gl.drawArrays(gl.TRIANGLES, 0, 3); it renders a beautiful triangle with rbg fill. But if I call gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_BYTE, 0); I get
[.CommandBufferContext.Offscreen-MainThread-0AB44528]GL ERROR :GL_INVALID_OPERATION : glDrawElements: attempt to access out of range vertices in attribute 1
Can’t figure out what is wrong here. drawElements without setting up colors buffer works alright.
Appreciate any help.

YOu proivide vertex data for 3 vertices, so the only valid vertex indices are 0,1,2. Yet, you try to render with an index array of 0,3,2, which will try to acces a fourth vertex, and would result in an out-of-bounds access to the vertex buffers.

Related

Vertex buffer object data being overwritten for some reason

I'm having this weird issue where my object vertex data is being overridden when I create a new vertex buffer object... I believe this section of code is the culprit, as I'm aware it's in the constructor, since the data that is overwritten switches if i change the order of instancing:
this.shader = shaderProgram(srcContainer.vert, srcContainer.frag);
this.theta = 0;
this.vbo = gl.createBuffer();
this.ibo = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.ibo);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(this.indices), gl.STATIC_DRAW);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
gl.useProgram(this.shader);
gl.bindBuffer(gl.ARRAY_BUFFER, this.vbo);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(this.verts), gl.STATIC_DRAW);
// vertex position
gl.vertexAttribPointer(0, /*size of attribute(x,y,z) in count*/3, gl.FLOAT, gl.FALSE, /*size of a vertex in bytes*/6*Float32Array.BYTES_PER_ELEMENT, /*offset to attribute in vertex*/0*Float32Array.BYTES_PER_ELEMENT);
gl.enableVertexAttribArray(0);
// vertex color
gl.vertexAttribPointer(1, /*size of attribute(r,g,b) in count*/3, gl.FLOAT, gl.FALSE, /*size of a vertex in bytes*/6*Float32Array.BYTES_PER_ELEMENT, /*offset to attribute in vertex*/3*Float32Array.BYTES_PER_ELEMENT);
gl.enableVertexAttribArray(1);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
this.verts is vertex data that is joined with color data vertex-wise. The following code is used to display the cubes to the screen:
let box, box2;
let canv, gl, time;
function setup() {
canv = document.querySelector('#glCanvas');
gl = loadGL(canv); // Grabs a reference to webGL from canvas in the middle of the page
box2 = new Cube([
1-0.4, 1-0.1, 1-0.8,
1-0.5, 1-0.0, 1-0.2,
1-0.6, 1-0.0, 1-0.0,
1-0.7, 1-0.2, 1-0.0,
1-0.6, 1-0.2, 1-0.9,
1-0.5, 1-0.1, 1-0.6,
1-0.7, 1-0.0, 1-0.5,
1-0.9, 1-0.5, 1-0.0], 0.5, 1/7); // initialize box2 to have inverted color vertex data
box = new Cube([
0.4, 0.1, 0.8,
0.5, 0.0, 0.2,
0.6, 0.0, 0.0,
0.7, 0.2, 0.0,
0.6, 0.2, 0.9,
0.5, 0.1, 0.6,
0.7, 0.0, 0.5,
0.9, 0.5, 0.0], 0.5, 1/10); // initialize box to have normal color data, which ends up overwriting the inverted data above.
box2.time = Math.PI/6; // Angle one box differently to see both
time = new Time(0); // Custom time class to keep track of the deltaTime, pass in 0 to start at 0 milliseconds.
window.requestAnimationFrame(draw); // the first call of requestAnimationFrame will start the draw loop.
}
// Draw is called every animation frame with requestAnimationFrame
function draw(timestamp) {
time.update(timestamp); // Calculate time.deltaTime
background(0, 0, 0);
//box.update();
box.show(); // show box 1 (meant to be normal colored)
//box2.update();
box2.show(); // show box 2 (meant to be inverted colored)
window.requestAnimationFrame(draw);
}
and this is the show, and bind functions:
bind() {
gl.useProgram(this.shader);
gl.bindBuffer(gl.ARRAY_BUFFER, this.vbo);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.ibo);
};
show() {
this.bind();
gl.drawElements(gl.TRIANGLES, this.indices.length, gl.UNSIGNED_SHORT, 0);
this.unbind();
};
this code renders them both to have normal vertex data which can be seen here
Answered by user LJᛃ,
"... you need to setup the attributes each time you render (so in your bind method), they're a global state. You may want to look into VAOs."

WebGL is not rendering 3d objects properly

I have a generator of 3d objects in a canvas context.
The rendering is carried out with the painter's algorithm. However, I need a more accurate approach for my project.
Therefore, I have implemented a WebGL renderer. The idea is to transform the objects generated in the canvas context to the WebGL context ( I have two overlayed canvases for this purpose) in order to render them accurately with regards to the HSA (hidden surface algorithm) problem.
I have a function that transforms the canvas coordinates to clip coordinates, and that sets up the different elements and peculiarities required by WebGL, basically, the function prepares the 3d objects to be rendered by WebGL.
As I also need the segments of the shapes to be rendered, my approach consists in creating a buffer, in which all the coordinates of all the objects are stored, together with the coordinates of the segments of these objects, which will be represented and drawn as thin 3d squares (that is, each line will be formed by 2 thin coupled-up triangles, whose vertices and positions will be determined beforehand in canvas coordinates).
So far I am only testing and have coded the rendering of the shapes without lines. The problem is, it is not working properly. Triangles are drawn wrongly, with points and positions that either do not exist in the buffer or are mistaken.
Here is what should be drawn: (this cube is rendered in the canvas with the painter's algorithm)
Here is the colored silhouette that is drawn, however:
If only drawing the face 0 with LINE_LOOP
soon things get pretty messed up, face 0 + face 1 (face 1 is obviously being mistakenly drawn)
3 faces
Things get worse with more complicated objects (notice that this one is not perfectly rendered either)
I do not really know what is happening. My knowledge of WebGL and of 3d graphics, in general, is pretty limited, not to say inexistent. I do not have studies in computer science or any IT-related domain either. I just need a function to render my javascript 3d objects properly for a personal project. Here is the code that I am using:
function webglPrepare(escena){ //Takes canvas 3d objects as inputs, and outputs the arrays requiered by webgl; vertices, indices, and colors
var zprep=2000;
var nbVertices; var FacesHSA=[]; var cont=0; var zmean=[]; var temp=[]; var vertices=[]; var cont2=0; var indices=[]; var sumer=0; var controlador=0;
var colors=[]; var cont3=0; var prueba=0; //These variables are irrelevant
object_for: for(var i=0; i<escena.length; i++){ //this is irrelevant
face_for: for(var a=0; a<escena[i].arrayObjetos.length; a++){ //Just looping over all the objects
check_loop: for(var ff=0; ff<escena[i].arrayObjetos[a].faces.length; ff++){ //for each face of the object
if(escena[i].arrayObjetos[a].faces[ff].vertices.length==3){ //If the face has 3 vertices, then
indices[cont2]=sumer; cont2=cont2+1; sumer=sumer+1; //We setup the indices array, which will store the indices to form the triangles, needed by webgl
indices[cont2]=sumer; cont2=cont2+1; sumer=sumer+1;
indices[cont2]=sumer; cont2=cont2+1; sumer=sumer+1;
}
else if(escena[i].arrayObjetos[a].faces[ff].vertices.length==4){ //The same, but if the face has 4 vertices. I do not have faces longer than that
indices[cont2]=sumer; cont2=cont2+1; sumer=sumer+1;
indices[cont2]=sumer; cont2=cont2+1; sumer=sumer+1;
indices[cont2]=sumer; cont2=cont2+1;
indices[cont2]=indices[cont2-3]; cont2=cont2+1;
indices[cont2]=indices[cont2-2]; cont2=cont2+1; sumer=sumer+1;
indices[cont2]=sumer; sumer=sumer+1; cont2=cont2+1;
}
for (var j = 0; j < (nbVertices = escena[i].arrayObjetos[a].faces[ff].vertices.length) ; j++) { // For each vertex of the face.
vertices[cont] = escena[i].arrayObjetos[a].vertices[j].x/ gl.canvas.width * 2 - 1; //The x coordinate is transformed to clip coordinates
cont=cont+1;
vertices[cont] = escena[i].arrayObjetos[a].faces[ff].vertices[j].y/ gl.canvas.height * -2 + 1; //Same with the y coordinate
cont=cont+1;
vertices[cont] = escena[i].arrayObjetos[a].faces[ff].vertices[j].z; //Same with the Z. Zprep is an arbitrary Zmax value, used to
//Used to carry out the transformation
if(vertices[cont]>=0){ if(vertices[cont]>zprep){alert("error en Z, es mayor");} vertices[cont]=vertices[cont]/zprep; }
else if(vertices[cont]<=0){ if(vertices[cont]>zprep){alert("error en Z, es menor");} vertices[cont]= -(vertices[cont]/zprep); }
//Supuestamente el z- es el mas cercano y el + el mas
cont=cont+1; //The colours are also prepared
//cont=cont+3;
colors[cont3]=0;
colors[cont3+1]=0;
colors[cont3+2]=0;
cont3=cont3+3;
}
}
}}
webgl2(vertices, indices, colors); //Once everything is ready, we call the WebGL renderer
}
The webgl2 function (which does the rendering)
function webgl2(vertices, indices, colors){
// Create and store data into vertex buffer
var vertex_buffer = gl.createBuffer ();
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
// Create and store data into color buffer
var color_buffer = gl.createBuffer ();
gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
// Create and store data into index buffer
var index_buffer = gl.createBuffer ();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
/*=================== SHADERS =================== */
var vertCode = 'attribute vec3 position;'+
'uniform mat4 Pmatrix;'+
'uniform mat4 Vmatrix;'+
'uniform mat4 Mmatrix;'+
'attribute vec3 color;'+//the color of the point
'varying vec3 vColor;'+
'void main(void) { '+//pre-built function
'gl_Position = Pmatrix*Vmatrix*Mmatrix*vec4(position, 1.);'+
'vColor = color;'+
'}';
var fragCode = 'precision mediump float;'+
'varying vec3 vColor;'+
'void main(void) {'+
'gl_FragColor = vec4(vColor, 1.);'+
'}';
var vertShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertShader, vertCode);
gl.compileShader(vertShader);
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragShader, fragCode);
gl.compileShader(fragShader);
var shaderprogram = gl.createProgram();
gl.attachShader(shaderprogram, vertShader);
gl.attachShader(shaderprogram, fragShader);
gl.linkProgram(shaderprogram);
/*======== Associating attributes to vertex shader =====*/
var _Pmatrix = gl.getUniformLocation(shaderprogram, "Pmatrix");
var _Vmatrix = gl.getUniformLocation(shaderprogram, "Vmatrix");
var _Mmatrix = gl.getUniformLocation(shaderprogram, "Mmatrix");
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
var _position = gl.getAttribLocation(shaderprogram, "position");
gl.vertexAttribPointer(_position, 3, gl.FLOAT, false,0,0);
gl.enableVertexAttribArray(_position);
gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer);
var _color = gl.getAttribLocation(shaderprogram, "color");
gl.vertexAttribPointer(_color, 3, gl.FLOAT, false,0,0) ;
gl.enableVertexAttribArray(_color);
gl.useProgram(shaderprogram);
var proj_matrix = get_projection(40, canvas.width/canvas.height, 1, 100); //The parameters inserted here are not used.
// Right now, get_projection returns an identity matrix
var mo_matrix = [ 1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 ];
var view_matrix = [ 1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 ];
gl.enable(gl.DEPTH_TEST);
// gl.depthFunc(gl.LEQUAL);
gl.clearColor(0.5, 0.5, 0.5, 0.9);
// gl.clearDepth(1.0);
gl.viewport(0.0, 0.0, canvas.width, canvas.height);
// gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.uniformMatrix4fv(_Pmatrix, false, proj_matrix);
gl.uniformMatrix4fv(_Vmatrix, false, view_matrix);
gl.uniformMatrix4fv(_Mmatrix, false, mo_matrix);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer);
// gl.drawElements(gl.LINE_LOOP, indices.length, gl.UNSIGNED_SHORT, 0);
gl.drawElements(gl.TRIANGLES, indices.length , gl.UNSIGNED_SHORT, 0);
// gl.drawArrays(gl.TRIANGLES, 0, indices.length);
// gl.drawArrays(gl.LINE_LOOP, 0, vertices.length/3);
// gl.drawArrays(gl.LINE_LOOP, 0, 56);
}
The get_projection function:
function get_projection(angle, a, zMin, zMax) {
var ang = Math.tan((angle*.5)*Math.PI/180);//angle*.5
/* return [
0.5/ang, 0 , 0, 0,
0, 0.5*a/ang, 0, 0,
0, 0, -(zMax+zMin)/(zMax-zMin), -1,
0, 0, (-2*zMax*zMin)/(zMax-zMin), 0
]; */
return [
1, 0 , 0, 0,
0, 1 , 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
];
}
It might probably be due to several errors instead of just 1, I just can't find any of them.

WebGL Application not working properly

I've just broken the ice on WebGL, and I'm trying to make an extremely basic program. All I want is a canvas with half of it colored, diagonally. So far, I got this code to try and draw the triangle:
var triangle_vertex=[
-1,-1,
1,-1,
1,1,
];
var TRIANGLE_VERTEX= GL.createBuffer ();
GL.bindBuffer(GL.ARRAY_BUFFER, TRIANGLE_VERTEX);
GL.bufferData(GL.ARRAY_BUFFER, new Float32Array(triangle_vertex), GL.STATIC_DRAW);
var triangle_faces = [0,1,2];
var TRIANGLE_FACES = GL.createBuffer ();
GL.bindBuffer(GL.ELEMENT_ARRAY_BUFFER, TRIANGLE_FACES);
GL.bufferData(GL.ELEMENT_ARRAY_BUFFER, new Uint16Array(triangle_faces), GL.STATIC_DRAW);
GL.clearColor(0.0, 0.0, 0.0, 0.0);
function animate()
{
GL.viewport(0.0, 0.0, canvas.width, canvas.height);
GL.clear(GL.COLOR_BUFFER_BIT);
GL.bindBuffer(GL.ARRAY_BUFFER, TRIANGLE_VERTEX);
GL.vertexAttribPointer(_position, 2, GL.FLOAT, false,4*2,0);
GL.bindBuffer(GL.ELEMENT_ARRAY_BUFFER, TRIANGLE_FACES);
GL.drawElements(GL.TRIANGLES, 3, GL.UNSIGNED_SHORT, 0);
GL.flush();
window.requestAnimationFrame(animate);
}
animate();
It's not drawing it though. It's just drawing a red canvas like I told it to in the HTML file. I am using c9.io to run the preview of the game, is that the problem? If not, where would my error be? I can provide plenty more code if necessary. Thank you.

Unable to render to framebuffer (texture)

I'm trying to implement shadows using shadow maps, so I need to render a scene to a separate framebuffer (texture). I cannot get it to work properly, so after stripping down my codebase I'm left with a relatively simple set of instructions which should render a scene to a texture, and then simply render the texture.
The program consists of two programs:
Ground program
Teapot program
The first should render a rectangle, with a certain texture. The second one should render a teapot (with colors based on its position). Eech render step does the following (well, that's the idea anyway):
Switch to framebuffer
Render teapot
Switch to normal buffer
Render teapot
Render ground
Now, the ground fragment shader looks like:
gl_FragColor = texture2D(shadowMap, fTexCoord);
'shadowMap' is the texture I render to in step 2. I expect to see a floating teapot with a rectangle drawn under it. That indeed works. Now, I also expect to have the 'ground' to contain a teapot. After all, we rendered the scene we are looking at without the ground to the framebuffer/texture.
Code
var UNSIGNED_SHORT_SIZE = 2;
// Variables filled by setup()
var glCanvas;
var gl, teapotProgram, groundProgram;
var vBuffer, iBuffer, fBuffer;
var vertices, indices, textures;
var teapot = null;
var model;
var view;
var light;
var projection;
var BASE_URL = "https://hmbastiaan.nl/martijn/webgl/W08P02_SO/";
var WIDTH = 150, HEIGHT = 150;
function makeTeapot(){
var drawingInfo = teapot.getDrawingInfoObjects();
var indices = drawingInfo.indices;
for(var i=0; i < indices.length; i++){
indices[i] += 4; // Add offset for 'ground'
}
return {
indices: drawingInfo.indices,
vertices: drawingInfo.vertices
}
}
function makeRectangle(x1, x2, y1, y2, z1, z2){
var x1 = -2,
x2 = 2,
y1 = -1,
y2 = -1,
z1 = -1,
z2 = -5;
var vertices = [
vec4(x1, y2, z1, 1),
vec4(x2, y1, z1, 1),
vec4(x2, y1, z2, 1),
vec4(x1, y2, z2, 1)
];
var textures = [
vec2(-1.0, -1.0),
vec2( 1.0, -1.0),
vec2( 1.0, 1.0),
vec2(-1.0, 1.0)
];
var indices = [
0, 1, 2,
0, 2, 3
];
return {
indices: indices,
vertices: vertices,
textures: textures
}
}
function resetBuffers(){
vertices = [];
indices = [];
textures = [];
// Add rectangle
var rectangle = makeRectangle();
Array.prototype.push.apply(vertices, rectangle.vertices);
Array.prototype.push.apply(indices, rectangle.indices);
Array.prototype.push.apply(textures, rectangle.textures);
// Add teapot
var teapot = makeTeapot();
Array.prototype.push.apply(vertices, teapot.vertices);
Array.prototype.push.apply(indices, teapot.indices);
console.log(vertices);
console.log(indices);
console.log(textures);
// Send to GPU
gl.bindBuffer(gl.ARRAY_BUFFER, vBuffer);
gl.bufferData(gl.ARRAY_BUFFER, flatten(vertices), gl.STATIC_DRAW);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, iBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
}
function setup(){
$.get(BASE_URL + "teapot.obj", function(teapot_obj_data){
teapot = new OBJDoc(BASE_URL + "teapot.obj");
if(!teapot.parse(teapot_obj_data, 1)){
alert("Parsing teapot.obj failed.");
return;
}
setup2();
}).fail(function(){
alert("Getting teapot.obj failed.");
});
}
function setup2(){
glCanvas = document.getElementById("gl-canvas");
gl = WebGLUtils.setupWebGL(glCanvas, {stencil: true, alpha: false});
gl.viewport(0, 0, WIDTH, HEIGHT);
teapotProgram = initShaders(gl, BASE_URL + "vshader-teapot.glsl", BASE_URL + "fshader-teapot.glsl");
groundProgram = initShaders(gl, BASE_URL + "vshader-ground.glsl", BASE_URL + "fshader-ground.glsl");
light = vec3(0.0, 2.0, -2.0);
view = lookAt(vec3(0, 0, 3), vec3(0,0,0), vec3(0,1,0));
projection = perspective(45, 1.0, 1, 100.0);
// Get teapot uniforms
gl.useProgram(teapotProgram);
teapotProgram.modelLoc = gl.getUniformLocation(teapotProgram, "Model");
teapotProgram.viewLoc = gl.getUniformLocation(teapotProgram, "View");
teapotProgram.projectionLoc = gl.getUniformLocation(teapotProgram, "Projection");
// Upload uniforms
gl.uniformMatrix4fv(teapotProgram.projectionLoc, false, flatten(projection));
gl.uniformMatrix4fv(teapotProgram.viewLoc, false, flatten(view));
gl.uniformMatrix4fv(teapotProgram.modelLoc, false, flatten(scalem(0.25, 0.25, 0.25)));
// Get teapot attributes
teapotProgram.vPosition = gl.getAttribLocation(teapotProgram, "vPosition");
// Get ground uniforms
gl.useProgram(groundProgram);
groundProgram.modelLoc = gl.getUniformLocation(groundProgram, "Model");
groundProgram.viewLoc = gl.getUniformLocation(groundProgram, "View");
groundProgram.projectionLoc = gl.getUniformLocation(groundProgram, "Projection");
groundProgram.shadowMap = gl.getUniformLocation(groundProgram, "shadowMap");
// Get ground attributes
groundProgram.vTexCoord = gl.getAttribLocation(groundProgram, "vTexCoord");
groundProgram.vPosition = gl.getAttribLocation(groundProgram, "vPosition");
// Allocate and fill vertices buffer
vBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vBuffer);
gl.vertexAttribPointer(teapotProgram.vPosition, 4, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(teapotProgram.vPosition);
gl.vertexAttribPointer(groundProgram.vPosition, 4, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(groundProgram.vPosition);
// Allocate indices buffer
iBuffer = gl.createBuffer();
// Setup FBO
fBuffer = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fBuffer);
fBuffer.renderbuffer = gl.createRenderbuffer();
gl.bindRenderbuffer(gl.RENDERBUFFER, fBuffer.renderbuffer);
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, 512, 512);
fBuffer.texture = gl.createTexture();
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, fBuffer.texture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 512, 512, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
gl.generateMipmap(gl.TEXTURE_2D);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST_MIPMAP_LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, fBuffer.texture, 0);
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, fBuffer.renderbuffer);
// Sanity checking: framebuffer seems to throw now errors
if (!gl.isFramebuffer(fBuffer)) {
throw("Invalid framebuffer");
}
var status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
switch (status) {
case gl.FRAMEBUFFER_COMPLETE:
break;
case gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
throw("Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_ATTACHMENT");
break;
case gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
throw("Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT");
break;
case gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
throw("Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_DIMENSIONS");
break;
case gl.FRAMEBUFFER_UNSUPPORTED:
throw("Incomplete framebuffer: FRAMEBUFFER_UNSUPPORTED");
break;
default:
throw("Incomplete framebuffer: " + status);
}
// Set ground textures
gl.uniform1i(groundProgram.shadowMap, 0);
// Upload uniforms
gl.uniformMatrix4fv(groundProgram.projectionLoc, false, flatten(projection));
gl.uniformMatrix4fv(groundProgram.viewLoc, false, flatten(view));
gl.uniformMatrix4fv(groundProgram.modelLoc, false, flatten(mat4()));
// Restore default buffers
gl.bindTexture(gl.TEXTURE_2D, null);
gl.bindRenderbuffer(gl.RENDERBUFFER, null);
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
// Set background colour
gl.clearColor(0.3921, 0.5843, 0.9294, 1.0);
gl.enable(gl.DEPTH_TEST);
gl.enable(gl.CULL_FACE);
resetBuffers();
window.requestAnimationFrame(render);
}
function render(){
var teapot = makeTeapot();
gl.useProgram(teapotProgram);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
// Switch to framebuffer
gl.bindFramebuffer(gl.FRAMEBUFFER, fBuffer);
// Draw teapot
teapot = makeTeapot();
gl.drawElements(gl.TRIANGLES, teapot.indices.length, gl.UNSIGNED_SHORT, 6 * UNSIGNED_SHORT_SIZE);
// Set framebuffer to defualt buffer (in-browser output)
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
// Draw ground
gl.useProgram(groundProgram);
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
// Render teapot
gl.useProgram(teapotProgram);
gl.drawElements(gl.TRIANGLES, teapot.indices.length, gl.UNSIGNED_SHORT, 6 * UNSIGNED_SHORT_SIZE);
}
setup();
<div>
<br/>
<canvas width="150" height="150" id="gl-canvas">Sorry :|</canvas>
</div>
<script type='text/javascript' src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<script type='text/javascript' src="https://hmbastiaan.nl/martijn/webgl/angel/webgl-utils.js"></script>
<script type='text/javascript' src="https://hmbastiaan.nl/martijn/webgl/angel/initShaders2.js"></script>
<script type='text/javascript' src="https://hmbastiaan.nl/martijn/webgl/angel/MV.js"></script>
<script type='text/javascript' src="https://hmbastiaan.nl/martijn/webgl/angel/objParser.js"></script>
Functions of interest:
setup2(): sets up all the buffers and uniforms.
render(): renders the scene.
Disclaimer: this is for an assignment, although this code is simplified enough to not look like the original assignment at all :).
At a glance there are several issues.
Texture bindings are global. Since in setup2 you unbind the 1 texture that means it's never used.
You need to bind whatever textures are needed before each draw call. In other words when you draw the ground you need to bind the teapot texture as in
gl.bindTexture(gl.TEXTURE_2D, fBuffer.texture);
Note: This is an over simplification of what's really needed. You really need to
Choose a texture unit to bind the texture to
var unit = 5;
gl.activeTexture(gl.TEXTURE0 + unit);
Bind the texture to that unit.
gl.bindTexture(gl.TEXTURE_2D, fBuffer.texture);
Set the uniform sampler to that texture unit
gl.uniform1i(groundProgram.shadowMap, unit);
The reason you don't need those extra steps is because (a) you only
have 1 texture so you're using texture unit #0, the default and (b) because
uniforms default to 0 so shadowMap is looking at texture unit #0.
Because you've made a mipmapped texture just rendering to level 0 will not update the mips.
In other words after you render the teapot you'll have a teapot in mip level 0 but mip levels 1, 2, 3, 4, 5 etc will still have nothing in them. You need to call
gl.generateMipmap(gl.TEXTURE_2D)
For that texture after you've rendered the teapot to it. Either that or stop using mips
You need to set the viewport every time you call gl.bindFramebuffer.
gl.bindFramebuffer should almost always be followed by a call to gl.viewport to make the viewport match the size of the thing you're rendering to
gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
// set to size of fb
gl.viewport(0, 0, widthOfFb, heightOfFb);
renderSomething();
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
// set to size of canvas's drawingBuffer
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
Attributes settings are global
You setup the teapot attributes. Then you draw a teapot to the texture. You then draw ground, but you're still using the teapot attributes.
Just like textures you need to setup attributes before each draw call.
I'm also guessing you really should not be calling makeTeapot in your render function but instead it should be called in setup.
You might find this article useful
You should also consider not putting properties on WebGL objects as it's arguably an anti-pattern.
Also synchronous XHR requests are not cool. You're getting this message in the JavaScript console
Synchronous XMLHttpRequest on the main thread is deprecated because
of its detrimental effects to the end user's experience. For more
help, check http://xhr.spec.whatwg.org/.

Webgl throws different error in browsers

Im am learning webgl I made an application to read PLY files and render them in with webgl. The application works fine in Chrome, but when I run it in safari or in Firefox it doesn't work. I tested it in 2 more computers and it just worked in one. Each the browsers throw different errors. This is the error in safari:
[Warning] WebGL: INVALID_OPERATION: drawElements: attempt to access out of bounds arrays
In Firefox I get the following error:
Error: WebGL: drawElements: no VBO bound to enabled vertex attrib index 2!
The same code in Chrome works perfectly. Using the debugger in the different browsers I could not find a difference in the buffers and the arrays used for drawing.
Here is the code:
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.textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord");
gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute);
shaderProgram.normalCoordAttribute = gl.getAttribLocation(shaderProgram, "aVertexNormal");
gl.enableVertexAttribArray(shaderProgram.normalCoordAttribute);
shaderProgram.pMatrixUniform = gl.getUniformLocation(shaderProgram, "uPMatrix");
shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix");
shaderProgram.nMatrixUniform = gl.getUniformLocation(shaderProgram, "uNMatrix");
shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler");
shaderProgram.ambientColorUniform = gl.getUniformLocation(shaderProgram, "uAmbientColor");
shaderProgram.lightingDirectionUniform = gl.getUniformLocation(shaderProgram, "uLightingDirection");
shaderProgram.directionalColorUniform = gl.getUniformLocation(shaderProgram, "uDirectionalColor");
}
function initPLYObjectBuffers (ply_obj) {
ply_obj.vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, ply_obj.vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(ply_obj.vertexArray), gl.STATIC_DRAW);
if(ply_obj.hasNormal){
ply_obj.normalBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, ply_obj.normalBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(ply_obj.normalArray), gl.STATIC_DRAW);
}
if(ply_obj.hasTexture){
ply_obj.textureBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, ply_obj.textureBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(ply_obj.textureArray), gl.STATIC_DRAW);
}
// if(ply_obj.hasColor){
// ply_obj.colorBuffer = gl.createBuffer();
// gl.bindBuffer(gl.ARRAY_BUFFER, ply_obj.colorBuffer);
// gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
// }
ply_obj.indexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ply_obj.indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(ply_obj.indexArray), gl.STATIC_DRAW);
}
function drawPLYObject(obj){
gl.bindBuffer(gl.ARRAY_BUFFER, obj.vertexBuffer);
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, obj.vertexItemSize, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, obj.normalBuffer);
gl.vertexAttribPointer(shaderProgram.vertexNormalAttribute, obj.normalItemSize, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, obj.textureBuffer);
gl.vertexAttribPointer(shaderProgram.textureCoordAttribute, obj.textureItemSize, gl.FLOAT, false, 0, 0);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, myTexture);
gl.uniform1i(shaderProgram.samplerUniform, 0);
gl.uniform3f(
shaderProgram.ambientColorUniform,
parseFloat(document.getElementById("ambientR").value),
parseFloat(document.getElementById("ambientG").value),
parseFloat(document.getElementById("ambientB").value)
);
var lightingDirection = [
parseFloat(document.getElementById("lightDirectionX").value),
parseFloat(document.getElementById("lightDirectionY").value),
parseFloat(document.getElementById("lightDirectionZ").value)
];
var adjustedLD = vec3.create();
vec3.normalize(lightingDirection, adjustedLD);
vec3.scale(adjustedLD, -1);
gl.uniform3fv(shaderProgram.lightingDirectionUniform, adjustedLD);
gl.uniform3f(
shaderProgram.directionalColorUniform,
parseFloat(document.getElementById("directionalR").value),
parseFloat(document.getElementById("directionalG").value),
parseFloat(document.getElementById("directionalB").value)
);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, obj.indexBuffer);
setMatrixUniforms();
gl.drawElements(gl.TRIANGLES, obj.getIndexCount(), gl.UNSIGNED_SHORT, 0);
}
Most of the code is from a tutorial. The only addition is the ply_obj, which contains the arrays for the vertex, normals, and texture of the obj in the file. I also save there the reference for the different buffers to use later in the drawPLYObject function. The code that generates the ply_obj is from this page http://threejs.org/examples/webgl_loader_ply.html. I just changed it to work with plain webgl without three.js.
The error always appears in this line:
gl.drawElements(gl.TRIANGLES, obj.getIndexCount(), gl.UNSIGNED_SHORT, 0);
I checked the arrays and they are correct and are the same in all browsers. I don't know what else could be the problem. Thank you in advance. If you need more information i would gladly provide it.
Ok it turned out to be really dumb. I was referencing a variable with another name. Somehow chrome managed to run the program with this error.

Categories

Resources