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.
Related
I'm trying to draw a quad in three.js, but three.js keeps complaining that 'tex' is not a 'WebGLTexture' and refuse to run, what's going on here? thank you.
// z= depth, tex is texture
function drawQuad(z, tex)
{
var verts = [
-1.0, 1.0, z, 0.0, 1.0,
-1.0, -1.0, z, 0.0, 0.0,
1.0, 1.0, z, 1.0, 1.0,
1.0, -1.0, z, 1.0, 0.0,
];
const gl = renderer.getContext();
gl.disable(gl.DEPTH_TEST);
gl.useProgram(quadShader);
var vb = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vb);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(verts), gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, vb);
gl.enableVertexAttribArray(0);
gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 20, 0);
gl.enableVertexAttribArray(1);
gl.vertexAttribPointer(1, 2, gl.FLOAT, false, 20, 12);
gl.uniform1i(gl.getUniformLocation(quadShader, 'su_tex'), 0)
gl.activeTexture(gl.TEXTURE0 + 0);
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4)
gl.enable(gl.DEPTH_TEST);
}
tex is loaded like this
wallTex = loader.load("https://r105.threejsfundamentals.org/threejs/resources/images/wall.jpg");
drawQuad(1.0, wallTex);
Ok, i've figured it out.
Anyway, this may help those who are still confused (c++ opengl pragrammers):
WebGlTexture is the id you created with glGenTextures(1, &texturId), it is for rendering.
THREE.js.Texture is a texture container, it contains texture descriptions and image data downloaded from web or whatever, it has a hidden property __webglTexture which is null if this THREE.js.Texture never been used for rendering. then what if it has been used for rendering? it will create a WebGLTexture (via glGenTextures(1, &textureId) internally i guess) and assign this WebGlTexture id to its __webglTexture, and now you can use it for rendering.
It might be more appropriate to call THREE.js.Texture as THREE.js.TextrureRes IMO, less mis-leading.
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."
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.
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.
In creating a webgl "hello world" for demonstration to a high school class, I am experiencing an anomalous result.
Using gl-matrix.js version 2.2.0, reversing the order of two transforms does not produce a difference in output.
This code produces the desired result:
function DrawScene(gl) {
var time_now = new Date();
var elapsed_time = new Date();
elapsed_time.setDate(time_program_started - time_now);
var projection_matrix = mat4.create();
var modelview_matrix = mat4.create();
var mvp = mat4.create();
gl.viewport(0, 0, gl.size[0], gl.size[1]);
gl.clearColor(0.2, 0.2, 0.2, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
mat4.perspective(projection_matrix, D2R(50.0), gl.size[0] / gl.size[1], 1.0, 10.0);
mat4.translate(modelview_matrix, modelview_matrix, [0.0, 0.0, -3.5]);
mat4.rotate(modelview_matrix, modelview_matrix, D2R(elapsed_time / 1000.0 * 60.0), [0.0, 1.0, 0.0]);
mat4.multiply(mvp, projection_matrix, modelview_matrix);
triangle.Render(gl, shader_index, [1.0, 1.0, 1.0, 1.0], mvp);
}
namely a triangle that spins in place about its Y axis.
Reversing the order of the translate and rotate should spin the triangle around the camera (part of my intended lesson), but instead continues to spin the triangle in place. I sanity checked this in an equivalent legacy OpenGL "hello world" producing exactly the expected results.
The vertex shader simply multiples the vertex position attribute with the mvp uniform. Is there a problem in gl-matrix.js or in this code?
For completeness, here is the render function.
Triangle.prototype.Render = function (gl, shader_index, color, mvp) {
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertex_buffer_object);
gl.vertexAttribPointer(shaders[shader_index].VP, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(shaders[shader_index].VP);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.element_buffer_object);
shaders[shader_index].Use(gl);
gl.uniformMatrix4fv(shaders[shader_index].MVP, false, mvp);
if (shader_index == 0)
gl.uniform4fv(shaders[shader_index].COLOR, color);
else {
gl.bindBuffer(gl.ARRAY_BUFFER, this.color_buffer_object);
gl.vertexAttribPointer(shaders[shader_index].COLOR, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(shaders[shader_index].COLOR);
}
gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_SHORT, 0);
shaders[shader_index].StopUsing(gl);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
}
Thank you.
I believe there is an error in my use of gl-matrix or gl-matrix itself. Replacing gl-matrix with mjs.js works as expacted.
function DrawScene(gl) {
var time_now = new Date();
var elapsed_time = new Date();
elapsed_time.setDate(time_program_started - time_now);
var projection_matrix = M4x4.I;
var modelview_matrix = M4x4.I;
var mvp = M4x4.I;
gl.viewport(0, 0, gl.size[0], gl.size[1]);
gl.clearColor(0.2, 0.2, 0.2, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
projection_matrix = M4x4.makePerspective(50.0, gl.size[0] / gl.size[1], 1.0, 10.0);
modelview_matrix = M4x4.rotate(D2R(elapsed_time / 1000.0 * 60.0), [0.0, 1.0, 0.0], modelview_matrix);
modelview_matrix = M4x4.translate([0.0, 0.0, -5.5], modelview_matrix);
mvp = M4x4.mul(projection_matrix, modelview_matrix);
triangle.Render(gl, shader_index, [1.0, 1.0, 1.0, 1.0], mvp);
}
Does indeed rotate about the camera. Reversing to translate then rotate spins about the Y axis of the triangle.
I would be very pleased to have my code for gl-matrix corrected. If it cannot, gl-matrix is very broken.