diff --git a/.vs/ProjectSettings.json b/.vs/ProjectSettings.json new file mode 100644 index 0000000..f8b4888 --- /dev/null +++ b/.vs/ProjectSettings.json @@ -0,0 +1,3 @@ +{ + "CurrentProjectSetting": null +} \ No newline at end of file diff --git a/.vs/VSWorkspaceState.json b/.vs/VSWorkspaceState.json new file mode 100644 index 0000000..aee516a --- /dev/null +++ b/.vs/VSWorkspaceState.json @@ -0,0 +1,12 @@ +{ + "ExpandedNodes": [ + "", + "\\src", + "\\src\\geometry", + "\\src\\rendering", + "\\src\\rendering\\gl", + "\\src\\shaders" + ], + "SelectedNode": "\\src\\shaders\\lambert-vert.glsl", + "PreviewInSolutionExplorer": false +} \ No newline at end of file diff --git a/.vs/hw00-webgl-intro/v16/.suo b/.vs/hw00-webgl-intro/v16/.suo new file mode 100644 index 0000000..3be2a0b Binary files /dev/null and b/.vs/hw00-webgl-intro/v16/.suo differ diff --git a/.vs/slnx.sqlite b/.vs/slnx.sqlite new file mode 100644 index 0000000..a486bab Binary files /dev/null and b/.vs/slnx.sqlite differ diff --git a/README.md b/README.md index c636328..f7c879e 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,16 @@ # HW 0: Noisy Planet Part 1 (Intro to Javascript and WebGL) +Description: +I implemented the dat.gui. +I used fractal brownian motion as the noise function to paint some procedural color on all geometries. Also, the fbm moves over time. +The geometries are changing size as well as changing position over time. + +Screenshot: +![](./mySS.png) + +Live Demo Link: +https://hli605.github.io/hw00-webgl-intro/ +

diff --git a/mySS.png b/mySS.png new file mode 100644 index 0000000..70e1cf4 Binary files /dev/null and b/mySS.png differ diff --git a/src/geometry/Cube.ts b/src/geometry/Cube.ts new file mode 100644 index 0000000..24bf111 --- /dev/null +++ b/src/geometry/Cube.ts @@ -0,0 +1,134 @@ +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(); + this.center = vec4.fromValues(center[0], center[1], center[2], 1); + } + + create() { + // array of vertex indices + 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 + ]); + + // array of vertex normals + 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, + + 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, 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, 0, + 0, -1, 0, 0 + ]); + + // array of vertex positions + this.positions = new Float32Array([ + 0.5, 0.5, 0.5, 1.0, + 0.5, -0.5, 0.5, 1.0, + -0.5, -0.5, 0.5, 1.0, + -0.5, 0.5, 0.5, 1.0, + + -0.5, 0.5, -0.5, 1.0, + -0.5, -0.5, -0.5, 1.0, + 0.5, -0.5, -0.5, 1.0, + 0.5, 0.5, -0.5, 1.0, + + 0.5, 0.5, -0.5, 1.0, + 0.5, -0.5, -0.5, 1.0, + 0.5, -0.5, 0.5, 1.0, + 0.5, 0.5, 0.5, 1.0, + + -0.5, 0.5, 0.5, 1.0, + -0.5, -0.5, 0.5, 1.0, + -0.5, -0.5, -0.5, 1.0, + -0.5, 0.5, -0.5, 1.0, + + 0.5, 0.5, -0.5, 1.0, + 0.5, 0.5, 0.5, 1.0, + -0.5, 0.5, 0.5, 1.0, + -0.5, 0.5, -0.5, 1.0, + + 0.5, -0.5, 0.5, 1.0, + 0.5, -0.5, -0.5, 1.0, + -0.5, -0.5, -0.5, 1.0, + -0.5, -0.5, 0.5, 1.0 + ]); + + for (let i = 0; i < this.positions.length; i++) { + if (i % 4 == 0) { + this.positions[i] += this.center[0]; + } + else if (i % 4 == 1) { + this.positions[i] += this.center[1]; + } + else if (i % 4 == 2) { + this.positions[i] += this.center[2]; + } + } + + 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..0f09134 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,103 +1,132 @@ -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'; -import ShaderProgram, {Shader} from './rendering/gl/ShaderProgram'; +import { setGL } from './globals'; +import ShaderProgram, { Shader } from './rendering/gl/ShaderProgram'; // 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 + Color: [0, 255, 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(); + icosphere = new Icosphere(vec3.fromValues(0, 3, 0), 1, controls.tesselations); + icosphere.create(); + square = new Square(vec3.fromValues(0, 0, 0)); + square.create(); + cube = new Cube(vec3.fromValues(3, 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 = document.getElementById('canvas'); - const gl = 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')), - ]); - - // 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(); + // 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'); + gui.addColor(controls, 'Color').onChange(setAllGeometryColor); + + // get canvas and webgl context + const canvas = document.getElementById('canvas'); + const gl = canvas.getContext('webgl2'); + if (!gl) { + alert('WebGL 2 not supported!'); } - renderer.render(camera, lambert, [ - icosphere, - // square, + // `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')), ]); - stats.end(); + lambert.setGeometryColor(vec4.fromValues(0, 1, 0, 1)); - // Tell the browser to call `tick` again whenever it renders a new frame - requestAnimationFrame(tick); - } + const custom = new ShaderProgram([ + new Shader(gl.VERTEX_SHADER, require('./shaders/custom-vert.glsl')), + new Shader(gl.FRAGMENT_SHADER, require('./shaders/custom-frag.glsl')), + ]); + custom.setGeometryColor(vec4.fromValues(0, 1, 0, 1)); + + // 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(); + } + + // Render with custom shader + renderer.render(camera, custom, [ + icosphere, + square, + cube, + ]); + + // Render with Lambert shader + //renderer.render(camera, lambert, [ + // icosphere, + // square, + // cube, + //]); + + 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); - 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(); + // Help function + function setAllGeometryColor() { + lambert.setGeometryColor(vec4.fromValues(controls.Color[0] / 255.0, controls.Color[1] / 255.0, controls.Color[2] / 255.0, 1)); + custom.setGeometryColor(vec4.fromValues(controls.Color[0] / 255.0, controls.Color[1] / 255.0, controls.Color[2] / 255.0, 1)); + } } main(); diff --git a/src/rendering/gl/OpenGLRenderer.ts b/src/rendering/gl/OpenGLRenderer.ts index 7e527c2..2e2e45d 100644 --- a/src/rendering/gl/OpenGLRenderer.ts +++ b/src/rendering/gl/OpenGLRenderer.ts @@ -1,42 +1,45 @@ -import {mat4, vec4} from 'gl-matrix'; +import { mat4, vec4 } from 'gl-matrix'; import Drawable from './Drawable'; import Camera from '../../Camera'; -import {gl} from '../../globals'; +import { gl } from '../../globals'; import ShaderProgram from './ShaderProgram'; // In this file, `gl` is accessible because it is imported above class OpenGLRenderer { - constructor(public canvas: HTMLCanvasElement) { - } - - setClearColor(r: number, g: number, b: number, a: number) { - gl.clearColor(r, g, b, a); - } - - setSize(width: number, height: number) { - this.canvas.width = width; - this.canvas.height = height; - } - - clear() { - gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); - } - - render(camera: Camera, prog: ShaderProgram, drawables: Array) { - 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); - - for (let drawable of drawables) { - prog.draw(drawable); + time: number; + + constructor(public canvas: HTMLCanvasElement) { + this.time = 0.0; + } + + setClearColor(r: number, g: number, b: number, a: number) { + gl.clearColor(r, g, b, a); + } + + setSize(width: number, height: number) { + this.canvas.width = width; + this.canvas.height = height; + } + + clear() { + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); + } + + render(camera: Camera, prog: ShaderProgram, drawables: Array) { + let model = mat4.create(); + let viewProj = mat4.create(); + + mat4.identity(model); + mat4.multiply(viewProj, camera.projectionMatrix, camera.viewMatrix); + prog.setModelMatrix(model); + prog.setViewProjMatrix(viewProj); + prog.setTime(this.time); + this.time += 0.01; + + for (let drawable of drawables) { + prog.draw(drawable); + } } - } }; export default OpenGLRenderer; diff --git a/src/rendering/gl/ShaderProgram.ts b/src/rendering/gl/ShaderProgram.ts index 67fef40..c2f634e 100644 --- a/src/rendering/gl/ShaderProgram.ts +++ b/src/rendering/gl/ShaderProgram.ts @@ -1,109 +1,118 @@ -import {vec4, mat4} from 'gl-matrix'; +import { vec4, mat4 } from 'gl-matrix'; import Drawable from './Drawable'; -import {gl} from '../../globals'; +import { gl } from '../../globals'; var activeProgram: WebGLProgram = null; export class Shader { - shader: WebGLShader; + shader: WebGLShader; - constructor(type: number, source: string) { - this.shader = gl.createShader(type); - gl.shaderSource(this.shader, source); - gl.compileShader(this.shader); + constructor(type: number, source: string) { + this.shader = gl.createShader(type); + gl.shaderSource(this.shader, source); + gl.compileShader(this.shader); - if (!gl.getShaderParameter(this.shader, gl.COMPILE_STATUS)) { - throw gl.getShaderInfoLog(this.shader); + if (!gl.getShaderParameter(this.shader, gl.COMPILE_STATUS)) { + throw gl.getShaderInfoLog(this.shader); + } } - } }; class ShaderProgram { - prog: WebGLProgram; - - attrPos: number; - attrNor: number; - attrCol: number; - - unifModel: WebGLUniformLocation; - unifModelInvTr: WebGLUniformLocation; - unifViewProj: WebGLUniformLocation; - unifColor: WebGLUniformLocation; - - constructor(shaders: Array) { - this.prog = gl.createProgram(); - - for (let shader of shaders) { - gl.attachShader(this.prog, shader.shader); - } - gl.linkProgram(this.prog); - if (!gl.getProgramParameter(this.prog, gl.LINK_STATUS)) { - throw gl.getProgramInfoLog(this.prog); + prog: WebGLProgram; + + attrPos: number; + attrNor: number; + attrCol: number; + + unifModel: WebGLUniformLocation; + unifModelInvTr: WebGLUniformLocation; + unifViewProj: WebGLUniformLocation; + unifColor: WebGLUniformLocation; + unifTime: WebGLUniformLocation; + + constructor(shaders: Array) { + this.prog = gl.createProgram(); + + for (let shader of shaders) { + gl.attachShader(this.prog, shader.shader); + } + gl.linkProgram(this.prog); + if (!gl.getProgramParameter(this.prog, gl.LINK_STATUS)) { + throw gl.getProgramInfoLog(this.prog); + } + + this.attrPos = gl.getAttribLocation(this.prog, "vs_Pos"); + this.attrNor = gl.getAttribLocation(this.prog, "vs_Nor"); + this.attrCol = gl.getAttribLocation(this.prog, "vs_Col"); + this.unifModel = gl.getUniformLocation(this.prog, "u_Model"); + 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"); } - this.attrPos = gl.getAttribLocation(this.prog, "vs_Pos"); - this.attrNor = gl.getAttribLocation(this.prog, "vs_Nor"); - this.attrCol = gl.getAttribLocation(this.prog, "vs_Col"); - this.unifModel = gl.getUniformLocation(this.prog, "u_Model"); - this.unifModelInvTr = gl.getUniformLocation(this.prog, "u_ModelInvTr"); - this.unifViewProj = gl.getUniformLocation(this.prog, "u_ViewProj"); - this.unifColor = gl.getUniformLocation(this.prog, "u_Color"); - } - - use() { - if (activeProgram !== this.prog) { - gl.useProgram(this.prog); - activeProgram = this.prog; + use() { + if (activeProgram !== this.prog) { + gl.useProgram(this.prog); + activeProgram = this.prog; + } } - } - setModelMatrix(model: mat4) { - this.use(); - if (this.unifModel !== -1) { - gl.uniformMatrix4fv(this.unifModel, false, model); + setModelMatrix(model: mat4) { + this.use(); + if (this.unifModel !== -1) { + gl.uniformMatrix4fv(this.unifModel, false, model); + } + + if (this.unifModelInvTr !== -1) { + let modelinvtr: mat4 = mat4.create(); + mat4.transpose(modelinvtr, model); + mat4.invert(modelinvtr, modelinvtr); + gl.uniformMatrix4fv(this.unifModelInvTr, false, modelinvtr); + } } - if (this.unifModelInvTr !== -1) { - let modelinvtr: mat4 = mat4.create(); - mat4.transpose(modelinvtr, model); - mat4.invert(modelinvtr, modelinvtr); - gl.uniformMatrix4fv(this.unifModelInvTr, false, modelinvtr); + setViewProjMatrix(vp: mat4) { + this.use(); + if (this.unifViewProj !== -1) { + gl.uniformMatrix4fv(this.unifViewProj, false, vp); + } } - } - setViewProjMatrix(vp: mat4) { - this.use(); - if (this.unifViewProj !== -1) { - gl.uniformMatrix4fv(this.unifViewProj, false, vp); + setGeometryColor(color: vec4) { + this.use(); + if (this.unifColor !== -1) { + gl.uniform4fv(this.unifColor, color); + } } - } - setGeometryColor(color: vec4) { - this.use(); - if (this.unifColor !== -1) { - gl.uniform4fv(this.unifColor, color); + setTime(time: number) { + this.use(); + if (this.unifTime !== -1) { + gl.uniform1f(this.unifTime, time); + } } - } - draw(d: Drawable) { - this.use(); + draw(d: Drawable) { + this.use(); - if (this.attrPos != -1 && d.bindPos()) { - gl.enableVertexAttribArray(this.attrPos); - gl.vertexAttribPointer(this.attrPos, 4, gl.FLOAT, false, 0, 0); - } + if (this.attrPos != -1 && d.bindPos()) { + gl.enableVertexAttribArray(this.attrPos); + gl.vertexAttribPointer(this.attrPos, 4, gl.FLOAT, false, 0, 0); + } - if (this.attrNor != -1 && d.bindNor()) { - gl.enableVertexAttribArray(this.attrNor); - gl.vertexAttribPointer(this.attrNor, 4, gl.FLOAT, false, 0, 0); - } + if (this.attrNor != -1 && d.bindNor()) { + gl.enableVertexAttribArray(this.attrNor); + gl.vertexAttribPointer(this.attrNor, 4, gl.FLOAT, false, 0, 0); + } - d.bindIdx(); - gl.drawElements(d.drawMode(), d.elemCount(), gl.UNSIGNED_INT, 0); + d.bindIdx(); + gl.drawElements(d.drawMode(), d.elemCount(), gl.UNSIGNED_INT, 0); - if (this.attrPos != -1) gl.disableVertexAttribArray(this.attrPos); - if (this.attrNor != -1) gl.disableVertexAttribArray(this.attrNor); - } + if (this.attrPos != -1) gl.disableVertexAttribArray(this.attrPos); + if (this.attrNor != -1) gl.disableVertexAttribArray(this.attrNor); + } }; export default ShaderProgram; diff --git a/src/shaders/custom-frag.glsl b/src/shaders/custom-frag.glsl new file mode 100644 index 0000000..bd7d6da --- /dev/null +++ b/src/shaders/custom-frag.glsl @@ -0,0 +1,69 @@ +#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. + +vec4 random(vec4 x){ + return fract(sin((x * 50.0) + 35.0)) * x; +} + +// Refer to a simple noise function online +float noise(vec3 pos){ + vec3 i = floor(pos); + vec3 f = fract(pos); + f = f * f * (3.0 - 2.0 * f); + + vec4 a = i.xxyy + vec4(0.0, 1.0, 0.0, 1.0); + vec4 k1 = random(a.xyxy); + vec4 k2 = random(k1.xyxy + a.zzww); + vec4 b = k2 + i.zzzz; + vec4 k3 = random(b); + vec4 k4 = random(b + 1.0); + + vec4 o1 = fract(k3 * (1.0 / 41.0)); + vec4 o2 = fract(k4 * (1.0 / 41.0)); + vec4 o3 = o2 * f.z + o1 * (1.0 - f.z); + vec2 o4 = o3.yw * f.x + o3.xz * (1.0 - f.x); + + return o4.y * f.y + o4.x * (1.0 - f.y); +} + +float fbm(vec3 pos) { + float noiseOutput = 0.0; + float amplitude = 0.5; + for (int i = 0; i < 6; i++) { + noiseOutput += amplitude * noise(pos); + pos = 2.5 * pos + vec3(10, 20, 30); + amplitude *= 0.5; + } + return noiseOutput; +} + +void main() +{ + vec3 color = vec3(1, 0.5, 0.3); + color = mix(color, u_Color.rgb, fbm(fs_Pos.xyz + vec3(u_Time))); + + out_Col = vec4(color.rgb, 1); +} diff --git a/src/shaders/custom-vert.glsl b/src/shaders/custom-vert.glsl new file mode 100644 index 0000000..9cf423d --- /dev/null +++ b/src/shaders/custom-vert.glsl @@ -0,0 +1,57 @@ +#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 float 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. + +void main() +{ + fs_Col = vs_Col; // Pass the vertex colors to the fragment shader for interpolation + + mat3 invTranspose = mat3(u_ModelInvTr); + fs_Nor = vec4(invTranspose * vec3(vs_Nor), 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; + fs_Pos = modelposition; + + modelposition = abs(sin(u_Time)) * modelposition + 0.5 * cos(2.0 * u_Time); + + fs_LightVec = lightPos - modelposition; // Compute the direction in which the light source lies + + gl_Position = u_ViewProj * modelposition;// gl_Position is a built-in variable of OpenGL which is + // used to render the final positions of the geometry's vertices +}