2
0
Эх сурвалжийг харах

Float16BufferAttribute: Unpack/pack float16's in in getters/setters. (#25519)

* .

* .

* .

* Fix some formatting issues.
simondevyoutube 2 жил өмнө
parent
commit
2b54088d99

+ 141 - 0
src/core/BufferAttribute.js

@@ -2,6 +2,7 @@ import { Vector3 } from '../math/Vector3.js';
 import { Vector2 } from '../math/Vector2.js';
 import { denormalize, normalize } from '../math/MathUtils.js';
 import { StaticDrawUsage } from '../constants.js';
+import { fromHalfFloat, toHalfFloat } from '../extras/DataUtils.js';
 
 const _vector = /*@__PURE__*/ new Vector3();
 const _vector2 = /*@__PURE__*/ new Vector2();
@@ -453,6 +454,146 @@ class Float16BufferAttribute extends BufferAttribute {
 
 	}
 
+	getX( index ) {
+
+		let x = fromHalfFloat( this.array[ index * this.itemSize ] );
+
+		if ( this.normalized ) x = denormalize( x, this.array );
+
+		return x;
+
+	}
+
+	setX( index, x ) {
+
+		if ( this.normalized ) x = normalize( x, this.array );
+
+		this.array[ index * this.itemSize ] = toHalfFloat( x );
+
+		return this;
+
+	}
+
+	getY( index ) {
+
+		let y = fromHalfFloat( this.array[ index * this.itemSize + 1 ] );
+
+		if ( this.normalized ) y = denormalize( y, this.array );
+
+		return y;
+
+	}
+
+	setY( index, y ) {
+
+		if ( this.normalized ) y = normalize( y, this.array );
+
+		this.array[ index * this.itemSize + 1 ] = toHalfFloat( y );
+
+		return this;
+
+	}
+
+	getZ( index ) {
+
+		let z = fromHalfFloat( this.array[ index * this.itemSize + 2 ] );
+
+		if ( this.normalized ) z = denormalize( z, this.array );
+
+		return z;
+
+	}
+
+	setZ( index, z ) {
+
+		if ( this.normalized ) z = normalize( z, this.array );
+
+		this.array[ index * this.itemSize + 2 ] = toHalfFloat( z );
+
+		return this;
+
+	}
+
+	getW( index ) {
+
+		let w = fromHalfFloat( this.array[ index * this.itemSize + 3 ] );
+
+		if ( this.normalized ) w = denormalize( w, this.array );
+
+		return w;
+
+	}
+
+	setW( index, w ) {
+
+		if ( this.normalized ) w = normalize( w, this.array );
+
+		this.array[ index * this.itemSize + 3 ] = toHalfFloat( w );
+
+		return this;
+
+	}
+
+	setXY( index, x, y ) {
+
+		index *= this.itemSize;
+
+		if ( this.normalized ) {
+
+			x = normalize( x, this.array );
+			y = normalize( y, this.array );
+
+		}
+
+		this.array[ index + 0 ] = toHalfFloat( x );
+		this.array[ index + 1 ] = toHalfFloat( y );
+
+		return this;
+
+	}
+
+	setXYZ( index, x, y, z ) {
+
+		index *= this.itemSize;
+
+		if ( this.normalized ) {
+
+			x = normalize( x, this.array );
+			y = normalize( y, this.array );
+			z = normalize( z, this.array );
+
+		}
+
+		this.array[ index + 0 ] = toHalfFloat( x );
+		this.array[ index + 1 ] = toHalfFloat( y );
+		this.array[ index + 2 ] = toHalfFloat( z );
+
+		return this;
+
+	}
+
+	setXYZW( index, x, y, z, w ) {
+
+		index *= this.itemSize;
+
+		if ( this.normalized ) {
+
+			x = normalize( x, this.array );
+			y = normalize( y, this.array );
+			z = normalize( z, this.array );
+			w = normalize( w, this.array );
+
+		}
+
+		this.array[ index + 0 ] = toHalfFloat( x );
+		this.array[ index + 1 ] = toHalfFloat( y );
+		this.array[ index + 2 ] = toHalfFloat( z );
+		this.array[ index + 3 ] = toHalfFloat( w );
+
+		return this;
+
+	}
+
 }
 
 

+ 67 - 0
test/unit/src/core/BufferAttribute.tests.js

@@ -16,6 +16,7 @@ import {
 } from '../../../../src/core/BufferAttribute.js';
 
 import { DynamicDrawUsage } from '../../../../src/constants.js';
+import { toHalfFloat, fromHalfFloat } from '../../../../src/extras/DataUtils.js';
 
 export default QUnit.module( 'Core', () => {
 
@@ -495,6 +496,72 @@ export default QUnit.module( 'Core', () => {
 
 		} );
 
+		const toHalfFloatArray = ( f32Array ) => {
+			const f16Array = new Uint16Array( f32Array.length );
+			for ( let i = 0, n = f32Array.length; i < n; ++i ) {
+				f16Array[ i ] = toHalfFloat( f32Array[ i ] );
+			}
+			return f16Array;
+		};
+
+		const fromHalfFloatArray = ( f16Array ) => {
+			const f32Array = new Float32Array( f16Array.length );
+			for ( let i = 0, n = f16Array.length; i < n; ++i ) {
+				f32Array[ i ] = fromHalfFloat( f16Array[ i ] );
+			}
+			return f32Array;
+		};
+
+		QUnit.test( 'set[X, Y, Z, W, XYZ, XYZW]/get[X, Y, Z, W]', ( assert ) => {
+
+			const f32a = new Float32Array( [ 1, 2, 3, 4, 5, 6, 7, 8 ] );
+			const a = new Float16BufferAttribute( toHalfFloatArray( f32a ), 4, false );
+			const expected = new Float32Array( [ 1, 2, - 3, - 4, - 5, - 6, 7, 8 ] );
+
+			a.setX( 1, a.getX( 1 ) * - 1 );
+			a.setY( 1, a.getY( 1 ) * - 1 );
+			a.setZ( 0, a.getZ( 0 ) * - 1 );
+			a.setW( 0, a.getW( 0 ) * - 1 );
+
+			assert.deepEqual( fromHalfFloatArray( a.array ), expected, 'Check all set* calls set the correct values' );
+
+		} );
+
+		QUnit.test( 'setXY', ( assert ) => {
+
+			const f32a = new Float32Array( [ 1, 2, 3, 4 ] );
+			const a = new Float16BufferAttribute( toHalfFloatArray( f32a ), 2, false );
+			const expected = new Float32Array( [ - 1, - 2, 3, 4 ] );
+
+			a.setXY( 0, - 1, - 2 );
+
+			assert.deepEqual( fromHalfFloatArray( a.array ), expected, 'Check for the correct values' );
+
+		} );
+
+		QUnit.test( 'setXYZ', ( assert ) => {
+
+			const f32a = new Float32Array( [ 1, 2, 3, 4, 5, 6 ] );
+			const a = new Float16BufferAttribute( toHalfFloatArray( f32a ), 3, false );
+			const expected = new Float32Array( [ 1, 2, 3, - 4, - 5, - 6 ] );
+
+			a.setXYZ( 1, - 4, - 5, - 6 );
+
+			assert.deepEqual( fromHalfFloatArray( a.array ), expected, 'Check for the correct values' );
+
+		} );
+
+		QUnit.test( 'setXYZW', ( assert ) => {
+
+			const f32a = new Float32Array( [ 1, 2, 3, 4 ] );
+			const a = new Float16BufferAttribute( toHalfFloatArray( f32a ), 4, false );
+			const expected = new Float32Array( [ - 1, - 2, - 3, - 4 ] );
+
+			a.setXYZW( 0, - 1, - 2, - 3, - 4 );
+
+			assert.deepEqual( fromHalfFloatArray( a.array ), expected, 'Check for the correct values' );
+
+		} );
 	} );
 
 	QUnit.module( 'Float32BufferAttribute', () => {

+ 49 - 0
test/unit/src/core/BufferGeometry.tests.js

@@ -4,6 +4,7 @@ import { BufferGeometry } from '../../../../src/core/BufferGeometry.js';
 
 import {
 	BufferAttribute,
+	Float16BufferAttribute,
 	Uint16BufferAttribute,
 	Uint32BufferAttribute
 } from '../../../../src/core/BufferAttribute.js';
@@ -13,6 +14,7 @@ import { Quaternion } from '../../../../src/math/Quaternion.js';
 import { Sphere } from '../../../../src/math/Sphere.js';
 import { x, y, z } from '../../utils/math-constants.js';
 import { EventDispatcher } from '../../../../src/core/EventDispatcher.js';
+import { toHalfFloat } from '../../../../src/extras/DataUtils.js';
 
 const DegToRad = Math.PI / 180;
 
@@ -459,6 +461,53 @@ export default QUnit.module( 'Core', () => {
 
 		} );
 
+		const toHalfFloatArray = ( f32Array ) => {
+			const f16Array = new Uint16Array( f32Array.length );
+			for ( let i = 0, n = f32Array.length; i < n; ++i ) {
+				f16Array[ i ] = toHalfFloat( f32Array[ i ] );
+			}
+			return f16Array;
+		};
+
+		QUnit.test( 'computeBoundingBox - Float16', ( assert ) => {
+			const vertices = [ - 1, - 2, - 3, 13, - 2, - 3.5, - 1, - 20, 0, - 4, 5, 6 ];
+			const geometry = new BufferGeometry();
+
+			geometry.setAttribute( 'position', new Float16BufferAttribute( toHalfFloatArray( vertices ), 3 ) );
+			geometry.computeBoundingBox();
+
+			let bb = geometry.boundingBox;
+
+			assert.ok( bb.min.x === - 4 && bb.min.y === - 20 && bb.min.z === - 3.5, 'min values are set correctly' );
+			assert.ok( bb.max.x === 13 && bb.max.y === 5 && bb.max.z === 6, 'max values are set correctly' );
+
+			bb = getBBForVertices( [ - 1, - 1, - 1 ] );
+
+			assert.ok( bb.min.x === bb.max.x && bb.min.y === bb.max.y && bb.min.z === bb.max.z, 'since there is only one vertex, max and min are equal' );
+			assert.ok( bb.min.x === - 1 && bb.min.y === - 1 && bb.min.z === - 1, 'since there is only one vertex, min and max are this vertex' );
+
+		} );
+
+		QUnit.test( 'computeBoundingSphere - Float16', ( assert ) => {
+			const vertices = [ - 10, 0, 0, 10, 0, 0 ];
+			const geometry = new BufferGeometry();
+
+			geometry.setAttribute( 'position', new Float16BufferAttribute( toHalfFloatArray( vertices ), 3 ) );
+			geometry.computeBoundingSphere();
+
+			let bs = geometry.boundingSphere;
+
+			assert.ok( bs.radius === 10, 'radius is equal to deltaMinMax / 2' );
+			assert.ok( bs.center.x === 0 && bs.center.y === 0 && bs.center.y === 0, 'bounding sphere is at ( 0, 0, 0 )' );
+
+			bs = getBSForVertices( [ - 5, 11, - 3, 5, - 11, 3 ] );
+			const radius = new Vector3( 5, 11, 3 ).length();
+
+			assert.ok( bs.radius === radius, 'radius is equal to directionLength' );
+			assert.ok( bs.center.x === 0 && bs.center.y === 0 && bs.center.y === 0, 'bounding sphere is at ( 0, 0, 0 )' );
+
+		} );
+
 		QUnit.todo( 'computeTangents', ( assert ) => {
 
 			assert.ok( false, 'everything\'s gonna be alright' );