From 68bf597b46541faff7d13f5f66d94bc9992eeee7 Mon Sep 17 00:00:00 2001 From: Michael Stauffer Date: Tue, 24 Jan 2017 15:48:23 -0500 Subject: [PATCH 1/3] First commit. Working well overall. For submission. --- README.md | 21 ++++++++++ src/framework.js | 8 +++- src/main.js | 84 +++++++++++++++++++++++++++++++------- src/shaders/adam-frag.glsl | 2 +- src/shaders/adam-vert.glsl | 4 +- 5 files changed, 100 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 9d68747..9a20598 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,26 @@ # [HW1: Noise](https://github.com/CIS700-Procedural-Graphics/Project1-Noise) +## Stauffer Notes - Project One - Noise + +Sorry for the inelegant code. I didn't have time to make it prettier. +I left my comments in so that I can know what was going on when I get back to the code one day. + +My code implements: + +1. Two independently controlled multi-octave noise (MON) generators. +2. Each uses the same underlying noise generator, unfortunately, although this may give some good continuity effects. +3. Each can have its parameters controlled from the GUI: + a. N1 is for generator one, N2 is for generator two + b. Time Scale - scales down the time value to control 'speed' of animation + c. fundamental - set the fundamental frequency of sampling + d. harmScale - set the scaling factor between harmonics of the MON. Harmonic N = fundamental * harmScale ^ (N-1). + e. components - the number of harmonics in the MON. + f. persistence - scales the amplitude of each component in the MON. Values > 1 are interesting! + g. symmetry[XYZ] - controls symmetry of noise across each axis. Only looks good if 0 or 1. Intermediate values look good in static renders but I had trouble making it smooth with how I was using time to vary vertex position. +4. Time is used simply to offset vertex position, and vertex position is used to generate noise. This has awkward effect of making noise look to be moving in a direction in some cases. Better would be to create true 4D noise with time as 4th dim. +5. The default settings combine symmetry in X for a slow movig, high spatial-frequency noise, with symmetry in Y for a faster-moving, low spatial-frequency noise. I think this makes it look alive, like a tiny plankton creature, undulating with water pressure and life processes. + + ## Getting Started 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 [three.js](https://threejs.org/), [dat.GUI](https://workshop.chromeexperiments.com/examples/gui/#1--Basic-Usage), and [glMatrix](http://glmatrix.net/). Some other packages we'll be using make it significantly easier to develop your code and create modules for better code reuse and clarity. These tools make it _signficantly_ easier to write code in multiple `.js` files without globally defining everything. diff --git a/src/framework.js b/src/framework.js index 9cfcd1b..0a39988 100644 --- a/src/framework.js +++ b/src/framework.js @@ -21,9 +21,14 @@ function init(callback, update) { stats: stats }; + //Stauffer test + window.addEventListener('click', function(event) { + console.log("You clicked:", event.screenX, event.screenY); + }); + // run this function after the window loads window.addEventListener('load', function() { - + console.log(" IN load callback func"); var scene = new THREE.Scene(); var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 ); var renderer = new THREE.WebGLRenderer( { antialias: true } ); @@ -43,6 +48,7 @@ function init(callback, update) { // resize the canvas when the window changes window.addEventListener('resize', function() { + console.log(" IN resize cback func"); camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight); diff --git a/src/main.js b/src/main.js index 5fa221d..9a77235 100644 --- a/src/main.js +++ b/src/main.js @@ -2,6 +2,43 @@ const THREE = require('three'); // older modules are imported like this. You shouldn't have to worry about this much import Framework from './framework' +//Make this a global so can see it in onUpdate to +// get at uniforms. +//Must be a better way!? +// +var adamMaterial = new THREE.ShaderMaterial({ +uniforms: { + image: { // Check the Three.JS documentation for the different allowed types and values + type: "t", + value: THREE.ImageUtils.loadTexture('./adam.jpg') + }, + //Maybe better to do this by creating a second shader? + uTimeMsec: { value: 0.0 }, + uN1TimeScale: { value: 15000.0 }, + uN1Scale: { value: 0.8 }, + uN1fundamental: { value: 2.71828 }, + uN1overtoneScale: { value: 2.71828 }, + uN1numComponents: { value: 3.0 }, + uN1persistence: { value: 2 }, + uN1symmetryX: {value: 1.0 }, + uN1symmetryY: {value: 0.0 }, + uN1symmetryZ: {value: 0.0 }, + + uN2TimeScale: { value: 1500.0 }, + uN2Scale: { value: 1.0 }, + uN2fundamental: { value: 0.1 }, + uN2overtoneScale: { value: 2.71828 }, + uN2numComponents: { value: 4.0 }, + uN2persistence: { value: 1.5 }, + uN2symmetryX: {value: 0.0 }, + uN2symmetryY: {value: 1.0 }, + uN2symmetryZ: {value: 0.0 } + + }, +vertexShader: require('./shaders/project1-vert.glsl'), +fragmentShader: require('./shaders/project1-frag.glsl') +}); + // called after the scene loads function onLoad(framework) { var scene = framework.scene; @@ -15,21 +52,13 @@ function onLoad(framework) { // initialize a simple box and material var box = new THREE.BoxGeometry(1, 1, 1); - - var adamMaterial = new THREE.ShaderMaterial({ - uniforms: { - image: { // Check the Three.JS documentation for the different allowed types and values - type: "t", - value: THREE.ImageUtils.loadTexture('./adam.jpg') - } - }, - vertexShader: require('./shaders/adam-vert.glsl'), - fragmentShader: require('./shaders/adam-frag.glsl') - }); - var adamCube = new THREE.Mesh(box, adamMaterial); - + var sphere = new THREE.SphereGeometry(1, 120, 120); + + //var adamCube = new THREE.Mesh(box, adamMaterial); + var adamCube = new THREE.Mesh(sphere, adamMaterial); + // set camera position - camera.position.set(1, 1, 2); + camera.position.set(0, 0, 3); camera.lookAt(new THREE.Vector3(0,0,0)); scene.add(adamCube); @@ -39,11 +68,36 @@ function onLoad(framework) { gui.add(camera, 'fov', 0, 180).onChange(function(newVal) { camera.updateProjectionMatrix(); }); + //console.log(adamMaterial.uniforms.uTime.value); + gui.add(adamMaterial.uniforms.uN1TimeScale, 'value', 0.01, 25000).name('N1 Time Scale'); + gui.add(adamMaterial.uniforms.uN1Scale, 'value', 0.01, 10).name('N1 Size Scale'); + gui.add(adamMaterial.uniforms.uN1fundamental, 'value', 0.01, 10).name('N1 fundamental'); + gui.add(adamMaterial.uniforms.uN1overtoneScale, 'value', 0.1, 10).name('N1 harmScale'); + gui.add(adamMaterial.uniforms.uN1numComponents, 'value', 1, 16).name('N1 components'); + gui.add(adamMaterial.uniforms.uN1persistence, 'value', 0.1, 4).name('N1 persistence'); + gui.add(adamMaterial.uniforms.uN1symmetryX, 'value', 0.0, 1.0).name('N1 symmetryX'); + gui.add(adamMaterial.uniforms.uN1symmetryY, 'value', 0.0, 1.0).name('N1 symmetryY'); + gui.add(adamMaterial.uniforms.uN1symmetryZ, 'value', 0.0, 1.0).name('N1 symmetryZ'); + + gui.add(adamMaterial.uniforms.uN2TimeScale, 'value', 0.01, 25000).name('N2 Time Scale'); + gui.add(adamMaterial.uniforms.uN2Scale, 'value', 0, 10).name('N2 Size Scale'); + gui.add(adamMaterial.uniforms.uN2fundamental, 'value', 0.01, 10).name('N2 fundamental'); + gui.add(adamMaterial.uniforms.uN2overtoneScale, 'value', 0.1, 10).name('N2 harmScale'); + gui.add(adamMaterial.uniforms.uN2numComponents, 'value', 1, 16).name('N2 components'); + gui.add(adamMaterial.uniforms.uN2persistence, 'value', 0.1, 4).name('N2 persistence'); + gui.add(adamMaterial.uniforms.uN2symmetryX, 'value', 0.0, 1.0).name('N2 symmetryX'); + gui.add(adamMaterial.uniforms.uN2symmetryY, 'value', 0.0, 1.0).name('N2 symmetryY'); + gui.add(adamMaterial.uniforms.uN2symmetryZ, 'value', 0.0, 1.0).name('N2 symmetryZ'); + + //start the time + framework.startTime = Date.now(); } // called on frame updates function onUpdate(framework) { - console.log(`the time is ${new Date()}`); + //console.log(`the time is ${new Date()}`); + adamMaterial.uniforms.uTimeMsec.value = Date.now() - framework.startTime; + //console.log(adamMaterial.uniforms.uTimeMsec.value); } // when the scene is done initializing, it will call onLoad, then on frame updates, call onUpdate diff --git a/src/shaders/adam-frag.glsl b/src/shaders/adam-frag.glsl index 64ca0e0..4e3b5f1 100644 --- a/src/shaders/adam-frag.glsl +++ b/src/shaders/adam-frag.glsl @@ -7,6 +7,6 @@ void main() { vec4 color = texture2D( image, vUv ); - gl_FragColor = vec4( color.rgb, 1.0 ); + gl_FragColor = vec4( color.gbr, 1.0 ); } \ No newline at end of file diff --git a/src/shaders/adam-vert.glsl b/src/shaders/adam-vert.glsl index e4b8cc0..aa0d85f 100644 --- a/src/shaders/adam-vert.glsl +++ b/src/shaders/adam-vert.glsl @@ -1,6 +1,6 @@ - +uniform float uScale; varying vec2 vUv; void main() { vUv = uv; - gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); + gl_Position = projectionMatrix * modelViewMatrix * vec4( position * uScale, 1.0 ); } \ No newline at end of file From f253f3fccbb91eed073cd3a9e41d6ddc76f8925a Mon Sep 17 00:00:00 2001 From: Michael Stauffer Date: Tue, 24 Jan 2017 15:48:55 -0500 Subject: [PATCH 2/3] Added new src files. Working well overall. For submission. --- src/npm-debug.log | 24 ++++ src/shaders/project1-frag.glsl | 17 +++ src/shaders/project1-vert.glsl | 250 +++++++++++++++++++++++++++++++++ 3 files changed, 291 insertions(+) create mode 100644 src/npm-debug.log create mode 100644 src/shaders/project1-frag.glsl create mode 100644 src/shaders/project1-vert.glsl diff --git a/src/npm-debug.log b/src/npm-debug.log new file mode 100644 index 0000000..c5f15a0 --- /dev/null +++ b/src/npm-debug.log @@ -0,0 +1,24 @@ +0 info it worked if it ends with ok +1 verbose cli [ '/usr/local/bin/node', '/usr/local/bin/npm', 'stop' ] +2 info using npm@3.10.10 +3 info using node@v6.9.4 +4 verbose stack Error: missing script: stop +4 verbose stack at run (/usr/local/lib/node_modules/npm/lib/run-script.js:151:19) +4 verbose stack at /usr/local/lib/node_modules/npm/lib/run-script.js:61:5 +4 verbose stack at /usr/local/lib/node_modules/npm/node_modules/read-package-json/read-json.js:356:5 +4 verbose stack at checkBinReferences_ (/usr/local/lib/node_modules/npm/node_modules/read-package-json/read-json.js:320:45) +4 verbose stack at final (/usr/local/lib/node_modules/npm/node_modules/read-package-json/read-json.js:354:3) +4 verbose stack at then (/usr/local/lib/node_modules/npm/node_modules/read-package-json/read-json.js:124:5) +4 verbose stack at /usr/local/lib/node_modules/npm/node_modules/read-package-json/read-json.js:311:12 +4 verbose stack at /usr/local/lib/node_modules/npm/node_modules/graceful-fs/graceful-fs.js:78:16 +4 verbose stack at tryToString (fs.js:455:3) +4 verbose stack at FSReqWrap.readFileAfterClose [as oncomplete] (fs.js:442:12) +5 verbose cwd /Users/michael/Box Sync/Penn/MES/700-006-Procedural-Gfx-Spr-2017/week1/HW1/Project1-Noise/src +6 error Darwin 14.5.0 +7 error argv "/usr/local/bin/node" "/usr/local/bin/npm" "stop" +8 error node v6.9.4 +9 error npm v3.10.10 +10 error missing script: stop +11 error If you need help, you may report this error at: +11 error +12 verbose exit [ 1, true ] diff --git a/src/shaders/project1-frag.glsl b/src/shaders/project1-frag.glsl new file mode 100644 index 0000000..7b9dc8a --- /dev/null +++ b/src/shaders/project1-frag.glsl @@ -0,0 +1,17 @@ +varying vec2 vUv; +varying float vNoise; +uniform sampler2D image; + +float getSin(float t){ + return sin( t * 1.57); +} + +void main() { + + //vec4 color = texture2D( image, vUv ); + //gl_FragColor = vec4( color.gbr, 1.0 ); + //float val = getSin( vUv.x ); + //gl_FragColor = vec4( val, val, val, 1.0 ); + + gl_FragColor = vec4( vNoise*vNoise*vNoise, vNoise*vNoise, (1.0-vNoise) * (1.0-vNoise), 1.0 ); +} \ No newline at end of file diff --git a/src/shaders/project1-vert.glsl b/src/shaders/project1-vert.glsl new file mode 100644 index 0000000..554f02c --- /dev/null +++ b/src/shaders/project1-vert.glsl @@ -0,0 +1,250 @@ +uniform float uTimeMsec; //current time in msec + +uniform float uN1Scale; +uniform float uN1persistence; +uniform float uN1fundamental; +uniform float uN1overtoneScale; +uniform float uN1numComponents; +uniform float uN1symmetryX, uN1symmetryY, uN1symmetryZ; +uniform float uN1TimeScale; //scaling factor for time + +//I think I could just make a uniform vec3 - but how to handle that in gui? +vec3 N1symmetry = vec3( uN1symmetryX, uN1symmetryY, uN1symmetryZ ); + +uniform float uN2Scale; +uniform float uN2persistence; +uniform float uN2fundamental; +uniform float uN2overtoneScale; +uniform float uN2numComponents; +uniform float uN2symmetryX, uN2symmetryY, uN2symmetryZ; +uniform float uN2TimeScale; //scaling factor for time + +vec3 N2symmetry = vec3( uN2symmetryX, uN2symmetryY, uN2symmetryZ ); + +varying vec2 vUv; +varying float vNoise; + + +////////// Interpolation /////////// + +//linear interp +//t must be [0,1] +// +float lerp( float v0, float v1, float t ){ + return v0 + (v1 - v0) * t; +} + +//bilinear interp +//Assumes points are 1.0 unit apart +//ll = "lower left" point, etc +//t01 and t02 are fractional [0,1] position between points[0,1] and points[0,2], respectively +// +float blerp( vec4 points, float t01, float t02 ){ + float llerp = lerp( points[0], points[1], t01 ); + float ulerp = lerp( points[2], points[3], t01 ); + return lerp( llerp, ulerp, t02 ); +} + +//trilinear interp +//Assumes points are 1.0 unit apart +//fll = "front lower left" point, etc +//t01, t02 and tfb are fractional [0,1] position between left/right points, +// lower/upper points, and front/rear points, respectively +// +float trilerp( vec4 face1, vec4 face2, float t01, float t02, float tfb ){ + float fblerp = blerp( face1, t01, t02 ); + float bblerp = blerp( face2, t01, t02 ); + return lerp( fblerp, bblerp, tfb ); +} + +/////////// Noise ////////////// + +//noise example from lecture slides +//Looks like this outputs [0,1] cuz of sin() +// +float noise_gen2(float x, float y) { + float val = sin( dot( vec2(x,y), vec2( 12.9898, 78.233 )) ) * 43758.5453; + return val - floor(val); +} +float noise_gen3(float x, float y, float z) { + float val = sin( dot( vec2(x, y), vec2( z, 78.233 )) ) * 43758.5453; + return val - floor(val); +} + +float noise_gen3b(float x, float y, float z) { + float val = sin( dot( vec2(x+y, y+z), vec2( z+x, (x+y+z)/3.0 /*78.233*/ )) ) * 43758.5453; + //changed to combos of vals to make symmetries around axes less obvious + //seems to make them become a little more radial, at least at the pole + return val - floor(val); + + //Interesting octant symmetries arise: + //float sign = 1.0 * sign(x) * sign(y) * sign(z); + //return ( ( (val - floor(val)) * sign ) + 1.0 ) / 2.0; +} + +float noise_gen3cSymm(float x, float y, float z) { + float xN = sin( dot( vec2(x, 23.1406926327792690), vec2( 2.6651441426902251, 78.233 )) ) * 43758.5453; + float yN = sin( dot( vec2(y, 2.6651441426902251), vec2( 78.233, 23.1406926327792690 )) ) * 43758.5453; + float zN = sin( dot( vec2(z, 78.233), vec2( 23.1406926327792690, 2.6651441426902251 )) ) * 43758.5453; + + /* + //Tried doing variable symmetry here, but is very jump as you move through [0,1]. But I don't + // understand why. For a given x,y,z, xN and xAbs don't change, so the lerp between + // them is smooth, so the change in valx and final val should be smooth. + // The per-axis symmetry looks right when symm val is 1.0, but in between it's jumpy. + float xAbs = sin( dot( vec2(abs(x), 23.1406926327792690), vec2( 2.6651441426902251, 78.233 )) ) * 43758.5453; + float yAbs = sin( dot( vec2(abs(y), 2.6651441426902251), vec2( 78.233, 23.1406926327792690 )) ) * 43758.5453; + float zAbs = sin( dot( vec2(abs(z), 78.233), vec2( 23.1406926327792690, 2.6651441426902251 )) ) * 43758.5453; + + float valx = lerp( xN, xAbs, uN1symmetryX ); + float valy = lerp( yN, yAbs, uN1symmetryY ); + float valz = lerp( zN, zAbs, uN1symmetryZ ); + */ + + float valx = xN, valy = yN, valz = zN; + + float val = (valx + valy + valz) / 3.0; + return fract(val); +} + +//This samples the generated noise at a particular frequency (relative freq's, really). +//x and y are called 'query' points, to distinguish from sample points +//It always samples the noise func at integer values, and interpolates between those. +//freq - Frequency 1 yields samples of floor(x) and floor(x)+1, and similarly for y. +//Frequency f samples at floor(f*x) and floor(f*x)+1. This will make the query points +// for a given domain get spread out over more sample bins and thus get more peaks (i.e. noisier) +// as f increases. This also 'moves' the sample points along for a given query domain, so +// we don't get output that's aligned over different frequencies. +//freq is a float so we can do non-integer harmonics +// +float noise_query3D(float x, float y, float z, float f /*frequency*/){ + //scale by frequency + float xs = x * f; + float ys = y * f; + float zs = z * f; + //"lower-left" value + vec4 face1; + face1[0] = noise_gen3cSymm( floor(xs), floor(ys), floor(zs) ); + face1[1] = noise_gen3cSymm( floor(xs) + 1.0, floor(ys), floor(zs) ); + face1[2] = noise_gen3cSymm( floor(xs), floor(ys) + 1.0, floor(zs) ); + face1[3] = noise_gen3cSymm( floor(xs) + 1.0, floor(ys) + 1.0, floor(zs) ); + + vec4 face2; + face2[0] = noise_gen3cSymm( floor(xs), floor(ys), floor(zs) + 1.0 ); + face2[1] = noise_gen3cSymm( floor(xs) + 1.0, floor(ys), floor(zs) + 1.0 ); + face2[2] = noise_gen3cSymm( floor(xs), floor(ys) + 1.0, floor(zs) + 1.0 ); + face2[3] = noise_gen3cSymm( floor(xs) + 1.0, floor(ys) + 1.0, floor(zs) + 1.0 ); + + return trilerp( face1, face2, xs - floor(xs), ys - floor(ys), zs - floor(zs) ); +} + + +//Simple time-varying sample. +//If just sample cube in two locations and interp, will have same trouble with symmetry. +//The thing to do is just make a 4D noise generator, to make it easy to keep symmetry +/* +float noise_query4D(float x, float y, float z, float t, float f ){ + float val0 = noise_query3D( x, y, z, f ); + float offset = uTimeMsec / uN1TimeScale; + ... +} +*/ + +//Multi-octave noise +//However, is generalized to non-octave overtones series, based on arbitrary overtone scale factor. +//numComponents - number of frequency components to generate, including fundamental +// +float MON(float x, float y, float z, float fundamental, float overtoneScale, float numComponents, float persistence ) { + float f = fundamental; + float amp = 1.0; + float result = 0.0; + float scale = 0.0; //Track accumlated maximum scale to keep result in [0,1] + //for-loop issue + //can't compare against a non-const expression in the loop, cuz (at least + // on some hardware), loop gets unrolled at compile time so it has to + // know how many iterations to do + #define MAX_COMPONENTS 16.0 //Can also do a const var + for( float component = 1.0; component <= MAX_COMPONENTS; component++ ){ + float noise = noise_query3D( x, y, z, f ); + result += noise * amp; + //update for next overtone + f *= overtoneScale; + scale += amp; + amp *= persistence; + if ( component == numComponents ) + break; + } + return result / scale; +} + +////////////// Main /////////////////// + +void main() { + vUv = uv; + //float noise = noise_gen2( uv.x, uv.y ); + //vNoise = noise_query( position.x, position.y, 1.0 /*freq*/ ); + float pOffset = 0.0; //offset to lessen symmetry from verts symmetrical around axes + + //////// First Noise //////// + + //"time" offset + // + vec3 newPos = position; + //this method spreads out sample points over time until things get really spikey + //vec3 newPos = position * vec3( uTimeMsec / uN1TimeScale ); + // + //this ruins symmetry because positions move towards all positive + //vec3 newPos = position + vec3( uTimeMsec / uN1TimeScale ); + // + //this keeps symmetry working but creates lines along axes, between octants - why? + //because it exagerates the difference betweem points at the axes, i.e. between pos/neg values? + //vec3 newPos = position + sign(position) * vec3( uTimeMsec / uN1TimeScale ); + // + //combine the two above methods, using the sign() method for symmetric values + // and blend. But still get artifact at intermediate values. + vec3 newPosR = position + vec3( uTimeMsec / uN1TimeScale ); + vec3 newPosAbs = position + sign(position) * vec3( uTimeMsec / uN1TimeScale ); + for( int i=0; i < 3; i++ ) + newPos[i] = lerp( newPosR[i], newPosAbs[i], N1symmetry[i]); + + + //Doing variable symmetry here by lerping between each vertex component and its abs(). + // This transitions smoothly from [0,1], as opposed to method above in noise_gen3cSymm. + // However when symm vals are close to 0.5, get artifacts in negative octants - looks like + // noise is going to 0, but can't understand why. Maybe cuz projections in noise_gen3cSymm + // get closer to same values since there's less movement in position. I tried using large (500) + // pOffset to get resultant position vals away from 0, but still seeing artifacts. + //AND the symmetry is skewed on local level, like order of quads is getting properly reversed but not + // the contents of each quad + float noiseN1 = MON( + lerp( newPos.x, abs(newPos.x), uN1symmetryX ) + pOffset, + lerp( newPos.y, abs(newPos.y), uN1symmetryY ) + pOffset, + lerp( newPos.z, abs(newPos.z), uN1symmetryZ ) + pOffset, + uN1fundamental, + uN1overtoneScale, + uN1numComponents, + uN1persistence); + + //////// Second noise //////// + + //Should set it up to use a different noise generator, but no time for that now... + + newPosR = position + vec3( uTimeMsec / uN2TimeScale ); + newPosAbs = position + sign(position) * vec3( uTimeMsec / uN2TimeScale ); + for( int i=0; i < 3; i++ ) + newPos[i] = lerp( newPosR[i], newPosAbs[i], N2symmetry[i]); + float noiseN2 = MON( + lerp( newPos.x, abs(newPos.x), uN2symmetryX ), + lerp( newPos.y, abs(newPos.y), uN2symmetryY ), + lerp( newPos.z, abs(newPos.z), uN2symmetryZ ), + uN2fundamental, + uN2overtoneScale, + uN2numComponents, + uN2persistence); + + + //add them together + vNoise = ( noiseN1 * uN1Scale + noiseN2 * uN2Scale ) / (uN1Scale + uN2Scale); + vec3 perturb = normal * vNoise; + gl_Position = projectionMatrix * modelViewMatrix * vec4( position + perturb, 1.0 ); +} \ No newline at end of file From ffab8b6a1e5d3f98e6c232b6528776d10840ff6a Mon Sep 17 00:00:00 2001 From: Michael Stauffer Date: Tue, 24 Jan 2017 15:51:51 -0500 Subject: [PATCH 3/3] Reformat README --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 9a20598..a62ace8 100644 --- a/README.md +++ b/README.md @@ -10,13 +10,21 @@ My code implements: 1. Two independently controlled multi-octave noise (MON) generators. 2. Each uses the same underlying noise generator, unfortunately, although this may give some good continuity effects. 3. Each can have its parameters controlled from the GUI: + a. N1 is for generator one, N2 is for generator two + b. Time Scale - scales down the time value to control 'speed' of animation + c. fundamental - set the fundamental frequency of sampling + d. harmScale - set the scaling factor between harmonics of the MON. Harmonic N = fundamental * harmScale ^ (N-1). + e. components - the number of harmonics in the MON. + f. persistence - scales the amplitude of each component in the MON. Values > 1 are interesting! + g. symmetry[XYZ] - controls symmetry of noise across each axis. Only looks good if 0 or 1. Intermediate values look good in static renders but I had trouble making it smooth with how I was using time to vary vertex position. + 4. Time is used simply to offset vertex position, and vertex position is used to generate noise. This has awkward effect of making noise look to be moving in a direction in some cases. Better would be to create true 4D noise with time as 4th dim. 5. The default settings combine symmetry in X for a slow movig, high spatial-frequency noise, with symmetry in Y for a faster-moving, low spatial-frequency noise. I think this makes it look alive, like a tiny plankton creature, undulating with water pressure and life processes.