Add program 5

This commit is contained in:
John 2022-07-28 06:12:55 -05:00
parent c4a9e9e42d
commit 841da67623
5 changed files with 398 additions and 0 deletions

7
.vscode/launch.json vendored
View File

@ -29,6 +29,13 @@
"request": "launch", "request": "launch",
"reAttach": true, "reAttach": true,
"file": "${workspaceFolder}/RotatingCube/RotatingCube.html" "file": "${workspaceFolder}/RotatingCube/RotatingCube.html"
},
{
"name": "BivariateFunction",
"type": "firefox",
"request": "launch",
"reAttach": true,
"file": "${workspaceFolder}/BivariateFunction/BivariateFunction.html"
} }
] ]
} }

View File

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Point lighted graph of bivariate function (Per fragment)</title>
</head>
<body onload="main()">
<canvas id="webgl" width="1280" height="800">
Please use a browser that supports "canvas"
</canvas>
<script src="../lib/webgl-utils.js"></script>
<script src="../lib/webgl-debug.js"></script>
<script src="../lib/cuon-utils.js"></script>
<script src="../lib/cuon-matrix.js"></script>
<script src="vec3.js"></script>
<script src="BivariateFunction.js"></script>
</body>
</html>

View File

@ -0,0 +1,280 @@
// PointLightedCube_perFragment.js (c) 2012 matsuda, 2022 Jonathon Doran
const vertex_shader = `
attribute vec4 a_Position;
attribute vec4 a_Color;
attribute vec4 a_Normal;
uniform mat4 u_MvpMatrix;
uniform mat4 u_ModelMatrix; // Model matrix
uniform mat4 u_NormalMatrix; // Transformation matrix of the normal
varying vec4 v_Color;
varying vec3 v_Normal;
varying vec3 v_Position;
void main()
{
gl_Position = u_MvpMatrix * a_Position;
// Calculate the vertex position in the world coordinate
v_Position = vec3(u_ModelMatrix * a_Position);
v_Normal = normalize(vec3(u_NormalMatrix * a_Normal));
v_Color = a_Color;
} `;
const fragment_shader = `
#ifdef GL_ES
precision mediump float;
#endif
uniform vec3 u_LightColor; // Light color
uniform vec3 u_LightPosition; // Position of the light source
uniform vec3 u_AmbientLight; // Ambient light color
varying vec3 v_Normal;
varying vec3 v_Position;
varying vec4 v_Color;
void main()
{
// Normalize the normal because it is interpolated and not 1.0 in length any more
vec3 normal = normalize(v_Normal);
// Calculate the light direction and make its length 1.
vec3 lightDirection = normalize(u_LightPosition - v_Position);
// The dot product of the light direction and the orientation of a surface (the normal)
float nDotL = max(dot(lightDirection, normal), 0.0);
// Calculate the final color from diffuse reflection and ambient reflection
vec3 diffuse = u_LightColor * v_Color.rgb * nDotL;
vec3 ambient = u_AmbientLight * v_Color.rgb;
gl_FragColor = vec4(diffuse + ambient, v_Color.a);
} `;
var scale = 192
function f(x, y) {
var u = 80 * x - 40, v = 90 * y - 45;
var norm = Math.sqrt(u * u + v * v);
return (1 / 2) * Math.pow(Math.E, -0.04 * norm) * Math.cos(0.15 * norm)
}
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, vertex_shader, fragment_shader)) {
console.log('Failed to intialize shaders.');
return;
}
//
var n = initVertexBuffers(gl);
if (n < 0) {
console.log('Failed to set the vertex information');
return;
}
// Set the clear color and enable the depth test
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.enable(gl.DEPTH_TEST);
// Get the storage locations of uniform variables
var u_ModelMatrix = gl.getUniformLocation(gl.program, 'u_ModelMatrix');
var u_MvpMatrix = gl.getUniformLocation(gl.program, 'u_MvpMatrix');
var u_NormalMatrix = gl.getUniformLocation(gl.program, 'u_NormalMatrix');
var u_LightColor = gl.getUniformLocation(gl.program, 'u_LightColor');
var u_LightPosition = gl.getUniformLocation(gl.program, 'u_LightPosition');
var u_AmbientLight = gl.getUniformLocation(gl.program, 'u_AmbientLight');
if (!u_ModelMatrix || !u_MvpMatrix || !u_NormalMatrix || !u_LightColor || !u_LightPosition || !u_AmbientLight) {
console.log('Failed to get the storage location');
return;
}
// Set the light color (white)
gl.uniform3f(u_LightColor, 1.0, 1.0, 1.0);
// Set the light direction (in the world coordinate)
gl.uniform3f(u_LightPosition, 2.3, 4.0, 3.5);
// Set the ambient light
gl.uniform3f(u_AmbientLight, 0.2, 0.2, 0.2);
var modelMatrix = new Matrix4(); // Model matrix
var mvpMatrix = new Matrix4(); // Model view projection matrix
var normalMatrix = new Matrix4(); // Transformation matrix for normals
// Calculate the model matrix
modelMatrix.setRotate(-90, 1, 0, 0); // Rotate around the *X* axis
// Calculate the view projection matrix
mvpMatrix.setPerspective(30, canvas.width / canvas.height, 1, 100);
mvpMatrix.translate(0, 0, -2)
var theta = Math.PI / 3
mvpMatrix.lookAt(
Math.tan(theta) / 4, Math.sin(theta) / 4, Math.cos(theta) / 4,
0, 0, 0,
0, 1, 0
);
mvpMatrix.multiply(modelMatrix);
// Calculate the matrix to transform the normal based on the model matrix
normalMatrix.setInverseOf(modelMatrix);
normalMatrix.transpose();
// Pass the model matrix to u_ModelMatrix
gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix.elements);
// Pass the model view projection matrix to u_mvpMatrix
gl.uniformMatrix4fv(u_MvpMatrix, false, mvpMatrix.elements);
// Pass the transformation matrix for normals to u_NormalMatrix
gl.uniformMatrix4fv(u_NormalMatrix, false, normalMatrix.elements);
// Clear color and depth buffer
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
// Draw the cube
gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_SHORT, 0);
}
//!!! RIGHT HERE
class BivariateFunction {
vertices = [];
vertex_colors = [];
vertex_normals = [];
indices = [];
func = (x, y) => { return 0; }
constructor({ width = 50, height = 50, func = this.func } = {}) {
this.width = width;
this.height = height;
this.func = func;
}
generate_quad(width, _height, index) {
var upper = [index + 1, index, index + width + 1]
var lower = [index + 1, index + width + 1, index + width + 2]
return [upper, lower]
}
generate_plane() {
var width = this.width, height = this.height;
var vertices = [], vertex_colors = [], vertex_normals = [];
var triangles = [];
for (var i = 0, y = 0; y <= width; y++) {
for (var x = 0; x <= height; x++) {
// Create a new vertex
vertices.push([x / width - 0.5, y / height - 0.5, this.func(x / width, y / width)]);
vertex_colors.push([0.625, 0.025, 0.075])
//vertex_colors.push([x / width, y / width, 1]);
vertex_normals.push([0, 0, 0]);
// If this point is the top-left corner of a quad,
// then create a new quad
if (x < width && y < height) {
triangles.push(...this.generate_quad(width, height, i));
}
i++
}
}
for (var triangle of triangles) {
// Turn verts into vec3's
var v = [new vec3(...vertices[triangle[0]]), new vec3(...vertices[triangle[1]]), new vec3(...vertices[triangle[2]])];
// Calculate alpha and beta vectors
var alpha = v[2].sub(v[0]);
var beta = v[1].sub(v[0]);
// Take the cross product & normalize to get the normal
var normal = alpha.cross(beta).normalize();
// Add the normal to each vertex
vertex_normals[triangle[0]] = normal.add(new vec3(...vertex_normals[triangle[0]])).a();
vertex_normals[triangle[1]] = normal.add(new vec3(...vertex_normals[triangle[1]])).a();
vertex_normals[triangle[2]] = normal.add(new vec3(...vertex_normals[triangle[2]])).a();
}
// Average the normals by normalizing the sums of the normals
// this assumes the sum of normals around a vertex is not 0
for (var i = 0; i < vertex_normals.length; i++) {
// taking full advantage of the garbage collector here
vertex_normals[i] = new vec3(...vertex_normals[i]).normalize().a();
}
// Save the vertices and indices
this.vertices = vertices;
this.vertex_colors = vertex_colors;
this.vertex_normals = vertex_normals;
this.indices = triangles;
return
}
}
function initVertexBuffers(gl) {
// Create a new BivariateFunction
var bf = new BivariateFunction({
width: scale, height: scale, func: f
});
bf.generate_plane();
var vertices = new Float32Array(bf.vertices.flat());
var colors = new Float32Array(bf.vertex_colors.flat());
var normals = new Float32Array(bf.vertex_normals.flat());
var indices = new Uint16Array(bf.indices.flat());
// Write the vertex property to buffers (coordinates, colors and normals)
if (!initArrayBuffer(gl, 'a_Position', vertices, 3)) return -1;
if (!initArrayBuffer(gl, 'a_Color', colors, 3)) return -1;
if (!initArrayBuffer(gl, 'a_Normal', normals, 3)) return -1;
// Unbind the buffer object
gl.bindBuffer(gl.ARRAY_BUFFER, null);
// Write the indices to the buffer object
var indexBuffer = gl.createBuffer();
if (!indexBuffer) {
console.log('Failed to create the buffer object');
return false;
}
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
return indices.length;
}
function initArrayBuffer(gl, attribute, data, num) {
// Create a buffer object
var buffer = gl.createBuffer();
if (!buffer) {
console.log('Failed to create the buffer object');
return false;
}
// Write date into the buffer object
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
// Assign the buffer object to the attribute variable
var a_attribute = gl.getAttribLocation(gl.program, attribute);
if (a_attribute < 0) {
console.log('Failed to get the storage location of ' + attribute);
return false;
}
gl.vertexAttribPointer(a_attribute, num, gl.FLOAT, false, 0, 0);
// Enable the assignment of the buffer object to the attribute variable
gl.enableVertexAttribArray(a_attribute);
return true;
}

66
BivariateFunction/vec3.js Normal file
View File

@ -0,0 +1,66 @@
// BetterVector3.js
// John Breaux 2022-07-28
// 3D Vector library
"use strict";
class vec3 {
constructor(x = 0, y = 0, z = 0) {
this.x = x;
this.y = y;
this.z = z;
}
add(rhs) {
return new vec3(this.x + rhs.x, this.y + rhs.y, this.z + rhs.z);
}
sub(rhs) {
return new vec3(this.x - rhs.x, this.y - rhs.y, this.z - rhs.z);
}
dot(rhs) {
return this.x * rhs.x + this.y * rhs.y + this.z * rhs.z;
}
cross(rhs) {
return new vec3(
this.y * rhs.z - this.z * rhs.y,
this.z * rhs.x - this.x * rhs.z,
this.x * rhs.y - this.y * rhs.x
);
}
magnitude() {
return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
}
normal() {
var m = this.magnitude();
if (m === 0) {return null};
return new vec3(
this.x / m,
this.y / m,
this.z / m
);
}
normalize() {
var m = this.magnitude();
if (m === 0) { return null };
this.x /= m;
this.y /= m;
this.z /= m;
return this;
}
// copy
copy() {
return new vec3(this.x, this.y, this.z);
}
// to array
a() {
return [this.x, this.y, this.z];
}
// to String
toString() {
return `{${this.x}, ${this.y}, ${this.z}}`
}
}

View File

@ -62,3 +62,28 @@ Orthographic rotating cube
Write a WebGL program that displays a cube with colored faces using an orthographic projection. Allow an interactive user to rotate the cube 15 degrees about the x and y axis. Write a WebGL program that displays a cube with colored faces using an orthographic projection. Allow an interactive user to rotate the cube 15 degrees about the x and y axis.
The viewing volume defined by setOrtho should be chosen so that the cube occupies most of the volume but no clipping occurs. The viewing volume defined by setOrtho should be chosen so that the cube occupies most of the volume but no clipping occurs.
# Program 5
Graph a bivariate function
### Problem Statement
Write a WebGL program that displays the graph of a bivariate function:
$z=f\left(x,y\right)$ for $(x,y)$ in $D=[0,1]*[0,1]$.
$$f(x,y) = \frac{1}{2} e^{[-0.04 \sqrt{(80x-40)^2 + (90y-45)^2)}]}cos(0.15\sqrt{(80x-40)^2+(90y-45)^2})$$
#### The following procedure creates the polygonal (triangle) mesh surface:
* partition D into a k+1 by k+1 uniform rectangular grid, and partition each of the k*k squares into a pair of triangles. A reasonable value of k is 50.
* Call f to obtain a z value at each of the grid points
* Use filled triangles with Gouraud shading and lighting. Note that each vertex normal must be computed by averaging the normals of the triangles which share the vertex.
* Use a depth buffer for hidden surface removal.
A good template for this program is LightedCube_animation in Matsuda Chapter 8 (one of our texts). It is sufficient to replace initVertexBuffers to create typed arrays of vertex positions, colors, normals, and indices for the triangle mesh surface rather than a cube.
Note, however, that the indices cannot be stored as 8-bit unsigned integers, and the third artument in function gl.drawElements must be changed from gl.UNSIGNED_BYTE to short or int.