Don't wanna be here? Send us removal request.
Text
Exercise 2: Interactive 3D Element
So this time we had to make a 3D element move to the pointer’s location. This was, however, not easy at all. I actually couldn’t make it work as expected at all. I worked with the Triforce I made for the last assignment, only taking one of the three golden pizzas and modifying it to accept a “mousedown” action”:
canvas.addEventListener("mousedown", function(event){ x=2*event.clientX/canvas.width-1; y=2*(canvas.height-event.clientY)/canvas.height-1; const buffers = initBuffers(gl, x, y);
function render(now) { now *= 0.001; // convert to seconds const deltaTime = now - then; then = now;
drawScene(gl, programInfo, buffers, deltaTime);
requestAnimationFrame(render); }
This event listener listens for a mouse event, then pinpoints the mouse location, and passes it to the four functions that draw the element: initBuffers, render, drawScene and requestAnimationFrame. These three work almost the same way as before, only changing it up a bit to include these mouse locations in initBuffers:
const positions = [ //1 // Front face x-1.0, y-1.0, 0.2, // 0 x+1.0, y-1.0, 0.2, // 1 x+0.0, y+0.8, 0.2, // 2
// Back face x-1.0, y-1.0, -0.2, // 3 x+0.0, y+0.8, -0.2, // 4 x+1.0, y-1.0, -0.2, // 5 ];
This work took about four or five hours of trying to modify this example to no avail:
https://www.dropbox.com/s/l1bjj7kbw12f7yl/click.html?dl=0
And then figuring it would be easier to add the “on click” funcionalities to the already finished 3D object. This step took three hours.
The result can be found here!
https://codepen.io/rgarcia11/pen/BYdYgy
0 notes
Text
Exercise 1
Here it is! The triforce!*
*figuring out if I can post it directly in here.
var cubeRotation = 0.0; main(); // // Start here // function main() { const canvas = document.querySelector('#glcanvas'); const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl'); // If we don't have a GL context, give up now if (!gl) { alert('Unable to initialize WebGL. Your browser or machine may not support it.'); return; } // Vertex shader program const vsSource = ` attribute vec4 aVertexPosition; attribute vec4 aVertexColor; uniform mat4 uModelViewMatrix; uniform mat4 uProjectionMatrix; varying lowp vec4 vColor; void main(void) { gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition; vColor = aVertexColor; } `; // Fragment shader program const fsSource = ` varying lowp vec4 vColor; void main(void) { gl_FragColor = vColor; } `; // Initialize a shader program; this is where all the lighting // for the vertices and so forth is established. const shaderProgram = initShaderProgram(gl, vsSource, fsSource); // Collect all the info needed to use the shader program. // Look up which attributes our shader program is using // for aVertexPosition, aVevrtexColor and also // look up uniform locations. const programInfo = { program: shaderProgram, attribLocations: { vertexPosition: gl.getAttribLocation(shaderProgram, 'aVertexPosition'), vertexColor: gl.getAttribLocation(shaderProgram, 'aVertexColor'), }, uniformLocations: { projectionMatrix: gl.getUniformLocation(shaderProgram, 'uProjectionMatrix'), modelViewMatrix: gl.getUniformLocation(shaderProgram, 'uModelViewMatrix'), }, }; // Here's where we call the routine that builds all the // objects we'll be drawing. const buffers = initBuffers(gl); var then = 0; // Draw the scene repeatedly function render(now) { now *= 0.001; // convert to seconds const deltaTime = now - then; then = now; drawScene(gl, programInfo, buffers, deltaTime); requestAnimationFrame(render); } requestAnimationFrame(render); } // // initBuffers // // Initialize the buffers we'll need. For this demo, we just // have one object -- a simple three-dimensional cube. // function initBuffers(gl) { // Create a buffer for the cube's vertex positions. const positionBuffer = gl.createBuffer(); // Select the positionBuffer as the one to apply buffer // operations to from here out. gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); // Now create an array of positions for the cube. const positions = [ //1 // Front face -1.0, -1.0, 0.2, // 0 1.0, -1.0, 0.2, // 1 0.0, 0.8, 0.2, // 2 // Back face -1.0, -1.0, -0.2, // 3 0.0, 0.8, -0.2, // 4 1.0, -1.0, -0.2, // 5 //2 // Front face -2.0, -2.8, 0.2, // 6 0.0, -2.8, 0.2, // 7 //-1.0, -1.0, 0.2, // 0 // Back face -2.0, -2.8, -0.2, // 8 //-1.0, -1.0, -0.2, // 3 0.0, -2.8, -0.2, // 9 //3 // Front face //0.0, -2.8, 0.2, // 7 2.0, -2.8, 0.2, //10 //1.0, -1.0, 0.2, // 1 // Back face // 0.0, -2.8, -0.2, //10 //1.0, -1.0, -0.2, // 5 2.0, -2.8, -0.2, //11 ]; // Now pass the list of positions into WebGL to build the // shape. We do this by creating a Float32Array from the // JavaScript array, then use it to fill the current buffer. gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW); // Now set up the colors for the faces. We'll use solid colors // for each face. const faceColors = [ [1.0, 0.8, 0.0, 1.0], // All faces: gold ]; // Convert the array of colors into a table for all the vertices. var colors = []; colors = colors.concat(faceColors[0], faceColors[0], faceColors[0]); colors = colors.concat(faceColors[0], faceColors[0], faceColors[0]); colors = colors.concat(faceColors[0], faceColors[0], faceColors[0], faceColors[0]); colors = colors.concat(faceColors[0], faceColors[0], faceColors[0], faceColors[0]); colors = colors.concat(faceColors[0], faceColors[0], faceColors[0], faceColors[0]); const colorBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW); // Build the element array buffer; this specifies the indices // into the vertex arrays for each face's vertices. const indexBuffer = gl.createBuffer(); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer); // This array defines each face as two triangles, using the // indices into the vertex array to specify each triangle's // position. const indices = [ //1 0, 1, 2, // front 3, 4, 5, // back 0, 3, 1, 1, 3, 5, // bottom 1, 4, 2, 1, 5, 4, // right 2, 4, 3, 0, 2, 3, // left //2 6, 7, 0, // front 8, 3, 9, // back 6, 8, 7, 7, 8, 9, // bottom 7, 3, 0, 7, 9, 3, // right 0, 3, 9, 6, 0, 8, // left //2 7, 10, 1, // front 9, 5, 11, // back 7, 9, 10, 10, 9, 11, // bottom 10, 5, 1, 10, 11, 5, // right 1, 5, 9, 7, 1, 9, // left ]; // Now send the element array to GL gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW); return { position: positionBuffer, color: colorBuffer, indices: indexBuffer, }; } // // Draw the scene. // function drawScene(gl, programInfo, buffers, deltaTime) { gl.clearColor(0.0, 0.0, 0.0, 1.0); // Clear to black, fully opaque gl.clearDepth(1.0); // Clear everything gl.enable(gl.DEPTH_TEST); // Enable depth testing gl.depthFunc(gl.LEQUAL); // Near things obscure far things // Clear the canvas before we start drawing on it. gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); // Create a perspective matrix, a special matrix that is // used to simulate the distortion of perspective in a camera. // Our field of view is 45 degrees, with a width/height // ratio that matches the display size of the canvas // and we only want to see objects between 0.1 units // and 100 units away from the camera. const fieldOfView = 45 * Math.PI / 180; // in radians const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight; const zNear = 0.1; const zFar = 100.0; const projectionMatrix = mat4.create(); // note: glmatrix.js always has the first argument // as the destination to receive the result. mat4.perspective(projectionMatrix, fieldOfView, aspect, zNear, zFar); // Set the drawing position to the "identity" point, which is // the center of the scene. const modelViewMatrix = mat4.create(); // Now move the drawing position a bit to where we want to // start drawing the square. mat4.translate(modelViewMatrix, // destination matrix modelViewMatrix, // matrix to translate [-0.0, 1.0, -9.0]); // amount to translate //mat4.rotate(modelViewMatrix, // destination matrix // modelViewMatrix, // matrix to rotate // cubeRotation, // amount to rotate in radians // [0, 0, 1]); // axis to rotate around (Z) mat4.rotate(modelViewMatrix, // destination matrix modelViewMatrix, // matrix to rotate cubeRotation * .5,// amount to rotate in radians [0, 1, 0]); // axis to rotate around (X) // Tell WebGL how to pull out the positions from the position // buffer into the vertexPosition attribute { const numComponents = 3; const type = gl.FLOAT; const normalize = false; const stride = 0; const offset = 0; gl.bindBuffer(gl.ARRAY_BUFFER, buffers.position); gl.vertexAttribPointer( programInfo.attribLocations.vertexPosition, numComponents, type, normalize, stride, offset); gl.enableVertexAttribArray( programInfo.attribLocations.vertexPosition); } // Tell WebGL how to pull out the colors from the color buffer // into the vertexColor attribute. { const numComponents = 4; const type = gl.FLOAT; const normalize = false; const stride = 0; const offset = 0; gl.bindBuffer(gl.ARRAY_BUFFER, buffers.color); gl.vertexAttribPointer( programInfo.attribLocations.vertexColor, numComponents, type, normalize, stride, offset); gl.enableVertexAttribArray( programInfo.attribLocations.vertexColor); } // Tell WebGL which indices to use to index the vertices gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffers.indices); // Tell WebGL to use our program when drawing gl.useProgram(programInfo.program); // Set the shader uniforms gl.uniformMatrix4fv( programInfo.uniformLocations.projectionMatrix, false, projectionMatrix); gl.uniformMatrix4fv( programInfo.uniformLocations.modelViewMatrix, false, modelViewMatrix); { const vertexCount = 72; const type = gl.UNSIGNED_SHORT; const offset = 0; gl.drawElements(gl.TRIANGLES, vertexCount, type, offset); } // Update the rotation for the next draw cubeRotation += deltaTime; } // // Initialize a shader program, so WebGL knows how to draw our data // function initShaderProgram(gl, vsSource, fsSource) { const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource); const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource); // Create the shader program const shaderProgram = gl.createProgram(); gl.attachShader(shaderProgram, vertexShader); gl.attachShader(shaderProgram, fragmentShader); gl.linkProgram(shaderProgram); // If creating the shader program failed, alert if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) { alert('Unable to initialize the shader program: ' + gl.getProgramInfoLog(shaderProgram)); return null; } return shaderProgram; } // // creates a shader of the given type, uploads the source and // compiles it. // function loadShader(gl, type, source) { const shader = gl.createShader(type); // Send the source to the shader object gl.shaderSource(shader, source); // Compile the shader program gl.compileShader(shader); // See if it compiled successfully if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { alert('An error occurred compiling the shaders: ' + gl.getShaderInfoLog(shader)); gl.deleteShader(shader); return null; } return shader; }
https://codepen.io/rgarcia11/pen/mXrJPm
I made it work in the following steps:
Checked Pablo Figueroa’s example/template here.
Set up a matrix with the vertices necessary to form a pizza.
Changed the pizza into three pizzas.
Figured out there were redundant vertices and fixed them.
Changed the way to form the triforce from Triangle primitives to Triangle Stripes.
Next step would be to use a single array buffer.
An important part I was missing in order to make it work was to change the number of vertices here:
{ const vertexCount = 72; const type = gl.UNSIGNED_SHORT; const offset = 0; gl.drawElements(gl.TRIANGLES, vertexCount, type, offset); }
Another step I took along the way was to change the rotation axis and speed, as well as camera position:
mat4.translate(modelViewMatrix, // modelViewMatrix, // [-0.0, 1.0, -9.0]); // camera mat4.rotate(modelViewMatrix, // modelViewMatrix, // cubeRotation * .5, // rotating speed [0, 1, 0]); // axis to rotate around
0 notes
Text
Week 2
There was no assignment due this week, but we were told to look for a cool WebGL example to show in class and to modify an example of a rotating cube and turn it into another rotating shape.
I shall attempt to change the cube’s shape to a Triforce:
An early idea is to have three gold triangular shapes. I’ll update with the result!
As for the example... I haven’t quite gotten to that.
0 notes
Text
Animation example
After seeing how to rotate a cube in class in only 400 lines of code in WebGL. I decided I’d check how other languages can do similar examples. Namely:
1. Processing
2. Unity
I found very pretty (and extremely complex) examples in Unity, but I haven’t yet checked how to run them on my machine, so I’ll rather show you a Processing example I found in https://processing.org/examples/ —pretty straightforward.
In order to run an example in Processing you need to download processing, open Processing, copy&paste the example and hit the “run” arrow, it’s quite simple.
Most examples are actually a lot shorter than a simple WebGL exercise, with this one being less than 100 lines of code. In WebGL we had to do a lot of “manual” work, like buffering data into the GPU and actually even writing in GLSL.
So, the differences:
GPU memory management
Explicitly coding for the GPU
Doesn’t need explicit colors
And the similarities:
Matrix definitions for each point that will be drawn on screen
The use of auxiliary matrixes that won’t be drawn, but will help set up the drawn matrix
In order to draw in WebGL, it was necessary to edit the vertices matrix “manually”. In Processing, some functions already do that for you, like “lerp”:
// Get the vertex we will draw PVector v2 = morph.get(i); // Lerp to the target v2.lerp(v1, 0.1);
Lerp means linear interpolation between two points, and what it means in the code is that it calculates this interpolation and displaces the vertex to the new point. In this case, it’s interpolating vertices v1 and v2, and moving v2 to v1′s position with a “speed” (or pace) of 0.1 (the higher this number, the quicker the “lerping” will be, and thus the animation will move quicker also)
// Draw relative to center translate(width/2, height/2); strokeWeight(4); // Draw a polygon that makes up all the vertices beginShape(); noFill(); stroke(255); for (PVector v : morph) { vertex(v.x, v.y); } endShape(CLOSE);
This part of the code actually draws the shape. It turns the vertices into an actual shape (a polygon). Another difference in the codes is that this Processing example is not trying to actively look for triangles, it just makes a simple polygon out of the vertices.
You can check out the Processing sketch here!
https://www.openprocessing.org/sketch/502225
0 notes