Bläddra i källkod

DataUtils: Add `toRGB9E5()` and `fromRGB9E5()`. (#28012)

* DataUtils: Add `toRGB9E5()` and `fromRGB9E5()`.

* DataUtils: Fix defines.
Michael Herzog 1 år sedan
förälder
incheckning
a03a74a1be
2 ändrade filer med 114 tillägg och 0 borttagningar
  1. 19 0
      docs/api/en/extras/DataUtils.html
  2. 95 0
      src/extras/DataUtils.js

+ 19 - 0
docs/api/en/extras/DataUtils.html

@@ -29,6 +29,25 @@
 			precision floating point value.
 			precision floating point value.
 		</p>
 		</p>
 
 
+
+		<h3>[method:Uint32Array toRGB9E5]( [param:Number r], [param:Number g], [param:Number b], [param:Uint32Array target] )</h3>
+		<p>
+			r -- A float representing the R channel.<br />
+			g -- A float representing the G channel.<br />
+			b -- A float representing the B channel.<br />
+			target -- An instance of `Uint32Array` with length `1`.<br /><br />
+
+			This method packs three floats into a single Uint32 value which is required for the `RGB9E5` texture format.
+		</p>
+
+		<h3>[method:Array fromRGB9E5]( [param:Uint32Array val], [param:Array target] )</h3>
+		<p>
+			val -- An instance of `Uint32Array` with length `1`.<br />
+			target -- An array holding the three unpacked floats.<br /><br />
+
+			This method unpacks three floats from a single Uint32 value holding a `RGB9E5` texel.
+		</p>
+
 		<h2>Source</h2>
 		<h2>Source</h2>
 
 
 		<p>
 		<p>

+ 95 - 0
src/extras/DataUtils.js

@@ -164,13 +164,108 @@ function fromHalfFloat( val ) {
 
 
 }
 }
 
 
+// RGB9E5 packing/unpacking
+
+const RGB9E5_MANTISSA_BITS = 9;
+const RGB9E5_EXP_BIAS = 15;
+const RGB9E5_MAX_VALID_BIASED_EXP = 31;
+
+const MAX_RGB9E5_EXP = ( RGB9E5_MAX_VALID_BIASED_EXP - RGB9E5_EXP_BIAS );
+const RGB9E5_MANTISSA_VALUES = ( 1 << RGB9E5_MANTISSA_BITS );
+const MAX_RGB9E5_MANTISSA = ( RGB9E5_MANTISSA_VALUES - 1 );
+const MAX_RGB9E5 = ( ( MAX_RGB9E5_MANTISSA ) / RGB9E5_MANTISSA_VALUES * ( 1 << MAX_RGB9E5_EXP ) );
+
+function ClampRange_for_rgb9e5( x ) {
+
+	if ( x > 0.0 ) {
+
+		if ( x >= MAX_RGB9E5 ) {
+
+			return MAX_RGB9E5;
+
+		} else {
+
+			return x;
+
+		}
+
+	} else {
+
+		/* NaN gets here too since comparisons with NaN always fail! */
+		return 0.0;
+
+	}
+
+}
+
+function FloorLog2( x ) {
+
+	return Math.floor( Math.log2( x ) );
+
+}
+
+// reference https://registry.khronos.org/OpenGL/extensions/EXT/EXT_texture_shared_exponent.txt
+
+function toRGB9E5( r, g, b, target ) {
+
+	const rc = ClampRange_for_rgb9e5( r );
+	const gc = ClampRange_for_rgb9e5( g );
+	const bc = ClampRange_for_rgb9e5( b );
+
+	const maxrgb = Math.max( rc, gc, bc );
+	let exp_shared = Math.max( - RGB9E5_EXP_BIAS - 1, FloorLog2( maxrgb ) ) + 1 + RGB9E5_EXP_BIAS;
+
+	let denom = Math.pow( 2, exp_shared - RGB9E5_EXP_BIAS - RGB9E5_MANTISSA_BITS );
+	const maxm = Math.floor( maxrgb / denom + 0.5 );
+
+	if ( maxm == MAX_RGB9E5_MANTISSA + 1 ) {
+
+		denom *= 2;
+		exp_shared += 1;
+
+	}
+
+	const rm = Math.floor( rc / denom + 0.5 );
+	const gm = Math.floor( gc / denom + 0.5 );
+	const bm = Math.floor( bc / denom + 0.5 );
+
+	//
+
+	target[ 0 ] = ( rm << 0 ) | ( gm << 9 ) | ( bm << 18 ) | ( exp_shared << 27 );
+
+	return target;
+
+}
+
+function fromRGB9E5( val, target ) {
+
+	const r = ( val[ 0 ] >> 0 ) & 0x1FF;
+	const g = ( val[ 0 ] >> 9 ) & 0x1FF;
+	const b = ( val[ 0 ] >> 18 ) & 0x1FF;
+	const e = ( val[ 0 ] >> 27 ) & 0x01F;
+
+	const exponent = e - RGB9E5_EXP_BIAS - RGB9E5_MANTISSA_BITS;
+	const scale = Math.pow( 2, exponent );
+
+	target[ 0 ] = r * scale;
+	target[ 1 ] = g * scale;
+	target[ 2 ] = b * scale;
+
+	return target;
+
+}
+
 const DataUtils = {
 const DataUtils = {
 	toHalfFloat: toHalfFloat,
 	toHalfFloat: toHalfFloat,
 	fromHalfFloat: fromHalfFloat,
 	fromHalfFloat: fromHalfFloat,
+	toRGB9E5: toRGB9E5,
+	fromRGB9E5: fromRGB9E5
 };
 };
 
 
 export {
 export {
 	toHalfFloat,
 	toHalfFloat,
 	fromHalfFloat,
 	fromHalfFloat,
+	toRGB9E5,
+	fromRGB9E5,
 	DataUtils
 	DataUtils
 };
 };