diff --git a/README.md b/README.md index c636328..7b572b3 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,24 @@

(source: Ken Perlin)

+## Name +David Li 13109274 + +## Description +Added Color selecter. Color is also modified by a very jank fbm noise in fragment shader. Vertex shader adjusts position of vertices based on trig functions. + +Used Fbm noise to generate terrain with detailing done by Perlin. Created a temperature map by using 2d fbm, spreading outward from poles. Created a moisture map using fbm. These maps make use of bias and gain functions to adjust the terrain more favorably. Smoothstep is used to make the noise blend nicely. Fbm and a gain function were used to texture the oceans a bit. Biome/Color depends on whether value sampled at moisture map or temperature map reach a certain threshold, if this is the case, a different cosine color function is used for surpassing the temperature or moisture threshhold. There also exists a default cosine color function if neither threshold is met. The thresholds for temperature and moisture are modifiable attributes which can be adjusted to change the coldness and dryness of the planet. The cosine color functions also make use of stepping functions to generate steps of colors rather than a gradient. I also created clouds by rendering another sphere and using noise to alter the alpha value. The clouds can be toggled in controls. Lastly, a blinn phong is used to make the snowcaps whiter. + +## Used Resourcess +https://blog.demofox.org/2012/09/24/bias-and-gain-are-your-friend/ + +http://dev.thi.ng/gradients/ + +Link: https://thecollegeboardofc.github.io/hw00-webgl-intro/ + +![Test Image 1](Ss1.png) +![Test Image 1](Ss2.png) +![Test Image 1](planet.PNG) ## Objective - Check that the tools and build configuration we will be using for the class works. diff --git a/Ss1.png b/Ss1.png new file mode 100644 index 0000000..baff075 Binary files /dev/null and b/Ss1.png differ diff --git a/Ss2.png b/Ss2.png new file mode 100644 index 0000000..988b167 Binary files /dev/null and b/Ss2.png differ diff --git a/planet.PNG b/planet.PNG new file mode 100644 index 0000000..b3c0c2f Binary files /dev/null and b/planet.PNG differ diff --git a/src/geometry/Cube.ts b/src/geometry/Cube.ts new file mode 100644 index 0000000..4d5bfb7 --- /dev/null +++ b/src/geometry/Cube.ts @@ -0,0 +1,93 @@ +import {vec3, vec4} from 'gl-matrix'; +import Drawable from '../rendering/gl/Drawable'; +import {gl} from '../globals'; + +class Cube extends Drawable { + buffer: ArrayBuffer; + indices: Uint32Array; + positions: Float32Array; + normals: Float32Array; + corner: vec4; + + constructor(corner: vec3, public length: number) { + super(); + this.corner = vec4.fromValues(corner[0], corner[1], corner[2], 1); + } + + create() { + this.positions = new Float32Array ( + // front face + [1, 1, 1, 1, + 1, -1, 1, 1, + -1, -1, 1, 1, + -1, 1, 1, 1, + // back face + 1, 1, -1, 1, + -1, 1, -1, 1, + -1, -1, -1, 1, + 1, -1, -1, 1, + // right fac + 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, + 1, -1, -1, 1]); + + this.normals = new Float32Array([0, 0, 1, 0, + 0, 0, 1, 0, + 0, 0, 1, 0, + 0, 0, 1, 0, + 0, 0, -1, 0, + 0, 0, -1, 0, + 0, 0, -1, 0, + 0, 0, -1, 0, + 1, 0, 0, 0, + 1, 0, 0, 0, + 1, 0, 0, 0, + 1, 0, 0, 0, + -1, 0, 0, 0, + -1, 0, 0, 0, + -1, 0, 0, 0, + -1, 0, 0, 0, + 0, 1, 0, 0, + 0, 1, 0, 0, + 0, 1, 0, 0, + 0, 1, 0, 0, + 0, -1, 0, 0, + 0, -1, 0, 0, + 0, -1, 0, 0, + 0, -1, 0, 0]); + + this.indices = new Uint32Array([0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, 8, 9, 10, 8, 10, 11, 12, 13, 14, 12, 14, 15, 16, 17, 18, 16, 18, 19, 20, 21, 22, 20, 22, 23]); + + this.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); + } +}; + +export default Cube; diff --git a/src/geometry/Square.ts b/src/geometry/Square.ts index 1a21a10..a68fcf7 100644 --- a/src/geometry/Square.ts +++ b/src/geometry/Square.ts @@ -30,6 +30,7 @@ class Square extends Drawable { 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); diff --git a/src/main.ts b/src/main.ts index 65a9461..460004e 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'; @@ -11,19 +12,32 @@ 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, + temperature: .5, + moisture: .5, + clouds: 0, 'Load Scene': loadScene, // A function pointer, essentially }; +var palette = { + color: [ 0, 128, 255 ], // RGB array +}; let icosphere: Icosphere; let square: Square; let prevTesselations: number = 5; - +let cube: Cube; +let date: Date; +let time = 0.0; function loadScene() { + date = new Date(); + time = date.getTime(); icosphere = new Icosphere(vec3.fromValues(0, 0, 0), 1, controls.tesselations); icosphere.create(); square = new Square(vec3.fromValues(0, 0, 0)); square.create(); + cube = new Cube(vec3.fromValues(0,0,0), 1); + cube.create() + } function main() { @@ -38,7 +52,12 @@ function main() { // Add controls to the gui const gui = new DAT.GUI(); gui.add(controls, 'tesselations', 0, 8).step(1); + gui.add(controls, 'temperature', 0., 1.).step(.1); + gui.add(controls, 'moisture', 0., 1.).step(.1); + gui.add(controls, 'clouds', 0, 1).step(1); + gui.add(controls, 'Load Scene'); + gui.addColor(palette, 'color'); // get canvas and webgl context const canvas = document.getElementById('canvas'); @@ -58,12 +77,21 @@ function main() { const renderer = new OpenGLRenderer(canvas); renderer.setClearColor(0.2, 0.2, 0.2, 1); gl.enable(gl.DEPTH_TEST); + gl.enable(gl.BLEND); + gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); + gl.enable(gl.CULL_FACE); + gl.frontFace(gl.CW); const lambert = new ShaderProgram([ new Shader(gl.VERTEX_SHADER, require('./shaders/lambert-vert.glsl')), new Shader(gl.FRAGMENT_SHADER, require('./shaders/lambert-frag.glsl')), ]); + const cloud = new ShaderProgram([ + new Shader(gl.VERTEX_SHADER, require('./shaders/fbm-vert.glsl')), + new Shader(gl.FRAGMENT_SHADER, require('./shaders/fbm-frag.glsl')), + ]); + // This function will be called every frame function tick() { camera.update(); @@ -76,10 +104,32 @@ function main() { icosphere = new Icosphere(vec3.fromValues(0, 0, 0), 1, prevTesselations); icosphere.create(); } + let newDate: Date = new Date(); + let tickRate = newDate.getTime() - time; + let temp = controls.temperature; + let moist = controls.moisture; + + let colorVec = vec3.fromValues(palette.color[0] / 255.0, palette.color[1] / 255.0, palette.color[2] / 255.0); renderer.render(camera, lambert, [ icosphere, - // square, - ]); + ], + colorVec, + tickRate / 100.0, + temp, + moist, + ); + + if (controls.clouds > .5) { + renderer.render(camera, cloud, [ + icosphere, + ], + colorVec, + tickRate / 100.0, + temp, + moist, + ); + } + 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..1b9a91c 100644 --- a/src/rendering/gl/OpenGLRenderer.ts +++ b/src/rendering/gl/OpenGLRenderer.ts @@ -1,4 +1,4 @@ -import {mat4, vec4} from 'gl-matrix'; +import {mat4, vec4, vec3} from 'gl-matrix'; import Drawable from './Drawable'; import Camera from '../../Camera'; import {gl} from '../../globals'; @@ -22,16 +22,19 @@ 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: vec3, tickRate: number, temp: number, moist: number) { let model = mat4.create(); let viewProj = mat4.create(); - let color = vec4.fromValues(1, 0, 0, 1); - + //let color = vec4.fromValues(1, 0, 0, 1); + let colour = vec4.fromValues(color[0], color[1], color[2], 1); mat4.identity(model); mat4.multiply(viewProj, camera.projectionMatrix, camera.viewMatrix); prog.setModelMatrix(model); prog.setViewProjMatrix(viewProj); - prog.setGeometryColor(color); + prog.setGeometryColor(colour); + prog.setTick(tickRate); + prog.setMoisture(moist); + prog.setTempearture(temp); for (let drawable of drawables) { prog.draw(drawable); diff --git a/src/rendering/gl/ShaderProgram.ts b/src/rendering/gl/ShaderProgram.ts index 67fef40..bb58e69 100644 --- a/src/rendering/gl/ShaderProgram.ts +++ b/src/rendering/gl/ShaderProgram.ts @@ -25,6 +25,9 @@ class ShaderProgram { attrNor: number; attrCol: number; + unifTemperature: WebGLUniformLocation; + unifMoisture: WebGLUniformLocation; + unifTick: WebGLUniformLocation; unifModel: WebGLUniformLocation; unifModelInvTr: WebGLUniformLocation; unifViewProj: WebGLUniformLocation; @@ -44,10 +47,13 @@ class ShaderProgram { this.attrPos = gl.getAttribLocation(this.prog, "vs_Pos"); this.attrNor = gl.getAttribLocation(this.prog, "vs_Nor"); this.attrCol = gl.getAttribLocation(this.prog, "vs_Col"); - this.unifModel = gl.getUniformLocation(this.prog, "u_Model"); - this.unifModelInvTr = gl.getUniformLocation(this.prog, "u_ModelInvTr"); - this.unifViewProj = gl.getUniformLocation(this.prog, "u_ViewProj"); - this.unifColor = gl.getUniformLocation(this.prog, "u_Color"); + this.unifTick = gl.getUniformLocation(this.prog, "u_Tick"); + this.unifModel = gl.getUniformLocation(this.prog, "u_Model"); + this.unifModelInvTr = gl.getUniformLocation(this.prog, "u_ModelInvTr"); + this.unifViewProj = gl.getUniformLocation(this.prog, "u_ViewProj"); + this.unifColor = gl.getUniformLocation(this.prog, "u_Color"); + this.unifTemperature = gl.getUniformLocation(this.prog, "u_Temp"); + this.unifMoisture = gl.getUniformLocation(this.prog, "u_Moist"); } use() { @@ -85,6 +91,27 @@ class ShaderProgram { } } + setTick(tickRate: number) { + this.use(); + if (this.unifTick !== -1) { + gl.uniform1f(this.unifTick, tickRate); + } + } + + setTempearture(temperature: number) { + this.use(); + if (this.unifTemperature !== -1) { + gl.uniform1f(this.unifTemperature, temperature); + } + } + + setMoisture(moisture: number) { + this.use(); + if (this.unifMoisture !== -1) { + gl.uniform1f(this.unifMoisture, moisture); + } + } + draw(d: Drawable) { this.use(); diff --git a/src/shaders/fbm-frag.glsl b/src/shaders/fbm-frag.glsl new file mode 100644 index 0000000..01bd20f --- /dev/null +++ b/src/shaders/fbm-frag.glsl @@ -0,0 +1,115 @@ +#version 300 es + +// This is a fragment shader. If you've opened this file first, please +// open and read lambert.vert.glsl before reading on. +// Unlike the vertex shader, the fragment shader actually does compute +// the shading of geometry. For every pixel in your program's output +// screen, the fragment shader is run for every bit of geometry that +// particular pixel overlaps. By implicitly interpolating the position +// data passed into the fragment shader by the vertex shader, the fragment shader +// can compute what color to apply to its pixel based on things like vertex +// position, light position, and vertex color. +precision highp float; + +uniform float u_Tick; + +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_LightVec; +in vec4 fs_Col; +in vec4 fs_Pos; + +out vec4 out_Col; // This is the final output color that you will see on your + // screen for the pixel that is currently being processed. + + +float dot(ivec3 a, ivec3 b) { + return float(a.x * b.x + a.y * b.y + a.z * b.z); +} + +float random(ivec3 p){ + return abs(fract(184.421631 * sin(dot(p, ivec3(1932, 324, 6247))))); + // vec3 k = vec3( 3.1415926, 2.71828,6.62607015); + // p = p*k + p.yzx; + // return fract( 131.673910 * fract( p.x*p.y*(p.x+p.y)) ); +} + + +float smoothStep(float a, float b, float t) { + //t = t*(t*(t * 5.0 - .23)); + //t = clamp(t, 0.0, 1.0); + return mix(a,b,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); +} + +float interpNoise3D(vec3 p) { + int intX = int(floor(p.x)); + float fractX = fract(p.x); + int intY = int(floor(p.y)); + float fractY = fract(p.y); + int intZ = int(floor(p.z)); + float fractZ = fract(p.z); + + float v1 = random(ivec3(intX, intY, intZ)); + float v2 = random(ivec3(intX + 1, intY, intZ)); + float v3 = random(ivec3(intX, intY + 1, intZ)); + float v4 = random(ivec3(intX + 1, intY + 1, intZ)); + + float v5 = random(ivec3(intX, intY, intZ + 1)); + float v6 = random(ivec3(intX + 1, intY, intZ + 1)); + float v7 = random(ivec3(intX, intY + 1, intZ + 1)); + float v8 = random(ivec3(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(vec3 v) { + v*= 1.2; + int octave = 4; + float a = 1.0; + float val = 0.0; + for (int i = 0; i < octave; ++i) { + val += a * interpNoise3D(vec3(v.x, v.y, v.z)); + v *= 2.; + a *= 0.5; + } + return val; +} + +void main() +{ + vec4 noiseInput = fs_Pos; + float noise = fbm(vec3(noiseInput.x * 0.1, noiseInput.y * cos(u_Tick / 100.) - 1., noiseInput.z * 0.1)); + float t = noise + sin(noiseInput.y * 7.0) * 0.1 - .8; + // Material base color (before shading) + vec4 diffuseColor = vec4(207. / 255., 232. / 255., 223. / 255., t); + + // 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); + + 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, t); +} diff --git a/src/shaders/fbm-vert.glsl b/src/shaders/fbm-vert.glsl new file mode 100644 index 0000000..6d00a84 --- /dev/null +++ b/src/shaders/fbm-vert.glsl @@ -0,0 +1,65 @@ +#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 float u_Tick; +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_Nor; // The array of normals that has been transformed by u_ModelInvTr. This is implicitly passed to the fragment shader. +out vec4 fs_LightVec; // The direction in which our virtual light lies, relative to each vertex. This is implicitly passed to the fragment shader. +out vec4 fs_Col; // The color of each vertex. This is implicitly passed to the fragment shader. +out vec4 fs_Pos; + +const vec4 lightPos = vec4(10, 10, 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); + // 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. + + + mat4 rot; + rot[0] = vec4(cos(u_Tick / 10.), 0., -sin(u_Tick / 10.), 0.); + rot[1] = vec4(0., 1., 0., 0.); + rot[2] = vec4(sin(u_Tick / 10.), 0., cos(u_Tick / 10.), 0.); + rot[3] = vec4(0., 0., 0., 1.); + vec4 modelposition = u_Model * rot * (vs_Pos + normalize(vs_Nor) * .9); // Temporarily store the transformed vertex positions for use below + + fs_Nor = vec4(invTranspose * vec3(rot * vs_Nor), 0); + + fs_LightVec = lightPos - modelposition; // Compute the direction in which the light source lies + + fs_Pos = vs_Pos + normalize(vs_Nor) * 1.; + + 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/lambert-frag.glsl b/src/shaders/lambert-frag.glsl index 2b8e11b..892e1ac 100644 --- a/src/shaders/lambert-frag.glsl +++ b/src/shaders/lambert-frag.glsl @@ -1,4 +1,7 @@ #version 300 es +precision highp float; + +#define RADIUS = 1.0; // This is a fragment shader. If you've opened this file first, please // open and read lambert.vert.glsl before reading on. @@ -9,35 +12,520 @@ // data passed into the fragment shader by the vertex shader, the fragment shader // can compute what color to apply to its pixel based on things like vertex // position, light position, and vertex color. -precision highp float; uniform vec4 u_Color; // The color with which to render this instance of geometry. +uniform float u_Tick; +uniform float u_Temp; +uniform float u_Moist; // 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 float heightIn; in vec4 fs_Nor; in vec4 fs_LightVec; in vec4 fs_Col; +in vec4 fs_Pos; +in vec4 vs_Pos2; 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. +// // STRIPES TEXTURE (GOOD FOR MAKING MARBLE) + +// float stripes(float x, float f) { +// float t = .5 + .5 * sin(f * 2.*3.14159 * x); +// return t * t - .5; +// } + + +// // TURBULENCE TEXTURE + +// float turbulence(float x, float y, float z, float f) { +// float t = -.5; +// for ( ; f <= W/12. ; f *= 2.) // W = Image width in pixels +// t += abs(perlin(x,y,z,f) / f); +// return t; +// } + +float random(vec2 p){ + return abs(fract(184.421631 * sin(dot(p, vec2(1932.1902, 6247.4617))))); +} + + +float random(vec3 p){ + return abs(fract(184.421631 * sin(dot(p, vec3(1932.1902, 324.012, 6247.4617))))); + // vec3 k = vec3( 3.1415926, 2.71828,6.62607015); + // p = p*k + p.yzx; + // return fract( 131.673910 * fract( p.x*p.y*(p.x+p.y)) ); +} + +float dot(ivec3 a, ivec3 b) { + return float(a.x * b.x + a.y * b.y + a.z * b.z); +} + +float random(ivec3 p){ + return abs(fract(184.421631 * sin(dot(p, ivec3(1932, 324, 6247))))); + // vec3 k = vec3( 3.1415926, 2.71828,6.62607015); + // p = p*k + p.yzx; + // return fract( 131.673910 * fract( p.x*p.y*(p.x+p.y)) ); +} + +float smoothStep(float a, float b, float t) { + //t = t*(t*(t * 5.0 - .23)); + //t = clamp(t, 0.0, 1.0); + return mix(a,b,t); +} + + +vec3 rand(vec3 p){ + const vec3 k = vec3( 3.1415926, 2.71828,6.62607015); + p = p*k + p.yzx; + return -1.0 + 2.0*fract( 2.0 * k * fract( p.x*p.y*(p.x+p.y)) ); +} + +float interpNoise2D(vec2 p) +{ + vec2 i = floor( p ); + vec2 f = fract( p ); + + vec2 u = f*f*(3.0-2.0*f); + + return mix( mix( random( i + vec2(0.0,0.0) ), + random( i + vec2(1.0,0.0) ), u.x), + mix( random( i + vec2(0.0,1.0) ), + random( i + vec2(1.0,1.0) ), u.x), u.y); +} + +float perlinNoise(vec3 p){ + vec3 i = floor(p); + vec3 f = fract(p); + vec3 u = f*f*f*(f*(f*6.0-15.0)+10.0); + + vec3 g1 = rand(i+vec3(0.0,0.0,0.0)); + vec3 g2 = rand(i+vec3(1.0,0.0,0.0)); + vec3 g3 = rand(i+vec3(0.0,1.0,0.0)); + vec3 g4 = rand(i+vec3(1.0,1.0,0.0)); + vec3 g5 = rand(i+vec3(0.0,0.0,1.0)); + vec3 g6 = rand(i+vec3(1.0,0.0,1.0)); + vec3 g7 = rand(i+vec3(0.0,1.0,1.0)); + vec3 g8 = rand(i+vec3(1.0,1.0,1.0)); + + vec3 d1 = f - vec3(0.0,0.0,0.0); + vec3 d2 = f - vec3(1.0,0.0,0.0); + vec3 d3 = f - vec3(0.0,1.0,0.0); + vec3 d4 = f - vec3(1.0,1.0,0.0); + vec3 d5 = f - vec3(0.0,0.0,1.0); + vec3 d6 = f - vec3(1.0,0.0,1.0); + vec3 d7 = f - vec3(0.0,1.0,1.0); + vec3 d8 = f - vec3(1.0,1.0,1.0); + + float n1 = dot(g1, d1); + float n2 = dot(g2, d2); + float n3 = dot(g3, d3); + float n4 = dot(g4, d4); + float n5 = dot(g5, d5); + float n6 = dot(g6, d6); + float n7 = dot(g7, d7); + float n8 = dot(g8, d8); + + float a = mix(n1,n2,u.x); + float b = mix(n3,n4,u.x); + float c1 = mix(a,b,u.y); + a = mix(n5,n6,u.x); + b = mix(n7,n8,u.x); + float c2 = mix(a,b,u.y); + float c = mix(c1,c2,u.z); + + return c; +} + +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(vec3 p) { + int intX = int(floor(p.x)); + float fractX = fract(p.x); + int intY = int(floor(p.y)); + float fractY = fract(p.y); + int intZ = int(floor(p.z)); + float fractZ = fract(p.z); + + float v1 = random(ivec3(intX, intY, intZ)); + float v2 = random(ivec3(intX + 1, intY, intZ)); + float v3 = random(ivec3(intX, intY + 1, intZ)); + float v4 = random(ivec3(intX + 1, intY + 1, intZ)); + + float v5 = random(ivec3(intX, intY, intZ + 1)); + float v6 = random(ivec3(intX + 1, intY, intZ + 1)); + float v7 = random(ivec3(intX, intY + 1, intZ + 1)); + float v8 = random(ivec3(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 stepping(float t, int steps) { + float dist = 1. / float(steps); + for (int i = 0 ; i < steps; i ++) { + if (t < dist * float(i)) { + return dist * float(i); + } + } +} + +float getBias(float bias, float t) +{ + return (t / ((( (1.0/bias) - 2.0 ) * (1.0 - t)) + 1.0)); +} + +float getGain(float gain, float t) +{ + if(t < 0.5){ + return getBias(t * 2.0, gain)/2.0; + } else { + return getBias(t * 2.0 - 1.0,1.0 - gain)/2.0 + 0.5; + } +} + +float perlin(vec3 v) { + //v /= 10000.0; + int octave = 4; + float a = 0.5; + float n = 0.; + for (int i = 0; i < octave; ++i) { + float frequency = pow(2.0, float(i)); + n += a * abs(perlinNoise(vec3(v.x * frequency, v.y * frequency, v.z * frequency))); + a *= 0.5; + } + //n = (clamp(getBias(n, .1), 0., 1.)); + return n; + //return vec3(0.,0.,0.); +} + +float perlin(vec3 v, int octave, float a, float zoom) { + //v /= 10000.0; + v *= zoom; + float n = 0.; + for (int i = 0; i < octave; ++i) { + float frequency = pow(2.0, float(i)); + n += a * abs(perlinNoise(vec3(v.x * frequency, v.y * frequency, v.z * frequency))); + a *= a; + } + //n = (clamp(getBias(n, .1), 0., 1.)); + return n; + //return vec3(0.,0.,0.); +} + +float fbm(vec3 v, int octave, float a, float zoom) { + v *= zoom; + float total = 0.; + float frequency = 2.0; + for (int i = 0; i < octave; ++i) { + total += a * interpNoise3D(frequency * v); + frequency *= 2.0f; + a *= a; + } + //n = (clamp(getBias(n, .1), ., 1.)); + return total; +} + +float fbm(vec4 v) { + v*= 1.2; + int octave = 4; + float a = 1.0; + float val = 0.0; + for (int i = 0; i < octave; ++i) { + val += a * abs(interpNoise3D(vec3(v.x, v.y, v.z))); + v *= 2.; + a *= 0.5; + } + return val; +} + +float fbm2d(vec2 v) { + v*= 1.2; + int octave = 4; + float a = 1.0; + float val = 0.0; + for (int i = 0; i < octave; ++i) { + val += a * abs(interpNoise2D(vec2(v.x, v.y))); + v *= 2.; + a *= 0.5; + } + return val; +} + + +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); +} + +// vec3 adjustNorm() { +// return vec3(fs_Nor); +// float offset = .0001; +// vec3 tangent = cross(vec3(fs_Nor), vec3(0.,1.,0.)); +// vec3 bitangent = cross(vec3(fs_Nor), tangent); +// vec4 norXSub = vec4(fs_Nor.x - offset, fs_Nor.y, fs_Nor.z, 1.); +// vec4 norXAdd = vec4(fs_Nor.x + offset, fs_Nor.y, fs_Nor.z, 1.); +// vec4 norYSub = vec4(fs_Nor.x, fs_Nor.y - offset, fs_Nor.z, 1.); +// vec4 norYAdd = vec4(fs_Nor.x, fs_Nor.y + offset, fs_Nor.z, 1.); +// vec4 norZSub = vec4(fs_Nor.x, fs_Nor.y, fs_Nor.z - offset, 1.); +// vec4 norZAdd = vec4(fs_Nor.x, fs_Nor.y, fs_Nor.z + offset, 1.); +// vec3 norm = vec3(fbm(norXAdd) - fbm(norXSub), fbm(norYAdd) - fbm(norYSub), fbm(norZAdd) - fbm(norZSub)); +// if (dot(norm, vec3(fs_Nor)) < 0.) { +// norm *= -1.; +// } +// return cross(tangent, bitangent); +// } + + + +float mountainMode(vec4 pos) { + pos += 27.6; + //float val = clamp(fbm(vec3(pos), 3, .5, 1.)* 2., 0., 1.)* 3.; + float val = 1. - getBias(clamp(perlin(vec3(pos), 5, .5, 5.), 0., 1.)* 2., .6); + //float val = perlin(vec3(pos)); + return val; + if (val > .35) { + return 1.; + } + return 0.; + +} + +float oceanMode(vec4 pos) { + //float val = clamp(fbm(vec3(pos), 3, .5, 1.)* 2., 0., 1.)* 3.; + + float val = getBias(clamp(fbm(pos.xyz, 5, .5, 1.), 0., 1.), .3); + //float val = perlin(vec3(pos)); + return val; + if (val > .25) { + return 0.; + } + return 1.; + +} + +float temperatureMode(vec4 pos) { + float newY = 1. - (abs(pos.y) + (fbm2d(vec2(pos.x, pos.z))/ 10.) - .4); + return newY; +} + +float moistureMode(vec4 pos) { + pos += 10.6; + //float val = clamp(fbm(vec3(pos), 3, .5, 1.)* 2., 0., 1.)* 3.; + float val = getGain(clamp(fbm(vec3(pos), 3, .5, .5), 0., 1.), .3); + + return val; +} + +vec3 paletteTemp(float t) +{ + t = stepping(t, 10) - .1; + vec3 a = vec3(0.800, 0.838, 0.888); + vec3 b = vec3(0.418, 0.468, 0.808); + vec3 c = vec3(0.718, 1.000, 1.000); + vec3 d = vec3(0.308, 0.078, 1.028); + vec3 ret = a + b*cos( 6.28318*(c*t+d) ); + //ret.xyz = vec3(stepping(ret.x, 5), stepping(ret.y, 5), stepping (ret.z, 5)); + return ret; +} + +vec3 paletteHeight(float t) +{ + t = stepping(t, 10) - .1; + vec3 a = vec3(0.448, 0.500, -0.282); + vec3 b = vec3(-0.472, 0.500, 0.600); + vec3 c = vec3(-0.672, 0.498, 0.278); + vec3 d = vec3(-0.472, -0.142, 0.748); + vec3 ret = a + b*cos( 6.28318*(c*t+d) ); + //ret.xyz = vec3(stepping(ret.x, 5), stepping(ret.y, 5), stepping (ret.z, 5)); + return ret; +} + +vec3 paletteMoist(float t) +{ + t = stepping(t, 10) - .1; + vec3 a = vec3(0.821, 0.328, 0.242); + vec3 b = vec3(0.659, 0.481, 0.896); + vec3 c = vec3(0.233, 0.129, 0.112); + vec3 d = vec3(2.820, 3.026, -0.273); + vec3 ret = a + b*cos( 6.28318*(c*t+d) ); + //ret.xyz = vec3(stepping(ret.x, 5), stepping(ret.y, 5), stepping (ret.z, 5)); + return ret; +} + +//Ocean is 1 +// + +float totalNoise(vec4 pos) { + float val = oceanMode(pos) * 2.; + if (val < .5) { + val = .5; + } else { + if (val > .62) { + val += clamp(mountainMode(pos) / 8., 0., 1.); + } + } + return val; +} + +vec4 setBiome(vec4 pos, float heightWeight, float tempWeight, float moistWeight) { + float height = totalNoise(pos); + float temp = temperatureMode(pos); + float moist = moistureMode(pos); + + vec4 retCol = vec4(0.); + vec4 heightCol = vec4(paletteHeight((height / 1.0 - 0.6) * 1.6), 1.); + vec4 tempCol = vec4(paletteTemp((height / 1.0 - 0.35) * 1.6), 1.); + vec4 moistCol = vec4(paletteMoist((height / 1.0 - 0.6) * 1.6), 1.); + + float totalWeight = heightWeight + tempWeight + moistWeight; + + if (height > .5) { + retCol += (heightCol * heightWeight + tempCol * tempWeight + moistCol * moistWeight) / totalWeight; + } else { + retCol = heightCol; + } + if (height < .505) { + retCol = vec4(0., .3, .5, 1.); + } + if (moist < u_Moist / 3.) { + retCol = moistCol; + if (height < .505) { + retCol = vec4(0., .5, .7, 1.); + } + } else if (moist < u_Moist / 3. + .1) { + + if (height < .505) { + retCol = mix(vec4(0., .3, .5, 1.), vec4(0., .5, .7, 1.), 1.+(u_Moist / 3. - moist) * 10.); + } else { + retCol = mix(retCol, moistCol, 1.+(u_Moist / 3. - moist) * 10.); + } + } + + float check = 1.; + if (temp < u_Temp) { + retCol = tempCol; + if (height > .75) { + check = -1.; + } + } else if (temp < u_Temp + .1) { + retCol = mix(retCol, tempCol, 1.+(u_Temp - temp) * 10.); + } + + if (height < .505) { + retCol = retCol + ((getGain(clamp(fbm(pos.xyz, 5, .5, 5.), 0., 1.), .1)) / 3.); + } + + + retCol.w = check; + return retCol; +} + +#define DELTA 1e-4 + +vec4 adjustNorm() { + vec4 p = vs_Pos2; + vec3 tangent = normalize(cross(vec3(0,1,0), fs_Nor.xyz)); + vec3 bitangent = cross(fs_Nor.xyz, tangent); + + vec3 xNeg = p.xyz - tangent * DELTA; + vec3 yNeg = p.xyz - bitangent * DELTA; + vec3 xPos = p.xyz + tangent * DELTA; + vec3 yPos = p.xyz + bitangent * DELTA; + + xNeg += fs_Nor.xyz * totalNoise(vec4(xNeg, 1.)); + yNeg += fs_Nor.xyz * totalNoise(vec4(yNeg, 1.)); + xPos += fs_Nor.xyz * totalNoise(vec4(xPos, 1.)); + yPos += fs_Nor.xyz * totalNoise(vec4(yPos, 1.)); + + vec3 newTan = xPos - xNeg; + vec3 newBit = yPos - yNeg; + + return vec4(normalize(cross(newTan, newBit)), 0.); +} + +vec4 adjustNormOLD() { + vec4 p = vs_Pos2; + 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 = totalNoise(xNeg); + float xPosNoise = totalNoise(xPos); + float yNegNoise = totalNoise(yNeg); + float yPosNoise = totalNoise(yPos); + + float xDiff = (xPosNoise - xNegNoise) * 10.; + float yDiff = (yPosNoise - yNegNoise) * 10.; + p.z = sqrt(1. - xDiff * xDiff - yDiff * yDiff); + + vec4 nor = vec4(vec3(xDiff, yDiff, p.z), 0); + + vec3 normal = normalize(vec3(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); +} void main() { // Material base color (before shading) - vec4 diffuseColor = u_Color; + vec4 diffuseColor = u_Color; + + // Calculate the diffuse term for Lambert shading + float diffuseTerm = clamp(dot(normalize(adjustNorm().xyz), normalize(fs_LightVec.xyz)), 0., 1.); + // Avoid negative lighting values + // diffuseTerm = clamp(diffuseTerm, 0, 1); + + float ambientTerm = 0.3; - // 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); + 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((vec3(diffuseColor)) * lightIntensity, diffuseColor.a); + //out_Col = vec4(vec3(mod(u_Tick, 255.0) / 255.0) * lightIntensity, diffuseColor.a); - float ambientTerm = 0.2; + vec4 v = vec4(0., 0., 20., 1.); + vec4 h = (v + fs_LightVec) / 2.; + float specularIntensity = max(pow(dot(normalize(h),normalize(fs_Nor)),.5),2.f); + vec3 timeAdj = vec3((mod(u_Tick, 255.0) / 255.0)); + vec4 col = setBiome(vs_Pos2, 1., 0., 0.); + if (col.w < 0.) { + out_Col = vec4(vec3(clamp(col * lightIntensity * specularIntensity, 0.0, 1.0)), 1.); + } else { + out_Col = vec4(vec3(clamp(col * lightIntensity, 0.0, 1.0)), 1.); + } + //out_Col = vec4(clamp(vec3(fs_Pos) * lightIntensity, 0.0, 1.0), diffuseColor.a); - 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. + // out_Col = vec4(diffuseTerm, diffuseTerm, diffuseTerm, 1.); - // Compute final shaded color - out_Col = vec4(diffuseColor.rgb * lightIntensity, diffuseColor.a); } diff --git a/src/shaders/lambert-vert.glsl b/src/shaders/lambert-vert.glsl index 7f95a37..1bcf75a 100644 --- a/src/shaders/lambert-vert.glsl +++ b/src/shaders/lambert-vert.glsl @@ -1,4 +1,5 @@ #version 300 es +precision highp float; //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. @@ -7,6 +8,10 @@ //This simultaneous transformation allows your program to run much faster, especially when rendering //geometry with millions of vertices. +uniform float u_Tick; +uniform float u_Temp; +uniform float u_Moist; + 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. @@ -28,26 +33,454 @@ 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; +out float heightIn; +out vec4 vs_Pos2; -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(10., 10., 3., 1); //The position of our virtual light, which is used to compute the shading of //the geometry in the fragment shader. +// // STRIPES TEXTURE (GOOD FOR MAKING MARBLE) + +// float stripes(float x, float f) { +// float t = .5 + .5 * sin(f * 2.*3.14159 * x); +// return t * t - .5; +// } + + +// // TURBULENCE TEXTURE + +// float turbulence(float x, float y, float z, float f) { +// float t = -.5; +// for ( ; f <= W/12. ; f *= 2.) // W = Image width in pixels +// t += abs(perlin(x,y,z,f) / f); +// return t; +// } + +float random(vec2 p){ + return abs(fract(184.421631 * sin(dot(p, vec2(1932.1902, 6247.4617))))); +} + + +float random(vec3 p){ + return abs(fract(184.421631 * sin(dot(p, vec3(1932.1902, 324.012, 6247.4617))))); + // vec3 k = vec3( 3.1415926, 2.71828,6.62607015); + // p = p*k + p.yzx; + // return fract( 131.673910 * fract( p.x*p.y*(p.x+p.y)) ); +} + +float dot(ivec3 a, ivec3 b) { + return float(a.x * b.x + a.y * b.y + a.z * b.z); +} + +float random(ivec3 p){ + return abs(fract(184.421631 * sin(dot(p, ivec3(1932, 324, 6247))))); + // vec3 k = vec3( 3.1415926, 2.71828,6.62607015); + // p = p*k + p.yzx; + // return fract( 131.673910 * fract( p.x*p.y*(p.x+p.y)) ); +} + +float smoothStep(float a, float b, float t) { + //t = t*(t*(t * 5.0 - .23)); + //t = clamp(t, 0.0, 1.0); + return mix(a,b,t); +} + + +vec3 rand(vec3 p){ + const vec3 k = vec3( 3.1415926, 2.71828,6.62607015); + p = p*k + p.yzx; + return -1.0 + 2.0*fract( 2.0 * k * fract( p.x*p.y*(p.x+p.y)) ); +} + +float interpNoise2D(vec2 p) +{ + vec2 i = floor( p ); + vec2 f = fract( p ); + + vec2 u = f*f*(3.0-2.0*f); + + return mix( mix( random( i + vec2(0.0,0.0) ), + random( i + vec2(1.0,0.0) ), u.x), + mix( random( i + vec2(0.0,1.0) ), + random( i + vec2(1.0,1.0) ), u.x), u.y); +} + +float perlinNoise(vec3 p){ + vec3 i = floor(p); + vec3 f = fract(p); + vec3 u = f*f*f*(f*(f*6.0-15.0)+10.0); + + vec3 g1 = rand(i+vec3(0.0,0.0,0.0)); + vec3 g2 = rand(i+vec3(1.0,0.0,0.0)); + vec3 g3 = rand(i+vec3(0.0,1.0,0.0)); + vec3 g4 = rand(i+vec3(1.0,1.0,0.0)); + vec3 g5 = rand(i+vec3(0.0,0.0,1.0)); + vec3 g6 = rand(i+vec3(1.0,0.0,1.0)); + vec3 g7 = rand(i+vec3(0.0,1.0,1.0)); + vec3 g8 = rand(i+vec3(1.0,1.0,1.0)); + + vec3 d1 = f - vec3(0.0,0.0,0.0); + vec3 d2 = f - vec3(1.0,0.0,0.0); + vec3 d3 = f - vec3(0.0,1.0,0.0); + vec3 d4 = f - vec3(1.0,1.0,0.0); + vec3 d5 = f - vec3(0.0,0.0,1.0); + vec3 d6 = f - vec3(1.0,0.0,1.0); + vec3 d7 = f - vec3(0.0,1.0,1.0); + vec3 d8 = f - vec3(1.0,1.0,1.0); + + float n1 = dot(g1, d1); + float n2 = dot(g2, d2); + float n3 = dot(g3, d3); + float n4 = dot(g4, d4); + float n5 = dot(g5, d5); + float n6 = dot(g6, d6); + float n7 = dot(g7, d7); + float n8 = dot(g8, d8); + + float a = mix(n1,n2,u.x); + float b = mix(n3,n4,u.x); + float c1 = mix(a,b,u.y); + a = mix(n5,n6,u.x); + b = mix(n7,n8,u.x); + float c2 = mix(a,b,u.y); + float c = mix(c1,c2,u.z); + + return c; +} + +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(vec3 p) { + int intX = int(floor(p.x)); + float fractX = fract(p.x); + int intY = int(floor(p.y)); + float fractY = fract(p.y); + int intZ = int(floor(p.z)); + float fractZ = fract(p.z); + + float v1 = random(ivec3(intX, intY, intZ)); + float v2 = random(ivec3(intX + 1, intY, intZ)); + float v3 = random(ivec3(intX, intY + 1, intZ)); + float v4 = random(ivec3(intX + 1, intY + 1, intZ)); + + float v5 = random(ivec3(intX, intY, intZ + 1)); + float v6 = random(ivec3(intX + 1, intY, intZ + 1)); + float v7 = random(ivec3(intX, intY + 1, intZ + 1)); + float v8 = random(ivec3(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 stepping(float t, int steps) { + float dist = 1. / float(steps); + for (int i = 0 ; i < steps; i ++) { + if (t < dist * float(i)) { + return dist * float(i); + } + } +} + +float getBias(float bias, float t) +{ + return (t / ((( (1.0/bias) - 2.0 ) * (1.0 - t)) + 1.0)); +} + +float getGain(float gain, float t) +{ + if(t < 0.5){ + return getBias(t * 2.0, gain)/2.0; + } else { + return getBias(t * 2.0 - 1.0,1.0 - gain)/2.0 + 0.5; + } +} + +float perlin(vec3 v) { + //v /= 10000.0; + int octave = 4; + float a = 0.5; + float n = 0.; + for (int i = 0; i < octave; ++i) { + float frequency = pow(2.0, float(i)); + n += a * abs(perlinNoise(vec3(v.x * frequency, v.y * frequency, v.z * frequency))); + a *= 0.5; + } + //n = (clamp(getBias(n, .1), 0., 1.)); + return n; + //return vec3(0.,0.,0.); +} + +float perlin(vec3 v, int octave, float a, float zoom) { + //v /= 10000.0; + v *= zoom; + float n = 0.; + for (int i = 0; i < octave; ++i) { + float frequency = pow(2.0, float(i)); + n += a * abs(perlinNoise(vec3(v.x * frequency, v.y * frequency, v.z * frequency))); + a *= a; + } + //n = (clamp(getBias(n, .1), 0., 1.)); + return n; + //return vec3(0.,0.,0.); +} + +float fbm(vec3 v, int octave, float a, float zoom) { + v *= zoom; + float total = 0.; + float frequency = 2.0; + for (int i = 0; i < octave; ++i) { + total += a * interpNoise3D(frequency * v); + frequency *= 2.0f; + a *= a; + } + //n = (clamp(getBias(n, .1), ., 1.)); + return total; +} + +float fbm(vec4 v) { + v*= 1.2; + int octave = 4; + float a = 1.0; + float val = 0.0; + for (int i = 0; i < octave; ++i) { + val += a * abs(interpNoise3D(vec3(v.x, v.y, v.z))); + v *= 2.; + a *= 0.5; + } + return val; +} + +float fbm2d(vec2 v) { + v*= 1.2; + int octave = 4; + float a = 1.0; + float val = 0.0; + for (int i = 0; i < octave; ++i) { + val += a * abs(interpNoise2D(vec2(v.x, v.y))); + v *= 2.; + a *= 0.5; + } + return val; +} + + +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); +} + +// vec3 adjustNorm() { +// return vec3(vs_Nor); +// float offset = .0001; +// vec3 tangent = cross(vec3(vs_Nor), vec3(0.,1.,0.)); +// vec3 bitangent = cross(vec3(vs_Nor), tangent); +// vec4 norXSub = vec4(vs_Nor.x - offset, vs_Nor.y, vs_Nor.z, 1.); +// vec4 norXAdd = vec4(vs_Nor.x + offset, vs_Nor.y, vs_Nor.z, 1.); +// vec4 norYSub = vec4(vs_Nor.x, vs_Nor.y - offset, vs_Nor.z, 1.); +// vec4 norYAdd = vec4(vs_Nor.x, vs_Nor.y + offset, vs_Nor.z, 1.); +// vec4 norZSub = vec4(vs_Nor.x, vs_Nor.y, vs_Nor.z - offset, 1.); +// vec4 norZAdd = vec4(vs_Nor.x, vs_Nor.y, vs_Nor.z + offset, 1.); +// vec3 norm = vec3(fbm(norXAdd) - fbm(norXSub), fbm(norYAdd) - fbm(norYSub), fbm(norZAdd) - fbm(norZSub)); +// if (dot(norm, vec3(fs_Nor)) < 0.) { +// norm *= -1.; +// } +// return cross(tangent, bitangent); +// } + + + +float mountainMode(vec4 pos) { + pos += 27.6; + //float val = clamp(fbm(vec3(pos), 3, .5, 1.)* 2., 0., 1.)* 3.; + float val = 1. - getBias(clamp(perlin(vec3(pos), 5, .5, 5.), 0., 1.)* 2., .6); + //float val = perlin(vec3(pos)); + return val; + if (val > .35) { + return 1.; + } + return 0.; + +} + +float oceanMode(vec4 pos) { + //float val = clamp(fbm(vec3(pos), 3, .5, 1.)* 2., 0., 1.)* 3.; + + float val = getBias(clamp(fbm(pos.xyz, 5, .5, 1.), 0., 1.), .3); + //float val = perlin(vec3(pos)); + return val; + if (val > .25) { + return 0.; + } + return 1.; + +} + +float temperatureMode(vec4 pos) { + float newY = 1. - (abs(pos.y) + (fbm2d(vec2(pos.x, pos.z))/ 10.) - .4); + return newY; +} + +float moistureMode(vec4 pos) { + pos += 10.6; + //float val = clamp(fbm(vec3(pos), 3, .5, 1.)* 2., 0., 1.)* 3.; + float val = getGain(clamp(fbm(vec3(pos), 3, .5, .5), 0., 1.), .3); + + return val; +} + +vec3 paletteTemp(float t) +{ + vec3 a = vec3(0.980, 0.880, 1.000); + vec3 b = vec3(0.495, 0.302, 0.496); + vec3 c = vec3(0.279, 0.430, 0.279); + vec3 d = vec3(-0.153, -0.145, 0.194); + vec3 ret = a + b*cos( 6.28318*(c*t+d) ); + ret.xyz = vec3(stepping(ret.x, 5), stepping(ret.y, 5), stepping (ret.z, 5)); + return ret; +} + +vec3 paletteHeight(float t) +{ + vec3 a = vec3(0.498, 0.500, 0.558); + vec3 b = vec3(0.500, 0.198, 0.468); + vec3 c = vec3(-0.442, 1.278, 0.558); + vec3 d = vec3(1.698, 0.358, 2.088); + vec3 ret = a + b*cos( 6.28318*(c*t+d) ); + ret.xyz = vec3(stepping(ret.x, 5), stepping(ret.y, 5), stepping (ret.z, 5)); + return ret; +} + +vec3 paletteMoist(float t) +{ + vec3 a = vec3(0.498, 0.500, 0.218); + vec3 b = vec3(0.500, 0.500, 0.500); + vec3 c = vec3(0.668, 0.338, -0.392); + vec3 d = vec3(0.418, -0.142, 0.968); + vec3 ret = a + b*cos( 6.28318*(c*t+d) ); + ret.xyz = vec3(stepping(ret.x, 5), stepping(ret.y, 5), stepping (ret.z, 5)); + return ret; +} + +//Ocean is 1 +// + +float totalNoise(vec4 pos) { + float val = oceanMode(pos) * 2.; + if (val < .5) { + val = .5; + } else { + if (val > .62) { + val += clamp(mountainMode(pos) / 8., 0., 1.); + } + } + return val; +} + +vec4 setBiome(vec4 pos, float heightWeight, float tempWeight, float moistWeight) { + float height = totalNoise(pos); + float temp = temperatureMode(pos); + float moist = moistureMode(pos); + + vec4 heightCol = vec4(paletteHeight((height) / .8 -.3), 1.); + vec4 tempCol = vec4(paletteTemp((temp)), 1.); + vec4 moistCol = vec4(paletteMoist((moist)), 1.); + if (height > .25 && height < .3) { + //heightCol = vec4(9., .8, 0., 1.); + } + float totalWeight = heightWeight + tempWeight + moistWeight; + vec4 retCol = vec4(0.); + if (height > .5) { + retCol += (heightCol * heightWeight + tempCol * tempWeight + moistCol * moistWeight) / totalWeight; + } else { + retCol = heightCol; + } + return retCol; +} + +vec4 adjustNorm() { + vec4 p = vs_Pos; + 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 = totalNoise(xNeg); + float xPosNoise = totalNoise(xPos); + float yNegNoise = totalNoise(yNeg); + float yPosNoise = totalNoise(yPos); + + float xDiff = (xPosNoise - xNegNoise) * 10.; + float yDiff = (yPosNoise - yNegNoise) * 10.; + p.z = sqrt(1. - xDiff * xDiff - yDiff * yDiff); + + fs_Nor = vec4(vec3(xDiff, yDiff, p.z), 0); + + 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 * fs_Nor)), 0.0); +} + +vec4 adjustAlongNorm() { + //vec3 vs_Pos3 = vec3(vs_Pos.x, vs_Pos.y, vs_Pos.z); + //return vs_Pos; + return vs_Pos + vs_Nor*totalNoise(vs_Pos); +} + void main() { - 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. + 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 newPos = adjustAlongNorm(); + vec4 modelposition = u_Model * newPos; // Temporarily store the transformed vertex positions for use below - vec4 modelposition = u_Model * vs_Pos; // Temporarily store the transformed vertex positions for use below - + heightIn = totalNoise(vs_Pos); + fs_Col = setBiome(vs_Pos, 6., 0., 0.); fs_LightVec = lightPos - modelposition; // Compute the direction in which the light source lies + vs_Pos2 = vs_Pos; + + //fs_Col = vec4(vec3(oceanMode(vs_Pos)), 1.); + //fs_Col = vec4(1., 1., 1., 1.); + vec4 sc_Pos = u_ViewProj * modelposition; - 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 = vec4(sc_Pos.x, sc_Pos.y, sc_Pos.z, sc_Pos.w); + //gl_Position = vec4(fs_Pos.x, fs_Pos.y+cos(u_Tick + fs_Pos.x + fs_Pos.z), fs_Pos.z, fs_Pos.w); + // gl_Position is a built-in variable of OpenGL which is + // used to render the final positions of the geometry's vertice }