Make it Better™️

This commit is contained in:
John 2022-07-01 03:45:53 -05:00
parent b0c303d029
commit 31c769defa
6 changed files with 290 additions and 339 deletions

39
Pendulum/Homogeneous2D.js Normal file
View File

@ -0,0 +1,39 @@
// Homogeneous2D.js
// John Breaux 2022-07-01
// 2D Homogeneous coordinate library
"use strict"
//
// Classes
//
// Homogeneous2D: Stores a 2d vector or point in homogeneous coords
class Homogeneous2D {
constructor(x = 0, y = 0, w = 0) {
this.x = x;
this.y = y;
this.w = w;
}
// Add with modify
add_m(rhs) {
if (rhs) {
this.x += rhs.x;
this.y += rhs.y;
this.w += rhs.w;
return this;
}
else return null;
}
// copy
copy() {
return new Homogeneous2D(this.x, this.y, this.w);
}
// create vector/point from 2d polar coordinates
from_polar(r = 0, theta = 0, w = 0) {
this.x = r * Math.cos(theta + Math.PI / 2);
this.y = r * Math.sin(theta + Math.PI / 2);
this.w = w;
return this;
}
}

View File

@ -21,6 +21,9 @@
<script src="../lib/webgl-debug.js"></script> <script src="../lib/webgl-debug.js"></script>
<script src="../lib/cuon-utils.js"></script> <script src="../lib/cuon-utils.js"></script>
<script src="../lib/cuon-matrix.js"></script> <script src="../lib/cuon-matrix.js"></script>
<script src="common.js"></script>
<script src="ShapedObject.js"></script>
<script src="Homogeneous2D.js"></script>
<script src="PendulumComponents.js"></script> <script src="PendulumComponents.js"></script>
<script src="Pendulum.js"></script> <script src="Pendulum.js"></script>
</body> </body>

View File

@ -7,94 +7,85 @@
"use strict" "use strict"
const vertex_shader = ` const vertex_shader = `
attribute vec4 a_Position; attribute vec4 a_Position;
uniform mat4 u_ModelMatrix; uniform mat4 u_ModelMatrix;
void main() void main()
{ {
gl_Position = u_ModelMatrix * a_Position; gl_Position = u_ModelMatrix * a_Position;
gl_PointSize = 5.0; gl_PointSize = 5.0;
} `; } `;
const fragment_shader = ` const fragment_shader = `
precision mediump float; precision mediump float;
uniform vec4 u_Color; uniform vec4 u_Color;
void main() void main()
{ {
gl_FragColor = u_Color; gl_FragColor = u_Color;
} `; } `;
// Point size of the anchor
var POINT_SIZE = 5;
// Radius of the bob
var BOB_RADIUS = 0.1;
// length of the wire
var PEN_LENGTH = 0.8;
// Rotation angle (degrees/second)
var A_VELOCITY = 45.0;
var SIDES_DELTA = 0;
function main() { function main() {
// Retrieve <canvas> element // Retrieve <canvas> element
var canvas = document.getElementById('webgl'); var canvas = document.getElementById('webgl');
// Get the rendering context for WebGL // Get the rendering context for WebGL
var gl = getWebGLContext(canvas); var gl = getWebGLContext(canvas);
if (!gl) { if (!gl) {
console.log('Failed to get the rendering context for WebGL'); console.log('Failed to get the rendering context for WebGL');
return; return;
} }
// Initialize shaders // Initialize shaders
if (!initShaders(gl, vertex_shader, fragment_shader)) { if (!initShaders(gl, vertex_shader, fragment_shader)) {
console.log('Failed to intialize shaders.'); console.log('Failed to intialize shaders.');
return; return;
} }
// create a pendulum object // create a pendulum object
var pendulum = new Pendulum({ angle: 0, length: PEN_LENGTH, radius: BOB_RADIUS }); var pendulum = new Pendulum({ angle: 0, length: PEN_LENGTH, radius: BOB_RADIUS });
pendulum.init(gl); pendulum.init(gl);
// Specify the color for clearing <canvas> // Specify the color for clearing <canvas>
gl.clearColor(0, 0, 0, 1); gl.clearColor(0, 0, 0, 1);
// Get storage location of u_ModelMatrix // Get storage location of u_ModelMatrix
var u_ModelMatrix = gl.getUniformLocation(gl.program, 'u_ModelMatrix'); var u_ModelMatrix = gl.getUniformLocation(gl.program, 'u_ModelMatrix');
if (!u_ModelMatrix) { if (!u_ModelMatrix) {
console.log('Failed to get the storage location of u_ModelMatrix'); console.log('Failed to get the storage location of u_ModelMatrix');
return; return;
} }
// Model matrix // Model matrix
var modelMatrix = new Matrix4(); var modelMatrix = new Matrix4();
// Set it to the I matrix // Set it to the I matrix
modelMatrix.setIdentity(); modelMatrix.setIdentity();
// Start drawing // Start drawing
var tick = function () { var tick = function () {
// Tick the pendulum // Tick the pendulum
pendulum.tick(); pendulum.tick();
// Draw the pendulum // Draw the pendulum
draw(gl, pendulum, modelMatrix, u_ModelMatrix); draw(gl, pendulum, modelMatrix, u_ModelMatrix);
// Request that the browser ?calls tick // Request that the browser ?calls tick
requestAnimationFrame(tick, canvas); requestAnimationFrame(tick, canvas);
}; };
tick(); tick();
} }
function draw(gl, pendulum, modelMatrix, u_ModelMatrix) { function draw(gl, pendulum, modelMatrix, u_ModelMatrix) {
// Clear <canvas> // Clear <canvas>
gl.clear(gl.COLOR_BUFFER_BIT); gl.clear(gl.COLOR_BUFFER_BIT);
// Draw the pendulum // Draw the pendulum
pendulum.draw(gl, modelMatrix, u_ModelMatrix); pendulum.draw(gl, modelMatrix, u_ModelMatrix);
} }
function up() { function up() {
A_VELOCITY += 10; A_VELOCITY += 10;
} }
function down() { function down() {
A_VELOCITY -= 10; A_VELOCITY -= 10;
} }

View File

@ -1,294 +1,72 @@
// PendulumComponents.js // PendulumComponents.js
// John Breaux 2022-06-30 // John Breaux 2022-06-30
// Classes, functions, and data structures for Pendulum.js // Classes used by Pendulum.js
"use strict" "use strict"
// Common functions: //
// acquire_buffer: Get a vertex buffer object from gl
function acquire_buffer(gl) {
// Create a buffer object
var vertexBuffer = gl.createBuffer();
if (!vertexBuffer) {
console.log('Failed to create the buffer object');
return -1;
}
return vertexBuffer;
}
function acquire_attribute(gl, name, size, type) {
// Acquire a reference to named attr
var ret = gl.getAttribLocation(gl.program, name);
if (ret < 0) {
console.log(`Failed to get the storage location of ${name}`);
return -1;
}
gl.vertexAttribPointer(ret, size, type, false, 0, 0);
return ret;
}
function acquire_uniform(gl, name) {
// Acquire a reference to named attr
var ret = gl.getUniformLocation(gl.program, name);
if (!ret) {
console.log(`Failed to get the storage location of ${name}`);
return -1;
}
return ret;
}
// Classes // Classes
// homo2: Stores a 2d vector or point in homog. coords //
class Homogeneous2D {
constructor(x = 0, y = 0, w = 0) {
this.x = x;
this.y = y;
this.w = w;
}
// Add with modify
add_m(rhs) {
if (rhs) {
this.x += rhs.x;
this.y += rhs.y;
this.w += rhs.w;
return this;
}
else return null;
}
// scalar multiply with modify
smul_m(scalar) {
if (typeof (rhs) === "number") {
this.x *= rhs;
this.y *= rhs;
this.w *= rhs;
return this;
}
else return null;
}
// copy
copy() {
return new Homogeneous2D(this.x, this.y, this.w);
}
// create vector/point from 2d polar coordinates
from_polar(r = 0, theta = 0, w = 0) {
this.x = r * Math.cos(theta);
this.y = r * Math.sin(theta);
this.w = w;
return this;
}
}
class Rod {
constructor({ anchor = { x: 0, y: 0 }, bob = { x: 0, y: 0 }, color = { r: 1.0, g: 0.0, b: 0.0, a: 1.0 } } = {}) {
// Set the object's vertices
this.vertices = [ new Homogeneous2D(anchor.x, anchor.y, 1),
new Homogeneous2D(bob.x, bob.y, 1)]
// Set object's color
this.color = [color.r, color.g, color.b, color.a];
}
// Convert to Float32Array [x, y]
vertex_array() {
// allocate space for center.xy + vertices.xy
var ret = new Float32Array((this.vertices.length) * 2);
// save the vertices
for (var i = 0; i < this.vertices.length; i++) {
var j = 2 * i;
ret[j] = this.vertices[i].x;
ret[j + 1] = this.vertices[i].y;
}
return ret;
}
// Generate the index_array for the shape
index_array() {
var ret = new Uint8Array(this.vertices.length + 1);
for (var i = 0; i < this.vertices.length; i++) {
ret[i] = i
}
ret[this.vertices.length] = 0;
return ret;
}
// Initialize the object's drawing parameters
init(gl) {
// Make the buffers
this.vertexBuffer = acquire_buffer(gl);
this.indexBuffer = acquire_buffer(gl);
// Bind the buffers // Polygon class: Construct and display a regular polygon in 2D
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); class Polygon extends ShapedObject {
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
// Write date into the buffers
gl.bufferData(gl.ARRAY_BUFFER, this.vertex_array(), gl.STATIC_DRAW);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.index_array(), gl.STATIC_DRAW);
}
// Draw the object
draw(gl, modelMatrix, u_ModelMatrix) {
// Bind the buffers
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
// Set the object's color
var u_Color = acquire_uniform(gl, 'u_Color');
gl.uniform4fv(u_Color, this.color);
// get a_Position
var a_Position = acquire_attribute(gl, 'a_Position', 2, gl.FLOAT);
// Enable the assignment to a_Position variable
gl.enableVertexAttribArray(a_Position);
// Pass the rotation matrix to the vertex shader
gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix.elements);
// Draw the Anchor
gl.drawElements(gl.LINES, 2, gl.UNSIGNED_BYTE, 0);
}
}
class Anchor {
constructor({ center = { x: 0, y: 0 }, color = { r: 0.0, g: 1.0, b: 0.0, a: 1.0 } } = {}) {
this.position = new Homogeneous2D(center.x, center.y, 1);
// Set object color
this.color = [color.r, color.g, color.b, color.a];
}
// Convert to Float32Array [x, y]
vertex_array() {
// allocate space for center.xy + vertices.xy
var ret = new Float32Array(2);
// save the vertices
ret[0] = this.position.x, ret[1] = this.position.y;
console.log(ret);
return ret;
}
// Generate the index_array for the shape
index_array() {
var ret = new Uint8Array(1);
ret[0] = 0;
console.log(ret);
return ret;
}
// Initialize the object's drawing parameters
init(gl) {
// Make the buffers
this.vertexBuffer = acquire_buffer(gl);
this.indexBuffer = acquire_buffer(gl);
// Bind the buffers
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
// Write date into the buffers
gl.bufferData(gl.ARRAY_BUFFER, this.vertex_array(), gl.STATIC_DRAW);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.index_array(), gl.STATIC_DRAW);
}
// Draw the object
draw(gl, modelMatrix, u_ModelMatrix) {
// Bind the buffers
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
// Set the object's color
var u_Color = acquire_uniform(gl, 'u_Color');
gl.uniform4fv(u_Color, this.color);
// get a_Position
var a_Position = acquire_attribute(gl, 'a_Position', 2, gl.FLOAT);
// Enable the assignment to a_Position variable
gl.enableVertexAttribArray(a_Position);
// Pass the rotation matrix to the vertex shader
gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix.elements);
// Draw the Anchor
gl.drawElements(gl.POINTS, 1, gl.UNSIGNED_BYTE, 0);
}
}
// Polygon class: Holds vertices and a center point. Only constructs regular polygons
class Polygon {
// constructor: Make a new regular polygon // constructor: Make a new regular polygon
constructor({ sides = 6, radius = 1, rotation = 0, center = { x: 0, y: 0 }, color = { r: 0, g: 0, b: 1, a: 1 } } = {}) { constructor({ sides = 6, radius = 1, center = { x: 0, y: 0 }, color = { r: 0, g: 0, b: 1, a: 1 } } = {}) {
this.length = 0; super({ color: color });
// Mark center point
this.center = new Homogeneous2D(center.x, center.y, 1);
// Create vertices // Create vertices
this.vertices = []; this.vertices = [];
for (var i = 0; i <= sides; i++) { for (var i = 0; i <= sides; i++) {
this.vertices[i] = new Homogeneous2D().from_polar(radius, rotation + (i * 2 * Math.PI / sides)).add_m(this.center); // Create vertices by adding center-point in Homogeneous coordinates to an offset vector generated from polar coordinates.
this.length++; this.vertices[i] = new Homogeneous2D().from_polar(radius, 2 * Math.PI * i / sides)
.add_m(new Homogeneous2D(center.x, center.y, 1));
} }
// Set object color
this.color = [color.r, color.g, color.b, color.a];
} }
// Convert to Float32Array [center, v0, v1, ...] // Wrap the init function to set the draw_primitive type to TRIANGLE_FAN
vertex_array() {
// allocate space for center.xy + vertices.xy
var ret = new Float32Array((this.vertices.length) * 2);
// save the vertices
for (var i = 0; i < this.vertices.length; i++) {
var j = 2 * i;
ret[j] = this.vertices[i].x;
ret[j + 1] = this.vertices[i].y;
}
return ret;
}
// Generate the index_array for the shape
index_array() {
var ret = new Uint8Array(this.vertices.length + 1);
for (var i = 0; i < this.vertices.length; i++) {
ret[i] = i
}
ret[this.vertices.length] = 0;
return ret;
}
// Initialize the object's drawing parameters
init(gl) { init(gl) {
// Make the buffers this.draw_primitive = gl.TRIANGLE_FAN;
this.vertexBuffer = acquire_buffer(gl); super.init(gl);
this.indexBuffer = acquire_buffer(gl);
// Bind the buffers
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
// Write date into the buffers
gl.bufferData(gl.ARRAY_BUFFER, this.vertex_array(), gl.STATIC_DRAW);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.index_array(), gl.STATIC_DRAW);
}
// Draw the object
draw(gl, modelMatrix, u_ModelMatrix) {
// Bind the buffers
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
// Set the object's color
var u_Color = acquire_uniform(gl, 'u_Color');
gl.uniform4fv(u_Color, this.color);
// get a_Position
var a_Position = acquire_attribute(gl, 'a_Position', 2, gl.FLOAT);
// Enable the assignment to a_Position variable
gl.enableVertexAttribArray(a_Position);
// Pass the rotation matrix to the vertex shader
gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix.elements);
// Draw the shape
gl.drawElements(gl.TRIANGLE_FAN, this.length, gl.UNSIGNED_BYTE, 0);
} }
} }
class Pendulum { class Rod extends ShapedObject {
constructor({ angle = 0, length = PEN_LENGTH, radius = BOB_RADIUS, anchor = { x: 0, y: 0 } } = {}) { constructor({ anchor = { x: 0, y: 0 }, bob = { x: 0, y: 0 }, color = { r: 1.0, g: 0.0, b: 0.0, a: 1.0 } } = {}) {
this.angle = angle; super({ color: color });
var bob = {x: 0, y: -length}; // Set the object's vertices
this.components = [ this.vertices = [new Homogeneous2D(anchor.x, anchor.y, 1), new Homogeneous2D(bob.x, bob.y, 1)]
new Rod({ anchor: anchor, bob: bob}),
new Anchor({ center: anchor }),
new Polygon({ radius: radius, center: { x: 0, y: -length } })
];
} }
// Wrap the init function to set the draw_primitive type to LINES
init(gl) {
this.draw_primitive = gl.LINES;
super.init(gl);
}
}
// Tick the pendulum (update and perform movement) class Anchor extends ShapedObject {
tick() { constructor({ center = { x: 0, y: 0 }, color = { r: 0.0, g: 1.0, b: 0.0, a: 1.0 } } = {}) {
var now = Date.now(), elapsed = now - this.t_prev; super({ color: color });
this.t_prev = now; // Set the object's vertices
this.angle = (this.angle + (A_VELOCITY * elapsed / 1000)) % 360; this.vertices = [new Homogeneous2D(center.x, center.y, 1)];
}
// Wrap the init function to set the draw_primitive type to POINTS
init(gl) {
this.draw_primitive = gl.POINTS;
super.init(gl);
}
}
// This doesn't need to extend ShapedObject, but I love the symmetry
class Pendulum extends ShapedObject {
constructor({ angle = 0, length = PEN_LENGTH, radius = BOB_RADIUS} = {}) {
super();
this.angle = angle;
var anchor = { x: 0, y: 0 }, bob = { x: 0, y: -length };
this.components = [
new Rod({ anchor: anchor, bob: bob }),
new Anchor({ center: anchor }),
new Polygon({ sides: 6, radius: radius, center: bob })
];
} }
// Initialize the pendulum // Initialize the pendulum
@ -300,13 +78,22 @@ class Pendulum {
// start the clock // start the clock
this.t_prev = Date.now(); this.t_prev = Date.now();
} }
// Draw the pendulum // Draw the pendulum
draw(gl, modelMatrix, u_ModelMatrix) { draw(gl, modelMatrix, u_ModelMatrix) {
// Rotate the pendulum // Rotate the pendulum
modelMatrix.setRotate(this.angle, 0, 0, 1); modelMatrix.setIdentity();
modelMatrix.rotate(this.angle, 0, 0, 1);
// Draw each component // Draw each component
for (var component of this.components) { for (var component of this.components) {
component?.draw(gl, modelMatrix, u_ModelMatrix); component?.draw(gl, modelMatrix, u_ModelMatrix);
} }
} }
// Tick the pendulum (update and perform movement)
tick() {
var now = Date.now(), elapsed = now - this.t_prev;
this.t_prev = now;
this.angle = (this.angle + (A_VELOCITY * elapsed / 1000)) % 360;
}
} }

76
Pendulum/ShapedObject.js Normal file
View File

@ -0,0 +1,76 @@
// PendulumComponents.js
// John Breaux 2022-06-30
// Super-class for simple, flat-color drawn primitives
"use strict"
//
// Classes
//
// ShapedObject: Super-class for simple drawn primitives
class ShapedObject {
constructor({ color = { r: 1, g: 1, b: 1, a: 0.5 } } = {}) {
// Set object color
this.color = [color.r, color.g, color.b, color.a];
}
// Convert to Float32Array [x, y]
vertex_array() {
// allocate space for center.xy + vertices.xy
var ret = new Float32Array((this.vertices.length) * 2);
// save the vertices
for (var i = 0; i < this.vertices.length; i++) {
var j = 2 * i;
ret[j] = this.vertices[i].x;
ret[j + 1] = this.vertices[i].y;
}
return ret;
}
// Generate the index_array for the shape
index_array() {
var ret = new Uint8Array(this.vertices.length + 1);
for (var i = 0; i < this.vertices.length; i++) {
ret[i] = i
}
ret[this.vertices.length] = 0;
return ret;
}
// Initialize the object's drawing parameters
init(gl) {
// Make the buffers
this.vertexBuffer = acquire_buffer(gl);
this.indexBuffer = acquire_buffer(gl);
// Bind the buffers
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
// Write date into the buffers
gl.bufferData(gl.ARRAY_BUFFER, this.vertex_array(), gl.STATIC_DRAW);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.index_array(), gl.STATIC_DRAW);
}
// Draw the object
draw(gl, modelMatrix, u_ModelMatrix) {
// Bind the buffers
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
// Set the object's color
var u_Color = acquire_uniform(gl, 'u_Color');
gl.uniform4fv(u_Color, this.color);
// get a_Position
enable_attribute(gl, 'a_Position', 2, gl.FLOAT);
// Pass the rotation matrix to the vertex shader
gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix.elements);
// Draw the Anchor
gl.drawElements(this.draw_primitive, this.vertices.length, gl.UNSIGNED_BYTE, 0);
}
}
// Give me your [HeartShapedObject]

55
Pendulum/common.js Normal file
View File

@ -0,0 +1,55 @@
// PendulumComponents.js
// John Breaux 2022-06-30
// Classes, functions, and data structures for Pendulum.js
"use strict"
//
// Global variables
//
// Point size of the anchor
var POINT_SIZE = 5;
// Radius of the bob
var BOB_RADIUS = 0.1;
// length of the wire
var PEN_LENGTH = 0.8;
// Rotation angle (degrees/second)
var A_VELOCITY = 45.0;
//
// Common functions:
//
// acquire_buffer: Get a vertex buffer object from gl
function acquire_buffer(gl) {
// Create a buffer object
var vertexBuffer = gl.createBuffer();
if (!vertexBuffer) {
console.log('Failed to create the buffer object');
return -1;
}
return vertexBuffer;
}
function enable_attribute(gl, name, size, type) {
// Acquire a reference to named attr
var attr = gl.getAttribLocation(gl.program, name);
if (attr < 0) {
console.log(`Failed to get the storage location of ${name}`);
return -1;
}
gl.vertexAttribPointer(attr, size, type, false, 0, 0);
// Switch GL state machine to use named attr
gl.enableVertexAttribArray(attr);
}
function acquire_uniform(gl, name) {
// Acquire a reference to named attr
var ret = gl.getUniformLocation(gl.program, name);
if (!ret) {
console.log(`Failed to get the storage location of ${name}`);
return -1;
}
return ret;
}