From edf091160af73c5cd4c18caf724011e18c74966d Mon Sep 17 00:00:00 2001 From: WestLangley Date: Sun, 7 Apr 2019 21:14:29 -0400 Subject: [PATCH 1/2] Added spherical harmonics class --- src/math/SphericalHarmonics3.js | 211 ++++++++++++++++++++++++++++++++ 1 file changed, 211 insertions(+) create mode 100644 src/math/SphericalHarmonics3.js diff --git a/src/math/SphericalHarmonics3.js b/src/math/SphericalHarmonics3.js new file mode 100644 index 00000000000000..75e9af5269bd9f --- /dev/null +++ b/src/math/SphericalHarmonics3.js @@ -0,0 +1,211 @@ +import { Vector3 } from './Vector3.js'; + +/** + * @author bhouston / http://clara.io + * @author WestLangley / http://github.com/WestLangley + * + * Primary reference: + * https://graphics.stanford.edu/papers/envmap/envmap.pdf + * + * Secondary reference: + * https://www.ppsloan.org/publications/StupidSH36.pdf + */ + +// 3-band SH defined by 9 coefficients + +function SphericalHarmonics3() { + + this.coefficients = []; + + for ( var i = 0; i < 9; i ++ ) { + + this.coefficients.push( new Vector3() ); + + } + +} + +Object.assign( SphericalHarmonics3.prototype, { + + isSphericalHarmonics3: true, + + set: function ( coefficients ) { + + for ( var i = 0; i < 9; i ++ ) { + + this.coefficients[ i ].copy( coefficients[ i ] ); + + } + + return this; + + }, + + zero: function () { + + for ( var i = 0; i < 9; i ++ ) { + + this.coefficients[ i ].set( 0, 0, 0 ); + + } + + return this; + + }, + + // get the radiance in the direction of the normal + // target is a Vector3 + getAt: function( normal, target ) { + + // normal is assumed to be unit length + + var x = normal.x, y = normal.y, z = normal.z; + + var coeff = this.coefficients; + + // band 0 + target = coeff[ 0 ] * 0.282095; + + // band 1 + target += coeff[ 1 ] * 0.488603 * y; + target += coeff[ 2 ] * 0.488603 * z; + target += coeff[ 3 ] * 0.488603 * x; + + // band 2 + target += coeff[ 4 ] * 1.092548 * ( x * y ); + target += coeff[ 5 ] * 1.092548 * ( y * z ); + target += coeff[ 6 ] * 0.315392 * ( 3.0 * z * z - 1.0 ); + target += coeff[ 7 ] * 1.092548 * ( x * z ); + target += coeff[ 8 ] * 0.546274 * ( x * x - y * y ); + + return target; + + }, + + // get the irradiance (radiance convolved with cosine lobe) in the direction of the normal + // target is a Vector3 + // https://graphics.stanford.edu/papers/envmap/envmap.pdf + getIrradianceAt: function( normal, target ) { + + // normal is assumed to be unit length + + var x = normal.x, y = normal.y, z = normal.z; + + var coeff = this.coefficients; + + // band 0 + target = coeff[ 0 ] * 0.886227; // π * 0.282095 + + // band 1 + target += coeff[ 1 ] * 2.0 * 0.511664 * y; // ( 2 * π / 3 ) * 0.488603 + target += coeff[ 2 ] * 2.0 * 0.511664 * z; + target += coeff[ 3 ] * 2.0 * 0.511664 * x; + + // band 2 + target += coeff[ 4 ] * 2.0 * 0.429043 * x * y; // ( π / 4 ) * 1.092548 + target += coeff[ 5 ] * 2.0 * 0.429043 * y * z; + target += coeff[ 6 ] * ( 0.743125 * z * z - 0.247708 ); // ( π / 4 ) * 0.315392 * 3 + target += coeff[ 7 ] * 2.0 * 0.429043 * x * z; + target += coeff[ 8 ] * 0.429043 * ( x * x - y * y ); // ( π / 4 ) * 0.546274 + + return target; + + }, + + add: function( sh ) { + + for ( var i = 0; i < 9; i ++ ) { + + this.coefficients[ i ].add( sh.coefficients[ i ] ); + + } + + return this; + + }, + + + scale: function( s ) { + + for ( var i = 0; i < 9; i ++ ) { + + this.coefficients[ i ].multiplyScalar( s ); + + } + + return this; + + }, + + lerp: function( sh, alpha ) { + + for ( var i = 0; i < 9; i ++ ) { + + this.coefficients[ i ].lerp( sh.coefficients[ i ], alpha ); + + } + + return this; + + }, + + equals: function ( sh ) { + + for ( var i = 0; i < 9; i ++ ) { + + if ( ! this.coefficients[ i ].equals( sh.coefficients[ i ] ) ) { + + return false; + + } + + } + + return true; + + }, + + copy: function ( sh ) { + + return this.set( sh.coefficients ); + + }, + + clone: function () { + + return new this.constructor().copy( this ); + + } + +} ); + +Object.assign( SphericalHarmonics3, { + + // evaluate the basis functions + // shBasis is an Array[ 9 ] + getBasisAt: function( normal, shBasis ) { + + // normal is assumed to be unit length + + var x = normal.x, y = normal.y, z = normal.z; + + // band 0 + shBasis[ 0 ] = 0.282095; + + // band 1 + shBasis[ 1 ] = 0.488603 * y; + shBasis[ 2 ] = 0.488603 * z; + shBasis[ 3 ] = 0.488603 * x; + + // band 2 + shBasis[ 4 ] = 1.092548 * x * y; + shBasis[ 5 ] = 1.092548 * y * z; + shBasis[ 6 ] = 0.315392 * ( 3 * z * z - 1 ); + shBasis[ 7 ] = 1.092548 * x * z; + shBasis[ 8 ] = 0.546274 * ( x * x - y * y ); + + } + +} ); + +export { SphericalHarmonics3 }; From 1152066f24b778173527601d1ac8ebda61dc9bbf Mon Sep 17 00:00:00 2001 From: WestLangley Date: Sun, 7 Apr 2019 21:40:12 -0400 Subject: [PATCH 2/2] Clean up --- src/math/SphericalHarmonics3.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/math/SphericalHarmonics3.js b/src/math/SphericalHarmonics3.js index 75e9af5269bd9f..542c7d471b9c13 100644 --- a/src/math/SphericalHarmonics3.js +++ b/src/math/SphericalHarmonics3.js @@ -55,7 +55,7 @@ Object.assign( SphericalHarmonics3.prototype, { // get the radiance in the direction of the normal // target is a Vector3 - getAt: function( normal, target ) { + getAt: function ( normal, target ) { // normal is assumed to be unit length @@ -85,7 +85,7 @@ Object.assign( SphericalHarmonics3.prototype, { // get the irradiance (radiance convolved with cosine lobe) in the direction of the normal // target is a Vector3 // https://graphics.stanford.edu/papers/envmap/envmap.pdf - getIrradianceAt: function( normal, target ) { + getIrradianceAt: function ( normal, target ) { // normal is assumed to be unit length @@ -94,25 +94,25 @@ Object.assign( SphericalHarmonics3.prototype, { var coeff = this.coefficients; // band 0 - target = coeff[ 0 ] * 0.886227; // π * 0.282095 + target = coeff[ 0 ] * 0.886227; // π * 0.282095 // band 1 - target += coeff[ 1 ] * 2.0 * 0.511664 * y; // ( 2 * π / 3 ) * 0.488603 + target += coeff[ 1 ] * 2.0 * 0.511664 * y; // ( 2 * π / 3 ) * 0.488603 target += coeff[ 2 ] * 2.0 * 0.511664 * z; target += coeff[ 3 ] * 2.0 * 0.511664 * x; // band 2 - target += coeff[ 4 ] * 2.0 * 0.429043 * x * y; // ( π / 4 ) * 1.092548 + target += coeff[ 4 ] * 2.0 * 0.429043 * x * y; // ( π / 4 ) * 1.092548 target += coeff[ 5 ] * 2.0 * 0.429043 * y * z; - target += coeff[ 6 ] * ( 0.743125 * z * z - 0.247708 ); // ( π / 4 ) * 0.315392 * 3 + target += coeff[ 6 ] * ( 0.743125 * z * z - 0.247708 ); // ( π / 4 ) * 0.315392 * 3 target += coeff[ 7 ] * 2.0 * 0.429043 * x * z; - target += coeff[ 8 ] * 0.429043 * ( x * x - y * y ); // ( π / 4 ) * 0.546274 + target += coeff[ 8 ] * 0.429043 * ( x * x - y * y ); // ( π / 4 ) * 0.546274 return target; }, - add: function( sh ) { + add: function ( sh ) { for ( var i = 0; i < 9; i ++ ) { @@ -125,7 +125,7 @@ Object.assign( SphericalHarmonics3.prototype, { }, - scale: function( s ) { + scale: function ( s ) { for ( var i = 0; i < 9; i ++ ) { @@ -137,7 +137,7 @@ Object.assign( SphericalHarmonics3.prototype, { }, - lerp: function( sh, alpha ) { + lerp: function ( sh, alpha ) { for ( var i = 0; i < 9; i ++ ) { @@ -183,7 +183,7 @@ Object.assign( SphericalHarmonics3, { // evaluate the basis functions // shBasis is an Array[ 9 ] - getBasisAt: function( normal, shBasis ) { + getBasisAt: function ( normal, shBasis ) { // normal is assumed to be unit length