Related
I'm trying to write examples in webgl where the implementation of fbo does not render successfully if the original size is changed.
The original size of OFFSCREEN_WIDTH and OFFSCREEN_HEIGHT is 256 pixels,When I change the value nothing is rendered on the screen, I'd like to know why this is?
after I changed the size, I tried to render only the textures in the fbo on the screen and it was able to display.
Effect
and code:
// FramebufferObject.js (c) matsuda and kanda
// Vertex shader program
var VSHADER_SOURCE =
'attribute vec4 a_Position;\n' +
'attribute vec2 a_TexCoord;\n' +
'uniform mat4 u_MvpMatrix;\n' +
'varying vec2 v_TexCoord;\n' +
'void main() {\n' +
' gl_Position = u_MvpMatrix * a_Position;\n' +
' v_TexCoord = a_TexCoord;\n' +
'}\n';
// Fragment shader program
var FSHADER_SOURCE =
'#ifdef GL_ES\n' +
'precision mediump float;\n' +
'#endif\n' +
'uniform sampler2D u_Sampler;\n' +
'varying vec2 v_TexCoord;\n' +
'void main() {\n' +
' gl_FragColor = texture2D(u_Sampler, v_TexCoord);\n' +
'}\n';
// Size of off screen
var OFFSCREEN_WIDTH = 256;
var OFFSCREEN_HEIGHT = 256;
function main() {
// Retrieve <canvas> element
var canvas = document.getElementById('webgl');
// Get the rendering context for WebGL
var gl = getWebGLContext(canvas);
if (!gl) {
console.log('Failed to get the rendering context for WebGL');
return;
}
// Initialize shaders
if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
console.log('Failed to intialize shaders.');
return;
}
// Get the storage location of attribute variables and uniform variables
var program = gl.program; // Get program object
program.a_Position = gl.getAttribLocation(program, 'a_Position');
program.a_TexCoord = gl.getAttribLocation(program, 'a_TexCoord');
program.u_MvpMatrix = gl.getUniformLocation(program, 'u_MvpMatrix');
if (program.a_Position < 0 || program.a_TexCoord < 0 || !program.u_MvpMatrix) {
console.log('Failed to get the storage location of a_Position, a_TexCoord, u_MvpMatrix');
return;
}
// Set the vertex information
var cube = initVertexBuffersForCube(gl);
var plane = initVertexBuffersForPlane(gl);
if (!cube || !plane) {
console.log('Failed to set the vertex information');
return;
}
// Set texture
var texture = initTextures(gl);
if (!texture) {
console.log('Failed to intialize the texture.');
return;
}
// Initialize framebuffer object (FBO)
var fbo = initFramebufferObject(gl);
if (!fbo) {
console.log('Failed to intialize the framebuffer object (FBO)');
return;
}
// Enable depth test
gl.enable(gl.DEPTH_TEST); // gl.enable(gl.CULL_FACE);
var viewProjMatrix = new Matrix4(); // Prepare view projection matrix for color buffer
viewProjMatrix.setPerspective(30, canvas.width/canvas.height, 1.0, 100.0);
viewProjMatrix.lookAt(0.0, 0.0, 7.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
var viewProjMatrixFBO = new Matrix4(); // Prepare view projection matrix for FBO
viewProjMatrixFBO.setPerspective(30.0, OFFSCREEN_WIDTH/OFFSCREEN_HEIGHT, 1.0, 100.0);
viewProjMatrixFBO.lookAt(0.0, 2.0, 7.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
// Start drawing
var currentAngle = 0.0; // Current rotation angle (degrees)
var tick = function() {
currentAngle = animate(currentAngle); // Update current rotation angle
draw(gl, canvas, fbo, plane, cube, currentAngle, texture, viewProjMatrix, viewProjMatrixFBO);
window.requestAnimationFrame(tick, canvas);
};
tick();
}
function initVertexBuffersForCube(gl) {
// Create a cube
// v6----- v5
// /| /|
// v1------v0|
// | | | |
// | |v7---|-|v4
// |/ |/
// v2------v3
// Vertex coordinates
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, // v0-v1-v2-v3 front
1.0, 1.0, 1.0, 1.0,-1.0, 1.0, 1.0,-1.0,-1.0, 1.0, 1.0,-1.0, // v0-v3-v4-v5 right
1.0, 1.0, 1.0, 1.0, 1.0,-1.0, -1.0, 1.0,-1.0, -1.0, 1.0, 1.0, // v0-v5-v6-v1 up
-1.0, 1.0, 1.0, -1.0, 1.0,-1.0, -1.0,-1.0,-1.0, -1.0,-1.0, 1.0, // v1-v6-v7-v2 left
-1.0,-1.0,-1.0, 1.0,-1.0,-1.0, 1.0,-1.0, 1.0, -1.0,-1.0, 1.0, // v7-v4-v3-v2 down
1.0,-1.0,-1.0, -1.0,-1.0,-1.0, -1.0, 1.0,-1.0, 1.0, 1.0,-1.0 // v4-v7-v6-v5 back
]);
// Texture coordinates
var texCoords = new Float32Array([
1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, // v0-v1-v2-v3 front
0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, // v0-v3-v4-v5 right
1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, // v0-v5-v6-v1 up
1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, // v1-v6-v7-v2 left
0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, // v7-v4-v3-v2 down
0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0 // v4-v7-v6-v5 back
]);
// Indices of the vertices
var indices = new Uint8Array([
0, 1, 2, 0, 2, 3, // front
4, 5, 6, 4, 6, 7, // right
8, 9,10, 8,10,11, // up
12,13,14, 12,14,15, // left
16,17,18, 16,18,19, // down
20,21,22, 20,22,23 // back
])
var o = new Object(); // Create the "Object" object to return multiple objects.
// Write vertex information to buffer object
o.vertexBuffer = initArrayBufferForLaterUse(gl, vertices, 3, gl.FLOAT);
o.texCoordBuffer = initArrayBufferForLaterUse(gl, texCoords, 2, gl.FLOAT);
o.indexBuffer = initElementArrayBufferForLaterUse(gl, indices, gl.UNSIGNED_BYTE);
if (!o.vertexBuffer || !o.texCoordBuffer || !o.indexBuffer) return null;
o.numIndices = indices.length;
// Unbind the buffer object
gl.bindBuffer(gl.ARRAY_BUFFER, null);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
return o;
}
function initVertexBuffersForPlane(gl) {
// Create face
// v1------v0
// | |
// | |
// | |
// v2------v3
// Vertex coordinates
var vertices = new Float32Array([
1.0, 1.0, 0.0, -1.0, 1.0, 0.0, -1.0,-1.0, 0.0, 1.0,-1.0, 0.0 // v0-v1-v2-v3
]);
// Texture coordinates
var texCoords = new Float32Array([1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0]);
// Indices of the vertices
var indices = new Uint8Array([0, 1, 2, 0, 2, 3]);
var o = new Object(); // Create the "Object" object to return multiple objects.
// Write vertex information to buffer object
o.vertexBuffer = initArrayBufferForLaterUse(gl, vertices, 3, gl.FLOAT);
o.texCoordBuffer = initArrayBufferForLaterUse(gl, texCoords, 2, gl.FLOAT);
o.indexBuffer = initElementArrayBufferForLaterUse(gl, indices, gl.UNSIGNED_BYTE);
if (!o.vertexBuffer || !o.texCoordBuffer || !o.indexBuffer) return null;
o.numIndices = indices.length;
// Unbind the buffer object
gl.bindBuffer(gl.ARRAY_BUFFER, null);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
return o;
}
function initArrayBufferForLaterUse(gl, data, num, type) {
// Create a buffer object
var buffer = gl.createBuffer();
if (!buffer) {
console.log('Failed to create the buffer object');
return null;
}
// Write date into the buffer object
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
// Store the necessary information to assign the object to the attribute variable later
buffer.num = num;
buffer.type = type;
return buffer;
}
function initElementArrayBufferForLaterUse(gl, data, type) {
// Create a buffer object
var buffer = gl.createBuffer();
if (!buffer) {
console.log('Failed to create the buffer object');
return null;
}
// Write date into the buffer object
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, data, gl.STATIC_DRAW);
buffer.type = type;
return buffer;
}
function initTextures(gl) {
var texture = gl.createTexture(); // Create a texture object
if (!texture) {
console.log('Failed to create the Texture object');
return null;
}
// Get storage location of u_Sampler
var u_Sampler = gl.getUniformLocation(gl.program, 'u_Sampler');
if (!u_Sampler) {
console.log('Failed to get the storage location of u_Sampler');
return null;
}
var image = new Image(); // Create image object
if (!image) {
console.log('Failed to create the Image object');
return null;
}
// Register the event handler to be called when image loading is completed
image.onload = function() {
// Write image data to texture object
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1); // Flip the image Y coordinate
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
// Pass the texure unit 0 to u_Sampler
gl.uniform1i(u_Sampler, 0);
gl.bindTexture(gl.TEXTURE_2D, null); // Unbind the texture object
};
// Tell the browser to load an Image
image.src = '../resources/sky_cloud.jpg';
return texture;
}
function initFramebufferObject(gl) {
var framebuffer, texture, depthBuffer;
// Define the error handling function
var error = function() {
if (framebuffer) gl.deleteFramebuffer(framebuffer);
if (texture) gl.deleteTexture(texture);
if (depthBuffer) gl.deleteRenderbuffer(depthBuffer);
return null;
}
// Create a frame buffer object (FBO)
framebuffer = gl.createFramebuffer();
if (!framebuffer) {
console.log('Failed to create frame buffer object');
return error();
}
// Create a texture object and set its size and parameters
texture = gl.createTexture(); // Create a texture object
if (!texture) {
console.log('Failed to create texture object');
return error();
}
gl.bindTexture(gl.TEXTURE_2D, texture); // Bind the object to target
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, OFFSCREEN_WIDTH, OFFSCREEN_HEIGHT, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
framebuffer.texture = texture; // Store the texture object
// Create a renderbuffer object and Set its size and parameters
depthBuffer = gl.createRenderbuffer(); // Create a renderbuffer object
if (!depthBuffer) {
console.log('Failed to create renderbuffer object');
return error();
}
gl.bindRenderbuffer(gl.RENDERBUFFER, depthBuffer); // Bind the object to target
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, OFFSCREEN_WIDTH, OFFSCREEN_HEIGHT);
// Attach the texture and the renderbuffer object to the FBO
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, depthBuffer);
// Check if FBO is configured correctly
var e = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
if (gl.FRAMEBUFFER_COMPLETE !== e) {
console.log('Frame buffer object is incomplete: ' + e.toString());
return error();
}
// Unbind the buffer object
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.bindTexture(gl.TEXTURE_2D, null);
gl.bindRenderbuffer(gl.RENDERBUFFER, null);
return framebuffer;
}
function draw(gl, canvas, fbo, plane, cube, angle, texture, viewProjMatrix, viewProjMatrixFBO) {
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); // Change the drawing destination to FBO
gl.viewport(0, 0, OFFSCREEN_WIDTH, OFFSCREEN_HEIGHT); // Set a viewport for FBO
gl.clearColor(0.2, 0.2, 0.4, 1.0); // Set clear color (the color is slightly changed)
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); // Clear FBO
drawTexturedCube(gl, gl.program, cube, angle, texture, viewProjMatrixFBO); // Draw the cube
gl.bindFramebuffer(gl.FRAMEBUFFER, null); // Change the drawing destination to color buffer
gl.viewport(0, 0, canvas.width, canvas.height); // Set the size of viewport back to that of <canvas>
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); // Clear the color buffer
drawTexturedPlane(gl, gl.program, plane, angle, fbo.texture, viewProjMatrix); // Draw the plane
}
// Coordinate transformation matrix
var g_modelMatrix = new Matrix4();
var g_mvpMatrix = new Matrix4();
function drawTexturedCube(gl, program, o, angle, texture, viewProjMatrix) {
// Calculate a model matrix
g_modelMatrix.setRotate(20.0, 1.0, 0.0, 0.0);
g_modelMatrix.rotate(angle, 0.0, 1.0, 0.0);
// Calculate the model view project matrix and pass it to u_MvpMatrix
g_mvpMatrix.set(viewProjMatrix);
g_mvpMatrix.multiply(g_modelMatrix);
gl.uniformMatrix4fv(program.u_MvpMatrix, false, g_mvpMatrix.elements);
drawTexturedObject(gl, program, o, texture);
}
function drawTexturedPlane(gl, program, o, angle, texture, viewProjMatrix) {
// Calculate a model matrix
g_modelMatrix.setTranslate(0, 0, 1);
g_modelMatrix.rotate(20.0, 1.0, 0.0, 0.0);
g_modelMatrix.rotate(angle, 0.0, 1.0, 0.0);
// Calculate the model view project matrix and pass it to u_MvpMatrix
g_mvpMatrix.set(viewProjMatrix);
g_mvpMatrix.multiply(g_modelMatrix);
gl.uniformMatrix4fv(program.u_MvpMatrix, false, g_mvpMatrix.elements);
drawTexturedObject(gl, program, o, texture);
}
function drawTexturedObject(gl, program, o, texture) {
// Assign the buffer objects and enable the assignment
initAttributeVariable(gl, program.a_Position, o.vertexBuffer); // Vertex coordinates
initAttributeVariable(gl, program.a_TexCoord, o.texCoordBuffer); // Texture coordinates
// Bind the texture object to the target
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texture);
// Draw
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, o.indexBuffer);
gl.drawElements(gl.TRIANGLES, o.numIndices, o.indexBuffer.type, 0);
}
// Assign the buffer objects and enable the assignment
function initAttributeVariable(gl, a_attribute, buffer) {
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.vertexAttribPointer(a_attribute, buffer.num, buffer.type, false, 0, 0);
gl.enableVertexAttribArray(a_attribute);
}
function drawTexturedCube2(gl, o, angle, texture, viewpProjMatrix, u_MvpMatrix) {
// Calculate a model matrix
g_modelMatrix.rotate(20.0, 1.0, 0.0, 0.0);
g_modelMatrix.rotate(angle, 0.0, 1.0, 0.0);
g_modelMatrix.scale(1, 1, 1);
// Calculate the model view project matrix and pass it to u_MvpMatrix
g_mvpMatrix.set(vpMatrix);
g_mvpMatrix.multiply(g_modelMatrix);
gl.uniformMatrix4fv(u_MvpMatrix, false, g_mvpMatrix.elements);
drawTexturedObject(gl, o, texture);
}
var ANGLE_STEP = 30; // The increments of rotation angle (degrees)
var last = Date.now(); // Last time that this function was called
function animate(angle) {
var now = Date.now(); // Calculate the elapsed time
var elapsed = now - last;
last = now;
// Update the current rotation angle (adjusted by the elapsed time)
var newAngle = angle + (ANGLE_STEP * elapsed) / 1000.0;
return newAngle % 360;
}
I am trying to create a 2d mesh plane in Three JS, and update the position of each vertex by accessing the position attribute like so:
function planeGeometry()
{
var mat = new THREE.MeshBasicMaterial({color: "red", wireframe: true, transparent: true, opacity: 1});
const geometry = new THREE.PlaneBufferGeometry( 2, 3, 0.01, 0.1 );
const plane = new THREE.Mesh( geometry, mat );
scene.add( plane );
}
const geometry = new THREE.BufferGeometry();
const 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.setAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) );
const material = new THREE.MeshBasicMaterial( { color: 0xff0000 } );
const mesh = new THREE.Mesh( geometry, material );
scene.add(mesh);
function animate()
{
requestAnimationFrame(animate);
mesh.geometry.attributes.position[0] += 0.01;
mesh.geometry.attributes.position.needsUpdate = true;
renderer.render(scene, camera);
}
animate();
But I get no change in position. What am I doing wrong?
"use strict";
var canvas;
var gl;
var axis = 0;
var xAxis = 0;
var yAxis =1;
var zAxis = 2;
var theta = [0, 0, 0];
var thetaLoc;
var flag = true;
var numElements = 36;
var vertices = [
vec3(-0.5, -0.5, 0.5),
vec3(-0.5, 0.5, 0.5),
vec3(0.5, 0.5, 0.5),
vec3(0.5, -0.5, 0.5),
vec3(-0.5, -0.5, -0.5),
vec3(-0.5, 0.5, -0.5),
vec3(0.5, 0.5, -0.5),
vec3(0.5, -0.5, -0.5)
];
var vertexColors = [
vec4(0.0, 0.0, 0.0, 1.0), // black
vec4(1.0, 0.0, 0.0, 1.0), // red
vec4(1.0, 1.0, 0.0, 1.0), // yellow
vec4(0.0, 1.0, 0.0, 1.0), // green
vec4(0.0, 0.0, 1.0, 1.0), // blue
vec4(1.0, 0.0, 1.0, 1.0), // magenta
vec4(1.0, 1.0, 1.0, 1.0), // white
vec4(0.0, 1.0, 1.0, 1.0) // cyan
];
// indices of the 12 triangles that compose the cube
var indices = [
1, 0, 3,
3, 2, 1,
2, 3, 7,
7, 6, 2,
3, 0, 4,
4, 7, 3,
6, 5, 1,
1, 2, 6,
4, 5, 6,
6, 7, 4,
5, 4, 0,
0, 1, 5
];
window.onload = function init()
{
// --------------- Cube --------------------------
canvas = document.getElementById("gl-canvas");
gl = canvas.getContext('webgl2');
if (!gl) alert("WebGL 2.0 isn't available");
gl.viewport(0, 0, canvas.width - 50, canvas.height - 50);
gl.clearColor(1.0, 1.0, 1.0, 1.0);
gl.enable(gl.DEPTH_TEST);
// Load shaders and initialize attribute buffers
// Create a buffer object, initialise it, and associate it
// with the associated attribute variable in our vertex shader
var programCube = initShaders(gl, "vertex-shader", "fragment-shader");
gl.useProgram(programCube);
// array element buffer
var iBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, iBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint8Array(indices), gl.STATIC_DRAW);
// color array atrribute buffer
var cBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, cBuffer);
gl.bufferData(gl.ARRAY_BUFFER, flatten(vertexColors), gl.STATIC_DRAW);
var colorLoc = gl.getAttribLocation(programCube, "aColor");
gl.vertexAttribPointer(colorLoc, 4, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(colorLoc);
// vertex array attribute buffer
var vBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vBuffer);
gl.bufferData(gl.ARRAY_BUFFER, flatten(vertices), gl.STATIC_DRAW);
var positionLoc = gl.getAttribLocation( programCube, "aPosition");
gl.vertexAttribPointer(positionLoc, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(positionLoc );
thetaLoc = gl.getUniformLocation(programCube, "uTheta");
render();
//event listeners for buttons
document.getElementById( "xButton" ).onclick = function () {
axis = xAxis;
};
document.getElementById( "yButton" ).onclick = function () {
axis = yAxis;
};
document.getElementById( "zButton" ).onclick = function () {
axis = zAxis;
};
document.getElementById("ButtonT").onclick = function(){flag = !flag;};
}
function render()
{
gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
if(flag) theta[axis] += 2.0;
gl.uniform3fv(thetaLoc, theta);
gl.drawElements(gl.TRIANGLES, numElements, gl.UNSIGNED_BYTE, 0);
requestAnimationFrame(render);
}
still, need to add below
Need to set up the surface normals for the objects being shown on the scene.
Properly setting up different material properties for the objects being shown on the scene.
Properly showing two different light sources at fixed locations that areused to illustrate properly the objects on the scene, and can be turned on and off independently.
Properly setting up the lights above with an ambient light sourcecomponent that is used to illustrate properly the objects on the scene and can be turned from totally dark to intense brightness using a dialor a slider (from 0-total darkness to 100-total brightness, with a default somewhere in between.
How can a triangle, made with three.js, be rotated around one of its edges? When I try to rotate it, it does around its center as it seems.
The triangle is made by:
var triangleMesh;
var triangleGeometry = new THREE.Geometry();
triangleGeometry.vertices.push( new THREE.Vector3( 0.0, 1.0, 0.0 ) );
triangleGeometry.vertices.push( new THREE.Vector3( -1.0, -1.0, 0.0 ) );
triangleGeometry.vertices.push( new THREE.Vector3( 1.0, -1.0, 0.0 ) );
triangleGeometry.faces.push( new THREE.Face3( 0, 1, 2 ) );
triangleGeometry.faces[0].vertexColors[0] = new THREE.Color(0xFF0000);
triangleGeometry.faces[0].vertexColors[1] = new THREE.Color(0x00FF00);
triangleGeometry.faces[0].vertexColors[2] = new THREE.Color(0x0000FF);
var triangleMaterial = new THREE.MeshBasicMaterial({ vertexColors:THREE.VertexColors, side:THREE.DoubleSide });
triangleMesh = new THREE.Mesh( triangleGeometry, triangleMaterial );
triangleMesh.position.set(-1.5, 0.0, 4.0 );
triangleMesh.position.z -= 5;
triangleMesh.rotation.z += angle * Math.PI / 180; // angle is from outer for loop
parent.add( triangleMesh );
I would need to rotate it around one edge to build prisms/hexagons.
To rotate a triangle around one of its corners, that corner must be in the center of coordinates. For this purpose you can use .translate ( x, y, z ) method of THREE.Geometry().
Take a look at the code snippet.
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(0, 0, 5);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var ngon = 11;
var radius = 2;
var angle = Math.PI / ngon;
var triHeight = Math.cos(angle) * radius;
var triWidth = Math.sin(angle) * radius;
var triangleMesh;
var triangleGeometry = new THREE.Geometry();
triangleGeometry.vertices.push(new THREE.Vector3(0.0, triHeight, 0.0));
triangleGeometry.vertices.push(new THREE.Vector3(-triWidth, 0, 0.0));
triangleGeometry.vertices.push(new THREE.Vector3(triWidth, 0, 0.0));
triangleGeometry.faces.push(new THREE.Face3(0, 1, 2));
triangleGeometry.faces[0].vertexColors[0] = new THREE.Color(0xFF0000);
triangleGeometry.faces[0].vertexColors[1] = new THREE.Color(0x00FF00);
triangleGeometry.faces[0].vertexColors[2] = new THREE.Color(0x0000FF);
triangleGeometry.translate(0, -triHeight, 0); // the upper vertex is at the center now
var triangleMaterial = new THREE.MeshBasicMaterial({
vertexColors: THREE.VertexColors,
side: THREE.DoubleSide
});
triangleMesh = new THREE.Mesh(triangleGeometry, triangleMaterial);
for (var i = 1; i < ngon; i++) {
var newTri = triangleMesh.clone();
newTri.rotation.z = i * angle * 2;
scene.add(newTri);
}
scene.add(triangleMesh);
render();
function render() {
requestAnimationFrame(render);
renderer.render(scene, camera);
}
body {
overflow: hidden;
margin: 0;
}
<script src="https://threejs.org/build/three.min.js"></script>
I'm learning how to use canvas in Webgl but im having some problems with textures. I want to draw a cube, an sphere, the axis and a grid. Everything is perfect if i only add the sphere, axis and grid but when i add the cube to the scene the grid disappears and shows me this error:
WebGL error INVALID_OPERATION in drawElements(TRIANGLES, 357, UNSIGNED_SHORT, 0)
[.WebGLRenderingContext]GL ERROR :GL_INVALID_OPERATION : glDrawElements: attempt to access out of range vertices in attribute 2.
this is my render class:
define([
'text!shaders/vertex-shader.glsl',
'text!shaders/fragment-shader.glsl',
'./Ejes',
'./Mesh',
'glMatrix',
'CuonUtils'], function(vsSource, fsSource,Ejes,Mesh,glMatrix, CuonUtils) {
var canvas = document.getElementById('canvas');
var gl = CuonUtils.getWebGLContext(canvas);
if (!gl) {
console.log('Failed to get the rendering context for WebGL');
return;
}
// Initialize shaders
if (!CuonUtils.initShaders(gl, vsSource, fsSource)) {
console.log('Failed to intialize shaders.');
return;
}
var program = gl.program;
// Cache attribute/uniform location
var aPostion = gl.getAttribLocation(program, 'aPostion');
var aNormal = gl.getAttribLocation(program, 'aNormal');
var aTexCoord = gl.getAttribLocation(program, 'aTexCoord');
var uModelMatrix = gl.getUniformLocation(program, 'uModelMatrix');
var uViewMatrix = gl.getUniformLocation(program, 'uViewMatrix');
var uProjectionMatrix = gl.getUniformLocation(program, 'uProjectionMatrix');
var uNormalMatrix = gl.getUniformLocation(program, 'uNormalMatrix');
var uLightColor = gl.getUniformLocation(program, 'uLightColor');
var uLightPosition = gl.getUniformLocation(program, 'uLightPosition');
var uAmbientLight = gl.getUniformLocation(program, 'uAmbientLight');
var uColor = gl.getUniformLocation(program, 'uColor');
var uSampler = gl.getUniformLocation(program, 'uSampler');
var uUseLighting = gl.getUniformLocation(program, 'uUseLighting');
var uUseTexture = gl.getUniformLocation(program, 'uUseTexture');
function initBuffers(gl, mesh){
if(mesh._webgl){
return;
}
mesh._webgl = {};
// Create Vertex Buffer Object
var VBOData = new Float32Array(
mesh.geometry.vertices);
var VBO = mesh._webgl.vbo = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, VBO);
gl.bufferData(gl.ARRAY_BUFFER, VBOData, gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
// Create Index Buffer Object
var IBOData = new Uint16Array(
mesh.geometry.faces);
var IBO = mesh._webgl.ibo = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, IBO);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, IBOData, gl.STATIC_DRAW);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
mesh._webgl.ibo.dataSize = IBOData.length;
// Create Normal Buffer Object
var NBOData = new Float32Array(
mesh.geometry.normals);
var NBO = mesh._webgl.nbo = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, NBO);
gl.bufferData(gl.ARRAY_BUFFER, NBOData, gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
if(mesh.useTexture){
// Create st Buffer Object
var STBOData = new Float32Array(
mesh.geometry.st);
var STBO = mesh._webgl.stbo = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, STBO);
gl.bufferData(gl.ARRAY_BUFFER, STBOData, gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
var TBO = mesh._webgl.tbo = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, TBO);
gl.texImage2D(
gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE,
new Uint8Array([255, 255, 255, 255])
);
loadTexture(gl, mesh.imgSrc, mesh._webgl.tbo, function() {
bindTextureToSampler(gl, mesh._webgl.tbo);
});
}
}
function render(scene, camera) {
// Specify the color for clearing <canvas>
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.enable(gl.DEPTH_TEST);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
// seteo las luces
gl.uniform3fv(uLightColor, scene.pointLight.getLightColor());
gl.uniform3fv(uLightPosition, scene.pointLight.getLightPosition());
gl.uniform3fv(uAmbientLight, scene.ambientLight.getLightColor());
for( var i = 0; i < scene.meshes.length; i++){
var mesh = scene.meshes[i];
initBuffers(gl, mesh);
gl.uniform1i(uUseLighting, mesh.useLight);
gl.uniform1i(uUseTexture, mesh.useTexture);
gl.enableVertexAttribArray(aPostion);
gl.bindBuffer(gl.ARRAY_BUFFER, mesh._webgl.vbo);
gl.vertexAttribPointer(
aPostion, 3, gl.FLOAT, false, 0, 0
);
gl.enableVertexAttribArray(aNormal);
gl.bindBuffer(gl.ARRAY_BUFFER, mesh._webgl.nbo);
gl.vertexAttribPointer(
aNormal, 3, gl.FLOAT, false, 0, 0
);
// Clean up
gl.bindBuffer(gl.ARRAY_BUFFER, null);
gl.uniformMatrix4fv(uModelMatrix, false, mesh.getModelMatrix());
gl.uniformMatrix4fv(uViewMatrix, false, camera.getViewMatrix());
gl.uniformMatrix4fv(uProjectionMatrix, false, camera.getProjectionMatrix());
gl.uniformMatrix4fv(uNormalMatrix, false, mesh.getNormalMatrix());
gl.uniform4fv(uColor, mesh.material.getColor());
if(mesh.useTexture){
gl.enableVertexAttribArray(aTexCoord);
gl.bindBuffer(gl.ARRAY_BUFFER, mesh._webgl.stbo);
gl.vertexAttribPointer(
aTexCoord, 2, gl.FLOAT, false, 0, 0
);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, mesh._webgl.tbo);
gl.uniform1i(uSampler, 0);
}
draw(gl,mesh);
}
}
function loadTexture(gl, imageSrc, textureBO, callback) {
var image = new Image();
image.src = imageSrc;
image.onload = function () {
gl.bindTexture(gl.TEXTURE_2D, textureBO);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
setupTexture(image.width, image.height);
gl.bindTexture(gl.TEXTURE_2D, null);
callback();
};
}
function bindTextureToSampler(gl, textureBO) {
gl.bindTexture(gl.TEXTURE_2D, textureBO);
gl.uniform1i(uSampler, 0);
}
function setupTexture(width, height) {
if (isPowerOf2(width) && isPowerOf2(height) ){
// the dimensions are power of 2 so generate mips and turn on
// tri-linear filtering.
gl.generateMipmap(gl.TEXTURE_2D);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
} else {
// at least one of the dimensions is not a power of 2 so set the filtering
// so WebGL will render it.
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
}
}
function isPowerOf2(value) {
return (value & (value - 1)) === 0;
}
function draw(gl, mesh) {
// gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, mesh._webgl.ibo);
gl.drawElements(mesh.tipe, mesh._webgl.ibo.dataSize, gl.UNSIGNED_SHORT, 0);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
gl.bindTexture(gl.TEXTURE_2D, null);
}
return {
render: render
};
});
and this is my main class:
define([
'./WebGLRenderer',
'./Scene',
'./Mesh',
'./Geometry',
'./Material',
'./RegularConvexPolygonGeometry',
'./Cubo',
'./Sphere',
'./Cylinder',
'./PerspectiveCamera',
'./OrthographicCamera',
'./Light',
'./PointLight',
'./Ejes',
'dat',
'./cuadrado',
'CuonUtils'
], function(WebGLRenderer, Scene, Mesh, Geometry, Material,
RegularConvexPolygonGeometry, Cubo, Sphere, Cylinder,
PerspectiveCamera, OrthographicCamera, Light, PointLight,
Ejes, dat, Cuadrado, CuonUtils) {
var canvas = document.getElementById('canvas');
var gl = CuonUtils.getWebGLContext(canvas);
if (!gl) {
console.log('Failed to get the rendering context for WebGL');
return;
}
////////////
// ESCENA //
////////////
var clearColor = [0.0,0.0,0.0];
//Ambient Light
var light = Object.create(Light);
light.init();
light.hex = Math.floor( 0xaaaaaa );
//Point Light
var pointLight = Object.create(PointLight);
pointLight.init();
var scene = Object.create(Scene);
scene.init(clearColor, light, pointLight);
//////////
// EJES //
//////////
//GRID
var GrillaGeometry = Object.create(Ejes);
GrillaGeometry.getGrillaGeometry();
var grillaMaterial = Object.create(Material);
grillaMaterial.init();
grillaMaterial.hex = Math.floor( 0x0f0f0f );
var GrillaMesh = Object.create(Mesh);
GrillaMesh.init(GrillaGeometry,grillaMaterial);
GrillaMesh.tipe = gl.LINES;
GrillaMesh.useLight = false;
GrillaMesh.useTexture = false;
//X
var EjeXGeometry = Object.create(Ejes);
EjeXGeometry.getXGeometry();
var EjeXMaterial = Object.create(Material);
EjeXMaterial.init();
EjeXMaterial.hex = Math.floor( 0xff0000 );
var EjeXMesh = Object.create(Mesh);
EjeXMesh.init(EjeXGeometry,EjeXMaterial);
EjeXMesh.tipe = gl.LINES;
EjeXMesh.useLight = false;
EjeXMesh.useTexture = false;
//Y
var EjeYGeometry = Object.create(Ejes);
EjeYGeometry.getYGeometry();
var EjeYMaterial = Object.create(Material);
EjeYMaterial.init();
EjeYMaterial.hex = Math.floor( 0x00ff00 );
var EjeYMesh = Object.create(Mesh);
EjeYMesh.init(EjeYGeometry,EjeYMaterial);
EjeYMesh.tipe = gl.LINES;
EjeYMesh.useLight = false;
EjeYMesh.useTexture = false;
//Z
var EjeZGeometry = Object.create(Ejes);
EjeZGeometry.getZGeometry();
var EjeZMaterial = Object.create(Material);
EjeZMaterial.init();
EjeZMaterial.hex = Math.floor( 0x0000ff );
var EjeZMesh = Object.create(Mesh);
EjeZMesh.init(EjeZGeometry,EjeZMaterial);
EjeZMesh.tipe = gl.LINES;
EjeZMesh.useLight = false;
EjeZMesh.useTexture = false;
scene.addMesh(GrillaMesh);
scene.addMesh(EjeXMesh);
scene.addMesh(EjeYMesh);
scene.addMesh(EjeZMesh);
////////////////
// ESFERA //
////////////////
var sphereGeometry = Object.create(Sphere);
sphereGeometry.init();
var sphereMaterial = Object.create(Material);
sphereMaterial.init();
sphereMaterial.hex = Math.floor( 0xffffff );
var sphereMesh = Object.create(Mesh);
sphereMesh.init(sphereGeometry,sphereMaterial);
sphereMesh.tipe = gl.TRIANGLES;
sphereMesh.tx = 5.0;
sphereMesh.useLight = true;
sphereMesh.useTexture = true;
sphereMesh.imgSrc = 'scripts/texture/earthmap.jpg';
scene.addMesh(sphereMesh);
////////////////
// CUBO //
////////////////
var cubeGeometry = Object.create(Cubo);
cubeGeometry.init();
var cubeMaterial = Object.create(Material);
cubeMaterial.init();
cubeMaterial.hex = Math.floor( 0xffffff );
var cubeMesh = Object.create(Mesh);
cubeMesh.init(cubeGeometry,cubeMaterial);
cubeMesh.tipe = gl.TRIANGLES;
cubeMesh.tz = 5.0;
cubeMesh.useLight = true;
cubeMesh.useTexture = true;
cubeMesh.imgSrc = 'scripts/texture/firefox-icon3.png';
scene.addMesh(cubeMesh);
//////////////////////////////
/// PERSPECTIVE PROJECTION ///
//////////////////////////////
// var camera = Object.create(PerspectiveCamera);
// PerspectiveCamera.init(Math.PI / 4,1,0.1,200);
///////////////////////////////
/// ORTHOGRAPHIC PROJECTION ///
///////////////////////////////
var camera = Object.create(OrthographicCamera);
OrthographicCamera.init(-8,8,-8,8,0.1,1000);
function tick(){
WebGLRenderer.render(scene, camera);
requestAnimationFrame(tick);
}
tick();
});
I'm almost sure that the problem is my render class but just in case i'll post the other classes too.
cube:
define(['glMatrix','./Geometry'], function(glMatrix, Geometry) {
var Cubo = Object.create(Geometry);
Cubo.init = function(){
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, // v0-v1-v2-v3 front
1.0, 1.0, 1.0, 1.0,-1.0, 1.0, 1.0,-1.0,-1.0, 1.0, 1.0,-1.0, // v0-v3-v4-v5 right
1.0, 1.0, 1.0, 1.0, 1.0,-1.0, -1.0, 1.0,-1.0, -1.0, 1.0, 1.0, // v0-v5-v6-v1 up
-1.0, 1.0, 1.0, -1.0, 1.0,-1.0, -1.0,-1.0,-1.0, -1.0,-1.0, 1.0, // v1-v6-v7-v2 left
-1.0,-1.0,-1.0, 1.0,-1.0,-1.0, 1.0,-1.0, 1.0, -1.0,-1.0, 1.0, // v7-v4-v3-v2 down
1.0,-1.0,-1.0, -1.0,-1.0,-1.0, -1.0, 1.0,-1.0, 1.0, 1.0,-1.0 // v4-v7-v6-v5 back
]);
//Creo las caras
var indexVertices = new Uint16Array([
0, 1, 2, 0, 2, 3, // front
4, 5, 6, 4, 6, 7, // right
8, 9,10, 8,10,11, // up
12,13,14, 12,14,15, // left
16,17,18, 16,18,19, // down
20,21,22, 20,22,23 // back
]);
//Normales
var normales = new Float32Array([
0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, // v0-v1-v2-v3 front
1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, // v0-v3-v4-v5 right
0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, // v0-v5-v6-v1 up
-1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, // v1-v6-v7-v2 left
0.0,-1.0, 0.0, 0.0,-1.0, 0.0, 0.0,-1.0, 0.0, 0.0,-1.0, 0.0, // v7-v4-v3-v2 down
0.0, 0.0,-1.0, 0.0, 0.0,-1.0, 0.0, 0.0,-1.0, 0.0, 0.0,-1.0 // v4-v7-v6-v5 back
]);
var st = new Float32Array([
// Front
0.0, 0.0,
1.0, 0.0,
1.0, 1.0,
0.0, 1.0,
// Back
0.0, 0.0,
1.0, 0.0,
1.0, 1.0,
0.0, 1.0,
// Top
0.0, 0.0,
1.0, 0.0,
1.0, 1.0,
0.0, 1.0,
// Bottom
0.0, 0.0,
1.0, 0.0,
1.0, 1.0,
0.0, 1.0,
// Right
0.0, 0.0,
1.0, 0.0,
1.0, 1.0,
0.0, 1.0,
// Left
0.0, 0.0,
1.0, 0.0,
1.0, 1.0,
0.0, 1.0
]);
Geometry.init.call(this, vertices, indexVertices, normales, st);
};
return Cubo;
});
sphere:
define(['./Geometry'], function(Geometry) {
var Sphere = Object.create(Geometry);
Sphere.init = function(){
var SPHERE_DIV = 13;
var i, ai, si, ci;
var j, aj, sj, cj;
var p1, p2;
var vertices = [];
var indexVertices = [];
var st = [];
//Creo los vertices
for (j = 0; j <= SPHERE_DIV; j++) {
aj = j * Math.PI / SPHERE_DIV;
sj = Math.sin(aj);
cj = Math.cos(aj);
for (i = 0; i <= SPHERE_DIV; i++) {
ai = i * 2 * Math.PI / SPHERE_DIV;
si = Math.sin(ai);
ci = Math.cos(ai);
vertices.push(si * sj); // X
vertices.push(cj); // Y
vertices.push(ci * sj); // Z
st.push(1 - (i / SPHERE_DIV) );
st.push(1 - (j / SPHERE_DIV) );
}
}
//Creo los indices
for (j = 0; j < SPHERE_DIV; j++) {
for (i = 0; i < SPHERE_DIV; i++) {
p1 = j * (SPHERE_DIV+1) + i;
p2 = p1 + (SPHERE_DIV+1);
indexVertices.push(p1);
indexVertices.push(p2);
indexVertices.push(p1 + 1);
indexVertices.push(p1 + 1);
indexVertices.push(p2);
indexVertices.push(p2 + 1);
}
}
Geometry.init.call(this, vertices, indexVertices, vertices, st);
};
return Sphere;
});
grid:
define(['./Geometry'], function(Geometry) {
var Ejes = Object.create(Geometry);
Ejes.getXGeometry = function(){
var vertices = [];
var indexVertices = [];
var st = [];
vertices.push(0.0,0.0,0.0);
vertices.push(10.0,0.0,0.0);
indexVertices.push(0,1);
Geometry.init.call(this,vertices,indexVertices, vertices, st);
};
Ejes.getYGeometry = function(){
var vertices = [];
var indexVertices = [];
var st = [];
vertices.push(0.0,0.0,0.0);
vertices.push(0.0,10.0,0.0);
indexVertices.push(0,1);
Geometry.init.call(this,vertices,indexVertices, vertices, st);
};
Ejes.getZGeometry = function(){
var vertices = [];
var indexVertices = [];
var st = [];
vertices.push(0.0,0.0,0.0);
vertices.push(0.0,0.0,10.0);
indexVertices.push(0,1);
Geometry.init.call(this,vertices,indexVertices,vertices, st);
};
Ejes.getGrillaGeometry = function(){
var vertices = [];
var indexVertices = [];
var st = [];
for(var i=-10; i<0; i+=1)
{
// verticales
vertices.push(i,0,-10);
vertices.push(i,0,10);
// horizontales
vertices.push(-10,0,i);
vertices.push(10,0,i);
}
vertices.push(0,0,-10);
vertices.push(0,0,0);
vertices.push(-10,0,0);
vertices.push(0,0,0);
for(i=1; i<=10; i+=1)
{
// verticales
vertices.push(i,0,-10);
vertices.push(i,0,10);
// horizontales
vertices.push(-10,0,i);
vertices.push(10,0,i);
}
for(i=0; i<84;i+=1)
{
indexVertices.push(i);
}
Geometry.init.call(this,vertices,indexVertices,vertices, vertices);
};
return Ejes;
});
I'd really appreciate any help you could give me.