Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# [Project 1: Noise](https://github.com/CIS700-Procedural-Graphics/Project1-Noise)

## Updates
Name: Grace Xu
Implemented up to 5 octaves of noise and gui controls for level of detail for the icosahedron geometry and strength of the noise (via persistence and number of octaves). Color is linear interpolated between black and white using the same noise strength.

## Objective

Get comfortable with using three.js and its shader support and generate an interesting 3D, continuous surface using a multi-octave noise algorithm.
Expand Down
82 changes: 57 additions & 25 deletions src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,31 @@ import Framework from './framework'
import Noise from './noise'
import {other} from './noise'

// used to animate the icosahedron
var programStartTime;

var myMaterial = new THREE.ShaderMaterial({
uniforms: {
time: { // Check the Three.JS documentation for the different allowed types and values
type: "f",
value: Date.now()
},
noiseStrength: {
type: "f",
value: 2.0
},
numOctaves: {
type: "f",
value: 3
}
},
vertexShader: require('./shaders/my-vert.glsl'),
fragmentShader: require('./shaders/my-frag.glsl')
});

// called after the scene loads
function onLoad(framework) {
programStartTime = Date.now();
var scene = framework.scene;
var camera = framework.camera;
var renderer = framework.renderer;
Expand All @@ -15,46 +38,55 @@ function onLoad(framework) {
// LOOK: the line below is synyatic sugar for the code above. Optional, but I sort of recommend it.
// var {scene, camera, renderer, gui, stats} = framework;

// initialize a simple box and material
var box = new THREE.BoxGeometry(1, 1, 1);
// initialize icosahedron object
var guiFields = {
icosahedronDetail: 3,
noiseStrength: 2.0,
numOctaves: 3
}

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 icosahedronGeometry = new THREE.IcosahedronGeometry(1, guiFields.icosahedronDetail);

var texturedIcosahedron = new THREE.Mesh(icosahedronGeometry, myMaterial);
scene.add(texturedIcosahedron);

// set camera position
camera.position.set(1, 1, 2);
camera.position.set(1, 1, 5);
camera.lookAt(new THREE.Vector3(0,0,0));

scene.add(adamCube);

// edit params and listen to changes like this
// more information here: https://workshop.chromeexperiments.com/examples/gui/#1--Basic-Usage
gui.add(camera, 'fov', 0, 180).onChange(function(newVal) {
camera.updateProjectionMatrix();
});

gui.add(guiFields, 'icosahedronDetail', 0, 5).step(1).onFinishChange(function(newVal) {
scene.remove(texturedIcosahedron);
guiFields.icosahedronDetail = newVal;
icosahedronGeometry = new THREE.IcosahedronGeometry(1, newVal);
texturedIcosahedron = new THREE.Mesh(icosahedronGeometry, myMaterial);
scene.add(texturedIcosahedron);
});

// changes persistence of noise
gui.add(guiFields, 'noiseStrength', 0.6, 8.0).onFinishChange(function(newVal) {
myMaterial.uniforms.noiseStrength.value = newVal;
myMaterial.needsUpdate = true;
});

// determines number of octaves of noise
gui.add(guiFields, 'numOctaves', 1, 5).step(1).onFinishChange(function(newVal) {
myMaterial.uniforms.numOctaves.value = newVal;
myMaterial.needsUpdate = true;
});
}

// called on frame updates
function onUpdate(framework) {
// console.log(`the time is ${new Date()}`);
// animates icosahedron
myMaterial.uniforms.time.value = Date.now() - programStartTime;
myMaterial.needsUpdate = true;
}

// when the scene is done initializing, it will call onLoad, then on frame updates, call onUpdate
Framework.init(onLoad, onUpdate);

// console.log('hello world');

// console.log(Noise.generateNoise());

// Noise.whatever()

// console.log(other())
66 changes: 60 additions & 6 deletions src/noise.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,70 @@
// a bunch of 3d pseudo-random noise functions that return floating point numbers between -1.0 and 1.0
function generateNoise1(x, y, z) {
var n = x + y + z * 57;
n = (n<<13) ^ n;
return ( 1.0 - ((n * (n * n * 15731 + 789221) + 1376312589) & 0x7FFFFFFF) / 1073741824.0);
}

function linearInterpolate(a, b, t) {
return a * (1 - t) + b * t;
}

function cosineInterpolate(a, b, t) {
var cos_t = (1 - Math.cos(t * Math.PI)) * 0.5;
return linearInterpolate(a, b, cos_t);
}

// given a point in 3d space, produces a noise value by interpolating surrounding points
function interpolateNoise(x, y, z) {
var integerX = Math.floor(x);
var weightX = x - integerX;

var integerY = Math.floor(y);
var weightY = y - integerY;

var integerZ = Math.floor(z);
var weightZ = z - integerZ;

function generateNoise() {
return Math.random()
var v1 = generateNoise1(integerX, integerY, integerZ);
var v2 = generateNoise1(integerX, integerY, integerZ + 1);
var v3 = generateNoise1(integerX, integerY + 1, integerZ + 1);
var v4 = generateNoise1(integerX, integerY + 1, integerZ);

var v5 = generateNoise1(integerX + 1, integerY, integerZ);
var v6 = generateNoise1(integerX + 1, integerY, integerZ + 1);
var v7 = generateNoise1(integerX + 1, integerY + 1, integerZ + 1);
var v8 = generateNoise1(integerX + 1, integerY + 1, integerZ);

var i1 = cosineInterpolate(v1, v5, weightX);
var i2 = cosineInterpolate(v2, v6, weightX);
var i3 = cosineInterpolate(v3, v7, weightX);
var i4 = cosineInterpolate(v4, v8, weightX);

var ii1 = cosineInterpolate(i1, i4, weightY);
var ii2 = cosineInterpolate(i2, i3, weightY);

return cosineInterpolate(ii1, ii2 , weightZ);
}

function whatever() {
console.log('hi');
// a multi-octave noise generation function that sums multiple noise functions together
// with each subsequent noise function increasing in frequency and decreasing in amplitude
function generateMultiOctaveNoise(x, y, z, numOctaves) {
var total = 0;
var persistence = 1/2.0;

//loop for some number of octaves
for (var i = 0; i < numOctaves; i++) {
var frequency = Math.pow(2, i);
var amplitude = Math.pow(persistence, i);

total += interpolateNoise(x * frequency, y * frequency, z * frequency) * amplitude;
}

return total;
}

export default {
generateNoise: generateNoise,
whatever: whatever
generateMultiOctaveNoise: generateMultiOctaveNoise
}

export function other() {
Expand Down
13 changes: 0 additions & 13 deletions src/shaders/adam-frag.glsl

This file was deleted.

6 changes: 0 additions & 6 deletions src/shaders/adam-vert.glsl

This file was deleted.

16 changes: 16 additions & 0 deletions src/shaders/my-frag.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
varying vec2 vUv;
varying float vNoise;
varying vec3 vNormal;

float linearInterpolate(float a, float b, float t) {
return a * (1.0 - t) + b * t;
}

void main() {
float r = linearInterpolate(0.0, 0.9, vNoise);
float g = linearInterpolate(0.0, 0.9, vNoise);
float b = linearInterpolate(0.0, 0.9, vNoise);

gl_FragColor = vec4(r, g, b, 1.0);
//gl_FragColor = vec4(vNormal.rgb, 1.0);
}
90 changes: 90 additions & 0 deletions src/shaders/my-vert.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
varying vec2 vUv;
varying vec3 vNormal;
varying float vNoise;
uniform int numOctaves;
uniform float time;
uniform float noiseStrength;
const int aLargeNumber = 10;

float generateNoise(int x, int y, int z, int numOctave) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice idea taking in the octave here to add variation

if (numOctave == 0) {
return fract(sin(dot(vec3(x,y,z), vec3(12.9898, 78.23, 107.81))) * 43758.5453);
} else if (numOctave == 1) {
return fract(sin(dot(vec3(z,x,y), vec3(16.363, 43.597, 199.73))) * 69484.7539);
} else if (numOctave == 2) {
return fract(sin(dot(vec3(y,x,z), vec3(13.0, 68.819, 90.989))) * 92041.9823);
} else if (numOctave == 3) {
return fract(sin(dot(vec3(x,y,z), vec3(98.1577, 47.45029, 154.85161))) * 84499.0);
} else if (numOctave == 4) {
return fract(sin(dot(vec3(z,x,y), vec3(9.75367, 83.3057, 390.353))) * 15485.653);
}
}

float linearInterpolate(float a, float b, float t) {
return a * (1.0 - t) + b * t;
}

float cosineInterpolate(float a, float b, float t) {
float cos_t = (1.0 - cos(t * 3.14159265359879323846264)) * 0.5;
return linearInterpolate(a, b, cos_t);
}

// given a point in 3d space, produces a noise value by interpolating surrounding points
float interpolateNoise(float x, float y, float z, int numOctave) {
int integerX = int(floor(x));
float weightX = x - float(integerX);

int integerY = int(floor(y));
float weightY = y - float(integerY);

int integerZ = int(floor(z));
float weightZ = z - float(integerZ);

float v1 = generateNoise(integerX, integerY, integerZ, numOctave);
float v2 = generateNoise(integerX, integerY, integerZ + 1, numOctave);
float v3 = generateNoise(integerX, integerY + 1, integerZ + 1, numOctave);
float v4 = generateNoise(integerX, integerY + 1, integerZ, numOctave);

float v5 = generateNoise(integerX + 1, integerY, integerZ, numOctave);
float v6 = generateNoise(integerX + 1, integerY, integerZ + 1, numOctave);
float v7 = generateNoise(integerX + 1, integerY + 1, integerZ + 1, numOctave);
float v8 = generateNoise(integerX + 1, integerY + 1, integerZ, numOctave);

float i1 = cosineInterpolate(v1, v5, weightX);
float i2 = cosineInterpolate(v2, v6, weightX);
float i3 = cosineInterpolate(v3, v7, weightX);
float i4 = cosineInterpolate(v4, v8, weightX);

float ii1 = cosineInterpolate(i1, i4, weightY);
float ii2 = cosineInterpolate(i2, i3, weightY);

return cosineInterpolate(ii1, ii2 , weightZ);
}

// a multi-octave noise generation function that sums multiple noise functions together
// with each subsequent noise function increasing in frequency and decreasing in amplitude
float generateMultiOctaveNoise(float x, float y, float z) {
float total = 0.0;
float persistence = 1.0/noiseStrength;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a little odd that less "noise" makes it more noisy.


//loop for some number of octaves
for (int i = 0; i < aLargeNumber; i++) {
if (i == numOctaves) break;
float frequency = pow(2.0, float(i));
float amplitude = pow(persistence, float(i));

total += interpolateNoise(x * frequency, y * frequency, z * frequency, i) * amplitude;
}

return total;
}

void main() {
float offset = generateMultiOctaveNoise(position[0] + time/999.0, position[1] + time/999.0, position[2] + time/999.0);
vec3 newPosition = position + offset * normal;

gl_Position = projectionMatrix * modelViewMatrix * vec4( newPosition, 1.0 );
vUv = uv;
vNormal = normal;
vNoise = offset;
}