Skip to content

Commit a03a74a

Browse files
authored
DataUtils: Add toRGB9E5() and fromRGB9E5(). (#28012)
* DataUtils: Add `toRGB9E5()` and `fromRGB9E5()`. * DataUtils: Fix defines.
1 parent fa5b009 commit a03a74a

File tree

2 files changed

+114
-0
lines changed

2 files changed

+114
-0
lines changed

docs/api/en/extras/DataUtils.html

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,25 @@ <h3>[method:Number fromHalfFloat]( [param:Number val] )</h3>
2929
precision floating point value.
3030
</p>
3131

32+
33+
<h3>[method:Uint32Array toRGB9E5]( [param:Number r], [param:Number g], [param:Number b], [param:Uint32Array target] )</h3>
34+
<p>
35+
r -- A float representing the R channel.<br />
36+
g -- A float representing the G channel.<br />
37+
b -- A float representing the B channel.<br />
38+
target -- An instance of `Uint32Array` with length `1`.<br /><br />
39+
40+
This method packs three floats into a single Uint32 value which is required for the `RGB9E5` texture format.
41+
</p>
42+
43+
<h3>[method:Array fromRGB9E5]( [param:Uint32Array val], [param:Array target] )</h3>
44+
<p>
45+
val -- An instance of `Uint32Array` with length `1`.<br />
46+
target -- An array holding the three unpacked floats.<br /><br />
47+
48+
This method unpacks three floats from a single Uint32 value holding a `RGB9E5` texel.
49+
</p>
50+
3251
<h2>Source</h2>
3352

3453
<p>

src/extras/DataUtils.js

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,13 +164,108 @@ function fromHalfFloat( val ) {
164164

165165
}
166166

167+
// RGB9E5 packing/unpacking
168+
169+
const RGB9E5_MANTISSA_BITS = 9;
170+
const RGB9E5_EXP_BIAS = 15;
171+
const RGB9E5_MAX_VALID_BIASED_EXP = 31;
172+
173+
const MAX_RGB9E5_EXP = ( RGB9E5_MAX_VALID_BIASED_EXP - RGB9E5_EXP_BIAS );
174+
const RGB9E5_MANTISSA_VALUES = ( 1 << RGB9E5_MANTISSA_BITS );
175+
const MAX_RGB9E5_MANTISSA = ( RGB9E5_MANTISSA_VALUES - 1 );
176+
const MAX_RGB9E5 = ( ( MAX_RGB9E5_MANTISSA ) / RGB9E5_MANTISSA_VALUES * ( 1 << MAX_RGB9E5_EXP ) );
177+
178+
function ClampRange_for_rgb9e5( x ) {
179+
180+
if ( x > 0.0 ) {
181+
182+
if ( x >= MAX_RGB9E5 ) {
183+
184+
return MAX_RGB9E5;
185+
186+
} else {
187+
188+
return x;
189+
190+
}
191+
192+
} else {
193+
194+
/* NaN gets here too since comparisons with NaN always fail! */
195+
return 0.0;
196+
197+
}
198+
199+
}
200+
201+
function FloorLog2( x ) {
202+
203+
return Math.floor( Math.log2( x ) );
204+
205+
}
206+
207+
// reference https://registry.khronos.org/OpenGL/extensions/EXT/EXT_texture_shared_exponent.txt
208+
209+
function toRGB9E5( r, g, b, target ) {
210+
211+
const rc = ClampRange_for_rgb9e5( r );
212+
const gc = ClampRange_for_rgb9e5( g );
213+
const bc = ClampRange_for_rgb9e5( b );
214+
215+
const maxrgb = Math.max( rc, gc, bc );
216+
let exp_shared = Math.max( - RGB9E5_EXP_BIAS - 1, FloorLog2( maxrgb ) ) + 1 + RGB9E5_EXP_BIAS;
217+
218+
let denom = Math.pow( 2, exp_shared - RGB9E5_EXP_BIAS - RGB9E5_MANTISSA_BITS );
219+
const maxm = Math.floor( maxrgb / denom + 0.5 );
220+
221+
if ( maxm == MAX_RGB9E5_MANTISSA + 1 ) {
222+
223+
denom *= 2;
224+
exp_shared += 1;
225+
226+
}
227+
228+
const rm = Math.floor( rc / denom + 0.5 );
229+
const gm = Math.floor( gc / denom + 0.5 );
230+
const bm = Math.floor( bc / denom + 0.5 );
231+
232+
//
233+
234+
target[ 0 ] = ( rm << 0 ) | ( gm << 9 ) | ( bm << 18 ) | ( exp_shared << 27 );
235+
236+
return target;
237+
238+
}
239+
240+
function fromRGB9E5( val, target ) {
241+
242+
const r = ( val[ 0 ] >> 0 ) & 0x1FF;
243+
const g = ( val[ 0 ] >> 9 ) & 0x1FF;
244+
const b = ( val[ 0 ] >> 18 ) & 0x1FF;
245+
const e = ( val[ 0 ] >> 27 ) & 0x01F;
246+
247+
const exponent = e - RGB9E5_EXP_BIAS - RGB9E5_MANTISSA_BITS;
248+
const scale = Math.pow( 2, exponent );
249+
250+
target[ 0 ] = r * scale;
251+
target[ 1 ] = g * scale;
252+
target[ 2 ] = b * scale;
253+
254+
return target;
255+
256+
}
257+
167258
const DataUtils = {
168259
toHalfFloat: toHalfFloat,
169260
fromHalfFloat: fromHalfFloat,
261+
toRGB9E5: toRGB9E5,
262+
fromRGB9E5: fromRGB9E5
170263
};
171264

172265
export {
173266
toHalfFloat,
174267
fromHalfFloat,
268+
toRGB9E5,
269+
fromRGB9E5,
175270
DataUtils
176271
};

0 commit comments

Comments
 (0)