Browse Source

Add randomDirection and random methods to Vector3 and Quaternion (#22494)

* Add a new Random module in examples with an onUnitSphere function (for #19047)

* Move Random to RandomUtils

* Remove RandomUtils

* Add randomDirection and random to Vector3 and Quaternion

* Fix quaternion ordering and indentation
Brian Peiris 3 years ago
parent
commit
0579cdeb72

+ 5 - 0
docs/api/en/math/Quaternion.html

@@ -138,6 +138,11 @@
 		<h3>[method:Quaternion premultiply]( [param:Quaternion q] )</h3>
 		<p>Pre-multiplies this quaternion by [page:Quaternion q].</p>
 
+		<h3>[method:Quaternion random]()</h3>
+		<p>
+		Sets this quaternion to a uniformly random, normalized quaternion.
+		</p>
+
 		<h3>[method:Quaternion rotateTowards]( [param:Quaternion q], [param:Float step] )</h3>
 		<p>
 			[page:Quaternion q] - The target quaternion.<br />

+ 5 - 0
docs/api/en/math/Vector3.html

@@ -440,6 +440,11 @@
 			Sets each component of this vector to a pseudo-random value between 0 and 1, excluding 1.
 		</p>
 
+		<h3>[method:this randomDirection]()</h3>
+		<p>
+		Sets this vector to a uniformly random point on a unit sphere.
+		</p>
+
 		<h2>Source</h2>
 
 		<p>

+ 23 - 0
src/math/Quaternion.js

@@ -608,6 +608,29 @@ class Quaternion {
 
 	}
 
+	random() {
+
+		// Derived from http://planning.cs.uiuc.edu/node198.html
+		// Note, this source uses w, x, y, z ordering,
+		// so we swap the order below.
+
+		const u1 = Math.random();
+		const sqrt1u1 = Math.sqrt( 1 - u1 );
+		const sqrtu1 = Math.sqrt( u1 );
+
+		const u2 = 2 * Math.PI * Math.random();
+
+		const u3 = 2 * Math.PI * Math.random();
+
+		return this.set(
+			sqrt1u1 * Math.cos( u2 ),
+			sqrtu1 * Math.sin( u3 ),
+			sqrtu1 * Math.cos( u3 ),
+			sqrt1u1 * Math.sin( u2 ),
+		);
+
+	}
+
 	equals( quaternion ) {
 
 		return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w );

+ 16 - 0
src/math/Vector3.js

@@ -711,6 +711,22 @@ class Vector3 {
 
 	}
 
+	randomDirection() {
+
+		// Derived from https://mathworld.wolfram.com/SpherePointPicking.html
+
+		const u = ( Math.random() - 0.5 ) * 2;
+		const t = Math.random() * Math.PI * 2;
+		const f = Math.sqrt( 1 - u ** 2 );
+
+		this.x = f * Math.cos( t );
+		this.y = f * Math.sin( t );
+		this.z = u;
+
+		return this;
+
+	}
+
 }
 
 Vector3.prototype.isVector3 = true;

+ 17 - 0
test/unit/src/math/Quaternion.tests.js

@@ -673,6 +673,23 @@ export default QUnit.module( 'Maths', () => {
 
 		} );
 
+		QUnit.test( "random", ( assert ) => {
+
+			var a = new Quaternion();
+
+			a.random();
+
+			var identity = new Quaternion();
+			assert.notDeepEqual(
+				a,
+				identity,
+				'randomizes at least one component of the quaternion'
+			);
+
+			assert.ok( ( 1 - a.length() ) <= Number.EPSILON, 'produces a normalized quaternion' );
+
+		} );
+
 		QUnit.test( "equals", ( assert ) => {
 
 			var a = new Quaternion( x, y, z, w );

+ 17 - 0
test/unit/src/math/Vector3.tests.js

@@ -989,6 +989,23 @@ export default QUnit.module( 'Maths', () => {
 
 		} );
 
+		QUnit.test( 'randomDirection', ( assert ) => {
+
+			var vec = new Vector3();
+
+			vec.randomDirection();
+
+			var zero = new Vector3();
+			assert.notDeepEqual(
+				vec,
+				zero,
+				'randomizes at least one component of the vector'
+			);
+
+			assert.ok( ( 1 - vec.length() ) <= Number.EPSILON, 'produces a unit vector' );
+
+		} );
+
 	} );
 
 } );