Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 25 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,32 @@
# HW 0: Intro to Javascript and WebGL

## Description
In this project, I implemented noise functions and practiced using Typescript and WebGL2.
I created a `Cube` class and rendered an instance of `Cube` to the scene.
I also updated the GUI to create a color picker that allows user to adjust the color of the object being rendered.
I wrote a custom fragment shader that implements Perlin Noise based on 3D inputs to alter the fragment color, as well as a custom vertex shader that uses a `sin` function to non-uniformly alter my cube's vertex positions over time using a Perlin Noise function.

## Resources used
- GLSL Noise Algorithms: https://gist.github.com/patriciogonzalezvivo/670c22f3966e662d2f83
- Surflet and PerlinNoise3D functions taken from from CIS 460 notes

## Screenshots of demo
<p align="center">
<img width="720" height="360" src=./demo-screenshots/hw00-pic1.png>
<img width="720" height="360" src=./demo-screenshots/hw00-pic3.png>
<img width="720" height="360" src=./demo-screenshots/hw00-pic2.png>
<img width="720" height="360" src=./demo-screenshots/hw00-pic4.png>
<img width="720" height="360" src=./demo-screenshots/hw00-pic5.png>
<img width="720" height="360" src=./demo-screenshots/hw00-pic6.png>
<p align="center">

## Link to Live Demo
https://debbylin02.github.io/hw00-intro-base/


<p align="center">
<img width="360" height="360" src="https://user-images.githubusercontent.com/1758825/132532354-e3a45402-e484-499e-bfa7-2d73b9f2c946.png">
</p>
<p align="center">
<p align="center">(source: Ken Perlin)</p>

## Objective
Expand Down
Binary file added demo-screenshots/hw00-pic1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added demo-screenshots/hw00-pic2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added demo-screenshots/hw00-pic3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added demo-screenshots/hw00-pic4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added demo-screenshots/hw00-pic5.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added demo-screenshots/hw00-pic6.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added demo-screenshots/hw00-pic7.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3,866 changes: 2,298 additions & 1,568 deletions package-lock.json

Large diffs are not rendered by default.

70 changes: 70 additions & 0 deletions src/geometry/Cube.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import {vec3, vec4} from 'gl-matrix';
import Drawable from '../rendering/gl/Drawable';
import {gl} from '../globals';

class Cube extends Drawable {
// indicies = indices of the triangles
indices: Uint32Array;
positions: Float32Array;
normals: Float32Array;
center: vec4;

constructor(center: vec3) {
super(); // Call the constructor of the super class. This is required.
this.center = vec4.fromValues(center[0], center[1], center[2], 1);
}

create() {
this.indices = new Uint32Array([0, 1, 2,
0, 2, 3,
// right side
1, 5, 6,
1, 6, 2,
// back
5, 4, 7,
5, 7, 6,
// left side
4, 0, 3,
4, 3, 7,
// top
3, 2, 6,
3, 6, 7,
// bottom
0, 1, 5,
0, 5, 4]);
this.normals = new Float32Array([0, 0, 1, 0,
0, 0, 1, 0,
0, 0, 1, 0,
0, 0, 1, 0,
0, 0, 1, 0,
0, 0, 1, 0,
0, 0, 1, 0,
0, 0, 1, 0]);
this.positions = new Float32Array([-1, -1, 1, 1,
1, -1, 1, 1,
1, 1, 1, 1,
-1, 1, 1, 1,
-1, -1, -1, 1,
1, -1, -1, 1,
1, 1, -1, 1,
-1, 1, -1, 1]);

this.generateIdx();
this.generatePos();
this.generateNor();

this.count = this.indices.length;
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.bufIdx);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.indices, gl.STATIC_DRAW);

gl.bindBuffer(gl.ARRAY_BUFFER, this.bufNor);
gl.bufferData(gl.ARRAY_BUFFER, this.normals, gl.STATIC_DRAW);

gl.bindBuffer(gl.ARRAY_BUFFER, this.bufPos);
gl.bufferData(gl.ARRAY_BUFFER, this.positions, gl.STATIC_DRAW);

console.log(`Created cube`);
}
};

export default Cube;
168 changes: 99 additions & 69 deletions src/main.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {vec3} from 'gl-matrix';
import {vec3, vec4} from 'gl-matrix';
const Stats = require('stats-js');
import * as DAT from 'dat.gui';
import Icosphere from './geometry/Icosphere';
Expand All @@ -7,97 +7,127 @@ import OpenGLRenderer from './rendering/gl/OpenGLRenderer';
import Camera from './Camera';
import {setGL} from './globals';
import ShaderProgram, {Shader} from './rendering/gl/ShaderProgram';
import Cube from './geometry/Cube';

// Define an object with application parameters and button callbacks
// This will be referred to by dat.GUI's functions that add GUI elements.

const controls = {
tesselations: 5,
'Load Scene': loadScene, // A function pointer, essentially
tesselations: 5,
'Load Scene': loadScene, // A function pointer, essentially

// Update the existing GUI w/ a parameter to alter the color passed to u_Color
color: [0, 255, 0, 1]
};

let icosphere: Icosphere;
let square: Square;
// added cube
let cube: Cube;
let prevTesselations: number = 5;

// added for tickCount
let tickCount: GLint = 0;

function loadScene() {
icosphere = new Icosphere(vec3.fromValues(0, 0, 0), 1, controls.tesselations);
icosphere.create();
square = new Square(vec3.fromValues(0, 0, 0));
square.create();
icosphere = new Icosphere(vec3.fromValues(0, 0, 0), 1, controls.tesselations);
icosphere.create();
square = new Square(vec3.fromValues(0, 0, 0));
square.create();
// create cube
cube = new Cube(vec3.fromValues(0, 0, 0));
cube.create();
}

function main() {
// Initial display for framerate
const stats = Stats();
stats.setMode(0);
stats.domElement.style.position = 'absolute';
stats.domElement.style.left = '0px';
stats.domElement.style.top = '0px';
document.body.appendChild(stats.domElement);

// Add controls to the gui
const gui = new DAT.GUI();
gui.add(controls, 'tesselations', 0, 8).step(1);
gui.add(controls, 'Load Scene');

// get canvas and webgl context
const canvas = <HTMLCanvasElement> document.getElementById('canvas');
const gl = <WebGL2RenderingContext> canvas.getContext('webgl2');
if (!gl) {
alert('WebGL 2 not supported!');
// Initial display for framerate
const stats = Stats();
stats.setMode(0);
stats.domElement.style.position = 'absolute';
stats.domElement.style.left = '0px';
stats.domElement.style.top = '0px';
document.body.appendChild(stats.domElement);

// Add controls to the gui
const gui = new DAT.GUI();
gui.add(controls, 'tesselations', 0, 8).step(1);
gui.add(controls, 'Load Scene');

// adding color picker
gui.addColor(controls, 'color');

// get canvas and webgl context
const canvas = <HTMLCanvasElement> document.getElementById('canvas');
const gl = <WebGL2RenderingContext> canvas.getContext('webgl2');
if (!gl) {
alert('WebGL 2 not supported!');
}
// `setGL` is a function imported above which sets the value of `gl` in the `globals.ts` module.
// Later, we can import `gl` from `globals.ts` to access it
setGL(gl);

// Initial call to load scene
loadScene();

const camera = new Camera(vec3.fromValues(0, 0, 5), vec3.fromValues(0, 0, 0));

const renderer = new OpenGLRenderer(canvas);
renderer.setClearColor(0.2, 0.2, 0.2, 1);
gl.enable(gl.DEPTH_TEST);

const lambert = new ShaderProgram([
new Shader(gl.VERTEX_SHADER, require('./shaders/lambert-vert.glsl')),
new Shader(gl.FRAGMENT_SHADER, require('./shaders/lambert-frag.glsl')),
]);

const custom = new ShaderProgram([
new Shader(gl.VERTEX_SHADER, require('./shaders/custom-vert.glsl')),
new Shader(gl.FRAGMENT_SHADER, require('./shaders/custom-frag.glsl')),
]);

// This function will be called every frame
function tick() {
// increase tickCount
tickCount++;

camera.update();
stats.begin();
gl.viewport(0, 0, window.innerWidth, window.innerHeight);
renderer.clear();
if(controls.tesselations != prevTesselations)
{
prevTesselations = controls.tesselations;
icosphere = new Icosphere(vec3.fromValues(0, 0, 0), 1, prevTesselations);
icosphere.create();
}
// `setGL` is a function imported above which sets the value of `gl` in the `globals.ts` module.
// Later, we can import `gl` from `globals.ts` to access it
setGL(gl);

// Initial call to load scene
loadScene();

const camera = new Camera(vec3.fromValues(0, 0, 5), vec3.fromValues(0, 0, 0));

const renderer = new OpenGLRenderer(canvas);
renderer.setClearColor(0.2, 0.2, 0.2, 1);
gl.enable(gl.DEPTH_TEST);

const lambert = new ShaderProgram([
new Shader(gl.VERTEX_SHADER, require('./shaders/lambert-vert.glsl')),
new Shader(gl.FRAGMENT_SHADER, require('./shaders/lambert-frag.glsl')),

// update color - pass to renderer/shader
// pass tickCount to renderer/shader
const updatedColor = vec4.fromValues(controls.color[0] / 255, controls.color[1] / 255, controls.color[2] / 255, controls.color[3]);
renderer.render(camera, custom, updatedColor, tickCount, [
// icosphere,
// square,
cube
]);
stats.end();

// This function will be called every frame
function tick() {
camera.update();
stats.begin();
gl.viewport(0, 0, window.innerWidth, window.innerHeight);
renderer.clear();
if(controls.tesselations != prevTesselations)
{
prevTesselations = controls.tesselations;
icosphere = new Icosphere(vec3.fromValues(0, 0, 0), 1, prevTesselations);
icosphere.create();
}
renderer.render(camera, lambert, [
icosphere,
// square,
]);
stats.end();

// Tell the browser to call `tick` again whenever it renders a new frame
requestAnimationFrame(tick);
}

window.addEventListener('resize', function() {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.setAspectRatio(window.innerWidth / window.innerHeight);
camera.updateProjectionMatrix();
}, false);
// Tell the browser to call `tick` again whenever it renders a new frame
requestAnimationFrame(tick);
}

window.addEventListener('resize', function() {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.setAspectRatio(window.innerWidth / window.innerHeight);
camera.updateProjectionMatrix();
}, false);

renderer.setSize(window.innerWidth, window.innerHeight);
camera.setAspectRatio(window.innerWidth / window.innerHeight);
camera.updateProjectionMatrix();

// Start the render loop
tick();
// Start the render loop
tick();
}

main();
12 changes: 10 additions & 2 deletions src/rendering/gl/OpenGLRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,25 @@ class OpenGLRenderer {
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
}

render(camera: Camera, prog: ShaderProgram, drawables: Array<Drawable>) {
// added updatedColor and time variable
render(camera: Camera, prog: ShaderProgram, updatedColor: vec4, tickCount: GLint, drawables: Array<Drawable>) {
let model = mat4.create();
let viewProj = mat4.create();
let color = vec4.fromValues(1, 0, 0, 1);
// let color = vec4.fromValues(1, 0, 0, 1);

// set color and time
let color = updatedColor;
let time = tickCount;

mat4.identity(model);
mat4.multiply(viewProj, camera.projectionMatrix, camera.viewMatrix);
prog.setModelMatrix(model);
prog.setViewProjMatrix(viewProj);
prog.setGeometryColor(color);

// call set time function
prog.setTime(time);

for (let drawable of drawables) {
prog.draw(drawable);
}
Expand Down
15 changes: 15 additions & 0 deletions src/rendering/gl/ShaderProgram.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ class ShaderProgram {
unifViewProj: WebGLUniformLocation;
unifColor: WebGLUniformLocation;

// added time
unifTime: WebGLUniformLocation;

constructor(shaders: Array<Shader>) {
this.prog = gl.createProgram();

Expand All @@ -48,6 +51,9 @@ class ShaderProgram {
this.unifModelInvTr = gl.getUniformLocation(this.prog, "u_ModelInvTr");
this.unifViewProj = gl.getUniformLocation(this.prog, "u_ViewProj");
this.unifColor = gl.getUniformLocation(this.prog, "u_Color");

// added for time
this.unifTime = gl.getUniformLocation(this.prog, "u_Time");
}

use() {
Expand Down Expand Up @@ -85,6 +91,15 @@ class ShaderProgram {
}
}

// setting the unifTime variable
setTime(t: GLint){
this.use();
if(this.unifTime != -1)
{
gl.uniform1i(this.unifTime, t);
}
}

draw(d: Drawable) {
this.use();

Expand Down
Loading