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
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,16 @@
</p>
<p align="center">(source: Ken Perlin)</p>

## Submitted Version
- Features:
- Cube class added
- User can toggle between "Lambert Shader" and "Custom Shader", using corresponding gui button
- User can change the color of the cube in Lamber Shader mode, using currColor color palette
- <img height="360" src="img/HW00-LambertShader.png">
- <img height="360" src="img/HW00-CustomShader-01.png">
- <img height="360" src="img/HW00-CustomShader-02.png">
- Live Demo Link: https://raykim1996.github.io/hw00-webgl-intro/

## Objective
- Check that the tools and build configuration we will be using for the class works.
- Start learning Typescript and WebGL2
Expand Down
Binary file added img/HW00-CustomShader-01.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 img/HW00-CustomShader-02.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 img/HW00-LambertShader.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
99 changes: 99 additions & 0 deletions src/geometry/Cube.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import {vec3, vec4} from 'gl-matrix';
import Drawable from '../rendering/gl/Drawable';
import {gl} from '../globals';

class Cube extends Drawable {
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.normals = new Float32Array([0, 0, 1, 0, //front face
0, 0, 1, 0,
0, 0, 1, 0,
0, 0, 1, 0,
1, 0, 0, 0, //right face
1, 0, 0, 0,
1, 0, 0, 0,
1, 0, 0, 0,
-1, 0, 0, 0, //left face
-1, 0, 0, 0,
-1, 0, 0, 0,
-1, 0, 0, 0,
0, 1, 0, 0, //up face
0, 1, 0, 0,
0, 1, 0, 0,
0, 1, 0, 0,
0, -1, 0, 0, //down face
0, -1, 0, 0,
0, -1, 0, 0,
0, -1, 0, 0,
0, 0, -1, 0, //back face
0, 0, -1, 0,
0, 0, -1, 0,
0, 0, -1, 0,]);

this.positions = new Float32Array([-1, -1, 1, 1, //front face
1, -1, 1, 1,
1, 1, 1, 1,
-1, 1, 1, 1,
1, -1, 1, 1, //right face
1, -1, -1, 1,
1, 1, -1, 1,
1, 1, 1, 1,
-1, -1, -1, 1, //left face
-1, -1, 1, 1,
-1, 1, 1, 1,
-1, 1, -1, 1,
-1, 1, 1, 1, //up face
1, 1, 1, 1,
1, 1, -1, 1,
-1, 1, -1, 1,
-1, -1, -1, 1, //down face
1, -1, -1, 1,
1, -1, 1, 1,
-1, -1, 1, 1,
-1, 1, -1, 1, //back face
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;
52 changes: 47 additions & 5 deletions src/main.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -13,17 +14,33 @@ import ShaderProgram, {Shader} from './rendering/gl/ShaderProgram';
const controls = {
tesselations: 5,
'Load Scene': loadScene, // A function pointer, essentially
'Lambert Shader': toggleLambert,
'Custom Shader': toggleCustom,
currColor: [0, 255, 255, 1],
};

let icosphere: Icosphere;
let square: Square;
let cube: Cube;
let prevTesselations: number = 5;
let time: number = 0;
let shader: 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 toggleLambert() {
shader = 0;
}

function toggleCustom() {
shader = 1;
}

function main() {
Expand All @@ -39,6 +56,9 @@ function main() {
const gui = new DAT.GUI();
gui.add(controls, 'tesselations', 0, 8).step(1);
gui.add(controls, 'Load Scene');
gui.add(controls, 'Lambert Shader');
gui.add(controls, 'Custom Shader');
gui.addColor(controls, "currColor");

// get canvas and webgl context
const canvas = <HTMLCanvasElement> document.getElementById('canvas');
Expand All @@ -64,6 +84,11 @@ 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')),
]);

// This function will be called every frame
function tick() {
camera.update();
Expand All @@ -76,10 +101,27 @@ function main() {
icosphere = new Icosphere(vec3.fromValues(0, 0, 0), 1, prevTesselations);
icosphere.create();
}
renderer.render(camera, lambert, [
icosphere,
// square,
]);
let newColor = vec4.fromValues((controls.currColor[0] / 255.0),
(controls.currColor[1] / 255.0),
(controls.currColor[2] / 255.0), 1);
time += 0.01;

if (shader == 0) {
renderer.render(camera, lambert, [
icosphere,
// square,
cube,
], newColor, time);
} else {
renderer.render(camera, custom, [
icosphere,
// square,
cube,
], newColor, time);
}



stats.end();

// Tell the browser to call `tick` again whenever it renders a new frame
Expand Down
4 changes: 2 additions & 2 deletions src/rendering/gl/OpenGLRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,16 @@ class OpenGLRenderer {
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
}

render(camera: Camera, prog: ShaderProgram, drawables: Array<Drawable>) {
render(camera: Camera, prog: ShaderProgram, drawables: Array<Drawable>, color: vec4, time: number) {
let model = mat4.create();
let viewProj = mat4.create();
let color = vec4.fromValues(1, 0, 0, 1);

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

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

constructor(shaders: Array<Shader>) {
this.prog = gl.createProgram();
Expand All @@ -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() {
Expand Down Expand Up @@ -78,6 +80,13 @@ class ShaderProgram {
}
}

setTime(t: number) {
this.use();
if (this.unifTime !== -1) {
gl.uniform1f(this.unifTime, t);
}
}

setGeometryColor(color: vec4) {
this.use();
if (this.unifColor !== -1) {
Expand Down
100 changes: 100 additions & 0 deletions src/shaders/custom-frag.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
#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 float 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.

//perlin noise function
vec3 random3(vec3 p) {
return fract(sin(vec3(dot(p,vec3(137.1, 927.6, 371.919)),
dot(p,vec3(716.5, 213.3, 617.14)),
dot(p, vec3(237.69, 313.2, 107.23))))
*23873.3207);
}

float surflet(vec3 p, vec3 gridPoint) {
// Compute the distance between p and the grid point along each axis, and warp it with a
// quintic function so we can smooth our cells
vec3 t2 = abs(p - gridPoint);
vec3 t = vec3(1.0) - 6.0 * pow(t2, vec3(5.0)) + 15.0 * pow(t2, vec3(4.0)) - 10.0 * pow(t2, vec3(3.0));
// Get the random vector for the grid point (assume we wrote a function random2
// that returns a vec2 in the range [0, 1])
vec3 gradient = random3(gridPoint) * 2. - vec3(1., 1., 1.);
// Get the vector from the grid point to P
vec3 diff = p - gridPoint;
// Get the value of our height field by dotting grid->P with our gradient
float height = dot(diff, gradient);
// Scale our height field (i.e. reduce it) by our polynomial falloff function
return height * t.x * t.y * t.z;
}

float perlinNoise3D(vec3 p)
{
float surfletSum = 0.0;
p = (p + (u_Time + 721.22913)) * 0.5;
for (int dx = 0; dx <= 1; ++dx) {
for (int dy = 0; dy <= 1; ++dy) {
for (int dz = 0; dz <= 1; ++dz) {
surfletSum += surflet(p, floor(p) + vec3(dx, dy, dz));
}
}
}
return surfletSum;
}

vec3 palette(in float t, in vec3 a, in vec3 b, in vec3 c, in vec3 d)
{
return a + b * cos(7.28318 * (c * t + d));
}

void main()
{
// Material base color (before shading)
vec4 diffuseColor = u_Color;

// apply perlin noise function
vec3 pos = vec3(fs_Pos.x, fs_Pos.y, fs_Pos.z);
float p = perlinNoise3D(pos);
// (fs_Col.xyz / 255.0)
vec3 perlinA = vec3(0.2,0.8,0.8);
vec3 perlinB = vec3(0.5,0.5,0.5);
vec3 perlinC = vec3(1.0,1.0,1.0);
vec3 perlinD = vec3(0.5,0.6,0.6);
vec3 newColor = palette(p, perlinA, perlinB, perlinC, perlinD);


// Calculate the diffuse term for Lambert shading
float diffuseTerm = dot(normalize(fs_Nor), normalize(fs_LightVec));
// Avoid negative lighting values
diffuseTerm = clamp(diffuseTerm, 0.0, 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(newColor.rgb * lightIntensity, diffuseColor.a);

}
Loading