diff --git a/README.md b/README.md
index c636328..7812067 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,10 @@
+# Di Lu Results
+
+
+
+
+Link: [dluisnothere.github.io/hw00-webgl-intro](https://dluisnothere.github.io/hw00-webgl-intro)
+
# HW 0: Noisy Planet Part 1 (Intro to Javascript and WebGL)
diff --git a/resultScreenshots/cube.png b/resultScreenshots/cube.png
new file mode 100644
index 0000000..6bca6f7
Binary files /dev/null and b/resultScreenshots/cube.png differ
diff --git a/resultScreenshots/cube2.png b/resultScreenshots/cube2.png
new file mode 100644
index 0000000..80118b5
Binary files /dev/null and b/resultScreenshots/cube2.png differ
diff --git a/src/geometry/Cube.ts b/src/geometry/Cube.ts
new file mode 100644
index 0000000..19d9c71
--- /dev/null
+++ b/src/geometry/Cube.ts
@@ -0,0 +1,97 @@
+import {vec3, vec4} from 'gl-matrix';
+import Drawable from '../rendering/gl/Drawable';
+import {gl} from '../globals';
+
+class Cube extends Drawable {
+ buffer: ArrayBuffer;
+ 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,
+ 4, 5, 6, 4, 6, 7,
+ 8, 9, 10, 8, 10, 11,
+ 12, 13, 14, 12, 14, 15,
+ 16, 17, 18, 16, 18, 19,
+ 20, 21, 22, 20, 22, 23]);
+
+
+ this.positions = new Float32Array([1, -1, -1, 1, //back
+ -1, -1, -1, 1,
+ -1, 1, -1, 1,
+ 1, 1, -1, 1,
+ -1, -1, -1, 1, //left
+ -1, -1, 1, 1,
+ -1, 1, 1, 1,
+ -1, 1, -1, 1,
+ 1, -1, 1, 1, //right
+ 1, -1, -1, 1,
+ 1, 1, -1, 1,
+ 1, 1, 1, 1,
+ 1, 1, 1, 1, //up
+ -1, 1, 1, 1,
+ -1, 1, -1, 1,
+ 1, 1, -1, 1,
+ -1, -1, -1, 1, //down
+ 1, -1, -1, 1,
+ 1, -1, 1, 1,
+ -1, -1, 1, 1,
+ 1, -1, 1, 1, //front
+ -1, -1, 1, 1,
+ -1, 1, 1, 1,
+ 1, 1, 1, 1
+ ]);
+
+ this.normals = new Float32Array([0, 0, -1, 0, //back
+ 0, 0, -1, 0,
+ 0, 0, -1, 0,
+ 0, 0, -1, 0,
+ -1, 0, 0, 0, //left
+ -1, 0, 0, 0,
+ -1, 0, 0, 0,
+ -1, 0, 0, 0,
+ 1, 0, 0, 0, //right
+ 1, 0, 0, 0,
+ 1, 0, 0, 0,
+ 1, 0, 0, 0,
+ 0, 1, 0, 0, //up
+ 0, 1, 0, 0,
+ 0, 1, 0, 0,
+ 0, 1, 0, 0,
+ 0, -1, 0, 0, //down
+ 0, -1, 0, 0,
+ 0, -1, 0, 0,
+ 0, -1, 0, 0,
+ 0, 0, 1, 0, //front
+ 0, 0, 1, 0,
+ 0, 0, 1, 0,
+ 0, 0, 1, 0,
+ ]);
+
+ 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;
\ No newline at end of file
diff --git a/src/main.ts b/src/main.ts
index 65a9461..8ed0149 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -1,8 +1,9 @@
-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';
import Square from './geometry/Square';
+import Cube from './geometry/Cube';
import OpenGLRenderer from './rendering/gl/OpenGLRenderer';
import Camera from './Camera';
import {setGL} from './globals';
@@ -17,13 +18,18 @@ const controls = {
let icosphere: Icosphere;
let square: Square;
+let cube: Cube;
let prevTesselations: number = 5;
+let time: number = 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();
+ cube = new Cube(vec3.fromValues(0, 0, 0));
+ cube.create();
}
function main() {
@@ -40,6 +46,14 @@ function main() {
gui.add(controls, 'tesselations', 0, 8).step(1);
gui.add(controls, 'Load Scene');
+ // add color controller to gui
+ var colorPalette = {
+ colorControls: [0.0, 128.0, 255.0]
+ }
+
+ var colorController = gui.addColor(colorPalette, 'colorControls');
+
+
// get canvas and webgl context
const canvas = document.getElementById('canvas');
const gl = canvas.getContext('webgl2');
@@ -56,7 +70,7 @@ function main() {
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);
+ renderer.setClearColor(0.17, 0.43, 0.52, 1.0);
gl.enable(gl.DEPTH_TEST);
const lambert = new ShaderProgram([
@@ -64,8 +78,26 @@ function main() {
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')),
+ ]);
+
+ var itemColor = vec4.fromValues(colorController.getValue()[0] / 255.0, colorController.getValue()[1] / 255.0,
+ colorController.getValue()[2] / 255.0, 1.0);
+
+
// This function will be called every frame
function tick() {
+
+ //increment time
+ custom.setTime(time);
+ time++;
+
+ colorController.onChange(color => {
+ itemColor = vec4.fromValues(color[0] / 255.0, color[1] / 255.0, color[2] / 255.0, 1.0);
+ });
+
camera.update();
stats.begin();
gl.viewport(0, 0, window.innerWidth, window.innerHeight);
@@ -76,10 +108,11 @@ function main() {
icosphere = new Icosphere(vec3.fromValues(0, 0, 0), 1, prevTesselations);
icosphere.create();
}
- renderer.render(camera, lambert, [
+ renderer.render(camera, custom /*lambert*/, [
icosphere,
- // square,
- ]);
+ //square,
+ cube
+ ], itemColor);
stats.end();
// Tell the browser to call `tick` again whenever it renders a new frame
@@ -95,6 +128,7 @@ function main() {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.setAspectRatio(window.innerWidth / window.innerHeight);
camera.updateProjectionMatrix();
+
// Start the render loop
tick();
diff --git a/src/rendering/gl/OpenGLRenderer.ts b/src/rendering/gl/OpenGLRenderer.ts
index 7e527c2..8e6d34b 100644
--- a/src/rendering/gl/OpenGLRenderer.ts
+++ b/src/rendering/gl/OpenGLRenderer.ts
@@ -11,7 +11,7 @@ class OpenGLRenderer {
setClearColor(r: number, g: number, b: number, a: number) {
gl.clearColor(r, g, b, a);
- }
+ }
setSize(width: number, height: number) {
this.canvas.width = width;
@@ -22,10 +22,11 @@ class OpenGLRenderer {
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
}
- render(camera: Camera, prog: ShaderProgram, drawables: Array) {
+ render(camera: Camera, prog: ShaderProgram, drawables: Array, inputColor: vec4) {
let model = mat4.create();
let viewProj = mat4.create();
- let color = vec4.fromValues(1, 0, 0, 1);
+ //let color = vec4.fromValues(1,0,0,1);
+ let color = inputColor;
mat4.identity(model);
mat4.multiply(viewProj, camera.projectionMatrix, camera.viewMatrix);
diff --git a/src/rendering/gl/ShaderProgram.ts b/src/rendering/gl/ShaderProgram.ts
index 67fef40..518f315 100644
--- a/src/rendering/gl/ShaderProgram.ts
+++ b/src/rendering/gl/ShaderProgram.ts
@@ -29,6 +29,7 @@ class ShaderProgram {
unifModelInvTr: WebGLUniformLocation;
unifViewProj: WebGLUniformLocation;
unifColor: WebGLUniformLocation;
+ unifTime: WebGLUniformLocation;
constructor(shaders: Array) {
this.prog = gl.createProgram();
@@ -48,6 +49,7 @@ 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");
+ this.unifTime = gl.getUniformLocation(this.prog, "u_Time");
}
use() {
@@ -85,6 +87,14 @@ class ShaderProgram {
}
}
+ //set time variable
+ setTime(time: number) {
+ this.use();
+ if (this.unifTime != -1) {
+ gl.uniform1i(this.unifTime, time);
+ }
+ }
+
draw(d: Drawable) {
this.use();
diff --git a/src/shaders/custom-frag.glsl b/src/shaders/custom-frag.glsl
new file mode 100644
index 0000000..94ba521
--- /dev/null
+++ b/src/shaders/custom-frag.glsl
@@ -0,0 +1,115 @@
+#version 300 es
+
+// This is a fragment shader. If you've opened this file first, please
+// open and read lambert.vert.glsl before reading on.
+// Unlike the vertex shader, the fragment shader actually does compute
+// the shading of geometry. For every pixel in your program's output
+// screen, the fragment shader is run for every bit of geometry that
+// particular pixel overlaps. By implicitly interpolating the position
+// data passed into the fragment shader by the vertex shader, the fragment shader
+// can compute what color to apply to its pixel based on things like vertex
+// position, light position, and vertex color.
+precision highp float;
+
+uniform vec4 u_Color; // The color with which to render this instance of geometry.
+uniform highp int u_Time;
+
+// These are the interpolated values out of the rasterizer, so you can't know
+// their specific values without knowing the vertices that contributed to them
+in vec4 fs_Nor;
+in vec4 fs_LightVec;
+in vec4 fs_Col;
+in vec4 fs_Pos;
+
+out vec4 out_Col; // This is the final output color that you will see on your
+ // screen for the pixel that is currently being processed.
+
+float random3D(vec3 p) {
+ return cos(float(u_Time) * 0.005) * sin(length(vec3(
+ dot(p, vec3(126.1, 316.8, 106.2)),
+ dot(p, vec3(266.5, 186.3, 206.4)),
+ dot(p, vec3(166.4, 246.2, 126.5))
+ ) * 0.01 ));
+}
+
+float interpolateNoise3D(float x, float y, float z)
+{
+ int intX = int(floor(x));
+ float fractX = fract(x);
+ int intY = int(floor(y));
+ float fractY = fract(y);
+ int intZ = int(floor(z));
+ float fractZ = fract(z);
+
+ float v1 = random3D(vec3(intX, intY, intZ));
+ float v2 = random3D(vec3(intX + 1, intY, intZ));
+ float v3 = random3D(vec3(intX, intY + 1, intZ));
+ float v4 = random3D(vec3(intX + 1, intY + 1, intZ));
+ float v5 = random3D(vec3(intX, intY, intZ + 1));
+ float v6 = random3D(vec3(intX + 1, intY, intZ + 1));
+ float v7 = random3D(vec3(intX, intY + 1, intZ + 1));
+ float v8 = random3D(vec3(intX + 1, intY + 1, intZ + 1));
+
+
+ float i1 = mix(v1, v2, fractX);
+ float i2 = mix(v3, v4, fractY);
+ float i3 = mix(v5, v6, fractY);
+ float i4 = mix(v7, v8, fractZ);
+ float i5 = mix(v1, v3, fractZ);
+ float i6 = mix(v2, v4, fractX);
+ float i7 = mix(v5, v7, fractZ);
+ float i8 = mix(v6, v8, fractX);
+
+ float mix1 = mix(mix(i1, i2, fractZ), mix(i3, i4, fractX), fractY);
+ float mix2 = mix(mix(i5, i6, fractX), mix(i7, i8, fractY), fractZ);
+ float finalMix = mix(mix1, mix2, fractX);
+ return finalMix;
+}
+
+float fbmNoise(float x, float y, float z)
+{
+ float total = 0.0;
+ float persistence = 0.5;
+ float frequency = 1.0;
+ float amplitude = 2.0;
+ int octaves = 5;
+
+ for (int i = 1; i <= octaves; i++) {
+ total += amplitude * interpolateNoise3D(frequency * x, frequency * y, frequency * z);
+ frequency *= 3.0;
+ amplitude *= persistence;
+ }
+ return total;
+}
+
+void main()
+{
+ float noiseValue = fbmNoise(fs_Pos.x, fs_Pos.y, fs_Pos.z);
+
+ vec4 a = vec4(0.5, 0.5, 0.5, 1.0);
+ vec4 b = vec4(0.5, 0.5, 0.5, 1.0);
+ vec4 c = vec4(2.0, 1.0, 0.0, 1.0);
+ vec4 d = vec4(0.5, 0.2, 0.25, 1.0);
+
+ // vec4 a = vec4(0.8, 0.5, 0.4, 1.0);
+ // vec4 b = vec4(0.2, 0.4, 0.2, 1.0);
+ // vec4 c = vec4(2.0, 1.0, 1.0, 1.0);
+ // vec4 d = vec4(0.00, 0.25, 0.25, 1.0);
+
+ vec4 diffuseColor = a + b * cos(6.3 * (c * noiseValue + u_Color + d));
+
+ // Calculate the diffuse term for Lambert shading
+ float diffuseTerm = dot(normalize(fs_Nor), normalize(fs_LightVec));
+ // Avoid negative lighting values
+ diffuseTerm = clamp(diffuseTerm, 0.3, 1.0);
+
+ float ambientTerm = 0.2;
+
+ float lightIntensity = diffuseTerm + ambientTerm; //Add a small float value to the color multiplier
+ //to simulate ambient lighting. This ensures that faces that are not
+ //lit by our point light are not completely black.
+
+ // Compute final shaded color
+ out_Col = vec4(diffuseColor.rgb * lightIntensity, diffuseColor.a);
+}
+
diff --git a/src/shaders/custom-vert.glsl b/src/shaders/custom-vert.glsl
new file mode 100644
index 0000000..d09e536
--- /dev/null
+++ b/src/shaders/custom-vert.glsl
@@ -0,0 +1,77 @@
+#version 300 es
+
+//This is a vertex shader. While it is called a "shader" due to outdated conventions, this file
+//is used to apply matrix transformations to the arrays of vertex data passed to it.
+//Since this code is run on your GPU, each vertex is transformed simultaneously.
+//If it were run on your CPU, each vertex would have to be processed in a FOR loop, one at a time.
+//This simultaneous transformation allows your program to run much faster, especially when rendering
+//geometry with millions of vertices.
+
+uniform mat4 u_Model; // The matrix that defines the transformation of the
+ // object we're rendering. In this assignment,
+ // this will be the result of traversing your scene graph.
+
+uniform mat4 u_ModelInvTr; // The inverse transpose of the model matrix.
+ // This allows us to transform the object's normals properly
+ // if the object has been non-uniformly scaled.
+
+uniform mat4 u_ViewProj; // The matrix that defines the camera's transformation.
+ // We've written a static matrix for you to use for HW2,
+ // but in HW3 you'll have to generate one yourself
+
+uniform highp int u_Time;
+
+in vec4 vs_Pos; // The array of vertex positions passed to the shader
+
+in vec4 vs_Nor; // The array of vertex normals passed to the shader
+
+in vec4 vs_Col; // The array of vertex colors passed to the shader.
+
+out vec4 fs_Nor; // The array of normals that has been transformed by u_ModelInvTr. This is implicitly passed to the fragment shader.
+out vec4 fs_LightVec; // The direction in which our virtual light lies, relative to each vertex. This is implicitly passed to the fragment shader.
+out vec4 fs_Col; // The color of each vertex. This is implicitly passed to the fragment shader.
+out vec4 fs_Pos;
+
+const vec4 lightPos = vec4(5, 5, 3, 1); //The position of our virtual light, which is used to compute the shading of
+ //the geometry in the fragment shader.
+
+float random(float inputValue) {
+ return fract((sin(inputValue)) *
+ 43758.5453123);
+}
+
+vec4 perturbVec(vec4 original)
+{
+ vec4 randomized = vec4(random(original.x), random(original.y) + cos(original.z),
+ random(original.z) + sin(original.x), 1.0);
+ return mix(randomized, original, cos(float(u_Time) * 0.005));
+}
+
+void main()
+{
+ fs_Col = vs_Col; // Pass the vertex colors to the fragment shader for interpolation
+
+ vec4 temp = vec4(normalize(vec3(vs_Pos.xyz)), 1.0);
+
+ vec4 noisedVec = u_Model * mix(perturbVec(vs_Pos), temp, cos(float(u_Time) * 0.001));
+
+ mat3 invTranspose = mat3(u_ModelInvTr);
+ fs_Nor = vec4(invTranspose * vec3(vs_Nor), 0.0); // Pass the vertex normals to the fragment shader for interpolation.
+ // Transform the geometry's normals by the inverse transpose of the
+ // model matrix. This is necessary to ensure the normals remain
+ // perpendicular to the surface after the surface is transformed by
+ // the model matrix.
+
+ vec4 modelposition = u_Model * vs_Pos; // Temporarily store the transformed vertex positions for use belo
+
+
+ //vec4 perturbedVec = perturbVec(modelposition) * vs_Nor;
+
+ fs_LightVec = lightPos - modelposition; // Compute the direction in which the light source lies
+
+ fs_Pos = vs_Pos;
+
+ //gl_Position = u_ViewProj * modelposition + random(vs_Pos.x) * perturbedVec;// gl_Position is a built-in variable of OpenGL which is
+ // used to render the final positions of the geometry's vertices
+ gl_Position = u_ViewProj * noisedVec;
+}