From 891d825285a7fb27c914d0ada64c0e169c8eef64 Mon Sep 17 00:00:00 2001 From: Sharon Dong Date: Fri, 10 Sep 2021 14:49:07 -0400 Subject: [PATCH 01/15] create cube and add color to gui --- src/geometry/Cube.ts | 91 ++++++++++++++++++++++++++++++ src/main.ts | 15 ++++- src/rendering/gl/OpenGLRenderer.ts | 6 +- 3 files changed, 106 insertions(+), 6 deletions(-) create mode 100644 src/geometry/Cube.ts diff --git a/src/geometry/Cube.ts b/src/geometry/Cube.ts new file mode 100644 index 0000000..e11e741 --- /dev/null +++ b/src/geometry/Cube.ts @@ -0,0 +1,91 @@ +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() { + this.indices = new Uint32Array([0, 1, 2, 0, 2, 3, //front face + 4, 5, 6, 4, 6, 7, // left face + 8, 9, 10, 8, 10, 11, // back face + 12, 13, 14, 12, 14, 15, // right face + 16, 17, 18, 16, 18, 19, // top face + 20, 21, 22, 20, 22, 23 // bottom face + ]); + 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, // left face + -1, 0, 0, 0, + -1, 0, 0, 0, + -1, 0, 0, 0, + 0, 0, -1, 0, // back 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, + 0, 1, 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, + ]); + 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, // left 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, // 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 + ]); + 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; diff --git a/src/main.ts b/src/main.ts index 65a9461..f45361c 100644 --- a/src/main.ts +++ b/src/main.ts @@ -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'; @@ -17,6 +18,7 @@ const controls = { let icosphere: Icosphere; let square: Square; +let cube: Cube; let prevTesselations: number = 5; function loadScene() { @@ -24,6 +26,8 @@ function loadScene() { icosphere.create(); square = new Square(vec3.fromValues(0, 0, 0)); square.create(); + cube = new Cube(vec3.fromValues(0, 0, 0)); + cube.create(); } function main() { @@ -39,6 +43,10 @@ function main() { const gui = new DAT.GUI(); gui.add(controls, 'tesselations', 0, 8).step(1); gui.add(controls, 'Load Scene'); + var color = { + color: [ 0, 128, 255 ], // RGB array + }; + gui.addColor(color, 'color'); // get canvas and webgl context const canvas = document.getElementById('canvas'); @@ -77,9 +85,10 @@ function main() { icosphere.create(); } renderer.render(camera, lambert, [ - icosphere, - // square, - ]); + //icosphere, + //square, + cube + ], color.color); stats.end(); // Tell the browser to call `tick` again whenever it renders a new frame diff --git a/src/rendering/gl/OpenGLRenderer.ts b/src/rendering/gl/OpenGLRenderer.ts index 7e527c2..1a8d3b4 100644 --- a/src/rendering/gl/OpenGLRenderer.ts +++ b/src/rendering/gl/OpenGLRenderer.ts @@ -22,16 +22,16 @@ 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, color: Array) { let model = mat4.create(); let viewProj = mat4.create(); - let color = vec4.fromValues(1, 0, 0, 1); + //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.setGeometryColor(vec4.fromValues(color[0]/255, color[1]/255, color[2]/255, 1)); for (let drawable of drawables) { prog.draw(drawable); From a4ae8b3e0b8ef35ce96e8df973153774ccf84319 Mon Sep 17 00:00:00 2001 From: Sharon Dong Date: Mon, 13 Sep 2021 12:47:21 -0400 Subject: [PATCH 02/15] added noise --- src/main.ts | 6 ++- src/shaders/lambert-frag.glsl | 2 +- src/shaders/noise-frag.glsl | 70 +++++++++++++++++++++++++++++++++++ src/shaders/noise-vert.glsl | 35 ++++++++++++++++++ 4 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 src/shaders/noise-frag.glsl create mode 100644 src/shaders/noise-vert.glsl diff --git a/src/main.ts b/src/main.ts index f45361c..6b9b8d2 100644 --- a/src/main.ts +++ b/src/main.ts @@ -71,6 +71,10 @@ function main() { new Shader(gl.VERTEX_SHADER, require('./shaders/lambert-vert.glsl')), new Shader(gl.FRAGMENT_SHADER, require('./shaders/lambert-frag.glsl')), ]); + const noise = new ShaderProgram([ + new Shader(gl.VERTEX_SHADER, require('./shaders/noise-vert.glsl')), + new Shader(gl.FRAGMENT_SHADER, require('./shaders/noise-frag.glsl')), + ]); // This function will be called every frame function tick() { @@ -84,7 +88,7 @@ function main() { icosphere = new Icosphere(vec3.fromValues(0, 0, 0), 1, prevTesselations); icosphere.create(); } - renderer.render(camera, lambert, [ + renderer.render(camera, noise, [ //icosphere, //square, cube diff --git a/src/shaders/lambert-frag.glsl b/src/shaders/lambert-frag.glsl index 2b8e11b..10bb4ff 100644 --- a/src/shaders/lambert-frag.glsl +++ b/src/shaders/lambert-frag.glsl @@ -30,7 +30,7 @@ void main() // Calculate the diffuse term for Lambert shading float diffuseTerm = dot(normalize(fs_Nor), normalize(fs_LightVec)); // Avoid negative lighting values - // diffuseTerm = clamp(diffuseTerm, 0, 1); + diffuseTerm = clamp(diffuseTerm, 0.f, 1.f); float ambientTerm = 0.2; diff --git a/src/shaders/noise-frag.glsl b/src/shaders/noise-frag.glsl new file mode 100644 index 0000000..2f8d7c4 --- /dev/null +++ b/src/shaders/noise-frag.glsl @@ -0,0 +1,70 @@ +#version 300 es + +precision highp float; + +uniform vec4 u_Color; + +in vec4 fs_Pos; +in vec4 fs_Nor; +in vec4 fs_LightVec; +in vec4 fs_Col; + +out vec4 out_Col; + +// Returns random vec3 in range [0, 1] +vec3 random3(vec3 p) { + return fract(sin(vec3(dot(p,vec3(127.1, 311.7, 191.999)), + dot(p,vec3(269.5, 183.3, 765.54)), + dot(p, vec3(420.69, 631.2,109.21)))) + *43758.5453); +} + +// Returns a surflet +float surflet(vec3 p, vec3 corner) { + vec3 t = abs(p - corner); + vec3 falloff = vec3(1.f) - 6.f * vec3(pow(t.x, 5.f),pow(t.y, 5.f), pow(t.z, 5.f)) + + 15.f * vec3(pow(t.x, 4.f), pow(t.y, 4.f),pow(t.z, 4.f)) + - 10.f * vec3(pow(t.x, 3.f), pow(t.y, 3.f),pow(t.z, 3.f)); + vec3 gradient = random3(corner) * 2.f - vec3(1.f); + vec3 dist = p - corner; + float dotProd = dot(dist, gradient); + return dotProd * falloff.x * falloff.y * falloff.z; +} + +float perlin(vec3 p) { + float surfletSum = 0.f; + for (int dx = 0; dx <= 1; dx++) { + for (int dy = 0; dy <= 1; dy++) { + for (int dz = 0; dz <= 1; dz++) { + surfletSum += surflet(p, vec3(floor(p.x), floor(p.y), floor(p.z)) + vec3(dx, dy, dz)); + } + } + } + return surfletSum; +} + +void main() +{ + vec4 diffuseColor = u_Color; + + // Calculate the diffuse term for Lambert shading + float diffuseTerm = dot(normalize(fs_Nor), normalize(fs_LightVec)); + // Avoid negative lighting values + diffuseTerm = clamp(diffuseTerm, 0.f, 1.f); + + 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. + float perlinNoise = perlin(vec3(fs_Pos.x, fs_Pos.y, fs_Pos.z)); + vec3 a = vec3(1.000, 0.500, 0.500); + vec3 b = vec3(0.5); + vec3 d = vec3(0.750, 1.000, 0.667); + vec3 c = vec3(0.800, 1.000, 0.333); + vec3 perlinColor = a + b * cos(6.28 * (perlinNoise * 2. * c * diffuseTerm + d)); + + // Compute final shaded color + // out_Col = vec4(diffuseColor.rgb * lightIntensity, diffuseColor.a); + out_Col = vec4(perlinColor.rgb * lightIntensity, diffuseColor.a);; +} diff --git a/src/shaders/noise-vert.glsl b/src/shaders/noise-vert.glsl new file mode 100644 index 0000000..9a92ecd --- /dev/null +++ b/src/shaders/noise-vert.glsl @@ -0,0 +1,35 @@ +#version 300 es + +uniform mat4 u_Model; +uniform mat4 u_ModelInvTr; +uniform mat4 u_ViewProj; +in vec4 vs_Pos; +in vec4 vs_Nor; +in vec4 vs_Col; +out vec4 fs_Pos; +out vec4 fs_Nor; +out vec4 fs_LightVec; +out vec4 fs_Col; + +const vec4 lightPos = vec4(5, 5, 3, 1); + +void main() +{ + fs_Pos = vs_Pos; + 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; // Temporarily store the transformed vertex positions for use below + + 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 +} From 22a93bf0020bc11407652e54009768a50faf2124 Mon Sep 17 00:00:00 2001 From: Sharon Dong Date: Mon, 13 Sep 2021 22:18:50 -0400 Subject: [PATCH 03/15] finished --- src/main.ts | 8 ++-- src/rendering/gl/OpenGLRenderer.ts | 3 +- src/rendering/gl/ShaderProgram.ts | 9 ++++ src/shaders/noise-frag.glsl | 41 ++++++++++++----- src/shaders/noise-vert.glsl | 71 ++++++++++++++++++++---------- 5 files changed, 94 insertions(+), 38 deletions(-) diff --git a/src/main.ts b/src/main.ts index 6b9b8d2..958440b 100644 --- a/src/main.ts +++ b/src/main.ts @@ -20,6 +20,7 @@ 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); @@ -44,7 +45,7 @@ function main() { gui.add(controls, 'tesselations', 0, 8).step(1); gui.add(controls, 'Load Scene'); var color = { - color: [ 0, 128, 255 ], // RGB array + color: [255, 128, 128], // RGB array }; gui.addColor(color, 'color'); @@ -64,7 +65,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(177.0 / 255.0, 204.0 / 255.0, 193.0 / 255.0, 1); gl.enable(gl.DEPTH_TEST); const lambert = new ShaderProgram([ @@ -78,6 +79,7 @@ function main() { // This function will be called every frame function tick() { + time++; camera.update(); stats.begin(); gl.viewport(0, 0, window.innerWidth, window.innerHeight); @@ -92,7 +94,7 @@ function main() { //icosphere, //square, cube - ], color.color); + ], color.color, time); stats.end(); // Tell the browser to call `tick` again whenever it renders a new frame diff --git a/src/rendering/gl/OpenGLRenderer.ts b/src/rendering/gl/OpenGLRenderer.ts index 1a8d3b4..61ced1b 100644 --- a/src/rendering/gl/OpenGLRenderer.ts +++ b/src/rendering/gl/OpenGLRenderer.ts @@ -22,7 +22,7 @@ class OpenGLRenderer { gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); } - render(camera: Camera, prog: ShaderProgram, drawables: Array, color: Array) { + render(camera: Camera, prog: ShaderProgram, drawables: Array, color: Array, time: number) { let model = mat4.create(); let viewProj = mat4.create(); //let color = vec4.fromValues(1, 0, 0, 1); @@ -32,6 +32,7 @@ class OpenGLRenderer { prog.setModelMatrix(model); prog.setViewProjMatrix(viewProj); prog.setGeometryColor(vec4.fromValues(color[0]/255, color[1]/255, color[2]/255, 1)); + prog.setTime(time); for (let drawable of drawables) { prog.draw(drawable); diff --git a/src/rendering/gl/ShaderProgram.ts b/src/rendering/gl/ShaderProgram.ts index 67fef40..78b6385 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,13 @@ class ShaderProgram { } } + setTime(time: number) { + this.use(); + if (this.unifTime !== -1) { + gl.uniform1i(this.unifTime, time); + } + } + draw(d: Drawable) { this.use(); diff --git a/src/shaders/noise-frag.glsl b/src/shaders/noise-frag.glsl index 2f8d7c4..81bbd64 100644 --- a/src/shaders/noise-frag.glsl +++ b/src/shaders/noise-frag.glsl @@ -2,7 +2,8 @@ precision highp float; -uniform vec4 u_Color; +uniform vec4 u_Color; +uniform highp int u_Time; in vec4 fs_Pos; in vec4 fs_Nor; @@ -25,13 +26,14 @@ float surflet(vec3 p, vec3 corner) { vec3 falloff = vec3(1.f) - 6.f * vec3(pow(t.x, 5.f),pow(t.y, 5.f), pow(t.z, 5.f)) + 15.f * vec3(pow(t.x, 4.f), pow(t.y, 4.f),pow(t.z, 4.f)) - 10.f * vec3(pow(t.x, 3.f), pow(t.y, 3.f),pow(t.z, 3.f)); - vec3 gradient = random3(corner) * 2.f - vec3(1.f); + vec3 gradient = random3(corner) * 2.f - vec3(sin(0.02 * float(u_Time)) + 1.f); vec3 dist = p - corner; float dotProd = dot(dist, gradient); return dotProd * falloff.x * falloff.y * falloff.z; } float perlin(vec3 p) { + p = p * 1.5; float surfletSum = 0.f; for (int dx = 0; dx <= 1; dx++) { for (int dy = 0; dy <= 1; dy++) { @@ -43,6 +45,26 @@ float perlin(vec3 p) { return surfletSum; } +float worley(vec3 p) { + p *= 1.5; + vec3 pInt = floor(p); + vec3 pFract = fract(p); + float minDist = 1.0; + for (int x = -1; x <= 1; x++) { + for (int y = -1; y <= 1; y++) { + for (int z = -1; z <= 1; z++) { + vec3 neighbor = vec3(float(x), float(y), float(z)); + vec3 voronoi = random3(pInt + neighbor); + voronoi = 0.5 + 0.5 * sin(0.1 * float(u_Time) + 13.2831 * voronoi); + vec3 diff = neighbor + voronoi - pFract; + float dist = length(diff); + minDist = min(minDist, dist); + } + } + } + return minDist; +} + void main() { vec4 diffuseColor = u_Color; @@ -57,14 +79,13 @@ void main() 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. - float perlinNoise = perlin(vec3(fs_Pos.x, fs_Pos.y, fs_Pos.z)); - vec3 a = vec3(1.000, 0.500, 0.500); - vec3 b = vec3(0.5); - vec3 d = vec3(0.750, 1.000, 0.667); - vec3 c = vec3(0.800, 1.000, 0.333); - vec3 perlinColor = a + b * cos(6.28 * (perlinNoise * 2. * c * diffuseTerm + d)); + float perlinNoise = perlin(vec3(fs_Pos)); + vec3 a = vec3(u_Color); + vec3 b = vec3(0.688, 0.558, 0.500); + vec3 c = vec3(255.0 / 255.0, 244.0 / 255.0, 224.0 / 255.0); + vec3 d = vec3(0.588, -0.342, 0.048); + vec3 perlinColor = a + b * cos(6.28 * worley(vec3(fs_Pos)) * perlinNoise * 4. * c + d); // Compute final shaded color - // out_Col = vec4(diffuseColor.rgb * lightIntensity, diffuseColor.a); - out_Col = vec4(perlinColor.rgb * lightIntensity, diffuseColor.a);; + out_Col = vec4(perlinColor.rgb * lightIntensity, diffuseColor.a); } diff --git a/src/shaders/noise-vert.glsl b/src/shaders/noise-vert.glsl index 9a92ecd..1400804 100644 --- a/src/shaders/noise-vert.glsl +++ b/src/shaders/noise-vert.glsl @@ -1,35 +1,58 @@ #version 300 es -uniform mat4 u_Model; -uniform mat4 u_ModelInvTr; -uniform mat4 u_ViewProj; -in vec4 vs_Pos; -in vec4 vs_Nor; -in vec4 vs_Col; -out vec4 fs_Pos; -out vec4 fs_Nor; -out vec4 fs_LightVec; -out vec4 fs_Col; - -const vec4 lightPos = vec4(5, 5, 3, 1); +//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_Pos; +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. + +const vec4 lightPos = vec4(5, 5, 5, 1); //The position of our virtual light, which is used to compute the shading of + //the geometry in the fragment shader. void main() { - fs_Pos = vs_Pos; - fs_Col = vs_Col; // Pass the vertex colors to the fragment shader for interpolation + 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. + 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; // Temporarily store the transformed vertex positions for use below + vec4 modelposition = u_Model * vs_Pos; // Temporarily store the transformed vertex positions for use below + fs_Pos = modelposition; + + modelposition.x += pow(sin((modelposition.y * 20.f + float(u_Time) * 0.05)), 2.0); + modelposition.y += sin((modelposition.y * 10.f + float(u_Time) * 0.05)); - fs_LightVec = lightPos - modelposition; // Compute the direction in which the light source lies + 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 + 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 } From 4ae2ec6546f855e085843932ed04cf76a3642614 Mon Sep 17 00:00:00 2001 From: Sharon Dong Date: Mon, 13 Sep 2021 22:24:21 -0400 Subject: [PATCH 04/15] test --- src/shaders/noise-vert.glsl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/shaders/noise-vert.glsl b/src/shaders/noise-vert.glsl index 1400804..9d6bf15 100644 --- a/src/shaders/noise-vert.glsl +++ b/src/shaders/noise-vert.glsl @@ -19,6 +19,7 @@ uniform mat4 u_ViewProj; // The matrix that defines the camera's transformati // 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 From 4ccb5a5c6aa59ad952edfce4b06d05f5e0482729 Mon Sep 17 00:00:00 2001 From: sharond106 <47503431+sharond106@users.noreply.github.com> Date: Mon, 13 Sep 2021 22:54:03 -0400 Subject: [PATCH 05/15] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index c636328..44a3023 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ # HW 0: Noisy Planet Part 1 (Intro to Javascript and WebGL) +Link: [https://sharond106.github.io/hw00-webgl-intro/](https://sharond106.github.io/hw00-webgl-intro/) -

- -

-

(source: Ken Perlin)

+The fragment shader is implemented with 3D perlin and worley noise, both displaced with time. You can change one of the base colors using the color picker in the gui on the top right. The vertex shader displaces x and y coordinates with a sin function over time. + +![Alt Text](https://media.giphy.com/media/MXjh2U0hGcgwJuGp27/giphy.gif?cid=790b761104e45ac8167ff98bc109ed47be8e78d0f975ffac&rid=giphy.gif&ct=g) ## Objective - Check that the tools and build configuration we will be using for the class works. From 3c177b28fbc45b25e6811b62db28bd48bff04c76 Mon Sep 17 00:00:00 2001 From: Sharon Dong Date: Sun, 19 Sep 2021 15:54:19 -0400 Subject: [PATCH 06/15] perlin and worley terrain --- src/main.ts | 18 ++-- src/shaders/planet-frag.glsl | 44 ++++++++++ src/shaders/planet-vert.glsl | 165 +++++++++++++++++++++++++++++++++++ src/shaders/test-frag.glsl | 98 +++++++++++++++++++++ src/shaders/test-vert.glsl | 55 ++++++++++++ 5 files changed, 375 insertions(+), 5 deletions(-) create mode 100644 src/shaders/planet-frag.glsl create mode 100644 src/shaders/planet-vert.glsl create mode 100644 src/shaders/test-frag.glsl create mode 100644 src/shaders/test-vert.glsl diff --git a/src/main.ts b/src/main.ts index 958440b..e766cd8 100644 --- a/src/main.ts +++ b/src/main.ts @@ -12,7 +12,7 @@ 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, + tesselations: 6, 'Load Scene': loadScene, // A function pointer, essentially }; @@ -62,7 +62,7 @@ function main() { // Initial call to load scene loadScene(); - const camera = new Camera(vec3.fromValues(0, 0, 5), vec3.fromValues(0, 0, 0)); + const camera = new Camera(vec3.fromValues(0, 0, 3), vec3.fromValues(0, 0, 0)); const renderer = new OpenGLRenderer(canvas); renderer.setClearColor(177.0 / 255.0, 204.0 / 255.0, 193.0 / 255.0, 1); @@ -76,6 +76,14 @@ function main() { new Shader(gl.VERTEX_SHADER, require('./shaders/noise-vert.glsl')), new Shader(gl.FRAGMENT_SHADER, require('./shaders/noise-frag.glsl')), ]); + const planet = new ShaderProgram([ + new Shader(gl.VERTEX_SHADER, require('./shaders/planet-vert.glsl')), + new Shader(gl.FRAGMENT_SHADER, require('./shaders/planet-frag.glsl')), + ]); + const test = new ShaderProgram([ + new Shader(gl.VERTEX_SHADER, require('./shaders/test-vert.glsl')), + new Shader(gl.FRAGMENT_SHADER, require('./shaders/test-frag.glsl')), + ]); // This function will be called every frame function tick() { @@ -90,10 +98,10 @@ function main() { icosphere = new Icosphere(vec3.fromValues(0, 0, 0), 1, prevTesselations); icosphere.create(); } - renderer.render(camera, noise, [ - //icosphere, + renderer.render(camera, planet, [ + icosphere, //square, - cube + //cube ], color.color, time); stats.end(); diff --git a/src/shaders/planet-frag.glsl b/src/shaders/planet-frag.glsl new file mode 100644 index 0000000..85b5a17 --- /dev/null +++ b/src/shaders/planet-frag.glsl @@ -0,0 +1,44 @@ +#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. + +// 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_Pos; +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. + +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)); + // Avoid negative lighting values + diffuseTerm = clamp(diffuseTerm, 0.f, 1.f); + + 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/planet-vert.glsl b/src/shaders/planet-vert.glsl new file mode 100644 index 0000000..de64dbf --- /dev/null +++ b/src/shaders/planet-vert.glsl @@ -0,0 +1,165 @@ +#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 + +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_Pos; +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. + +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. + +// Returns random vec3 in range [0, 1] +vec3 random3(vec3 p) { + return fract(sin(vec3(dot(p,vec3(127.1, 311.7, 191.999)), + dot(p,vec3(269.5, 183.3, 765.54)), + dot(p, vec3(420.69, 631.2,109.21)))) + *43758.5453); +} + +vec3 bias(vec3 b, float t) { + return vec3(pow(t, log(b.x) / log(0.5)), pow(t, log(b.y) / log(0.5)), pow(t, log(b.z) / log(0.5))); +} + +vec3 gain(vec3 g, float t) { + if (t < 0.5) { + return bias(vec3(1.0) - g, 2.0 * t) / 2.0; + } else { + return vec3(1.0) - bias(vec3(1.0) - g, 2.0 - 2.0 * t) / 2.0; + } +} + +// Returns a surflet +float surflet(vec3 p, vec3 corner) { + vec3 t = abs(p - corner); + vec3 falloff = vec3(1.f) - 6.f * vec3(pow(t.x, 5.f),pow(t.y, 5.f), pow(t.z, 5.f)) + + 15.f * vec3(pow(t.x, 4.f), pow(t.y, 4.f),pow(t.z, 4.f)) + - 10.f * vec3(pow(t.x, 3.f), pow(t.y, 3.f),pow(t.z, 3.f)); + falloff = vec3(1.0) - 3.f * vec3(pow(t.x, 2.f),pow(t.y, 2.f), pow(t.z, 2.f)) + + 2.f * vec3(pow(t.x, 3.f), pow(t.y, 3.f),pow(t.z, 3.f)); + falloff = vec3(1.0) - t; + //falloff = vec3(1.f) - gain(t, .5); + vec3 gradient = random3(corner); + vec3 dist = p - corner; + float dotProd = dot(dist, gradient); + return dotProd * falloff.x * falloff.y * falloff.z; +} + +float perlin(vec3 p) { + p = p * 2.5; + float surfletSum = 0.f; + for (int dx = 0; dx <= 1; dx++) { + for (int dy = 0; dy <= 1; dy++) { + for (int dz = 0; dz <= 1; dz++) { + surfletSum += surflet(p, vec3(floor(p.x), floor(p.y), floor(p.z)) + vec3(dx, dy, dz)); + } + } + } + return surfletSum; +} + +float worley(vec3 p) { + p *= 3.5; + vec3 pInt = floor(p); + vec3 pFract = fract(p); + float minDist = 1.0; + float secondDist = 1.0; + for (int x = -1; x <= 1; x++) { + for (int y = -1; y <= 1; y++) { + for (int z = -1; z <= 1; z++) { + vec3 neighbor = vec3(float(x), float(y), float(z)); + vec3 voronoi = random3(pInt + neighbor); + vec3 diff = neighbor + voronoi - pFract; + float dist = length(diff); + if (dist < minDist) { + secondDist = minDist; + minDist = dist; + } else if (dist < secondDist) { + secondDist = dist; + } + //minDist = min(minDist, dist); + } + } + } + return -1. * minDist + 1. * secondDist; +} + +vec4 offsetPos(vec4 pos) { + vec3 offset = vec3(worley(vec3(pos))) / vec3(2.0); // Can divide by different factors or not at all for plateus!!!!!!!!!!!!!! + + offset.x = clamp(offset.x, 0.1, .4); // Can change these values!!!!!!!!!!!!!!!!!! + offset.y = clamp(offset.y, 0.1, .4); + offset.z = clamp(offset.z, 0.1, .4); + vec4 noise = pos + vs_Nor * vec4(offset + random3(offset) / vec3(50.0), 0); + // Can try subtracting offset!!!!!!!!!!!!!!!!!!!!!!! + // make sure the clamp min is 0 so sphere doesn't shrink + return noise; +} + +void main() +{ + fs_Col = vs_Col; + mat3 invTranspose = mat3(u_ModelInvTr); + fs_Nor = vec4(invTranspose * vec3(vs_Nor), 0); + + vec4 noise = offsetPos(vs_Pos); + float perlin = perlin(vec3(vs_Pos)) + .5 * perlin(2.f * vec3(vs_Pos)) + 0.25 * perlin(4.f * vec3(vs_Pos)); + + //perlin = perlin / (1.f + .5 + .25); // this and next line for valleys + //perlin = pow(perlin, .2); + + vec4 perlinNoise = vs_Pos + vs_Nor * perlin; + + vec4 modelposition = u_Model * perlinNoise; // Temporarily store the transformed vertex positions for use below + fs_Pos = modelposition; + + vec4 xNeg = offsetPos(vs_Pos + vec4(-.0000001, 0, 0, 0)); + vec4 xPos = offsetPos(vs_Pos + vec4(.0000001, 0, 0, 0)); + vec4 xDiff = xPos - xNeg; + vec4 yNeg = offsetPos(vs_Pos + vec4(0, -.0000001, 0, 0)); + vec4 yPos = offsetPos(vs_Pos + vec4(0, .0000001, 0, 0)); + vec4 yDiff = yPos - yNeg; + vec4 zNeg = offsetPos(vs_Pos + vec4(0, 0, -.0000001, 0)); + vec4 zPos = offsetPos(vs_Pos + vec4(0, 0, .0000001, 0)); + vec4 zDiff = zPos - zNeg; + //fs_Nor = normalize(vec4(vec3(xDiff.x, yDiff.y, zDiff.z), 0)); + + vec3 normal = normalize(vec3(xDiff.x, yDiff.y, zDiff.z)); + vec3 tangent = normalize(cross(vec3(0.0, 1.0, 0.0), normal)); + vec3 bitangent = normalize(cross(normal, tangent)); + mat4 transform; + transform[0] = vec4(tangent, 0.0); + transform[1] = vec4(bitangent, 0.0); + transform[2] = vec4(normal, 0.0); + transform[3] = vec4(0.0, 0.0, 0.0, 1.0); + //fs_Nor = vec4(normalize(vec3(transform * vec4(normal, 0.0))), 0.0); + + 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 +} diff --git a/src/shaders/test-frag.glsl b/src/shaders/test-frag.glsl new file mode 100644 index 0000000..c371102 --- /dev/null +++ b/src/shaders/test-frag.glsl @@ -0,0 +1,98 @@ +#version 300 es + +precision highp float; + +uniform vec4 u_Color; +uniform highp int u_Time; + +in vec4 fs_Pos; +in vec4 fs_Nor; +in vec4 fs_LightVec; +in vec4 fs_Col; + +out vec4 out_Col; + +// Returns random vec3 in range [0, 1] +vec3 random3(vec3 p) { + return fract(sin(vec3(dot(p,vec3(127.1, 311.7, 191.999)), + dot(p,vec3(269.5, 183.3, 765.54)), + dot(p, vec3(420.69, 631.2,109.21)))) + *43758.5453); +} + +// Returns a surflet +float surflet(vec3 p, vec3 corner) { + vec3 t = abs(p - corner); + vec3 falloff = vec3(1.f) - 6.f * vec3(pow(t.x, 5.f),pow(t.y, 5.f), pow(t.z, 5.f)) + + 15.f * vec3(pow(t.x, 4.f), pow(t.y, 4.f),pow(t.z, 4.f)) + - 10.f * vec3(pow(t.x, 3.f), pow(t.y, 3.f),pow(t.z, 3.f)); + vec3 gradient = random3(corner); + vec3 dist = p - corner; + float dotProd = dot(dist, gradient); + return dotProd * falloff.x * falloff.y * falloff.z; +} + +float perlin(vec3 p) { + p = p * 2.5; + float surfletSum = 0.f; + for (int dx = 0; dx <= 1; dx++) { + for (int dy = 0; dy <= 1; dy++) { + for (int dz = 0; dz <= 1; dz++) { + surfletSum += surflet(p, vec3(floor(p.x), floor(p.y), floor(p.z)) + vec3(dx, dy, dz)); + } + } + } + return surfletSum; +} + +float worley(vec3 p) { + p *= 1.5; + vec3 pInt = floor(p); + vec3 pFract = fract(p); + float minDist = 1.0; + float secondDist = 1.0; + for (int x = -1; x <= 1; x++) { + for (int y = -1; y <= 1; y++) { + for (int z = -1; z <= 1; z++) { + vec3 neighbor = vec3(float(x), float(y), float(z)); + vec3 voronoi = random3(pInt + neighbor); + //voronoi = 0.5 + 0.5 * sin(0.1 * float(u_Time) + 13.2831 * voronoi); + vec3 diff = neighbor + voronoi - pFract; + float dist = length(diff); + if (dist < minDist) { + secondDist = minDist; + minDist = dist; + } else if (dist < secondDist) { + secondDist = dist; + } + //minDist = min(minDist, dist); + } + } + } + return -1. * minDist + 1. * secondDist; +} + +void main() +{ + vec4 diffuseColor = u_Color; + + // Calculate the diffuse term for Lambert shading + float diffuseTerm = dot(normalize(fs_Nor), normalize(fs_LightVec)); + // Avoid negative lighting values + diffuseTerm = clamp(diffuseTerm, 0.f, 1.f); + + float ambientTerm = 0.4; + + 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. + float perlinNoise = perlin(vec3(fs_Pos)); + vec3 a = vec3(u_Color); + vec3 b = vec3(0.688, 0.558, 0.500); + vec3 c = vec3(255.0 / 255.0, 244.0 / 255.0, 224.0 / 255.0); + vec3 d = vec3(0.588, -0.342, 0.048); + vec3 perlinColor = a + b * cos(6.28 * worley(vec3(fs_Pos)) * perlinNoise * 4. * c + d); + + // Compute final shaded color + out_Col = vec4(vec3(perlinNoise * perlinNoise * perlinNoise), diffuseColor.a); +} diff --git a/src/shaders/test-vert.glsl b/src/shaders/test-vert.glsl new file mode 100644 index 0000000..ddf5a5f --- /dev/null +++ b/src/shaders/test-vert.glsl @@ -0,0 +1,55 @@ +#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 + +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_Pos; +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. + +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; // Temporarily store the transformed vertex positions for use below + fs_Pos = modelposition; + + 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 +} From 3e689b3487dc1b1bf981143567298eefa986eb80 Mon Sep 17 00:00:00 2001 From: Sharon Dong Date: Mon, 20 Sep 2021 23:54:17 -0400 Subject: [PATCH 07/15] added fbm in test and terraces for perlin --- src/main.ts | 6 +-- src/shaders/planet-frag.glsl | 1 + src/shaders/planet-vert.glsl | 102 ++++++++++++++++++++++++----------- src/shaders/test-frag.glsl | 65 ++++++++++++++++++++-- 4 files changed, 136 insertions(+), 38 deletions(-) diff --git a/src/main.ts b/src/main.ts index e766cd8..968a71f 100644 --- a/src/main.ts +++ b/src/main.ts @@ -12,14 +12,14 @@ 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: 6, + tesselations: 8, 'Load Scene': loadScene, // A function pointer, essentially }; let icosphere: Icosphere; let square: Square; let cube: Cube; -let prevTesselations: number = 5; +let prevTesselations: number = 8; let time: number = 0; function loadScene() { @@ -98,7 +98,7 @@ function main() { icosphere = new Icosphere(vec3.fromValues(0, 0, 0), 1, prevTesselations); icosphere.create(); } - renderer.render(camera, planet, [ + renderer.render(camera, test, [ icosphere, //square, //cube diff --git a/src/shaders/planet-frag.glsl b/src/shaders/planet-frag.glsl index 85b5a17..ac24304 100644 --- a/src/shaders/planet-frag.glsl +++ b/src/shaders/planet-frag.glsl @@ -41,4 +41,5 @@ void main() // Compute final shaded color out_Col = vec4(diffuseColor.rgb * lightIntensity, diffuseColor.a); + //out_Col = vec4(abs(fs_Nor.rgb), 1); } diff --git a/src/shaders/planet-vert.glsl b/src/shaders/planet-vert.glsl index de64dbf..717642b 100644 --- a/src/shaders/planet-vert.glsl +++ b/src/shaders/planet-vert.glsl @@ -30,9 +30,16 @@ out vec4 fs_Nor; // The array of normals that has been transformed by 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. -const vec4 lightPos = vec4(5, 5, 3, 1); //The position of our virtual light, which is used to compute the shading of +const vec4 lightPos = vec4(2, 0, 3, 1); //The position of our virtual light, which is used to compute the shading of //the geometry in the fragment shader. +float random1( vec3 p ) { + return fract(sin((dot(p, vec3(127.1, + 311.7, + 191.999)))) * + 43758.5453); +} + // Returns random vec3 in range [0, 1] vec3 random3(vec3 p) { return fract(sin(vec3(dot(p,vec3(127.1, 311.7, 191.999)), @@ -82,6 +89,29 @@ float perlin(vec3 p) { return surfletSum; } +float perlinAdded(vec4 p) { + float noise = perlin(vec3(p)) + .5 * perlin(2.f * vec3(p)) + 0.25 * perlin(4.f * vec3(p)); + //noise = noise / (1.f + .5 + .25); // this and next line for valleys + //noise = pow(noise, .2); + + float terrace = round(noise * 12.f) / 12.f; + noise = mix(noise, terrace, random1(vec3(terrace))); + return noise; +} + +vec4 perlinNormal(vec4 p) { + float xNeg = perlinAdded((p + vec4(-.00001, 0, 0, 0))); + float xPos = perlinAdded((p + vec4(.00001, 0, 0, 0))); + float xDiff = xPos - xNeg; + float yNeg = perlinAdded((p + vec4(0, -.00001, 0, 0))); + float yPos = perlinAdded((p + vec4(0, .00001, 0, 0))); + float yDiff = yPos - yNeg; + float zNeg = perlinAdded((p + vec4(0, 0, -.00001, 0))); + float zPos = perlinAdded((p + vec4(0, 0, .00001, 0))); + float zDiff = zPos - zNeg; + return vec4(vec3(xDiff, yDiff, zDiff), 0); +} + float worley(vec3 p) { p *= 3.5; vec3 pInt = floor(p); @@ -105,19 +135,40 @@ float worley(vec3 p) { } } } - return -1. * minDist + 1. * secondDist; + //return 1.0 - minDist; + return (-1. * minDist + 1. * secondDist); } -vec4 offsetPos(vec4 pos) { - vec3 offset = vec3(worley(vec3(pos))) / vec3(2.0); // Can divide by different factors or not at all for plateus!!!!!!!!!!!!!! +vec4 worleyAdded(vec4 pos) { + vec3 offset = vec3(pow(worley(vec3(pos)), 2.f)) / vec3(3.0); // Can divide by different factors or not at all for plateus!!!!!!!!!!!!!! - offset.x = clamp(offset.x, 0.1, .4); // Can change these values!!!!!!!!!!!!!!!!!! - offset.y = clamp(offset.y, 0.1, .4); - offset.z = clamp(offset.z, 0.1, .4); - vec4 noise = pos + vs_Nor * vec4(offset + random3(offset) / vec3(50.0), 0); - // Can try subtracting offset!!!!!!!!!!!!!!!!!!!!!!! - // make sure the clamp min is 0 so sphere doesn't shrink - return noise; + //offset.x = clamp(offset.x, 0.2, .4); // Can change these values!!!!!!!!!!!!!!!!!! + //offset.y = clamp(offset.y, 0.2, .4); + //offset.z = clamp(offset.z, 0.2, .4); + //offset = offset + random3(offset) / vec3(50.0); + return vec4(offset, 0.); +} + +vec4 worleyNormal(vec4 p) { + float xNeg = worleyAdded((p + vec4(-.00001, 0, 0, 0))).x; + float xPos = worleyAdded((p + vec4(.00001, 0, 0, 0))).x; + float xDiff = (xPos - xNeg); + if (p.x == 0.2) { + xDiff = vs_Nor.x; + } + float yNeg = worleyAdded((p + vec4(0, -.00001, 0, 0))).y; + float yPos = worleyAdded((p + vec4(0, .00001, 0, 0))).y; + float yDiff = (yPos - yNeg); + if (p.y == 0.2) { + yDiff = vs_Nor.y; + } + float zNeg = worleyAdded((p + vec4(0, 0, -.00001, 0))).z; + float zPos = worleyAdded((p + vec4(0, 0, .00001, 0))).z; + float zDiff = (zPos - zNeg); + if (p.z == 0.2) { + zDiff = vs_Nor.z; + } + return (vec4(vec3(xDiff, yDiff, zDiff), 0)); } void main() @@ -126,29 +177,17 @@ void main() mat3 invTranspose = mat3(u_ModelInvTr); fs_Nor = vec4(invTranspose * vec3(vs_Nor), 0); - vec4 noise = offsetPos(vs_Pos); - float perlin = perlin(vec3(vs_Pos)) + .5 * perlin(2.f * vec3(vs_Pos)) + 0.25 * perlin(4.f * vec3(vs_Pos)); - - //perlin = perlin / (1.f + .5 + .25); // this and next line for valleys - //perlin = pow(perlin, .2); - - vec4 perlinNoise = vs_Pos + vs_Nor * perlin; + vec4 worleyNoise = vs_Pos + vs_Nor * worleyAdded(vs_Pos); + vec4 perlinNoise = vs_Pos + vs_Nor * perlinAdded(vs_Pos); - vec4 modelposition = u_Model * perlinNoise; // Temporarily store the transformed vertex positions for use below + vec4 modelposition = u_Model * worleyNoise; + //vec4 modelposition = u_Model * perlinNoise; // Temporarily store the transformed vertex positions for use below fs_Pos = modelposition; - vec4 xNeg = offsetPos(vs_Pos + vec4(-.0000001, 0, 0, 0)); - vec4 xPos = offsetPos(vs_Pos + vec4(.0000001, 0, 0, 0)); - vec4 xDiff = xPos - xNeg; - vec4 yNeg = offsetPos(vs_Pos + vec4(0, -.0000001, 0, 0)); - vec4 yPos = offsetPos(vs_Pos + vec4(0, .0000001, 0, 0)); - vec4 yDiff = yPos - yNeg; - vec4 zNeg = offsetPos(vs_Pos + vec4(0, 0, -.0000001, 0)); - vec4 zPos = offsetPos(vs_Pos + vec4(0, 0, .0000001, 0)); - vec4 zDiff = zPos - zNeg; - //fs_Nor = normalize(vec4(vec3(xDiff.x, yDiff.y, zDiff.z), 0)); - - vec3 normal = normalize(vec3(xDiff.x, yDiff.y, zDiff.z)); + //fs_Nor = normalize(worleyNormal(vs_Pos)); + //fs_Nor = perlinNormal(vs_Pos); + //fs_Nor = vec4(invTranspose * vec3(fs_Nor), 0); + vec3 normal = normalize(normalize(vec3(worleyNormal(vs_Pos)))); vec3 tangent = normalize(cross(vec3(0.0, 1.0, 0.0), normal)); vec3 bitangent = normalize(cross(normal, tangent)); mat4 transform; @@ -159,7 +198,6 @@ void main() //fs_Nor = vec4(normalize(vec3(transform * vec4(normal, 0.0))), 0.0); 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 } diff --git a/src/shaders/test-frag.glsl b/src/shaders/test-frag.glsl index c371102..2c1df06 100644 --- a/src/shaders/test-frag.glsl +++ b/src/shaders/test-frag.glsl @@ -46,7 +46,7 @@ float perlin(vec3 p) { } float worley(vec3 p) { - p *= 1.5; + p *= 1.; vec3 pInt = floor(p); vec3 pFract = fract(p); float minDist = 1.0; @@ -69,7 +69,61 @@ float worley(vec3 p) { } } } - return -1. * minDist + 1. * secondDist; + return 1.0 - minDist; + //return -1. * minDist + 1. * secondDist; +} + +float random1( vec3 p ) { + return fract(sin((dot(p, vec3(127.1, + 311.7, + 191.999)))) * + 28.5453); +} + +float mySmootherStep(float a, float b, float t) { + t = t*t*t*(t*(t*6.0 - 15.0) + 10.0); + return mix(a, b, t); +} + +float interpNoise3D(float x, float y, float z) { + x *= 2.; + y *= 2.; + z *= 2.; + float intX = floor(x); + float fractX = fract(x); + float intY = floor(y); + float fractY = fract(y); + float intZ = floor(z); + float fractZ = fract(z); + float v1 = random1(vec3(intX, intY, intZ)); + float v2 = random1(vec3(intX + 1., intY, intZ)); + float v3 = random1(vec3(intX, intY + 1., intZ)); + float v4 = random1(vec3(intX + 1., intY + 1., intZ)); + + float v5 = random1(vec3(intX, intY, intZ + 1.)); + float v6 = random1(vec3(intX + 1., intY, intZ + 1.)); + float v7 = random1(vec3(intX, intY + 1., intZ + 1.)); + float v8 = random1(vec3(intX + 1., intY + 1., intZ + 1.)); + + float i1 = mySmootherStep(v1, v2, fractX); + float i2 = mySmootherStep(v3, v4, fractX); + float result1 = mySmootherStep(i1, i2, fractY); + float i3 = mySmootherStep(v5, v6, fractX); + float i4 = mySmootherStep(v7, v8, fractX); + float result2 = mySmootherStep(i3, i4, fractY); + return mySmootherStep(result1, result2, fractZ); +} + +float fbm(float x, float y, float z) { + float total = 0.; + float persistence = 0.5f; + float octaves = 4.; + for(float i = 1.; i <= octaves; i++) { + float freq = pow(2.f, i); + float amp = pow(persistence, i); + total += interpNoise3D(x * freq, y * freq, z * freq) * amp; + } + return total; } void main() @@ -94,5 +148,10 @@ void main() vec3 perlinColor = a + b * cos(6.28 * worley(vec3(fs_Pos)) * perlinNoise * 4. * c + d); // Compute final shaded color - out_Col = vec4(vec3(perlinNoise * perlinNoise * perlinNoise), diffuseColor.a); + float f = fbm(fs_Pos.x, fs_Pos.y, fs_Pos.z); + vec4 pos = fs_Pos; + pos = fs_Pos + f; // THIS IS COOL!!!!!!!!!!!! + out_Col = vec4(vec3(fbm(pos.x, pos.y, pos.z)), diffuseColor.a); // swirly fbm + out_Col = vec4(vec3(worley(vec3(f))), diffuseColor.a); // + //out_Col = vec4(vec3(perlin(vec3(pos))) * lightIntensity, diffuseColor.a); } From e468e024970769ea06797f5e92f16855256c73f1 Mon Sep 17 00:00:00 2001 From: Sharon Dong Date: Tue, 21 Sep 2021 21:54:47 -0400 Subject: [PATCH 08/15] added all 4 biomes to sphere --- src/main.ts | 2 +- src/shaders/planet-vert.glsl | 254 +++++++++++++++++++++++++++++------ src/shaders/test-frag.glsl | 26 ++-- 3 files changed, 230 insertions(+), 52 deletions(-) diff --git a/src/main.ts b/src/main.ts index 968a71f..d956d88 100644 --- a/src/main.ts +++ b/src/main.ts @@ -98,7 +98,7 @@ function main() { icosphere = new Icosphere(vec3.fromValues(0, 0, 0), 1, prevTesselations); icosphere.create(); } - renderer.render(camera, test, [ + renderer.render(camera, planet, [ icosphere, //square, //cube diff --git a/src/shaders/planet-vert.glsl b/src/shaders/planet-vert.glsl index 717642b..f54055f 100644 --- a/src/shaders/planet-vert.glsl +++ b/src/shaders/planet-vert.glsl @@ -18,6 +18,7 @@ uniform mat4 u_ModelInvTr; // The inverse transpose of the model matrix. 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 int u_Time; in vec4 vs_Pos; // The array of vertex positions passed to the shader @@ -30,14 +31,14 @@ out vec4 fs_Nor; // The array of normals that has been transformed by 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. -const vec4 lightPos = vec4(2, 0, 3, 1); //The position of our virtual light, which is used to compute the shading of +const vec4 lightPos = vec4(4, 7, 7, 1); //The position of our virtual light, which is used to compute the shading of //the geometry in the fragment shader. float random1( vec3 p ) { return fract(sin((dot(p, vec3(127.1, 311.7, 191.999)))) * - 43758.5453); + 18.5453); } // Returns random vec3 in range [0, 1] @@ -77,7 +78,7 @@ float surflet(vec3 p, vec3 corner) { } float perlin(vec3 p) { - p = p * 2.5; + p = p * 4.5; float surfletSum = 0.f; for (int dx = 0; dx <= 1; dx++) { for (int dy = 0; dy <= 1; dy++) { @@ -86,34 +87,120 @@ float perlin(vec3 p) { } } } - return surfletSum; + return surfletSum / 4.; } -float perlinAdded(vec4 p) { +float perlinTerrace(vec4 p) { float noise = perlin(vec3(p)) + .5 * perlin(2.f * vec3(p)) + 0.25 * perlin(4.f * vec3(p)); + float rounded = (round(noise * 30.f) / 30.f); + float terrace = (noise + sin(190.*noise + 4.)*.008); + //terrace = rounded; + //terrace *= random1(vec3(terrace)); + //noise = mix(noise, terrace, random1(vec3(terrace))); + return terrace; +} + +float perlinMountains(vec4 p) { + float noise = perlin(vec3(p)) * 4. + .5 * perlin(2.f * vec3(p)) * 4. + 0.25 * perlin(4.f * vec3(p)) * 4.; //noise = noise / (1.f + .5 + .25); // this and next line for valleys //noise = pow(noise, .2); - - float terrace = round(noise * 12.f) / 12.f; - noise = mix(noise, terrace, random1(vec3(terrace))); return noise; } vec4 perlinNormal(vec4 p) { - float xNeg = perlinAdded((p + vec4(-.00001, 0, 0, 0))); - float xPos = perlinAdded((p + vec4(.00001, 0, 0, 0))); + float xNeg = perlinTerrace((p + vec4(-.00001, 0, 0, 0))); + float xPos = perlinTerrace((p + vec4(.00001, 0, 0, 0))); + float xDiff = xPos - xNeg; + float yNeg = perlinTerrace((p + vec4(0, -.00001, 0, 0))); + float yPos = perlinTerrace((p + vec4(0, .00001, 0, 0))); + float yDiff = yPos - yNeg; + float zNeg = perlinTerrace((p + vec4(0, 0, -.00001, 0))); + float zPos = perlinTerrace((p + vec4(0, 0, .00001, 0))); + float zDiff = zPos - zNeg; + return vec4(vec3(xDiff, yDiff, zDiff), 0); +} + + +float fbmRandom( vec3 p ) { + return fract(sin((dot(p, vec3(127.1, + 311.7, + 191.999)))) * + 18.5453); +} + +float smootherStep(float a, float b, float t) { + t = t*t*t*(t*(t*6.0 - 15.0) + 10.0); + return mix(a, b, t); +} + +float interpNoise3D(float x, float y, float z) { + x *= 2.; + y *= 2.; + z *= 2.; + float intX = floor(x); + float fractX = fract(x); + float intY = floor(y); + float fractY = fract(y); + float intZ = floor(z); + float fractZ = fract(z); + float v1 = fbmRandom(vec3(intX, intY, intZ)); + float v2 = fbmRandom(vec3(intX + 1., intY, intZ)); + float v3 = fbmRandom(vec3(intX, intY + 1., intZ)); + float v4 = fbmRandom(vec3(intX + 1., intY + 1., intZ)); + + float v5 = fbmRandom(vec3(intX, intY, intZ + 1.)); + float v6 = fbmRandom(vec3(intX + 1., intY, intZ + 1.)); + float v7 = fbmRandom(vec3(intX, intY + 1., intZ + 1.)); + float v8 = fbmRandom(vec3(intX + 1., intY + 1., intZ + 1.)); + + float i1 = smootherStep(v1, v2, fractX); + float i2 = smootherStep(v3, v4, fractX); + float result1 = smootherStep(i1, i2, fractY); + float i3 = smootherStep(v5, v6, fractX); + float i4 = smootherStep(v7, v8, fractX); + float result2 = smootherStep(i3, i4, fractY); + return smootherStep(result1, result2, fractZ); +} + +float fbm(vec4 p, float oct, float freq) { + float total = 0.; + float persistence = 0.5f; + float octaves = oct; + for(float i = 1.; i <= octaves; i++) { + float freq = pow(freq, i); + float amp = pow(persistence, i); + total += interpNoise3D(p.x * freq, p.y * freq, p.z * freq) * amp; + } + return total; +} + +float fbm2(vec4 p) { + float total = 0.; + float persistence = 0.5f; + float octaves = 4.; + for(float i = 1.; i <= octaves; i++) { + float freq = pow(2.f, i); + float amp = pow(persistence, i); + total += interpNoise3D(p.x * freq, p.y * freq, p.z * freq) * amp; + } + return total; +} + +vec4 fbmNormal(vec4 p, float oct, float freq) { + float xNeg = fbm((p + vec4(-.00001, 0, 0, 0)), oct, freq); + float xPos = fbm((p + vec4(.00001, 0, 0, 0)), oct, freq); float xDiff = xPos - xNeg; - float yNeg = perlinAdded((p + vec4(0, -.00001, 0, 0))); - float yPos = perlinAdded((p + vec4(0, .00001, 0, 0))); + float yNeg = fbm((p + vec4(0, -.00001, 0, 0)), oct, freq); + float yPos = fbm((p + vec4(0, .00001, 0, 0)), oct, freq); float yDiff = yPos - yNeg; - float zNeg = perlinAdded((p + vec4(0, 0, -.00001, 0))); - float zPos = perlinAdded((p + vec4(0, 0, .00001, 0))); + float zNeg = fbm((p + vec4(0, 0, -.00001, 0)), oct, freq); + float zPos = fbm((p + vec4(0, 0, .00001, 0)), oct, freq); float zDiff = zPos - zNeg; return vec4(vec3(xDiff, yDiff, zDiff), 0); } float worley(vec3 p) { - p *= 3.5; + p *= 1.5; vec3 pInt = floor(p); vec3 pFract = fract(p); float minDist = 1.0; @@ -121,8 +208,12 @@ float worley(vec3 p) { for (int x = -1; x <= 1; x++) { for (int y = -1; y <= 1; y++) { for (int z = -1; z <= 1; z++) { + // if (random1(vec3(x, y, z)) < .6) { + // continue; + // } vec3 neighbor = vec3(float(x), float(y), float(z)); vec3 voronoi = random3(pInt + neighbor); + //voronoi = 0.5 + 0.5 * sin(0.01 * float(u_Time) + 13.2831 * voronoi); vec3 diff = neighbor + voronoi - pFract; float dist = length(diff); if (dist < minDist) { @@ -130,8 +221,7 @@ float worley(vec3 p) { minDist = dist; } else if (dist < secondDist) { secondDist = dist; - } - //minDist = min(minDist, dist); + } } } } @@ -139,13 +229,40 @@ float worley(vec3 p) { return (-1. * minDist + 1. * secondDist); } +float worley2(vec3 p) { + vec3 pInt = floor(p); + vec3 pFract = fract(p); + float minDist = 1.0; + float secondDist = 1.0; + for (int x = -1; x <= 1; x++) { + for (int y = -1; y <= 1; y++) { + for (int z = -1; z <= 1; z++) { + vec3 neighbor = vec3(float(x), float(y), float(z)); + vec3 voronoi = random3(pInt + neighbor); + vec3 diff = neighbor + voronoi - pFract; + float dist = length(diff); + if (dist < minDist) { + secondDist = minDist; + minDist = dist; + } else if (dist < secondDist) { + secondDist = dist; + } + } + } + } + return 1.0 - minDist; +} + vec4 worleyAdded(vec4 pos) { - vec3 offset = vec3(pow(worley(vec3(pos)), 2.f)) / vec3(3.0); // Can divide by different factors or not at all for plateus!!!!!!!!!!!!!! - - //offset.x = clamp(offset.x, 0.2, .4); // Can change these values!!!!!!!!!!!!!!!!!! - //offset.y = clamp(offset.y, 0.2, .4); - //offset.z = clamp(offset.z, 0.2, .4); - //offset = offset + random3(offset) / vec3(50.0); + vec3 offset = vec3((worley(vec3(pos * 6.)))) / .5; // Can divide by different factors or not at all for plateus!!!!!!!!!!!!!! + offset.x = clamp(offset.x, .1, .15); + offset.y = clamp(offset.y, .1, .15); + offset.z = clamp(offset.z, .1, .15); + + // if (offset.x > 0. && offset.y > 0. && offset.z > 0.) { + // offset = vec3(mix(vec3(fbm2(pos)), offset, .85)); + // } + offset/=5.; return vec4(offset, 0.); } @@ -153,21 +270,15 @@ vec4 worleyNormal(vec4 p) { float xNeg = worleyAdded((p + vec4(-.00001, 0, 0, 0))).x; float xPos = worleyAdded((p + vec4(.00001, 0, 0, 0))).x; float xDiff = (xPos - xNeg); - if (p.x == 0.2) { - xDiff = vs_Nor.x; - } + float yNeg = worleyAdded((p + vec4(0, -.00001, 0, 0))).y; float yPos = worleyAdded((p + vec4(0, .00001, 0, 0))).y; float yDiff = (yPos - yNeg); - if (p.y == 0.2) { - yDiff = vs_Nor.y; - } + float zNeg = worleyAdded((p + vec4(0, 0, -.00001, 0))).z; float zPos = worleyAdded((p + vec4(0, 0, .00001, 0))).z; float zDiff = (zPos - zNeg); - if (p.z == 0.2) { - zDiff = vs_Nor.z; - } + return (vec4(vec3(xDiff, yDiff, zDiff), 0)); } @@ -176,20 +287,87 @@ void main() fs_Col = vs_Col; mat3 invTranspose = mat3(u_ModelInvTr); fs_Nor = vec4(invTranspose * vec3(vs_Nor), 0); + + float terrainMap = worley2(vec3(fbm(vs_Pos, 1., 1.2))) * 2. - .5; + vec4 noisePos = vs_Pos; + if (terrainMap < .02 || terrainMap > .97) { + // interpolate between 1 and 4 + // terraces + noisePos = vs_Pos + vs_Nor * perlinTerrace(vs_Pos); + } else if (terrainMap < .27) { + // terrain 1 + // terraces + noisePos = vs_Pos + vs_Nor * perlinTerrace(vs_Pos); + } else if (terrainMap < .32) { + // interpolate between 1 and 2 + // big mountains2 + noisePos = vs_Pos + vs_Nor * fbm(vs_Pos, 6., 2.) / 5.; + } else if (terrainMap < .52) { + // terrain 2 + // big mountains2 + noisePos = vs_Pos + vs_Nor * fbm(vs_Pos, 6., 2.) / 5.; + } else if (terrainMap < .55) { + // interpolate between 2 and 3 + // big mountains + noisePos = vs_Pos + vs_Nor * (perlinMountains(vs_Pos * 2.) + fbm(vs_Pos * 2., 6., 2.)) / 3.; + } else if (terrainMap < .7) { + // terrain 3 + // big mountains + noisePos = vs_Pos + vs_Nor * (perlinMountains(vs_Pos * 2.) + fbm(vs_Pos * 2., 6., 2.)) / 3.; + } else if (terrainMap < .75) { + // interpolate between 3 and 4 + // cracked floor + vec4 worl = worleyAdded(vs_Pos); + noisePos = vs_Pos + vs_Nor * worl; + } else { + // terain 4 + // cracked floor + vec4 worl = worleyAdded(vs_Pos); + noisePos = vs_Pos + vs_Nor * worl; + } + // // cracked floor + // vec4 worl = worleyAdded(vs_Pos); + // vec4 worleyNoise = vs_Pos + vs_Nor * worl; - vec4 worleyNoise = vs_Pos + vs_Nor * worleyAdded(vs_Pos); - vec4 perlinNoise = vs_Pos + vs_Nor * perlinAdded(vs_Pos); + // // terraces + // vec4 perlinTerrace = vs_Pos + vs_Nor * perlinTerrace(vs_Pos); + + // // big mountains + // vec4 perlinMountains = vs_Pos + vs_Nor * (perlinMountains(vs_Pos * 2.) + fbm(vs_Pos * 2., 6.)) / 2.; + // // big mountains2 + // vec4 fbmNoise = vs_Pos + vs_Nor * fbm(vs_Pos, 6.); + + // // hills + // vec4 hills = vs_Pos + vs_Nor * mix(fbm2(vs_Pos), worley(vec3(worley(vec3(vs_Pos)))) / 4., .9); - vec4 modelposition = u_Model * worleyNoise; - //vec4 modelposition = u_Model * perlinNoise; // Temporarily store the transformed vertex positions for use below + vec4 modelposition = u_Model * noisePos; + //vec4 modelposition = u_Model * perlinTerrace; + //vec4 modelposition = u_Model * perlinMountains; + //vec4 modelposition = u_Model * (fbmNoise); fs_Pos = modelposition; //fs_Nor = normalize(worleyNormal(vs_Pos)); - //fs_Nor = perlinNormal(vs_Pos); + //fs_Nor = normalize(perlinNormal(vs_Pos)); + //fs_Nor = normalize(fbmNormal(vs_Pos, 6.)); //fs_Nor = vec4(invTranspose * vec3(fs_Nor), 0); - vec3 normal = normalize(normalize(vec3(worleyNormal(vs_Pos)))); + vec3 normal = normalize(normalize(vec3(vs_Nor))); vec3 tangent = normalize(cross(vec3(0.0, 1.0, 0.0), normal)); vec3 bitangent = normalize(cross(normal, tangent)); + + float xNeg = worleyAdded((vs_Pos + vec4(tangent, 0) * vec4(-.00001, 0, 0, 0))).x; + float xPos = worleyAdded((vs_Pos + vec4(tangent, 0) * vec4(.00001, 0, 0, 0))).x; + float xDiff = (xPos - xNeg); + + float yNeg = worleyAdded((vs_Pos + vec4(bitangent, 0) * vec4(0, -.00001, 0, 0))).y; + float yPos = worleyAdded((vs_Pos + vec4(bitangent, 0) * vec4(0, .00001, 0, 0))).y; + float yDiff = (yPos - yNeg); + + float zNeg = worleyAdded((vs_Pos + vs_Nor * vec4(0, 0, -.00001, 0))).z; + float zPos = worleyAdded((vs_Pos + vs_Nor * vec4(0, 0, .00001, 0))).z; + float zDiff = (zPos - zNeg); + + //fs_Nor = (vec4(vec3(xDiff, yDiff, zDiff), 0)); + mat4 transform; transform[0] = vec4(tangent, 0.0); transform[1] = vec4(bitangent, 0.0); diff --git a/src/shaders/test-frag.glsl b/src/shaders/test-frag.glsl index 2c1df06..61090b1 100644 --- a/src/shaders/test-frag.glsl +++ b/src/shaders/test-frag.glsl @@ -77,10 +77,10 @@ float random1( vec3 p ) { return fract(sin((dot(p, vec3(127.1, 311.7, 191.999)))) * - 28.5453); + 18.5453); } -float mySmootherStep(float a, float b, float t) { +float smootherStep(float a, float b, float t) { t = t*t*t*(t*(t*6.0 - 15.0) + 10.0); return mix(a, b, t); } @@ -105,21 +105,21 @@ float interpNoise3D(float x, float y, float z) { float v7 = random1(vec3(intX, intY + 1., intZ + 1.)); float v8 = random1(vec3(intX + 1., intY + 1., intZ + 1.)); - float i1 = mySmootherStep(v1, v2, fractX); - float i2 = mySmootherStep(v3, v4, fractX); - float result1 = mySmootherStep(i1, i2, fractY); - float i3 = mySmootherStep(v5, v6, fractX); - float i4 = mySmootherStep(v7, v8, fractX); - float result2 = mySmootherStep(i3, i4, fractY); - return mySmootherStep(result1, result2, fractZ); + float i1 = smootherStep(v1, v2, fractX); + float i2 = smootherStep(v3, v4, fractX); + float result1 = smootherStep(i1, i2, fractY); + float i3 = smootherStep(v5, v6, fractX); + float i4 = smootherStep(v7, v8, fractX); + float result2 = smootherStep(i3, i4, fractY); + return smootherStep(result1, result2, fractZ); } float fbm(float x, float y, float z) { float total = 0.; float persistence = 0.5f; - float octaves = 4.; + float octaves = 1.; for(float i = 1.; i <= octaves; i++) { - float freq = pow(2.f, i); + float freq = pow(1.2, i); float amp = pow(persistence, i); total += interpNoise3D(x * freq, y * freq, z * freq) * amp; } @@ -151,7 +151,7 @@ void main() float f = fbm(fs_Pos.x, fs_Pos.y, fs_Pos.z); vec4 pos = fs_Pos; pos = fs_Pos + f; // THIS IS COOL!!!!!!!!!!!! - out_Col = vec4(vec3(fbm(pos.x, pos.y, pos.z)), diffuseColor.a); // swirly fbm - out_Col = vec4(vec3(worley(vec3(f))), diffuseColor.a); // + //out_Col = vec4(vec3(fbm(pos.x, pos.y, pos.z)), diffuseColor.a); // swirly fbm + out_Col = vec4(vec3(worley(vec3(f))) * 2. - .5 , diffuseColor.a); //worley and fbm (lowered octave from 4 to 2 for bigger chunks) //out_Col = vec4(vec3(perlin(vec3(pos))) * lightIntensity, diffuseColor.a); } From 2155fbad6915f1708f2ac1f4ae2580d9916668a7 Mon Sep 17 00:00:00 2001 From: Sharon Dong Date: Fri, 24 Sep 2021 01:30:13 -0400 Subject: [PATCH 09/15] planet looks like a planet now --- src/main.ts | 4 +- src/shaders/planet-frag.glsl | 128 +++++++++++++++++- src/shaders/planet-vert.glsl | 255 +++++++++++++++++++---------------- src/shaders/test-frag.glsl | 68 ++++++---- 4 files changed, 309 insertions(+), 146 deletions(-) diff --git a/src/main.ts b/src/main.ts index d956d88..26fda49 100644 --- a/src/main.ts +++ b/src/main.ts @@ -62,10 +62,10 @@ function main() { // Initial call to load scene loadScene(); - const camera = new Camera(vec3.fromValues(0, 0, 3), vec3.fromValues(0, 0, 0)); + const camera = new Camera(vec3.fromValues(0, 0, 2.5), vec3.fromValues(0, 0, 0)); const renderer = new OpenGLRenderer(canvas); - renderer.setClearColor(177.0 / 255.0, 204.0 / 255.0, 193.0 / 255.0, 1); + renderer.setClearColor(171. / 255.0, 224. / 255.0, 237. / 255.0, 1); gl.enable(gl.DEPTH_TEST); const lambert = new ShaderProgram([ diff --git a/src/shaders/planet-frag.glsl b/src/shaders/planet-frag.glsl index ac24304..7a9abea 100644 --- a/src/shaders/planet-frag.glsl +++ b/src/shaders/planet-frag.glsl @@ -11,6 +11,7 @@ // position, light position, and vertex color. precision highp float; +uniform highp int u_Time; uniform vec4 u_Color; // The color with which to render this instance of geometry. // These are the interpolated values out of the rasterizer, so you can't know @@ -19,10 +20,91 @@ in vec4 fs_Pos; in vec4 fs_Nor; in vec4 fs_LightVec; in vec4 fs_Col; +in float noise; +in float terrain_Type; 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 random1( vec3 p ) { + return fract(sin((dot(p, vec3(127.1, + 311.7, + 191.999)))) * + 18.5453); +} + +// Returns random vec3 in range [0, 1] +vec3 random3(vec3 p) { + return fract(sin(vec3(dot(p,vec3(127.1, 311.7, 191.999)), + dot(p,vec3(269.5, 183.3, 765.54)), + dot(p, vec3(420.69, 631.2,109.21)))) + *43758.5453); +} + +float worley(vec3 p) { + vec3 pInt = floor(p); + vec3 pFract = fract(p); + float minDist = 1.0; + for (int x = -1; x <= 1; x++) { + for (int y = -1; y <= 1; y++) { + for (int z = -1; z <= 1; z++) { + vec3 neighbor = vec3(float(x), float(y), float(z)); + vec3 voronoi = random3(pInt + neighbor); + //voronoi = 0.5 + 0.5 * sin(0.1 * float(u_Time) + 13.2831 * voronoi); + vec3 diff = neighbor + voronoi - pFract; + float dist = length(diff); + minDist = min(minDist, dist); + } + } + } + return 1.0 - minDist; +} + +float smootherStep(float a, float b, float t) { + t = t*t*t*(t*(t*6.0 - 15.0) + 10.0); + return mix(a, b, t); +} + +float interpNoise3D(float x, float y, float z) { + x *= 2.; + y *= 2.; + z *= 2.; + float intX = floor(x); + float fractX = fract(x); + float intY = floor(y); + float fractY = fract(y); + float intZ = floor(z); + float fractZ = fract(z); + float v1 = random1(vec3(intX, intY, intZ)); + float v2 = random1(vec3(intX + 1., intY, intZ)); + float v3 = random1(vec3(intX, intY + 1., intZ)); + float v4 = random1(vec3(intX + 1., intY + 1., intZ)); + + float v5 = random1(vec3(intX, intY, intZ + 1.)); + float v6 = random1(vec3(intX + 1., intY, intZ + 1.)); + float v7 = random1(vec3(intX, intY + 1., intZ + 1.)); + float v8 = random1(vec3(intX + 1., intY + 1., intZ + 1.)); + + float i1 = smootherStep(v1, v2, fractX); + float i2 = smootherStep(v3, v4, fractX); + float result1 = smootherStep(i1, i2, fractY); + float i3 = smootherStep(v5, v6, fractX); + float i4 = smootherStep(v7, v8, fractX); + float result2 = smootherStep(i3, i4, fractY); + return smootherStep(result1, result2, fractZ); +} + +float fbm(float x, float y, float z, float octaves) { + float total = 0.; + float persistence = 0.5f; + for(float i = 1.; i <= octaves; i++) { + float freq = pow(2., i); + float amp = pow(persistence, i); + total += interpNoise3D(x * freq, y * freq, z * freq) * amp; + } + return total; +} + void main() { // Material base color (before shading) @@ -33,13 +115,53 @@ void main() // Avoid negative lighting values diffuseTerm = clamp(diffuseTerm, 0.f, 1.f); - float ambientTerm = 0.2; + 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. - + vec3 color; // Compute final shaded color - out_Col = vec4(diffuseColor.rgb * lightIntensity, diffuseColor.a); + if (terrain_Type < 0.5) { // ocean color + float f = fbm(fs_Pos.x, fs_Pos.y, fs_Pos.z, 6.); + vec4 pos = fs_Pos; + pos = fs_Pos + f; + f = fbm(pos.x + .008*float(u_Time), pos.y, pos.z, 6.); + vec3 a = vec3(0.040, 0.50, 0.60); + vec3 b = vec3(0.00 ,0.4, 0.3); + vec3 c = vec3(0.00 , .8, .8); + vec3 d = vec3(0.050 ,0.1, 0.08); + color = a + b * cos(6.28 * (f * c + d)); + } else if (terrain_Type < 1.5) { // mountains + float f = fbm(fs_Pos.x * 2., fs_Pos.y * 2., fs_Pos.z * 2., 16.); + vec3 a = vec3(0.68, .66, .6); + vec3 b = vec3(0.250); + vec3 c = vec3(1.000); + vec3 d = vec3(0); + color = a + b * cos(6.28 * (worley(vec3(f)) * c + d)); + } else { // terrace tops + float f = fbm(fs_Pos.x*1.5, fs_Pos.y*1.5, fs_Pos.z*1.5, 16.); + vec3 a = vec3(0.350, 0.658, 0.000); + vec3 b = vec3(.25); + vec3 c = vec3(.9); + vec3 d = vec3(0); + color = a + b * cos(6.28 * (f * c + d)); + } + // else { // terrace sides + // float f = fbm(fs_Pos.x*1.5, fs_Pos.y*1.5, fs_Pos.z*1.5, 16.); + // vec3 a = vec3(0.38, .36, .3); + // vec3 b = vec3(0.150); + // vec3 c = vec3(1.000); + // vec3 d = vec3(0); + // color = a + b * cos(6.28 * (f * c + d)); + // } + out_Col = vec4(color * lightIntensity, 1.); + + vec3 height = vec3(noise); + height = (height + vec3(1.)) / 2.; + // out_Col = vec4(height, diffuseColor.a); //out_Col = vec4(abs(fs_Nor.rgb), 1); + // out_Col = vec4(diffuseColor.rgb * lightIntensity, diffuseColor.a); + + // out_Col = vec4((fs_Nor.xyz + vec3(1.)) * 0.5, 1.); } diff --git a/src/shaders/planet-vert.glsl b/src/shaders/planet-vert.glsl index f54055f..fdbefe7 100644 --- a/src/shaders/planet-vert.glsl +++ b/src/shaders/planet-vert.glsl @@ -26,12 +26,14 @@ 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 float noise; out vec4 fs_Pos; 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 float terrain_Type; -const vec4 lightPos = vec4(4, 7, 7, 1); //The position of our virtual light, which is used to compute the shading of +const vec4 lightPos = vec4(4, 7, 10, 1); //The position of our virtual light, which is used to compute the shading of //the geometry in the fragment shader. float random1( vec3 p ) { @@ -49,18 +51,6 @@ vec3 random3(vec3 p) { *43758.5453); } -vec3 bias(vec3 b, float t) { - return vec3(pow(t, log(b.x) / log(0.5)), pow(t, log(b.y) / log(0.5)), pow(t, log(b.z) / log(0.5))); -} - -vec3 gain(vec3 g, float t) { - if (t < 0.5) { - return bias(vec3(1.0) - g, 2.0 * t) / 2.0; - } else { - return vec3(1.0) - bias(vec3(1.0) - g, 2.0 - 2.0 * t) / 2.0; - } -} - // Returns a surflet float surflet(vec3 p, vec3 corner) { vec3 t = abs(p - corner); @@ -87,37 +77,95 @@ float perlin(vec3 p) { } } } + // float sum = surfletSum / 4.; + // return (sum + 1. )/2.; return surfletSum / 4.; } float perlinTerrace(vec4 p) { + p *= 1.5; float noise = perlin(vec3(p)) + .5 * perlin(2.f * vec3(p)) + 0.25 * perlin(4.f * vec3(p)); float rounded = (round(noise * 30.f) / 30.f); - float terrace = (noise + sin(190.*noise + 4.)*.008); + float terrace = (noise + sin(200.*noise + 3.)*.006) *.9; + + // float rounded = perlin(p.xyz); //terrace = rounded; //terrace *= random1(vec3(terrace)); //noise = mix(noise, terrace, random1(vec3(terrace))); - return terrace; + return terrace + .01; } float perlinMountains(vec4 p) { - float noise = perlin(vec3(p)) * 4. + .5 * perlin(2.f * vec3(p)) * 4. + 0.25 * perlin(4.f * vec3(p)) * 4.; + p *= 2.; + float noise = perlin(vec3(p)) + .5 * perlin(2.f * vec3(p)) + 0.25 * perlin(4.f * vec3(p)); //noise = noise / (1.f + .5 + .25); // this and next line for valleys //noise = pow(noise, .2); - return noise; + noise *= 1.5; + return noise + .05; } -vec4 perlinNormal(vec4 p) { - float xNeg = perlinTerrace((p + vec4(-.00001, 0, 0, 0))); - float xPos = perlinTerrace((p + vec4(.00001, 0, 0, 0))); - float xDiff = xPos - xNeg; - float yNeg = perlinTerrace((p + vec4(0, -.00001, 0, 0))); - float yPos = perlinTerrace((p + vec4(0, .00001, 0, 0))); - float yDiff = yPos - yNeg; - float zNeg = perlinTerrace((p + vec4(0, 0, -.00001, 0))); - float zPos = perlinTerrace((p + vec4(0, 0, .00001, 0))); - float zDiff = zPos - zNeg; - return vec4(vec3(xDiff, yDiff, zDiff), 0); +vec4 cartesian(float r, float theta, float phi) { + return vec4(r * sin(phi) * cos(theta), + r * sin(phi) * sin(theta), + r * cos(phi), 1.); +} + +// output is vec3(radius, theta, phi) +vec3 polar(vec4 p) { + float r = sqrt(p.x * p.x + p.y * p.y + p.z * p.z); + float theta = atan(p.y / p.x); + // float phi = atan(sqrt(p.x * p.x + p.y * p.y) / p.z); + float phi = acos(p.z / sqrt(p.x * p.x + p.y * p.y + p.z * p.z)); + return vec3(r, theta, phi); +} + +vec4 transformToWorld(vec4 nor) { + vec3 normal = normalize(vec3(vs_Nor)); + vec3 tangent = normalize(cross(vec3(0.0, 1.0, 0.0), normal)); + vec3 bitangent = normalize(cross(normal, tangent)); + mat4 transform; + transform[0] = vec4(tangent, 0.0); + transform[1] = vec4(bitangent, 0.0); + transform[2] = vec4(normal, 0.0); + transform[3] = vec4(0.0, 0.0, 0.0, 1.0); + return vec4(normalize(vec3(transform * nor)), 0.0); + // return nor; +} + +vec4 perlinTerraceNormal(vec4 p) { + vec3 polars = polar(p); + float offset = .0001; + vec4 xNeg = cartesian(polars.x, polars.y - offset, polars.z); + vec4 xPos = cartesian(polars.x, polars.y + offset, polars.z); + vec4 yNeg = cartesian(polars.x, polars.y, polars.z - offset); + vec4 yPos = cartesian(polars.x, polars.y, polars.z + offset); + float xNegNoise = perlinTerrace(xNeg); + float xPosNoise = perlinTerrace(xPos); + float yNegNoise = perlinTerrace(yNeg); + float yPosNoise = perlinTerrace(yPos); + + float xDiff = (xPosNoise - xNegNoise) * 1000.; + float yDiff = (yPosNoise - yNegNoise) * 1000.; + p.z = sqrt(1. - xDiff * xDiff - yDiff * yDiff); + return vec4(vec3(xDiff, yDiff, p.z), 0); +} + +vec4 perlinMoutainNormal(vec4 p) { + vec3 polars = polar(p); + float offset = .01; + vec4 xNeg = cartesian(polars.x, polars.y - offset, polars.z); + vec4 xPos = cartesian(polars.x, polars.y + offset, polars.z); + vec4 yNeg = cartesian(polars.x, polars.y, polars.z - offset); + vec4 yPos = cartesian(polars.x, polars.y, polars.z + offset); + float xNegNoise = perlinMountains(xNeg); + float xPosNoise = perlinMountains(xPos); + float yNegNoise = perlinMountains(yNeg); + float yPosNoise = perlinMountains(yPos); + + float xDiff = (xPosNoise - xNegNoise) * 10.; + float yDiff = (yPosNoise - yNegNoise) * 10.; + p.z = sqrt(1. - xDiff * xDiff - yDiff * yDiff); + return vec4(vec3(xDiff, yDiff, p.z), 0); } @@ -233,7 +281,6 @@ float worley2(vec3 p) { vec3 pInt = floor(p); vec3 pFract = fract(p); float minDist = 1.0; - float secondDist = 1.0; for (int x = -1; x <= 1; x++) { for (int y = -1; y <= 1; y++) { for (int z = -1; z <= 1; z++) { @@ -241,99 +288,101 @@ float worley2(vec3 p) { vec3 voronoi = random3(pInt + neighbor); vec3 diff = neighbor + voronoi - pFract; float dist = length(diff); - if (dist < minDist) { - secondDist = minDist; - minDist = dist; - } else if (dist < secondDist) { - secondDist = dist; - } + minDist = min(minDist, dist); } } } return 1.0 - minDist; } -vec4 worleyAdded(vec4 pos) { - vec3 offset = vec3((worley(vec3(pos * 6.)))) / .5; // Can divide by different factors or not at all for plateus!!!!!!!!!!!!!! - offset.x = clamp(offset.x, .1, .15); - offset.y = clamp(offset.y, .1, .15); - offset.z = clamp(offset.z, .1, .15); +float worleyAdded(vec4 pos) { + float offset = ((worley(vec3(pos * 6.)))) / .5; // Can divide by different factors or not at all for plateus!!!!!!!!!!!!!! + offset = clamp(offset, .1, .15); // if (offset.x > 0. && offset.y > 0. && offset.z > 0.) { // offset = vec3(mix(vec3(fbm2(pos)), offset, .85)); // } offset/=5.; - return vec4(offset, 0.); + return offset; } vec4 worleyNormal(vec4 p) { - float xNeg = worleyAdded((p + vec4(-.00001, 0, 0, 0))).x; - float xPos = worleyAdded((p + vec4(.00001, 0, 0, 0))).x; + float xNeg = worleyAdded((p + vec4(-.00001, 0, 0, 0))); + float xPos = worleyAdded((p + vec4(.00001, 0, 0, 0))); float xDiff = (xPos - xNeg); - float yNeg = worleyAdded((p + vec4(0, -.00001, 0, 0))).y; - float yPos = worleyAdded((p + vec4(0, .00001, 0, 0))).y; + float yNeg = worleyAdded((p + vec4(0, -.00001, 0, 0))); + float yPos = worleyAdded((p + vec4(0, .00001, 0, 0))); float yDiff = (yPos - yNeg); - float zNeg = worleyAdded((p + vec4(0, 0, -.00001, 0))).z; - float zPos = worleyAdded((p + vec4(0, 0, .00001, 0))).z; + float zNeg = worleyAdded((p + vec4(0, 0, -.00001, 0))); + float zPos = worleyAdded((p + vec4(0, 0, .00001, 0))); float zDiff = (zPos - zNeg); return (vec4(vec3(xDiff, yDiff, zDiff), 0)); } +float GetBias(float time, float bias) +{ + return (time / ((((1.0/bias) - 2.0)*(1.0 - time))+1.0)); +} + +float GetGain(float time, float gain) +{ + if(time < 0.5) + return GetBias(time * 2.0,gain)/2.0; + else + return GetBias(time * 2.0 - 1.0,1.0 - gain)/2.0 + 0.5; +} + +vec4 getTerrain() { + // biomes = water, terraces, mountains, lakes? snowcaps? + // toolbox = smooth step (fbm and perlin), sin wave (terraces), jitter scattering (worley) + // gui = modify boundaries of terrains, modify fbm octaves or freq, modify which axis it rotates on + float terrainMap = worley2(vec3(fbm(vs_Pos, 6., 1.7))); + vec4 noisePos = vs_Pos; + if (terrainMap < .28) { + // water (use worley to animate?) and use blinn phong? + fs_Nor = vs_Nor; + terrain_Type = 0.; + } else if (terrainMap < .44) { + // terraces + noisePos = vs_Pos + vs_Nor * perlinTerrace(vs_Pos); + vec4 norLocal = normalize(perlinTerraceNormal(vs_Pos)); + float dot = dot(normalize(norLocal), vec4(0, 0, 1, 0)); + fs_Nor = transformToWorld(norLocal); + if (dot > .98) { + terrain_Type = 2.; + } else { + terrain_Type = 3.; + } + } else { + // mountains + float perlin = perlinMountains(vs_Pos); + noisePos = vs_Pos + vs_Nor * perlin; + fs_Nor = transformToWorld(normalize(perlinMoutainNormal(vs_Pos))); + terrain_Type = 1.; + } + return noisePos; +} + void main() { fs_Col = vs_Col; mat3 invTranspose = mat3(u_ModelInvTr); fs_Nor = vec4(invTranspose * vec3(vs_Nor), 0); - float terrainMap = worley2(vec3(fbm(vs_Pos, 1., 1.2))) * 2. - .5; - vec4 noisePos = vs_Pos; - if (terrainMap < .02 || terrainMap > .97) { - // interpolate between 1 and 4 - // terraces - noisePos = vs_Pos + vs_Nor * perlinTerrace(vs_Pos); - } else if (terrainMap < .27) { - // terrain 1 - // terraces - noisePos = vs_Pos + vs_Nor * perlinTerrace(vs_Pos); - } else if (terrainMap < .32) { - // interpolate between 1 and 2 - // big mountains2 - noisePos = vs_Pos + vs_Nor * fbm(vs_Pos, 6., 2.) / 5.; - } else if (terrainMap < .52) { - // terrain 2 - // big mountains2 - noisePos = vs_Pos + vs_Nor * fbm(vs_Pos, 6., 2.) / 5.; - } else if (terrainMap < .55) { - // interpolate between 2 and 3 - // big mountains - noisePos = vs_Pos + vs_Nor * (perlinMountains(vs_Pos * 2.) + fbm(vs_Pos * 2., 6., 2.)) / 3.; - } else if (terrainMap < .7) { - // terrain 3 - // big mountains - noisePos = vs_Pos + vs_Nor * (perlinMountains(vs_Pos * 2.) + fbm(vs_Pos * 2., 6., 2.)) / 3.; - } else if (terrainMap < .75) { - // interpolate between 3 and 4 - // cracked floor - vec4 worl = worleyAdded(vs_Pos); - noisePos = vs_Pos + vs_Nor * worl; - } else { - // terain 4 - // cracked floor - vec4 worl = worleyAdded(vs_Pos); - noisePos = vs_Pos + vs_Nor * worl; - } + vec4 noisePos = getTerrain(); + // // cracked floor - // vec4 worl = worleyAdded(vs_Pos); + // float worl = worleyAdded(vs_Pos); // vec4 worleyNoise = vs_Pos + vs_Nor * worl; // // terraces - // vec4 perlinTerrace = vs_Pos + vs_Nor * perlinTerrace(vs_Pos); + vec4 perlinTerrace = vs_Pos + vs_Nor * perlinTerrace(vs_Pos); // // big mountains - // vec4 perlinMountains = vs_Pos + vs_Nor * (perlinMountains(vs_Pos * 2.) + fbm(vs_Pos * 2., 6.)) / 2.; + // vec4 perlinMountains = vs_Pos + vs_Nor * (perlinMountains(vs_Pos)); // // big mountains2 // vec4 fbmNoise = vs_Pos + vs_Nor * fbm(vs_Pos, 6.); @@ -341,39 +390,9 @@ void main() // vec4 hills = vs_Pos + vs_Nor * mix(fbm2(vs_Pos), worley(vec3(worley(vec3(vs_Pos)))) / 4., .9); vec4 modelposition = u_Model * noisePos; - //vec4 modelposition = u_Model * perlinTerrace; - //vec4 modelposition = u_Model * perlinMountains; - //vec4 modelposition = u_Model * (fbmNoise); fs_Pos = modelposition; - - //fs_Nor = normalize(worleyNormal(vs_Pos)); - //fs_Nor = normalize(perlinNormal(vs_Pos)); - //fs_Nor = normalize(fbmNormal(vs_Pos, 6.)); - //fs_Nor = vec4(invTranspose * vec3(fs_Nor), 0); - vec3 normal = normalize(normalize(vec3(vs_Nor))); - vec3 tangent = normalize(cross(vec3(0.0, 1.0, 0.0), normal)); - vec3 bitangent = normalize(cross(normal, tangent)); - - float xNeg = worleyAdded((vs_Pos + vec4(tangent, 0) * vec4(-.00001, 0, 0, 0))).x; - float xPos = worleyAdded((vs_Pos + vec4(tangent, 0) * vec4(.00001, 0, 0, 0))).x; - float xDiff = (xPos - xNeg); - - float yNeg = worleyAdded((vs_Pos + vec4(bitangent, 0) * vec4(0, -.00001, 0, 0))).y; - float yPos = worleyAdded((vs_Pos + vec4(bitangent, 0) * vec4(0, .00001, 0, 0))).y; - float yDiff = (yPos - yNeg); - - float zNeg = worleyAdded((vs_Pos + vs_Nor * vec4(0, 0, -.00001, 0))).z; - float zPos = worleyAdded((vs_Pos + vs_Nor * vec4(0, 0, .00001, 0))).z; - float zDiff = (zPos - zNeg); - //fs_Nor = (vec4(vec3(xDiff, yDiff, zDiff), 0)); - - mat4 transform; - transform[0] = vec4(tangent, 0.0); - transform[1] = vec4(bitangent, 0.0); - transform[2] = vec4(normal, 0.0); - transform[3] = vec4(0.0, 0.0, 0.0, 1.0); - //fs_Nor = vec4(normalize(vec3(transform * vec4(normal, 0.0))), 0.0); + fs_Nor = vec4(invTranspose * vec3(fs_Nor), 0); 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 diff --git a/src/shaders/test-frag.glsl b/src/shaders/test-frag.glsl index 61090b1..3979fff 100644 --- a/src/shaders/test-frag.glsl +++ b/src/shaders/test-frag.glsl @@ -46,7 +46,6 @@ float perlin(vec3 p) { } float worley(vec3 p) { - p *= 1.; vec3 pInt = floor(p); vec3 pFract = fract(p); float minDist = 1.0; @@ -117,9 +116,9 @@ float interpNoise3D(float x, float y, float z) { float fbm(float x, float y, float z) { float total = 0.; float persistence = 0.5f; - float octaves = 1.; + float octaves = 16.; for(float i = 1.; i <= octaves; i++) { - float freq = pow(1.2, i); + float freq = pow(2., i); float amp = pow(persistence, i); total += interpNoise3D(x * freq, y * freq, z * freq) * amp; } @@ -128,30 +127,53 @@ float fbm(float x, float y, float z) { void main() { - vec4 diffuseColor = u_Color; + // vec4 diffuseColor = u_Color; - // Calculate the diffuse term for Lambert shading - float diffuseTerm = dot(normalize(fs_Nor), normalize(fs_LightVec)); - // Avoid negative lighting values - diffuseTerm = clamp(diffuseTerm, 0.f, 1.f); + // // Calculate the diffuse term for Lambert shading + // float diffuseTerm = dot(normalize(fs_Nor), normalize(fs_LightVec)); + // // Avoid negative lighting values + // diffuseTerm = clamp(diffuseTerm, 0.f, 1.f); - float ambientTerm = 0.4; - - 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. - float perlinNoise = perlin(vec3(fs_Pos)); - vec3 a = vec3(u_Color); - vec3 b = vec3(0.688, 0.558, 0.500); - vec3 c = vec3(255.0 / 255.0, 244.0 / 255.0, 224.0 / 255.0); - vec3 d = vec3(0.588, -0.342, 0.048); - vec3 perlinColor = a + b * cos(6.28 * worley(vec3(fs_Pos)) * perlinNoise * 4. * c + d); + // float ambientTerm = 0.4; + + // 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. + // float perlinNoise = perlin(vec3(fs_Pos)); + // vec3 a = vec3(u_Color); + // vec3 b = vec3(0.688, 0.558, 0.500); + // vec3 c = vec3(255.0 / 255.0, 244.0 / 255.0, 224.0 / 255.0); + // vec3 d = vec3(0.588, -0.342, 0.048); + // vec3 perlinColor = a + b * cos(6.28 * worley(vec3(fs_Pos)) * perlinNoise * 4. * c + d); // Compute final shaded color - float f = fbm(fs_Pos.x, fs_Pos.y, fs_Pos.z); + float f = fbm(fs_Pos.x*1.5, fs_Pos.y*1.5, fs_Pos.z*1.5); vec4 pos = fs_Pos; pos = fs_Pos + f; // THIS IS COOL!!!!!!!!!!!! - //out_Col = vec4(vec3(fbm(pos.x, pos.y, pos.z)), diffuseColor.a); // swirly fbm - out_Col = vec4(vec3(worley(vec3(f))) * 2. - .5 , diffuseColor.a); //worley and fbm (lowered octave from 4 to 2 for bigger chunks) - //out_Col = vec4(vec3(perlin(vec3(pos))) * lightIntensity, diffuseColor.a); + // f = fbm(pos.x, pos.y + .001*float(u_Time), pos.z); + + vec3 a = vec3(0.38, .36, .3); + vec3 b = vec3(0.150); + vec3 c = vec3(1.000); + vec3 d = vec3(0); + vec3 color = a + b * cos(6.28 * (f * c + d)); + + out_Col = vec4(color, 1.); // swirly fbm + + // float terrainMap = worley(vec3(f)); + // vec3 color; + // if (terrainMap < .28) { + // color = vec3(0., 0., 1); + // } else if (terrainMap < .44) { + // color = vec3(1., 1., 0.); + // } else { + // color = vec3(.5); + // } + + // vec3 a = vec3(0.9); + // vec3 b = vec3(0.250); + // vec3 c = vec3(1.000); + // vec3 d = vec3(0); + // vec3 color = a + b * cos(6.28 * (worley(vec3(f)) * c + d)); + // out_Col = vec4(color, 1); //worley and fbm (lowered octave from 4 to 2 for bigger chunks) } From 8da1fcf4259d0afe8bfbe62ccf85f271110f9ae2 Mon Sep 17 00:00:00 2001 From: Sharon Dong Date: Sat, 25 Sep 2021 14:30:04 -0400 Subject: [PATCH 10/15] added gui elements and stuff --- src/main.ts | 28 +++++++-- src/rendering/gl/OpenGLRenderer.ts | 7 ++- src/rendering/gl/ShaderProgram.ts | 36 ++++++++++++ src/shaders/planet-frag.glsl | 75 ++++++++++++++---------- src/shaders/planet-vert.glsl | 93 ++++++++++++++++-------------- src/shaders/test-frag.glsl | 33 ++++++----- 6 files changed, 175 insertions(+), 97 deletions(-) diff --git a/src/main.ts b/src/main.ts index 26fda49..8b02b77 100644 --- a/src/main.ts +++ b/src/main.ts @@ -20,6 +20,7 @@ let icosphere: Icosphere; let square: Square; let cube: Cube; let prevTesselations: number = 8; +let prevColor = [171., 224., 237.]; let time: number = 0; function loadScene() { @@ -42,12 +43,24 @@ function main() { // Add controls to the gui const gui = new DAT.GUI(); - gui.add(controls, 'tesselations', 0, 8).step(1); - gui.add(controls, 'Load Scene'); + gui.add(controls, 'tesselations', 0, 8).step(1).name('Tesselations'); + // gui.add(controls, 'Load Scene'); var color = { - color: [255, 128, 128], // RGB array + color: [171., 224., 237.], // RGB array }; - gui.addColor(color, 'color'); + gui.addColor(color, 'color').name('Background Color'); + var sea = { + level : 0 + }; + gui.add(sea, 'level', 0, 5).name('Sea Level'); + var terrain = { + mountains : 10 + }; + gui.add(terrain, 'mountains', 0, 10).name('Mountains'); + var fragments = { + level : 5 + }; + gui.add(fragments, 'level', 0, 8).name('Fragmentation'); // get canvas and webgl context const canvas = document.getElementById('canvas'); @@ -91,6 +104,11 @@ function main() { camera.update(); stats.begin(); gl.viewport(0, 0, window.innerWidth, window.innerHeight); + if(color.color[0] != prevColor[0] || color.color[1] != prevColor[1] || color.color[2] != prevColor[2]) + { + prevColor = color.color; + renderer.setClearColor(color.color[0] / 255.0, color.color[1] / 255.0, color.color[2] / 255.0, 1); + } renderer.clear(); if(controls.tesselations != prevTesselations) { @@ -102,7 +120,7 @@ function main() { icosphere, //square, //cube - ], color.color, time); + ], color.color, time, sea.level, terrain.mountains, fragments.level); stats.end(); // Tell the browser to call `tick` again whenever it renders a new frame diff --git a/src/rendering/gl/OpenGLRenderer.ts b/src/rendering/gl/OpenGLRenderer.ts index 61ced1b..a356f41 100644 --- a/src/rendering/gl/OpenGLRenderer.ts +++ b/src/rendering/gl/OpenGLRenderer.ts @@ -22,7 +22,8 @@ class OpenGLRenderer { gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); } - render(camera: Camera, prog: ShaderProgram, drawables: Array, color: Array, time: number) { + render(camera: Camera, prog: ShaderProgram, drawables: Array, color: Array, + time: number, sea: number, mtn: number, frag: number) { let model = mat4.create(); let viewProj = mat4.create(); //let color = vec4.fromValues(1, 0, 0, 1); @@ -33,6 +34,10 @@ class OpenGLRenderer { prog.setViewProjMatrix(viewProj); prog.setGeometryColor(vec4.fromValues(color[0]/255, color[1]/255, color[2]/255, 1)); prog.setTime(time); + prog.setCamPos(vec4.fromValues(camera.position[0], camera.position[1], camera.position[2], 1.)); + prog.setSea(sea); + prog.setMountains(mtn); + prog.setFragments(frag); for (let drawable of drawables) { prog.draw(drawable); diff --git a/src/rendering/gl/ShaderProgram.ts b/src/rendering/gl/ShaderProgram.ts index 78b6385..b763a12 100644 --- a/src/rendering/gl/ShaderProgram.ts +++ b/src/rendering/gl/ShaderProgram.ts @@ -30,6 +30,10 @@ class ShaderProgram { unifViewProj: WebGLUniformLocation; unifColor: WebGLUniformLocation; unifTime: WebGLUniformLocation; + unifCamPos: WebGLUniformLocation; + unifSeaLevel: WebGLUniformLocation; + unifMountains: WebGLUniformLocation; + unifFragments: WebGLUniformLocation; constructor(shaders: Array) { this.prog = gl.createProgram(); @@ -50,6 +54,10 @@ class ShaderProgram { 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.unifCamPos = gl.getUniformLocation(this.prog, "u_CameraPos"); + this.unifSeaLevel = gl.getUniformLocation(this.prog, "u_Sea"); + this.unifMountains = gl.getUniformLocation(this.prog, "u_Mountains"); + this.unifFragments = gl.getUniformLocation(this.prog, "u_Fragments"); } use() { @@ -94,6 +102,34 @@ class ShaderProgram { } } + setCamPos(pos: vec4) { + this.use(); + if (this.unifCamPos !== -1) { + gl.uniform4fv(this.unifCamPos, pos); + } + } + + setSea(sea: number) { + this.use(); + if(this.unifSeaLevel != -1) { + gl.uniform1f(this.unifSeaLevel, sea); + } + } + + setMountains(mtn: number) { + this.use(); + if(this.unifMountains != -1) { + gl.uniform1f(this.unifMountains, mtn); + } + } + + setFragments(frag: number) { + this.use(); + if(this.unifFragments != -1) { + gl.uniform1f(this.unifFragments, frag); + } + } + draw(d: Drawable) { this.use(); diff --git a/src/shaders/planet-frag.glsl b/src/shaders/planet-frag.glsl index 7a9abea..544c4e8 100644 --- a/src/shaders/planet-frag.glsl +++ b/src/shaders/planet-frag.glsl @@ -13,6 +13,7 @@ precision highp float; uniform highp int u_Time; uniform vec4 u_Color; // The color with which to render this instance of geometry. +uniform vec4 u_CameraPos; // 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 @@ -22,6 +23,7 @@ in vec4 fs_LightVec; in vec4 fs_Col; in float noise; in float terrain_Type; +in vec4 fs_LightPos; 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. @@ -107,6 +109,10 @@ float fbm(float x, float y, float z, float octaves) { void main() { + vec4 view = normalize(u_CameraPos - fs_Pos); + vec4 H = normalize(view + normalize(fs_LightVec)); + vec3 specularIntensity = pow(max(dot(H, normalize(fs_Nor)), 0.), 50.) * vec3(230./255., 233./255., 190./255.); + // Material base color (before shading) vec4 diffuseColor = u_Color; @@ -123,39 +129,44 @@ void main() vec3 color; // Compute final shaded color if (terrain_Type < 0.5) { // ocean color - float f = fbm(fs_Pos.x, fs_Pos.y, fs_Pos.z, 6.); - vec4 pos = fs_Pos; - pos = fs_Pos + f; - f = fbm(pos.x + .008*float(u_Time), pos.y, pos.z, 6.); - vec3 a = vec3(0.040, 0.50, 0.60); - vec3 b = vec3(0.00 ,0.4, 0.3); - vec3 c = vec3(0.00 , .8, .8); - vec3 d = vec3(0.050 ,0.1, 0.08); - color = a + b * cos(6.28 * (f * c + d)); + float f = fbm(fs_Pos.x, fs_Pos.y, fs_Pos.z, 6.); + vec4 pos = fs_Pos; + pos = fs_Pos + f; + f = fbm(pos.x + .008*float(u_Time), pos.y, pos.z, 6.); + vec3 a = vec3(0.040, 0.50, 0.60); + vec3 b = vec3(0.00 ,0.4, 0.3); + vec3 c = vec3(0.00 , .8, .8); + vec3 d = vec3(0.050 ,0.1, 0.08); + color = a + b * cos(6.28 * (f * c + d)); + specularIntensity = vec3(0.); } else if (terrain_Type < 1.5) { // mountains - float f = fbm(fs_Pos.x * 2., fs_Pos.y * 2., fs_Pos.z * 2., 16.); - vec3 a = vec3(0.68, .66, .6); - vec3 b = vec3(0.250); - vec3 c = vec3(1.000); - vec3 d = vec3(0); - color = a + b * cos(6.28 * (worley(vec3(f)) * c + d)); - } else { // terrace tops - float f = fbm(fs_Pos.x*1.5, fs_Pos.y*1.5, fs_Pos.z*1.5, 16.); - vec3 a = vec3(0.350, 0.658, 0.000); - vec3 b = vec3(.25); - vec3 c = vec3(.9); - vec3 d = vec3(0); - color = a + b * cos(6.28 * (f * c + d)); - } - // else { // terrace sides - // float f = fbm(fs_Pos.x*1.5, fs_Pos.y*1.5, fs_Pos.z*1.5, 16.); - // vec3 a = vec3(0.38, .36, .3); - // vec3 b = vec3(0.150); - // vec3 c = vec3(1.000); - // vec3 d = vec3(0); - // color = a + b * cos(6.28 * (f * c + d)); - // } - out_Col = vec4(color * lightIntensity, 1.); + float f = fbm(fs_Pos.x * 2., fs_Pos.y * 2., fs_Pos.z * 2., 16.); + vec3 a = vec3(0.68, .66, .6); + vec3 b = vec3(0.250); + vec3 c = vec3(1.000); + vec3 d = vec3(0); + color = a + b * cos(6.28 * (worley(vec3(f)) * c + d)); + } else if (terrain_Type < 2.5) { // terrace + float f = fbm(fs_Pos.x*1.5, fs_Pos.y*1.5, fs_Pos.z*1.5, 16.); + vec3 a = vec3(0.40, 0.7, 0.000); + vec3 b = vec3(.25); + vec3 c = vec3(.9); + vec3 d = vec3(0); + color = a + b * cos(6.28 * (f * c + d)); + specularIntensity = vec3(0.); + } else if (terrain_Type <= 3.5) { // sand + float f = fbm(fs_Pos.x*2.5, fs_Pos.y*2.5, fs_Pos.z*2.5, 8.); + vec3 a = vec3(.9, .8, .7); + vec3 b = vec3(0.20); + vec3 c = vec3(1.000); + vec3 d = vec3(0); + color = a + b * cos(6.28 * (f * c + d)); + } else { + color = vec3(0); + } + + out_Col = vec4(color * lightIntensity + specularIntensity, 1.); + // out_Col = vec4(color, 1.); vec3 height = vec3(noise); height = (height + vec3(1.)) / 2.; diff --git a/src/shaders/planet-vert.glsl b/src/shaders/planet-vert.glsl index fdbefe7..3042574 100644 --- a/src/shaders/planet-vert.glsl +++ b/src/shaders/planet-vert.glsl @@ -19,6 +19,10 @@ uniform mat4 u_ViewProj; // The matrix that defines the camera's transformati // We've written a static matrix for you to use for HW2, // but in HW3 you'll have to generate one yourself uniform int u_Time; +uniform vec4 u_CameraPos; +uniform float u_Sea; +uniform float u_Mountains; +uniform float u_Fragments; in vec4 vs_Pos; // The array of vertex positions passed to the shader @@ -32,9 +36,7 @@ out vec4 fs_Nor; // The array of normals that has been transformed by 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 float terrain_Type; - -const vec4 lightPos = vec4(4, 7, 10, 1); //The position of our virtual light, which is used to compute the shading of - //the geometry in the fragment shader. +out vec4 fs_LightPos; float random1( vec3 p ) { return fract(sin((dot(p, vec3(127.1, @@ -92,16 +94,16 @@ float perlinTerrace(vec4 p) { //terrace = rounded; //terrace *= random1(vec3(terrace)); //noise = mix(noise, terrace, random1(vec3(terrace))); - return terrace + .01; + return terrace + .005; } -float perlinMountains(vec4 p) { +float perlinMountains(vec4 p, float factor) { p *= 2.; float noise = perlin(vec3(p)) + .5 * perlin(2.f * vec3(p)) + 0.25 * perlin(4.f * vec3(p)); //noise = noise / (1.f + .5 + .25); // this and next line for valleys //noise = pow(noise, .2); - noise *= 1.5; - return noise + .05; + noise *= factor; + return noise + .02; } vec4 cartesian(float r, float theta, float phi) { @@ -150,17 +152,17 @@ vec4 perlinTerraceNormal(vec4 p) { return vec4(vec3(xDiff, yDiff, p.z), 0); } -vec4 perlinMoutainNormal(vec4 p) { +vec4 perlinMoutainNormal(vec4 p, float factor) { vec3 polars = polar(p); float offset = .01; vec4 xNeg = cartesian(polars.x, polars.y - offset, polars.z); vec4 xPos = cartesian(polars.x, polars.y + offset, polars.z); vec4 yNeg = cartesian(polars.x, polars.y, polars.z - offset); vec4 yPos = cartesian(polars.x, polars.y, polars.z + offset); - float xNegNoise = perlinMountains(xNeg); - float xPosNoise = perlinMountains(xPos); - float yNegNoise = perlinMountains(yNeg); - float yPosNoise = perlinMountains(yPos); + float xNegNoise = perlinMountains(xNeg, factor); + float xPosNoise = perlinMountains(xPos, factor); + float yNegNoise = perlinMountains(yNeg, factor); + float yPosNoise = perlinMountains(yPos, factor); float xDiff = (xPosNoise - xNegNoise) * 10.; float yDiff = (yPosNoise - yNegNoise) * 10.; @@ -322,50 +324,51 @@ vec4 worleyNormal(vec4 p) { return (vec4(vec3(xDiff, yDiff, zDiff), 0)); } -float GetBias(float time, float bias) -{ - return (time / ((((1.0/bias) - 2.0)*(1.0 - time))+1.0)); -} - -float GetGain(float time, float gain) -{ - if(time < 0.5) - return GetBias(time * 2.0,gain)/2.0; - else - return GetBias(time * 2.0 - 1.0,1.0 - gain)/2.0 + 0.5; -} - vec4 getTerrain() { - // biomes = water, terraces, mountains, lakes? snowcaps? - // toolbox = smooth step (fbm and perlin), sin wave (terraces), jitter scattering (worley) - // gui = modify boundaries of terrains, modify fbm octaves or freq, modify which axis it rotates on - float terrainMap = worley2(vec3(fbm(vs_Pos, 6., 1.7))); + // biomes = water, terraces, mountains, sand + // toolbox = smooth step (fbm and perlin), sin wave (terraces), jitter scattering (worley), gain to animate light + // gui = modify boundaries of terrains, modify fbm octaves or freq, + float terrainMap = worley2(vec3(fbm(vs_Pos, 6., 1.2 + u_Fragments * .1))); vec4 noisePos = vs_Pos; - if (terrainMap < .28) { + if (terrainMap < .28 + (u_Sea * .06)) { // water (use worley to animate?) and use blinn phong? fs_Nor = vs_Nor; terrain_Type = 0.; - } else if (terrainMap < .44) { + } else if (terrainMap < .3) { + fs_Nor = vs_Nor; + terrain_Type = 3.; + } else if (terrainMap < .94 - (u_Mountains * .05)) { // terraces noisePos = vs_Pos + vs_Nor * perlinTerrace(vs_Pos); - vec4 norLocal = normalize(perlinTerraceNormal(vs_Pos)); - float dot = dot(normalize(norLocal), vec4(0, 0, 1, 0)); - fs_Nor = transformToWorld(norLocal); - if (dot > .98) { - terrain_Type = 2.; - } else { - terrain_Type = 3.; - } + fs_Nor = transformToWorld(normalize(perlinTerraceNormal(vs_Pos))); + terrain_Type = 2.; + } else if (terrainMap < .98 - (u_Mountains * .05)) { + // smaller mountains + noisePos = vs_Pos + vs_Nor * perlinMountains(vs_Pos, 1.); + fs_Nor = transformToWorld(normalize(perlinMoutainNormal(vs_Pos, .4))); + terrain_Type = 1.; } else { // mountains - float perlin = perlinMountains(vs_Pos); - noisePos = vs_Pos + vs_Nor * perlin; - fs_Nor = transformToWorld(normalize(perlinMoutainNormal(vs_Pos))); + noisePos = vs_Pos + vs_Nor * perlinMountains(vs_Pos, 1.7); + fs_Nor = transformToWorld(normalize(perlinMoutainNormal(vs_Pos, 1.7))); terrain_Type = 1.; } return noisePos; } +float GetBias(float time, float bias) +{ + return (time / ((((1.0/bias) - 2.0)*(1.0 - time))+1.0)); +} + +float GetGain(float time, float gain) +{ + if(time < 0.5) + return GetBias(time * 2.0,gain)/2.0; + else + return GetBias(time * 2.0 - 1.0,1.0 - gain)/2.0 + 0.5; +} + void main() { fs_Col = vs_Col; @@ -393,8 +396,10 @@ void main() fs_Pos = modelposition; fs_Nor = vec4(invTranspose * vec3(fs_Nor), 0); - - fs_LightVec = lightPos - modelposition; // Compute the direction in which the light source lies + + vec4 light = mix(vec4(10., 4., 10., 1.), vec4(-10., 4., 10., 1.), GetGain((sin(float(u_Time)*.04) + 1.)/2., .75)); + fs_LightPos = light; + fs_LightVec = light - 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 } diff --git a/src/shaders/test-frag.glsl b/src/shaders/test-frag.glsl index 3979fff..ef41ab4 100644 --- a/src/shaders/test-frag.glsl +++ b/src/shaders/test-frag.glsl @@ -116,9 +116,9 @@ float interpNoise3D(float x, float y, float z) { float fbm(float x, float y, float z) { float total = 0.; float persistence = 0.5f; - float octaves = 16.; + float octaves = 6.; for(float i = 1.; i <= octaves; i++) { - float freq = pow(2., i); + float freq = pow(1.9, i); float amp = pow(persistence, i); total += interpNoise3D(x * freq, y * freq, z * freq) * amp; } @@ -147,33 +147,36 @@ void main() // vec3 perlinColor = a + b * cos(6.28 * worley(vec3(fs_Pos)) * perlinNoise * 4. * c + d); // Compute final shaded color - float f = fbm(fs_Pos.x*1.5, fs_Pos.y*1.5, fs_Pos.z*1.5); + float f = fbm(fs_Pos.x, fs_Pos.y, fs_Pos.z); vec4 pos = fs_Pos; pos = fs_Pos + f; // THIS IS COOL!!!!!!!!!!!! // f = fbm(pos.x, pos.y + .001*float(u_Time), pos.z); - vec3 a = vec3(0.38, .36, .3); - vec3 b = vec3(0.150); + vec3 a = vec3(1, .9, .8); + vec3 b = vec3(0.20); vec3 c = vec3(1.000); vec3 d = vec3(0); vec3 color = a + b * cos(6.28 * (f * c + d)); out_Col = vec4(color, 1.); // swirly fbm - // float terrainMap = worley(vec3(f)); - // vec3 color; - // if (terrainMap < .28) { - // color = vec3(0., 0., 1); - // } else if (terrainMap < .44) { - // color = vec3(1., 1., 0.); - // } else { - // color = vec3(.5); - // } + float terrainMap = worley(vec3(f)); + if (terrainMap < .28) { + color = vec3(.2, .2, .8); + } else if (terrainMap < .3) { + color = vec3(.5, .5, .2); + } else if (terrainMap < .44) { + color = vec3(.2, .8, .2); + } else if (terrainMap < .48) { + color = vec3(.5, .5, .5); + } else { + color = vec3(0); + } // vec3 a = vec3(0.9); // vec3 b = vec3(0.250); // vec3 c = vec3(1.000); // vec3 d = vec3(0); // vec3 color = a + b * cos(6.28 * (worley(vec3(f)) * c + d)); - // out_Col = vec4(color, 1); //worley and fbm (lowered octave from 4 to 2 for bigger chunks) + out_Col = vec4(color, 1); //worley and fbm (lowered octave from 4 to 2 for bigger chunks) } From 015ab3368ef497e3ad0b31d3685c19f4f02bf8de Mon Sep 17 00:00:00 2001 From: Sharon Dong Date: Sat, 25 Sep 2021 22:46:57 -0400 Subject: [PATCH 11/15] idk what i did --- src/shaders/planet-vert.glsl | 83 ++---------------------------------- 1 file changed, 3 insertions(+), 80 deletions(-) diff --git a/src/shaders/planet-vert.glsl b/src/shaders/planet-vert.glsl index 3042574..34f28cd 100644 --- a/src/shaders/planet-vert.glsl +++ b/src/shaders/planet-vert.glsl @@ -80,7 +80,7 @@ float perlin(vec3 p) { } } // float sum = surfletSum / 4.; - // return (sum + 1. )/2.; + // return (sum + 1. )/2.; // kinda creates cool earth like land masses return surfletSum / 4.; } @@ -88,12 +88,7 @@ float perlinTerrace(vec4 p) { p *= 1.5; float noise = perlin(vec3(p)) + .5 * perlin(2.f * vec3(p)) + 0.25 * perlin(4.f * vec3(p)); float rounded = (round(noise * 30.f) / 30.f); - float terrace = (noise + sin(200.*noise + 3.)*.006) *.9; - - // float rounded = perlin(p.xyz); - //terrace = rounded; - //terrace *= random1(vec3(terrace)); - //noise = mix(noise, terrace, random1(vec3(terrace))); + float terrace = (noise + sin(290.*noise + 3.)*.004) *.8; return terrace + .005; } @@ -250,36 +245,6 @@ vec4 fbmNormal(vec4 p, float oct, float freq) { } float worley(vec3 p) { - p *= 1.5; - vec3 pInt = floor(p); - vec3 pFract = fract(p); - float minDist = 1.0; - float secondDist = 1.0; - for (int x = -1; x <= 1; x++) { - for (int y = -1; y <= 1; y++) { - for (int z = -1; z <= 1; z++) { - // if (random1(vec3(x, y, z)) < .6) { - // continue; - // } - vec3 neighbor = vec3(float(x), float(y), float(z)); - vec3 voronoi = random3(pInt + neighbor); - //voronoi = 0.5 + 0.5 * sin(0.01 * float(u_Time) + 13.2831 * voronoi); - vec3 diff = neighbor + voronoi - pFract; - float dist = length(diff); - if (dist < minDist) { - secondDist = minDist; - minDist = dist; - } else if (dist < secondDist) { - secondDist = dist; - } - } - } - } - //return 1.0 - minDist; - return (-1. * minDist + 1. * secondDist); -} - -float worley2(vec3 p) { vec3 pInt = floor(p); vec3 pFract = fract(p); float minDist = 1.0; @@ -297,38 +262,11 @@ float worley2(vec3 p) { return 1.0 - minDist; } -float worleyAdded(vec4 pos) { - float offset = ((worley(vec3(pos * 6.)))) / .5; // Can divide by different factors or not at all for plateus!!!!!!!!!!!!!! - offset = clamp(offset, .1, .15); - - // if (offset.x > 0. && offset.y > 0. && offset.z > 0.) { - // offset = vec3(mix(vec3(fbm2(pos)), offset, .85)); - // } - offset/=5.; - return offset; -} - -vec4 worleyNormal(vec4 p) { - float xNeg = worleyAdded((p + vec4(-.00001, 0, 0, 0))); - float xPos = worleyAdded((p + vec4(.00001, 0, 0, 0))); - float xDiff = (xPos - xNeg); - - float yNeg = worleyAdded((p + vec4(0, -.00001, 0, 0))); - float yPos = worleyAdded((p + vec4(0, .00001, 0, 0))); - float yDiff = (yPos - yNeg); - - float zNeg = worleyAdded((p + vec4(0, 0, -.00001, 0))); - float zPos = worleyAdded((p + vec4(0, 0, .00001, 0))); - float zDiff = (zPos - zNeg); - - return (vec4(vec3(xDiff, yDiff, zDiff), 0)); -} - vec4 getTerrain() { // biomes = water, terraces, mountains, sand // toolbox = smooth step (fbm and perlin), sin wave (terraces), jitter scattering (worley), gain to animate light // gui = modify boundaries of terrains, modify fbm octaves or freq, - float terrainMap = worley2(vec3(fbm(vs_Pos, 6., 1.2 + u_Fragments * .1))); + float terrainMap = worley(vec3(fbm(vs_Pos, 6., 1.2 + u_Fragments * .1))); vec4 noisePos = vs_Pos; if (terrainMap < .28 + (u_Sea * .06)) { // water (use worley to animate?) and use blinn phong? @@ -376,21 +314,6 @@ void main() fs_Nor = vec4(invTranspose * vec3(vs_Nor), 0); vec4 noisePos = getTerrain(); - - // // cracked floor - // float worl = worleyAdded(vs_Pos); - // vec4 worleyNoise = vs_Pos + vs_Nor * worl; - - // // terraces - vec4 perlinTerrace = vs_Pos + vs_Nor * perlinTerrace(vs_Pos); - - // // big mountains - // vec4 perlinMountains = vs_Pos + vs_Nor * (perlinMountains(vs_Pos)); - // // big mountains2 - // vec4 fbmNoise = vs_Pos + vs_Nor * fbm(vs_Pos, 6.); - - // // hills - // vec4 hills = vs_Pos + vs_Nor * mix(fbm2(vs_Pos), worley(vec3(worley(vec3(vs_Pos)))) / 4., .9); vec4 modelposition = u_Model * noisePos; fs_Pos = modelposition; From 7b4e074ab8cd0fc762b370881f74318330cabaf8 Mon Sep 17 00:00:00 2001 From: sharond106 <47503431+sharond106@users.noreply.github.com> Date: Sun, 26 Sep 2021 00:55:24 -0400 Subject: [PATCH 12/15] Create README.md --- README.md | 113 +++++++++++++++++++----------------------------------- 1 file changed, 39 insertions(+), 74 deletions(-) diff --git a/README.md b/README.md index 44a3023..f22fc90 100644 --- a/README.md +++ b/README.md @@ -1,77 +1,42 @@ -# HW 0: Noisy Planet Part 1 (Intro to Javascript and WebGL) -Link: [https://sharond106.github.io/hw00-webgl-intro/](https://sharond106.github.io/hw00-webgl-intro/) - +# HW 1: Noisy Planets +Sharon Dong (PennKey: sharondo) + +Live demo: https://sharond106.github.io/hw00-webgl-intro/ + +## Techniques +- Terrain Placement + - The base noise function that determines where the terrain and ocean lie uses worley noise warped with fbm: `color = worley(fbm(p))` +- Mountains + - Terrain created with summed perlin noise at different frequencies: `height = perlin(p) + 0.5*perlin(2*p) + .25*perlin(4*p)` + - Colored with a cosine color palette and worley noise warped with fbm +- Terraces + - Terrain created with summed perlin noise at different frequencies + - Steps created with a modified sin function: `(perlin + A *sin(B*perlin + C))*f` + - Colored with a cosine color palette and fbm +- Ocean + - Colored with a cosine color palette and warped fbm: `color = fbm(p + fbm(p))` + - Animated by displacing the input to my fbm noise with time + - Blinn phong shading to make white parts look a little snowy +- Sand + - Colored with a cosine color palette and fbm + - Blinn phong shading to represent wet sand +- Sun + - Moves from left to right and animated with a .75 gain function +- GUI + - Sea level slider changes the threshold of the terrain placement noise value that determines where ocean lies + - Mountains slider works similarly + - Fragmentation slider changes the frequency of the fbm used for terrain placement +- More about the noise functions + - All noise functions are 3D + - My perlin noise and fbm functions use a quintic smooth step function for interpolation + - +## Helpful Resources I Used +- https://www.redblobgames.com/maps/terrain-from-noise/ +- https://iquilezles.org/www/articles/warp/warp.htm +- https://iquilezles.org/www/articles/palettes/palettes.htm +- https://thebookofshaders.com/edit.php#12/metaballs.frag + +# HW 0: Intro to Javascript and WebGL The fragment shader is implemented with 3D perlin and worley noise, both displaced with time. You can change one of the base colors using the color picker in the gui on the top right. The vertex shader displaces x and y coordinates with a sin function over time. ![Alt Text](https://media.giphy.com/media/MXjh2U0hGcgwJuGp27/giphy.gif?cid=790b761104e45ac8167ff98bc109ed47be8e78d0f975ffac&rid=giphy.gif&ct=g) - -## Objective -- Check that the tools and build configuration we will be using for the class works. -- Start learning Typescript and WebGL2 -- Practice implementing noise - -## Forking the Code -Rather than cloning the homework repository, please __fork__ the code into your own repository using the `Fork` button in the upper-right hand corner of the Github UI. This will enable you to have your own personal repository copy of the code, and let you make a live demo (described later in this document). - -## Running the Code - -1. [Install Node.js](https://nodejs.org/en/download/). Node.js is a JavaScript runtime. It basically allows you to run JavaScript when not in a browser. For our purposes, this is not necessary. The important part is that with it comes `npm`, the Node Package Manager. This allows us to easily declare and install external dependencies such as [dat.GUI](https://workshop.chromeexperiments.com/examples/gui/#1--Basic-Usage), and [glMatrix](http://glmatrix.net/). - -2. Using a command terminal, run `npm install` in the root directory of your project. This will download all of those dependencies. - -3. Do either of the following (but we highly recommend the first one for reasons we will explain later). - - a. Run `npm start` and then go to `localhost:5660` in your web browser - - b. Run `npm run build` and then go open `dist/index.html` in your web browser - -## Module Bundling -One of the most important dependencies of our projects is [Webpack](https://webpack.js.org/concepts/). Webpack is a module bundler which allows us to write code in separate files and use `import`s and `export`s to load classes and functions for other files. It also allows us to preprocess code before compiling to a single file. We will be using [Typescript](https://www.typescriptlang.org/docs/home.html) for this course which is Javascript augmented with type annotations. Webpack will convert Typescript files to Javascript files on compilation and in doing so will also check for proper type-safety and usage. Read more about Javascript modules in the resources section below. - -## Developing Your Code -All of the JavaScript code is living inside the `src` directory. The main file that gets executed when you load the page as you may have guessed is `main.ts`. Here, you can make any changes you want, import functions from other files, etc. The reason that we highly suggest you build your project with `npm start` is that doing so will start a process that watches for any changes you make to your code. If it detects anything, it'll automagically rebuild your project and then refresh your browser window for you. Wow. That's cool. If you do it the other way, you'll need to run `npm build` and then refresh your page every time you want to test something. - -We would suggest editing your project with Visual Studio Code https://code.visualstudio.com/. Microsoft develops it and Microsoft also develops Typescript so all of the features work nicely together. Sublime Text and installing the Typescript plugins should probably work as well. - -## Assignment Details -1. Take some time to go through the existing codebase so you can get an understanding of syntax and how the code is architected. Much of the code is designed to mirror the class structures used in CIS 460's OpenGL assignments, so it should hopefully be somewhat familiar. -2. Take a look at the resources linked in the section below. Definitely read about Javascript modules and Typescript. The other links provide documentation for classes used in the code. -3. Add a `Cube` class that inherits from `Drawable` and at the very least implement a constructor and its `create` function. Then, add a `Cube` instance to the scene to be rendered. -4. Read the documentation for dat.GUI below. Update the existing GUI in `main.ts` with a parameter to alter the color passed to `u_Color` in the Lambert shader. -5. Write a custom fragment shader that implements FBM, Worley Noise, or Perlin Noise based on 3D inputs (as opposed to the 2D inputs in the slides). This noise must be used to modify your fragment color. If your custom shader is particularly interesting, you'll earn some bonus points. -6. Write a custom vertex shader that uses a trigonometric function (e.g. `sin`, `tan`) to non-uniformly modify your cube's vertex positions over time. This will necessitate instantiating an incrementing variable in your Typescript code that you pass to your shader every tick. Refer to the base code's methods of passing variables to shaders if you are unsure how to do so. -7. Feel free to update any of the files when writing your code. The implementation of the `OpenGLRenderer` is currently very simple. - -## Making a Live Demo -When you push changes to the `master` branch of your repository on Github, a Github workflow will run automatically which builds your code and pushes the build to a new branch `gh-pages`. The configuration file which handles this is located at `.github/workflows/build-and-deploy.yml`. If you want to modify this, you can read more about workflows [here](https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions). - -Once your built code is pushed to `gh-pages`, Github can automatically publish a live site. Configure that by: - - 1. Open the Settings tab of your repository in Github. - - 2. Scroll down to the Pages tab of the Settings (in the table on the left) and choose which branch to make the source for the deployed project. This should be the `gh-pages` branch which is automatically created after the first successful build of the `master` branch. - - 3. Done! Now, any new commits on the `master` branch will be built and pushed to `gh-pages`. The project should be visible at http://username.github.io/repo-name. -  - -To check if everything is on the right track: - -1. Make sure the `gh-pages` branch of your repo has a files called `index.html`, `bundle.js`, and `bundle.js.map` - -2. In the settings tab of the repo, under Pages, make sure it says your site is published at some url. - -## Submission -1. Create a pull request to this repository with your completed code. -2. Update README.md to contain a solid description of your project with a screenshot of some visuals, and a link to your live demo. -3. Submit the link to your pull request on Canvas, and add a comment to your submission with a hyperlink to your live demo. -4. Include a link to your live site. - -## Resources -- Javascript modules https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import -- Typescript https://www.typescriptlang.org/docs/home.html -- dat.gui https://workshop.chromeexperiments.com/examples/gui/ -- glMatrix http://glmatrix.net/docs/ -- WebGL - - Interfaces https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API - - Types https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Types - - Constants https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Constants From 9bd85162eec194b71ad2ac0587fe75f4e8147ac2 Mon Sep 17 00:00:00 2001 From: Sharon Dong Date: Mon, 27 Sep 2021 15:54:26 -0400 Subject: [PATCH 13/15] added moon and gui options --- src/main.ts | 29 +++++- src/rendering/gl/OpenGLRenderer.ts | 30 +++--- src/rendering/gl/ShaderProgram.ts | 9 ++ src/shaders/moon-frag.glsl | 98 +++++++++++++++++++ src/shaders/moon-vert.glsl | 150 +++++++++++++++++++++++++++++ src/shaders/planet-vert.glsl | 21 +++- src/shaders/test-frag.glsl | 26 ++--- 7 files changed, 331 insertions(+), 32 deletions(-) create mode 100644 src/shaders/moon-frag.glsl create mode 100644 src/shaders/moon-vert.glsl diff --git a/src/main.ts b/src/main.ts index 8b02b77..1ce7161 100644 --- a/src/main.ts +++ b/src/main.ts @@ -17,6 +17,7 @@ const controls = { }; let icosphere: Icosphere; +let moon: Icosphere; let square: Square; let cube: Cube; let prevTesselations: number = 8; @@ -26,6 +27,9 @@ let time: number = 0; function loadScene() { icosphere = new Icosphere(vec3.fromValues(0, 0, 0), 1, controls.tesselations); icosphere.create(); + moon = new Icosphere(vec3.fromValues(0, 0, 0), .25, 8.); + // moon = new Icosphere(vec3.fromValues(2, 0, 0), .25, 6.); + moon.create(); square = new Square(vec3.fromValues(0, 0, 0)); square.create(); cube = new Cube(vec3.fromValues(0, 0, 0)); @@ -61,6 +65,10 @@ function main() { level : 5 }; gui.add(fragments, 'level', 0, 8).name('Fragmentation'); + var showObjs = { + display : "Planet and moon" + } + gui.add(showObjs, 'display').options(['Planet and moon', 'Planet only', 'Moon only']).name('Display'); // get canvas and webgl context const canvas = document.getElementById('canvas'); @@ -97,6 +105,10 @@ function main() { new Shader(gl.VERTEX_SHADER, require('./shaders/test-vert.glsl')), new Shader(gl.FRAGMENT_SHADER, require('./shaders/test-frag.glsl')), ]); + const moon_lambert = new ShaderProgram([ + new Shader(gl.VERTEX_SHADER, require('./shaders/moon-vert.glsl')), + new Shader(gl.FRAGMENT_SHADER, require('./shaders/moon-frag.glsl')), + ]); // This function will be called every frame function tick() { @@ -116,11 +128,18 @@ function main() { icosphere = new Icosphere(vec3.fromValues(0, 0, 0), 1, prevTesselations); icosphere.create(); } - renderer.render(camera, planet, [ - icosphere, - //square, - //cube - ], color.color, time, sea.level, terrain.mountains, fragments.level); + + if (showObjs.display === "Planet and moon") { + renderer.render(camera, [planet, moon_lambert], + [icosphere, moon], color.color, time, sea.level, terrain.mountains, fragments.level, true); + } else if (showObjs.display === "Planet only") { + renderer.render(camera, [planet], + [icosphere], color.color, time, sea.level, terrain.mountains, fragments.level, false); + } else { + renderer.render(camera, [moon_lambert], + [moon], color.color, time, sea.level, terrain.mountains, fragments.level, false); + } + stats.end(); // Tell the browser to call `tick` again whenever it renders a new frame diff --git a/src/rendering/gl/OpenGLRenderer.ts b/src/rendering/gl/OpenGLRenderer.ts index a356f41..970b2e5 100644 --- a/src/rendering/gl/OpenGLRenderer.ts +++ b/src/rendering/gl/OpenGLRenderer.ts @@ -22,25 +22,29 @@ class OpenGLRenderer { gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); } - render(camera: Camera, prog: ShaderProgram, drawables: Array, color: Array, - time: number, sea: number, mtn: number, frag: number) { + render(camera: Camera, progs: Array, drawables: Array, color: Array, + time: number, sea: number, mtn: number, frag: number, display: boolean) { 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(vec4.fromValues(color[0]/255, color[1]/255, color[2]/255, 1)); - prog.setTime(time); - prog.setCamPos(vec4.fromValues(camera.position[0], camera.position[1], camera.position[2], 1.)); - prog.setSea(sea); - prog.setMountains(mtn); - prog.setFragments(frag); - - for (let drawable of drawables) { - prog.draw(drawable); + for (let i = 0; i < progs.length; ++i) { + let prog = progs[i]; + prog.setModelMatrix(model); + prog.setViewProjMatrix(viewProj); + // prog.setGeometryColor(vec4.fromValues(color[0]/255, color[1]/255, color[2]/255, 1)); + prog.setTime(time); + prog.setCamPos(vec4.fromValues(camera.position[0], camera.position[1], camera.position[2], 1.)); + prog.setSea(sea); + prog.setMountains(mtn); + prog.setFragments(frag); + prog.draw(drawables[i]); + if (display) + prog.setPlanetAndMoon(1.); + else + prog.setPlanetAndMoon(0.); } } }; diff --git a/src/rendering/gl/ShaderProgram.ts b/src/rendering/gl/ShaderProgram.ts index b763a12..157627f 100644 --- a/src/rendering/gl/ShaderProgram.ts +++ b/src/rendering/gl/ShaderProgram.ts @@ -34,6 +34,7 @@ class ShaderProgram { unifSeaLevel: WebGLUniformLocation; unifMountains: WebGLUniformLocation; unifFragments: WebGLUniformLocation; + unifPlanetAndMoon: WebGLUniformLocation; constructor(shaders: Array) { this.prog = gl.createProgram(); @@ -58,6 +59,7 @@ class ShaderProgram { this.unifSeaLevel = gl.getUniformLocation(this.prog, "u_Sea"); this.unifMountains = gl.getUniformLocation(this.prog, "u_Mountains"); this.unifFragments = gl.getUniformLocation(this.prog, "u_Fragments"); + this.unifPlanetAndMoon = gl.getUniformLocation(this.prog, "u_PlanetAndMoon"); } use() { @@ -130,6 +132,13 @@ class ShaderProgram { } } + setPlanetAndMoon(x: number) { + this.use(); + if(this.unifPlanetAndMoon != -1) { + gl.uniform1f(this.unifPlanetAndMoon, x); + } + } + draw(d: Drawable) { this.use(); diff --git a/src/shaders/moon-frag.glsl b/src/shaders/moon-frag.glsl new file mode 100644 index 0000000..86c8a2f --- /dev/null +++ b/src/shaders/moon-frag.glsl @@ -0,0 +1,98 @@ +#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. + +// 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_Pos; +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. +float random1( vec3 p ) { + return fract(sin((dot(p, vec3(127.1, + 311.7, + 191.999)))) * + 18.5453); +} + +float smootherStep(float a, float b, float t) { + t = t*t*t*(t*(t*6.0 - 15.0) + 10.0); + return mix(a, b, t); +} + +float interpNoise3D(float x, float y, float z) { + x *= 2.; + y *= 2.; + z *= 2.; + float intX = floor(x); + float fractX = fract(x); + float intY = floor(y); + float fractY = fract(y); + float intZ = floor(z); + float fractZ = fract(z); + float v1 = random1(vec3(intX, intY, intZ)); + float v2 = random1(vec3(intX + 1., intY, intZ)); + float v3 = random1(vec3(intX, intY + 1., intZ)); + float v4 = random1(vec3(intX + 1., intY + 1., intZ)); + + float v5 = random1(vec3(intX, intY, intZ + 1.)); + float v6 = random1(vec3(intX + 1., intY, intZ + 1.)); + float v7 = random1(vec3(intX, intY + 1., intZ + 1.)); + float v8 = random1(vec3(intX + 1., intY + 1., intZ + 1.)); + + float i1 = smootherStep(v1, v2, fractX); + float i2 = smootherStep(v3, v4, fractX); + float result1 = smootherStep(i1, i2, fractY); + float i3 = smootherStep(v5, v6, fractX); + float i4 = smootherStep(v7, v8, fractX); + float result2 = smootherStep(i3, i4, fractY); + return smootherStep(result1, result2, fractZ); +} + +float fbm(float x, float y, float z) { + float total = 0.; + float persistence = 0.5f; + float octaves = 6.; + for(float i = 1.; i <= octaves; i++) { + float freq = pow(2., i); + float amp = pow(persistence, i); + total += interpNoise3D(x * freq, y * freq, z * freq) * amp; + } + return total; +} + +void main() +{ + // Material base color (before shading) + vec4 diffuseColor = vec4(.5, .5, .5, 1); + + // Calculate the diffuse term for Lambert shading + float diffuseTerm = dot(normalize(fs_Nor), normalize(fs_LightVec)); + // Avoid negative lighting values + diffuseTerm = clamp(diffuseTerm, 0.f, 1.f); + + 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. + float f = fbm(fs_Pos.x, fs_Pos.y, fs_Pos.z); + + // Compute final shaded color + out_Col = vec4(vec3(clamp(f * 1.2 * lightIntensity, 0., .9)), 1); + // out_Col = vec4((fs_Nor.xyz + vec3(1.)) * 0.5, 1.); +} diff --git a/src/shaders/moon-vert.glsl b/src/shaders/moon-vert.glsl new file mode 100644 index 0000000..fd55fd6 --- /dev/null +++ b/src/shaders/moon-vert.glsl @@ -0,0 +1,150 @@ +#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 int u_Time; +uniform float u_PlanetAndMoon; + +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; + + +vec3 random3(vec3 p) { + return fract(sin(vec3(dot(p,vec3(127.1, 311.7, 191.999)), + dot(p,vec3(269.5, 183.3, 765.54)), + dot(p, vec3(420.69, 631.2,109.21)))) + *43758.5453); +} + +float worley(vec3 p) { + p *= 20.; + vec3 pInt = floor(p); + vec3 pFract = fract(p); + float minDist = 1.0; + for (int x = -1; x <= 1; x++) { + for (int y = -1; y <= 1; y++) { + for (int z = -1; z <= 1; z++) { + vec3 neighbor = vec3(float(x), float(y), float(z)); + vec3 voronoi = random3(pInt + neighbor); + vec3 diff = neighbor + voronoi - pFract; + float dist = length(diff); + minDist = min(minDist, dist*minDist); + } + } + } + return minDist; +} + + +vec3 cartesian(float r, float theta, float phi) { + return vec3(r * sin(phi) * cos(theta), + r * sin(phi) * sin(theta), + r * cos(phi)); +} + +// output is vec3(radius, theta, phi) +vec3 polar(vec4 p) { + float r = sqrt(p.x * p.x + p.y * p.y + p.z * p.z); + float theta = atan(p.y / p.x); + float phi = acos(p.z / sqrt(p.x * p.x + p.y * p.y + p.z * p.z)); + return vec3(r, theta, phi); +} + +vec4 transformToWorld(vec4 nor) { + vec3 normal = normalize(vec3(vs_Nor)); + vec3 tangent = normalize(cross(vec3(0.0, 1.0, 0.0), normal)); + vec3 bitangent = normalize(cross(normal, tangent)); + mat4 transform; + transform[0] = vec4(tangent, 0.0); + transform[1] = vec4(bitangent, 0.0); + transform[2] = vec4(normal, 0.0); + transform[3] = vec4(0.0, 0.0, 0.0, 1.0); + return vec4(normalize(vec3(transform * nor)), 0.0); +} + +vec4 worleyNormal(vec4 p) { + vec3 polars = polar(p); + float offset = .01; + vec3 xNeg = cartesian(polars.x, polars.y - offset, polars.z); + vec3 xPos = cartesian(polars.x, polars.y + offset, polars.z); + vec3 yNeg = cartesian(polars.x, polars.y, polars.z - offset); + vec3 yPos = cartesian(polars.x, polars.y, polars.z + offset); + float xNegNoise = step(.12, worley(xNeg)) * .02; + float xPosNoise = step(.12, worley(xPos)) * .02; + float yNegNoise = step(.12, worley(yNeg)) * .02; + float yPosNoise = step(.12, worley(yPos)) * .02; + + float xDiff = (xPosNoise - xNegNoise) * 10.; + float yDiff = (yPosNoise - yNegNoise) * 10.; + p.z = sqrt(1. - xDiff * xDiff - yDiff * yDiff); + return vec4(vec3(xDiff, yDiff, p.z), 0); +} + +float GetBias(float time, float bias) +{ + return (time / ((((1.0/bias) - 2.0)*(1.0 - time))+1.0)); +} + +float GetGain(float time, float gain) +{ + if(time < 0.5) + return GetBias(time * 2.0,gain)/2.0; + else + return GetBias(time * 2.0 - 1.0,1.0 - gain)/2.0 + 0.5; +} + +void main() +{ + fs_Col = vs_Col; // Pass the vertex colors to the fragment shader for interpolation + + mat3 invTranspose = mat3(u_ModelInvTr); + + vec4 pos; + vec4 lightPos; + if (u_PlanetAndMoon > 0.) { + float angle = .01 * float(u_Time); + vec4 col0 = vec4(cos(angle), 0, -1.*sin(angle), 0); + vec4 col1 = vec4(0, 1, 0, 0); + vec4 col2 = vec4(sin(angle), 0, cos(angle), 0); + vec4 col3 = vec4(0, 0, 0, 1); + mat4 rotate = mat4(col0, col1, col2, col3); + pos = rotate * (vs_Pos + vec4(2., 0., 0., 0.)); + lightPos = rotate * vec4(10, 0, 0, 1); + } else { + pos = vs_Pos; + lightPos = mix(vec4(10., 4., 10., 1.), vec4(-10., 4., 10., 1.), GetGain((sin(float(u_Time)*.01) + 1.)/2., .75)); + } + + vec4 modelposition = u_Model * pos; + fs_Pos = vs_Pos; + fs_Nor = transformToWorld(normalize(worleyNormal(vs_Pos))); + + 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 +} diff --git a/src/shaders/planet-vert.glsl b/src/shaders/planet-vert.glsl index 34f28cd..e6a3dae 100644 --- a/src/shaders/planet-vert.glsl +++ b/src/shaders/planet-vert.glsl @@ -23,6 +23,7 @@ uniform vec4 u_CameraPos; uniform float u_Sea; uniform float u_Mountains; uniform float u_Fragments; +uniform float u_PlanetAndMoon; in vec4 vs_Pos; // The array of vertex positions passed to the shader @@ -145,6 +146,13 @@ vec4 perlinTerraceNormal(vec4 p) { float yDiff = (yPosNoise - yNegNoise) * 1000.; p.z = sqrt(1. - xDiff * xDiff - yDiff * yDiff); return vec4(vec3(xDiff, yDiff, p.z), 0); + // vec3 normal = vec3(vs_Nor); + // vec3 tangent = cross(vec3(0, 1, 0), normal); + // vec3 bitangent = cross(normal, tangent); + // vec3 p1 = vec3(vs_Pos) + .0001 * tangent + tangent * perlinTerrace(p + vec4(.0001*tangent, 0.)); + // vec3 p2 = vec3(vs_Pos) + .0001 * bitangent + bitangent * perlinTerrace(p + vec4(.0001*bitangent, 0.)); + // vec3 p3 = vec3(vs_Pos) + normal * perlinTerrace(p); + // return vec4(cross(p3 - p1, p3 - p2), 0); } vec4 perlinMoutainNormal(vec4 p, float factor) { @@ -320,7 +328,18 @@ void main() fs_Nor = vec4(invTranspose * vec3(fs_Nor), 0); - vec4 light = mix(vec4(10., 4., 10., 1.), vec4(-10., 4., 10., 1.), GetGain((sin(float(u_Time)*.04) + 1.)/2., .75)); + vec4 light; + if (u_PlanetAndMoon > 0.) { + float angle = .01 * float(u_Time); + vec4 col0 = vec4(cos(angle), 0, -1.*sin(angle), 0); + vec4 col1 = vec4(0, 1, 0, 0); + vec4 col2 = vec4(sin(angle), 0, cos(angle), 0); + vec4 col3 = vec4(0, 0, 0, 1); + mat4 rotate = mat4(col0, col1, col2, col3); + light = rotate * vec4(-2, 0, 0, 1); + } else { + light = mix(vec4(10., 4., 10., 1.), vec4(-10., 4., 10., 1.), GetGain((sin(float(u_Time)*.02) + 1.)/2., .75)); + } fs_LightPos = light; fs_LightVec = light - 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 diff --git a/src/shaders/test-frag.glsl b/src/shaders/test-frag.glsl index ef41ab4..8ad9123 100644 --- a/src/shaders/test-frag.glsl +++ b/src/shaders/test-frag.glsl @@ -118,7 +118,7 @@ float fbm(float x, float y, float z) { float persistence = 0.5f; float octaves = 6.; for(float i = 1.; i <= octaves; i++) { - float freq = pow(1.9, i); + float freq = pow(2., i); float amp = pow(persistence, i); total += interpNoise3D(x * freq, y * freq, z * freq) * amp; } @@ -160,18 +160,18 @@ void main() out_Col = vec4(color, 1.); // swirly fbm - float terrainMap = worley(vec3(f)); - if (terrainMap < .28) { - color = vec3(.2, .2, .8); - } else if (terrainMap < .3) { - color = vec3(.5, .5, .2); - } else if (terrainMap < .44) { - color = vec3(.2, .8, .2); - } else if (terrainMap < .48) { - color = vec3(.5, .5, .5); - } else { - color = vec3(0); - } + // loat terrainMap = worley(vec3(f)); + // if (terrainMap < .28) { + // color = vec3(.2, .2, .8); + // } else if (terrainMap < .3) { + // color = vec3(.5, .5, .2); + // } else if (terrainMap < .44) { + // color = vec3(.2, .8, .2); + // } else if (terrainMap < .48) { + // color = vec3(.5, .5, .5); + // } else { + // color = vec3(0); + // }f // vec3 a = vec3(0.9); // vec3 b = vec3(0.250); From fb125fd931c0d3b37adf7379bff67441229a6635 Mon Sep 17 00:00:00 2001 From: sharond106 <47503431+sharond106@users.noreply.github.com> Date: Mon, 27 Sep 2021 15:59:49 -0400 Subject: [PATCH 14/15] Update README.md --- README.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f22fc90..0bb0bd9 100644 --- a/README.md +++ b/README.md @@ -20,16 +20,22 @@ Live demo: https://sharond106.github.io/hw00-webgl-intro/ - Sand - Colored with a cosine color palette and fbm - Blinn phong shading to represent wet sand +- Moon + - Normals displaced with worley noise and a step function to create craters + - Rotates around the planet + - Colored with fbm - Sun - - Moves from left to right and animated with a .75 gain function + - When both planet and moon are displayed, the sun rotates with the moon, and the moon has another light source following it + - When only one of the planet/moon is displayed (selected by GUI), the sun moves from left to right, animated with a .75 gain function - GUI - Sea level slider changes the threshold of the terrain placement noise value that determines where ocean lies - Mountains slider works similarly - Fragmentation slider changes the frequency of the fbm used for terrain placement + - Drop down menu lets you choose between seeing the planet/moon - More about the noise functions - - All noise functions are 3D + - All noise functions for my vertex displacements and colors are 3D - My perlin noise and fbm functions use a quintic smooth step function for interpolation - - + ## Helpful Resources I Used - https://www.redblobgames.com/maps/terrain-from-noise/ - https://iquilezles.org/www/articles/warp/warp.htm From d236bddb2692bc034476d15cee033740461e8151 Mon Sep 17 00:00:00 2001 From: sharond106 <47503431+sharond106@users.noreply.github.com> Date: Mon, 27 Sep 2021 16:19:27 -0400 Subject: [PATCH 15/15] Update README.md --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 0bb0bd9..18fd5e4 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,12 @@ Sharon Dong (PennKey: sharondo) Live demo: https://sharond106.github.io/hw00-webgl-intro/ +![Demo](https://media.giphy.com/media/sTUCU2lnhDfj42Yg9Z/giphy.gif?cid=790b76118589ab6a6189ca2b12c1848f512325f88af6fa46&rid=giphy.gif&ct=g) + +![Orbiting](https://media.giphy.com/media/ZQpx4HRMlUwK5onReY/giphy.gif?cid=790b7611f197b4a50cf632ad91cab51d97bc258eeec0439e&rid=giphy.gif&ct=g) + +![Moon](https://media.giphy.com/media/V6r7E6UyiEFOmsn4Tv/giphy.gif?cid=790b7611ecb29652578529ac985e2ba06380ea58a0c33667&rid=giphy.gif&ct=g) + ## Techniques - Terrain Placement - The base noise function that determines where the terrain and ocean lie uses worley noise warped with fbm: `color = worley(fbm(p))`