Skip to content

Commit 8696fad

Browse files
authored
I3DMLoader: Add oct-encoding support for normal vectors (#1433)
1 parent fbf00df commit 8696fad

1 file changed

Lines changed: 59 additions & 14 deletions

File tree

src/three/renderer/loaders/I3DMLoader.js

Lines changed: 59 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,32 @@ const tempEnuFrame = /* @__PURE__ */ new Matrix4();
1717
const tempLocalQuat = /* @__PURE__ */ new Quaternion();
1818
const tempLatLon = {};
1919

20+
// Oct-encoding helper functions
21+
// Decode oct-encoded normal from unsigned [0, rangeMax] to normalized vector
22+
// Based on CesiumJS's AttributeCompression.octDecodeInRange
23+
function octDecodeInRange( x, y, rangeMax, result ) {
24+
25+
// Map from unsigned [0, rangeMax] to signed normalized [-1.0, 1.0]
26+
x = ( x / rangeMax ) * 2.0 - 1.0;
27+
y = ( y / rangeMax ) * 2.0 - 1.0;
28+
29+
result.x = x;
30+
result.y = y;
31+
result.z = 1.0 - Math.abs( x ) - Math.abs( y );
32+
33+
if ( result.z < 0.0 ) {
34+
35+
const oldX = result.x;
36+
result.x = ( 1.0 - Math.abs( result.y ) ) * ( oldX >= 0.0 ? 1.0 : - 1.0 );
37+
result.y = ( 1.0 - Math.abs( oldX ) ) * ( result.y >= 0.0 ? 1.0 : - 1.0 );
38+
39+
}
40+
41+
result.normalize();
42+
return result;
43+
44+
}
45+
2046
export class I3DMLoader extends I3DMLoaderBase {
2147

2248
constructor( manager = DefaultLoadingManager ) {
@@ -85,24 +111,13 @@ export class I3DMLoader extends I3DMLoaderBase {
85111
const QUANTIZED_VOLUME_SCALE = featureTable.getData( 'QUANTIZED_VOLUME_SCALE', 1, 'FLOAT', 'VEC3' );
86112
const NORMAL_UP = featureTable.getData( 'NORMAL_UP', INSTANCES_LENGTH, 'FLOAT', 'VEC3' );
87113
const NORMAL_RIGHT = featureTable.getData( 'NORMAL_RIGHT', INSTANCES_LENGTH, 'FLOAT', 'VEC3' );
114+
const NORMAL_UP_OCT32P = featureTable.getData( 'NORMAL_UP_OCT32P', INSTANCES_LENGTH, 'UNSIGNED_SHORT', 'VEC2' );
115+
const NORMAL_RIGHT_OCT32P = featureTable.getData( 'NORMAL_RIGHT_OCT32P', INSTANCES_LENGTH, 'UNSIGNED_SHORT', 'VEC2' );
88116
const SCALE_NON_UNIFORM = featureTable.getData( 'SCALE_NON_UNIFORM', INSTANCES_LENGTH, 'FLOAT', 'VEC3' );
89117
const SCALE = featureTable.getData( 'SCALE', INSTANCES_LENGTH, 'FLOAT', 'SCALAR' );
90118
const RTC_CENTER = featureTable.getData( 'RTC_CENTER', 1, 'FLOAT', 'VEC3' );
91119
const EAST_NORTH_UP = featureTable.getData( 'EAST_NORTH_UP' );
92120

93-
[
94-
'NORMAL_UP_OCT32P',
95-
'NORMAL_RIGHT_OCT32P',
96-
].forEach( feature => {
97-
98-
if ( feature in featureTable.header ) {
99-
100-
console.warn( `I3DMLoader: Unsupported FeatureTable feature "${ feature }" detected.` );
101-
102-
}
103-
104-
} );
105-
106121
// use quantized position if position is missing
107122
if ( ! POSITION && POSITION_QUANTIZED ) {
108123

@@ -173,7 +188,9 @@ export class I3DMLoader extends I3DMLoaderBase {
173188

174189
// account for EAST_NORTH_UP per-instance below
175190

176-
if ( NORMAL_UP ) {
191+
// Use NORMAL_UP and NORMAL_RIGHT if available (higher precision)
192+
// Otherwise fall back to oct-encoded normals
193+
if ( NORMAL_UP && NORMAL_RIGHT ) {
177194

178195
tempUp.set(
179196
NORMAL_UP[ i * 3 + 0 ],
@@ -198,6 +215,34 @@ export class I3DMLoader extends I3DMLoaderBase {
198215

199216
tempQuat.setFromRotationMatrix( tempMat );
200217

218+
} else if ( NORMAL_UP_OCT32P && NORMAL_RIGHT_OCT32P ) {
219+
220+
// Decode oct-encoded normals
221+
octDecodeInRange(
222+
NORMAL_UP_OCT32P[ i * 2 + 0 ],
223+
NORMAL_UP_OCT32P[ i * 2 + 1 ],
224+
65535,
225+
tempUp
226+
);
227+
228+
octDecodeInRange(
229+
NORMAL_RIGHT_OCT32P[ i * 2 + 0 ],
230+
NORMAL_RIGHT_OCT32P[ i * 2 + 1 ],
231+
65535,
232+
tempRight
233+
);
234+
235+
tempFwd.crossVectors( tempRight, tempUp )
236+
.normalize();
237+
238+
tempMat.makeBasis(
239+
tempRight,
240+
tempUp,
241+
tempFwd,
242+
);
243+
244+
tempQuat.setFromRotationMatrix( tempMat );
245+
201246
}
202247

203248
// scale

0 commit comments

Comments
 (0)