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.
Related
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'm studying WebGl transformations and I understood the it is possible to build transformation matrices in the application (Javascript file) or in the shader programs (html).
For example I can write all the code about a rotation matrix on the x axis directly in the GLSL program :
uniform mat 4 rx;
mat4 rx = mat4( 1.0, 0.0, 0.0, 0.0,
0.0, c.x, s.x, 0.0,
0.0, -s.x, c.x, 0.0,
0.0, 0.0, 0.0, 1.0 );
Or i can write it into the Javascript file and use the :
rx = context.getUniformLocation(program, "rx");
To specify the value of my uniform.
I would like to understand which is the best choice and why.
Thanks for the help.
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.
Which one is the best (fastest) method to create a geometry out of this data-array? I create the Array on-the-fly and can also create a object instead of an array. Everything that I can do to improve this would be perfect.
Data (x,y,z):
var data = [
[-500,0,-500],
[-496,0,-500],
[-492,0,-500],
//..
[488,0,496],
[492,0,496],
[496,0,496]
];
//data.length: 62500
My way:
var geo = new THREE.Geometry();
for(i = 0; i < data.length; i++)
geo.vertices.push(data[i][0],data[i][1],data[i][2]);
And then I loop trough all vertices and create the faces to get a terrain (like the following picture, but not flat)
If you are looking for speed, I suggest using BufferGeometry.
It uses a flat Float23Array to reduce the cost of sending data to the GPU.
e.g.
var geometry = new THREE.BufferGeometry();
// create a simple square shape. We duplicate the top left and bottom right
// vertices because each vertex needs to appear once per triangle.
var vertices = new Float32Array([
-1.0, -1.0, 1.0,
1.0, -1.0, 1.0,
1.0, 1.0, 1.0,
1.0, 1.0, 1.0,
-1.0, 1.0, 1.0,
-1.0, -1.0, 1.0
]);
// itemSize = 3 because there are 3 values (components) per vertex
geometry.addAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) );
var material = new THREE.MeshBasicMaterial( { color: 0xff0000 } );
var mesh = new THREE.Mesh( geometry, material );
Source https://threejs.org/docs/#api/en/core/BufferGeometry
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.