Skip to content

Commit e1eca27

Browse files
authored
TSL: Introduce float packing / unpacking intrinsics (#32329)
1 parent a3b6c77 commit e1eca27

File tree

6 files changed

+264
-2
lines changed

6 files changed

+264
-2
lines changed

src/Three.TSL.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,9 @@ export const output = TSL.output;
417417
export const outputStruct = TSL.outputStruct;
418418
export const overlay = TSL.overlay;
419419
export const overloadingFn = TSL.overloadingFn;
420+
export const packHalf2x16 = TSL.packHalf2x16;
421+
export const packSnorm2x16 = TSL.packSnorm2x16;
422+
export const packUnorm2x16 = TSL.packUnorm2x16;
420423
export const parabola = TSL.parabola;
421424
export const parallaxDirection = TSL.parallaxDirection;
422425
export const parallaxUV = TSL.parallaxUV;
@@ -583,6 +586,9 @@ export const uniformCubeTexture = TSL.uniformCubeTexture;
583586
export const uniformGroup = TSL.uniformGroup;
584587
export const uniformFlow = TSL.uniformFlow;
585588
export const uniformTexture = TSL.uniformTexture;
589+
export const unpackHalf2x16 = TSL.unpackHalf2x16;
590+
export const unpackSnorm2x16 = TSL.unpackSnorm2x16;
591+
export const unpackUnorm2x16 = TSL.unpackUnorm2x16;
586592
export const unpremultiplyAlpha = TSL.unpremultiplyAlpha;
587593
export const userData = TSL.userData;
588594
export const uv = TSL.uv;

src/nodes/TSL.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ export * from './math/BitcastNode.js';
2323
export * from './math/BitcountNode.js';
2424
export * from './math/Hash.js';
2525
export * from './math/MathUtils.js';
26+
export * from './math/PackFloatNode.js';
27+
export * from './math/UnpackFloatNode.js';
2628
export * from './math/TriNoise3D.js';
2729

2830
// utils

src/nodes/math/PackFloatNode.js

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
import TempNode from '../core/TempNode.js';
2+
import { nodeProxyIntent } from '../tsl/TSLCore.js';
3+
4+
/**
5+
* This node represents an operation that packs floating-point values of a vector into an unsigned 32-bit integer
6+
*
7+
* @augments TempNode
8+
*/
9+
class PackFloatNode extends TempNode {
10+
11+
static get type() {
12+
13+
return 'PackFloatNode';
14+
15+
}
16+
17+
/**
18+
*
19+
* @param {'snorm' | 'unorm' | 'float16'} encoding - The numeric encoding that describes how the float values are mapped to the integer range.
20+
* @param {Node} vectorNode - The vector node to be packed
21+
*/
22+
constructor( encoding, vectorNode ) {
23+
24+
super();
25+
26+
/**
27+
* The vector to be packed.
28+
*
29+
* @type {Node}
30+
*/
31+
this.vectorNode = vectorNode;
32+
33+
/**
34+
* The numeric encoding.
35+
*
36+
* @type {string}
37+
*/
38+
this.encoding = encoding;
39+
40+
/**
41+
* This flag can be used for type testing.
42+
*
43+
* @type {boolean}
44+
* @readonly
45+
* @default true
46+
*/
47+
this.isPackFloatNode = true;
48+
49+
}
50+
51+
getNodeType() {
52+
53+
return 'uint';
54+
55+
}
56+
57+
generate( builder ) {
58+
59+
const inputType = this.vectorNode.getNodeType( builder );
60+
return `${ builder.getFloatPackingMethod( this.encoding ) }(${ this.vectorNode.build( builder, inputType )})`;
61+
62+
}
63+
64+
}
65+
66+
export default PackFloatNode;
67+
68+
/**
69+
* Converts each component of the normalized float to 16-bit integer values. The results are packed into a single unsigned integer.
70+
* round(clamp(c, -1, +1) * 32767.0)
71+
*
72+
* @tsl
73+
* @function
74+
* @param {Node<vec2>} value - The 2-component vector to be packed
75+
* @returns {Node}
76+
*/
77+
export const packSnorm2x16 = /*@__PURE__*/ nodeProxyIntent( PackFloatNode, 'snorm' ).setParameterLength( 1 );
78+
79+
/**
80+
* Converts each component of the normalized float to 16-bit integer values. The results are packed into a single unsigned integer.
81+
* round(clamp(c, 0, +1) * 65535.0)
82+
*
83+
* @tsl
84+
* @function
85+
* @param {Node<vec2>} value - The 2-component vector to be packed
86+
* @returns {Node}
87+
*/
88+
export const packUnorm2x16 = /*@__PURE__*/ nodeProxyIntent( PackFloatNode, 'unorm' ).setParameterLength( 1 );
89+
90+
/**
91+
* Converts each component of the vec2 to 16-bit floating-point values. The results are packed into a single unsigned integer.
92+
*
93+
* @tsl
94+
* @function
95+
* @param {Node<vec2>} value - The 2-component vector to be packed
96+
* @returns {Node}
97+
*/
98+
export const packHalf2x16 = /*@__PURE__*/ nodeProxyIntent( PackFloatNode, 'float16' ).setParameterLength( 1 );

src/nodes/math/UnpackFloatNode.js

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import TempNode from '../core/TempNode.js';
2+
import { nodeProxyIntent } from '../tsl/TSLCore.js';
3+
4+
/**
5+
* This node represents an operation that unpacks values from a 32-bit unsigned integer, reinterpreting the results as a floating-point vector
6+
*
7+
* @augments TempNode
8+
*/
9+
class UnpackFloatNode extends TempNode {
10+
11+
static get type() {
12+
13+
return 'UnpackFloatNode';
14+
15+
}
16+
17+
/**
18+
*
19+
* @param {'snorm' | 'unorm' | 'float16'} encoding - The numeric encoding that describes how the integer values are mapped to the float range
20+
* @param {Node} uintNode - The uint node to be unpacked
21+
*/
22+
constructor( encoding, uintNode ) {
23+
24+
super();
25+
26+
/**
27+
* The unsigned integer to be unpacked.
28+
*
29+
* @type {Node}
30+
*/
31+
this.uintNode = uintNode;
32+
33+
/**
34+
* The numeric encoding.
35+
*
36+
* @type {string}
37+
*/
38+
this.encoding = encoding;
39+
40+
/**
41+
* This flag can be used for type testing.
42+
*
43+
* @type {boolean}
44+
* @readonly
45+
* @default true
46+
*/
47+
this.isUnpackFloatNode = true;
48+
49+
}
50+
51+
getNodeType() {
52+
53+
return 'vec2';
54+
55+
}
56+
57+
generate( builder ) {
58+
59+
const inputType = this.uintNode.getNodeType( builder );
60+
return `${ builder.getFloatUnpackingMethod( this.encoding ) }(${ this.uintNode.build( builder, inputType )})`;
61+
62+
}
63+
64+
}
65+
66+
export default UnpackFloatNode;
67+
68+
/**
69+
* Unpacks a 32-bit unsigned integer into two 16-bit values, interpreted as normalized signed integers. Returns a vec2 with both values.
70+
*
71+
* @tsl
72+
* @function
73+
* @param {Node<uint>} value - The unsigned integer to be unpacked
74+
* @returns {Node}
75+
*/
76+
export const unpackSnorm2x16 = /*@__PURE__*/ nodeProxyIntent( UnpackFloatNode, 'snorm' ).setParameterLength( 1 );
77+
78+
/**
79+
* Unpacks a 32-bit unsigned integer into two 16-bit values, interpreted as normalized unsigned integers. Returns a vec2 with both values.
80+
*
81+
* @tsl
82+
* @function
83+
* @param {Node<uint>} value - The unsigned integer to be unpacked
84+
* @returns {Node}
85+
*/
86+
export const unpackUnorm2x16 = /*@__PURE__*/ nodeProxyIntent( UnpackFloatNode, 'unorm' ).setParameterLength( 1 );
87+
88+
/**
89+
* Unpacks a 32-bit unsigned integer into two 16-bit values, interpreted as 16-bit floating-point numbers. Returns a vec2 with both values.
90+
*
91+
* @tsl
92+
* @function
93+
* @param {Node<uint>} value - The unsigned integer to be unpacked
94+
* @returns {Node}
95+
*/
96+
export const unpackHalf2x16 = /*@__PURE__*/ nodeProxyIntent( UnpackFloatNode, 'float16' ).setParameterLength( 1 );

src/renderers/webgl-fallback/nodes/GLSLNodeBuilder.js

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,13 @@ const glslMethods = {
2222
bitcast_uint_float: 'uintBitsToFloat',
2323
bitcast_float_uint: 'floatBitsToUint',
2424
bitcast_uint_int: 'tsl_bitcast_uint_to_int',
25-
bitcast_int_uint: 'tsl_bitcast_int_to_uint'
25+
bitcast_int_uint: 'tsl_bitcast_int_to_uint',
26+
floatpack_snorm_2x16: 'packSnorm2x16',
27+
floatpack_unorm_2x16: 'packUnorm2x16',
28+
floatpack_float16_2x16: 'packHalf2x16',
29+
floatunpack_snorm_2x16: 'unpackSnorm2x16',
30+
floatunpack_unorm_2x16: 'unpackUnorm2x16',
31+
floatunpack_float16_2x16: 'unpackHalf2x16'
2632
};
2733

2834
const precisionLib = {
@@ -184,6 +190,30 @@ class GLSLNodeBuilder extends NodeBuilder {
184190

185191
}
186192

193+
/**
194+
* Returns the float packing method name for a given numeric encoding.
195+
*
196+
* @param {string} encoding - The numeric encoding that describes how the float values are mapped to the integer range.
197+
* @returns {string} The resolved GLSL float packing method name.
198+
*/
199+
getFloatPackingMethod( encoding ) {
200+
201+
return this.getMethod( `floatpack_${ encoding }_2x16` );
202+
203+
}
204+
205+
/**
206+
* Returns the float unpacking method name for a given numeric encoding.
207+
*
208+
* @param {string} encoding - The numeric encoding that describes how the integer values are mapped to the float range.
209+
* @returns {string} The resolved GLSL float unpacking method name.
210+
*/
211+
getFloatUnpackingMethod( encoding ) {
212+
213+
return this.getMethod( `floatunpack_${ encoding }_2x16` );
214+
215+
}
216+
187217
/**
188218
* Returns the native snippet for a ternary operation.
189219
*

src/renderers/webgpu/nodes/WGSLNodeBuilder.js

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,13 @@ const wgslMethods = {
128128
equals_bvec3: 'tsl_equals_bvec3',
129129
equals_bvec4: 'tsl_equals_bvec4',
130130
inversesqrt: 'inverseSqrt',
131-
bitcast: 'bitcast<f32>'
131+
bitcast: 'bitcast<f32>',
132+
floatpack_snorm_2x16: 'pack2x16snorm',
133+
floatpack_unorm_2x16: 'pack2x16unorm',
134+
floatpack_float16_2x16: 'pack2x16float',
135+
floatunpack_snorm_2x16: 'unpack2x16snorm',
136+
floatunpack_unorm_2x16: 'unpack2x16unorm',
137+
floatunpack_float16_2x16: 'unpack2x16float'
132138
};
133139

134140
//
@@ -1990,6 +1996,30 @@ ${ flowData.code }
19901996

19911997
}
19921998

1999+
/**
2000+
* Returns the float packing method name for a given numeric encoding.
2001+
*
2002+
* @param {string} encoding - The numeric encoding that describes how the float values are mapped to the integer range.
2003+
* @returns {string} The resolve WGSL float packing method name.
2004+
*/
2005+
getFloatPackingMethod( encoding ) {
2006+
2007+
return this.getMethod( `floatpack_${ encoding }_2x16` );
2008+
2009+
}
2010+
2011+
/**
2012+
* Returns the float unpacking method name for a given numeric encoding.
2013+
*
2014+
* @param {string} encoding - The numeric encoding that describes how the integer values are mapped to the float range.
2015+
* @returns {string} The resolve WGSL float unpacking method name.
2016+
*/
2017+
getFloatUnpackingMethod( encoding ) {
2018+
2019+
return this.getMethod( `floatunpack_${ encoding }_2x16` );
2020+
2021+
}
2022+
19932023
/**
19942024
* Returns the native snippet for a ternary operation.
19952025
*

0 commit comments

Comments
 (0)