Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JichuMao-finished-HW0 #12

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
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
Binary file added 5660HW0.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,21 @@
</p>
<p align="center">(source: Ken Perlin)</p>

## Results
<p align="center">
<img align="center" width="550" height="500" src="5660HW0.gif">
</p>

Features:

- Added cube geometry.

- Added DAT control, allowing free setting of the cube's initial color.

- Implemented a custom vertex shader where all cube vertices change position along a sine wave over time.

- Implemented a custom fragment shader where the cube's surface color is linearly interpolated between the initial color and RGB(0, 0, 0), with the interpolation factor determined by 3D Perlin Noise, which takes vertex position and time as input.

## Objective
- Check that the tools and build configuration we will be using for the class works.
- Start learning Typescript and WebGL2
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"scripts": {
"start": "webpack-dev-server --no-hot --live-reload",
"start": "set NODE_OPTIONS=--openssl-legacy-provider && webpack-dev-server --no-hot --live-reload",
"build": "webpack"
},
"devDependencies": {
Expand Down
124 changes: 124 additions & 0 deletions src/geometry/Cube.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
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, // front
4, 5, 6, 4, 6, 7, // back
8, 9, 10, 8, 10, 11, // left
12, 13, 14, 12, 14, 15, // right
16, 17, 18, 16, 18, 19, // top
20, 21, 22, 20, 22, 23 // bottom
]);

// 定义立方体的顶点位置
this.positions = new Float32Array([
// Front 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,
-1, 1, -1, 1,

// Left 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,

// Top face
-1, 1, -1, 1,
-1, 1, 1, 1,
1, 1, 1, 1,
1, 1, -1, 1,

// Bottom face
-1, -1, -1, 1,
-1, -1, 1, 1,
1, -1, 1, 1,
1, -1, -1, 1,
]);

// Normals
this.normals = new Float32Array([
// Front face
0, 0, 1, 0,
0, 0, 1, 0,
0, 0, 1, 0,
0, 0, 1, 0,

// Back face
0, 0, -1, 0,
0, 0, -1, 0,
0, 0, -1, 0,
0, 0, -1, 0,

// Left face
-1, 0, 0, 0,
-1, 0, 0, 0,
-1, 0, 0, 0,
-1, 0, 0, 0,

// Right face
1, 0, 0, 0,
1, 0, 0, 0,
1, 0, 0, 0,
1, 0, 0, 0,

// Top face
0, 1, 0, 0,
0, 1, 0, 0,
0, 1, 0, 0,
0, 1, 0, 0,

// Bottom face
0, -1, 0, 0,
0, -1, 0, 0,
0, -1, 0, 0,
0, -1, 0, 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;
29 changes: 23 additions & 6 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ 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,21 @@ import ShaderProgram, {Shader} from './rendering/gl/ShaderProgram';
const controls = {
tesselations: 5,
'Load Scene': loadScene, // A function pointer, essentially
color: [255, 0, 0],
};

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

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() {
Expand All @@ -37,8 +42,10 @@ function main() {

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

// get canvas and webgl context
const canvas = <HTMLCanvasElement> document.getElementById('canvas');
Expand All @@ -60,8 +67,10 @@ function main() {
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')),
// new Shader(gl.VERTEX_SHADER, require('./shaders/lambert-vert.glsl')),
// new Shader(gl.FRAGMENT_SHADER, require('./shaders/lambert-frag.glsl')),
new Shader(gl.VERTEX_SHADER, require('./shaders/custom-noise-vert.glsl')),
new Shader(gl.FRAGMENT_SHADER, require('./shaders/custom-noise-frag.glsl')),
]);

// This function will be called every frame
Expand All @@ -76,10 +85,18 @@ function main() {
icosphere = new Icosphere(vec3.fromValues(0, 0, 0), 1, prevTesselations);
icosphere.create();
}

const colorVec = vec3.fromValues(
controls.color[0] / 255, // Normalize to [0, 1]
controls.color[1] / 255,
controls.color[2] / 255,
);

renderer.render(camera, lambert, [
icosphere,
// square,
]);
//icosphere,
//square,
cube,
], colorVec);
stats.end();

// Tell the browser to call `tick` again whenever it renders a new frame
Expand Down
12 changes: 7 additions & 5 deletions src/rendering/gl/OpenGLRenderer.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {mat4, vec4} from 'gl-matrix';
import {mat4, vec4, vec3} from 'gl-matrix';
import Drawable from './Drawable';
import Camera from '../../Camera';
import {gl} from '../../globals';
Expand All @@ -22,17 +22,19 @@ 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>, colorVec: vec3) {
let model = mat4.create();
let viewProj = mat4.create();
let color = vec4.fromValues(1, 0, 0, 1);

//let color = vec4.fromValues(1, 1, 0, 1);
let color = vec4.fromValues(colorVec[0], colorVec[1], colorVec[2], 1.0);
mat4.identity(model);
mat4.multiply(viewProj, camera.projectionMatrix, camera.viewMatrix);
prog.setModelMatrix(model);
prog.setViewProjMatrix(viewProj);
prog.setGeometryColor(color);

const time = performance.now()/ 10;
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 @@ -85,6 +87,13 @@ class ShaderProgram {
}
}

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

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

Expand Down
89 changes: 89 additions & 0 deletions src/shaders/custom-noise-frag.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#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;

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.


vec3 random3(vec3 gridPoint) {
float sinX = sin(gridPoint.x * 12.9898 + gridPoint.y * 78.233 + gridPoint.z * 54.578) * 43758.5453;
float sinY = sin(gridPoint.y * 12.9898 + gridPoint.x * 78.233 + gridPoint.z * 54.578) * 43758.5453;
float sinZ = sin(gridPoint.z * 12.9898 + gridPoint.y * 78.233 + gridPoint.x * 54.578) * 43758.5453;

return fract(vec3(sinX, sinY, sinZ));
}


vec3 custom_pow(vec3 v, float exponent) {
return vec3(pow(v.x, exponent), pow(v.y, exponent), pow(v.z, exponent));
}


float surflet3D(vec3 p, vec3 gridPoint) {
vec3 t2 = abs(p - gridPoint);

vec3 t = vec3(1.0) - 6.0 * custom_pow(t2, 5.0) + 15.0 * custom_pow(t2, 4.0) - 10.0 * custom_pow(t2, 3.0);

vec3 gradient = normalize(random3(gridPoint) * 2.0 - vec3(1.0));

vec3 diff = p - gridPoint;

float height = dot(diff, gradient);

return height * t.x * t.y * t.z;
}


float perlinNoise3D(vec3 p) {
float surfletSum = 0.0;
for (int dx = 0; dx <= 1; ++dx) {
for (int dy = 0; dy <= 1; ++dy) {
for (int dz = 0; dz <= 1; ++dz) {
vec3 gridPoint = floor(p) + vec3(float(dx), float(dy), float(dz));
surfletSum += surflet3D(p, gridPoint);
}
}
}

return surfletSum;
}


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

// Calculate the diffuse term for Lambert shading
float diffuseTerm = dot(normalize(fs_Nor), normalize(fs_LightVec));

float ambientTerm = 0.3;

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.

diffuseColor.rgb = mix(diffuseColor.rgb, vec3(0.0, 0.0, 0.0), perlinNoise3D(diffuseColor.rgb * 0.1 + u_Time * 0.005));

// Compute final shaded color
out_Col = vec4(diffuseColor.rgb * lightIntensity, diffuseColor.a);
}
Loading