Skip to content

Commit 8e16eaf

Browse files
cmhhelgesonsunag
andauthored
TSL: Add bitcast functions and transpiler support (#31781)
* add bitcast to wgsl/tsl encoders * alias GLSL functions * glsl aliasing, change outputType based on inputType * fix bracket spacing ah-gain * add js-doc --------- Co-authored-by: sunag <[email protected]>
1 parent f28712f commit 8e16eaf

File tree

3 files changed

+106
-10
lines changed

3 files changed

+106
-10
lines changed

examples/jsm/transpiler/WGSLEncoder.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@ const wgslLib = {
8080
'textureLod': 'textureSampleLevel',
8181
'texelFetch': 'textureLoad',
8282
'textureGrad': 'textureSampleGrad',
83+
'floatBitsToInt': 'bitcast<i32>',
84+
'floatBitsToUint': 'bitcast<u32>',
85+
'intBitsToFloat': 'bitcast<f32>',
86+
'uintBitsToFloat': 'bitcast<f32>',
8387
};
8488

8589
class WGSLEncoder {
@@ -170,6 +174,26 @@ class WGSLEncoder {
170174

171175
code = `${ modFnName }( ${ snippets.join( ', ' ) } )`;
172176

177+
} else if ( fnName.startsWith( 'bitcast' ) ) {
178+
179+
const params = node.params.map( p => this.emitExpression( p ) ).join( ',' );
180+
const types = node.params.map( p => p.getType() );
181+
182+
if ( /.*vec[234]/.test( types[ 0 ] ) ) {
183+
184+
const conversionType = fnName.substring( 8, fnName.length - 1 );
185+
const vectorType = types[ 0 ].substring( - 1 );
186+
187+
code = `bitcast<${ vectorType }<${ conversionType }>>`;
188+
189+
} else {
190+
191+
code = fnName;
192+
193+
}
194+
195+
code += `( ${ params } )`;
196+
173197
} else if ( fnName.startsWith( 'texture' ) ) {
174198

175199
// Handle texture functions separately due to sampler handling

src/Three.TSL.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,8 @@ export const faceDirection = TSL.faceDirection;
179179
export const faceForward = TSL.faceForward;
180180
export const faceforward = TSL.faceforward;
181181
export const float = TSL.float;
182+
export const floatBitsToInt = TSL.floatBitsToInt;
183+
export const floatBitsToUint = TSL.floatBitsToUint;
182184
export const floor = TSL.floor;
183185
export const fog = TSL.fog;
184186
export const fract = TSL.fract;
@@ -221,6 +223,7 @@ export const instancedBufferAttribute = TSL.instancedBufferAttribute;
221223
export const instancedDynamicBufferAttribute = TSL.instancedDynamicBufferAttribute;
222224
export const instancedMesh = TSL.instancedMesh;
223225
export const int = TSL.int;
226+
export const intBitsToFloat = TSL.intBitsToFloat;
224227
export const inverse = TSL.inverse;
225228
export const inverseSqrt = TSL.inverseSqrt;
226229
export const inversesqrt = TSL.inversesqrt;
@@ -562,6 +565,7 @@ export const triplanarTexture = TSL.triplanarTexture;
562565
export const triplanarTextures = TSL.triplanarTextures;
563566
export const trunc = TSL.trunc;
564567
export const uint = TSL.uint;
568+
export const uintBitsToFloat = TSL.uintBitsToFloat;
565569
export const uniform = TSL.uniform;
566570
export const uniformArray = TSL.uniformArray;
567571
export const uniformCubeTexture = TSL.uniformCubeTexture;

src/nodes/math/BitcastNode.js

Lines changed: 78 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,9 @@ class BitcastNode extends TempNode {
1919
*
2020
* @param {Node} valueNode - The value to convert.
2121
* @param {string} conversionType - The type to convert to.
22+
* @param {?string} [inputType = null] - The expected input data type of the bitcast operation.
2223
*/
23-
constructor( valueNode, conversionType ) {
24+
constructor( valueNode, conversionType, inputType = null ) {
2425

2526
super();
2627

@@ -35,10 +36,19 @@ class BitcastNode extends TempNode {
3536
* The type the value will be converted to.
3637
*
3738
* @type {string}
38-
* @default null
3939
*/
4040
this.conversionType = conversionType;
4141

42+
43+
/**
44+
* The expected input data type of the bitcast operation.
45+
*
46+
*
47+
* @type {string}
48+
* @default null
49+
*/
50+
this.inputType = inputType;
51+
4252
/**
4353
* This flag can be used for type testing.
4454
*
@@ -50,12 +60,17 @@ class BitcastNode extends TempNode {
5060

5161
}
5262

53-
/**
54-
* The node's type is defined by the conversion type.
55-
*
56-
* @return {string} The node type.
57-
*/
58-
getNodeType() {
63+
getNodeType( builder ) {
64+
65+
// GLSL aliasing
66+
if ( this.inputType !== null ) {
67+
68+
const valueType = this.valueNode.getNodeType( builder );
69+
const valueLength = builder.getTypeLength( valueType );
70+
71+
return builder.getTypeFromLength( valueLength, this.conversionType );
72+
73+
}
5974

6075
return this.conversionType;
6176

@@ -65,9 +80,22 @@ class BitcastNode extends TempNode {
6580
generate( builder ) {
6681

6782
const type = this.getNodeType( builder );
68-
const inputType = this.valueNode.getNodeType( builder );
83+
let inputType = '';
84+
85+
if ( this.inputType !== null ) {
86+
87+
const valueType = this.valueNode.getNodeType( builder );
88+
const valueTypeLength = builder.getTypeLength( valueType );
6989

70-
return `${builder.getBitcastMethod( type, inputType )}( ${ this.valueNode.build( builder, inputType ) } )`;
90+
inputType = valueTypeLength === 1 ? this.inputType : builder.changeComponentType( valueType, this.inputType );
91+
92+
} else {
93+
94+
inputType = this.valueNode.getNodeType( builder );
95+
96+
}
97+
98+
return `${ builder.getBitcastMethod( type, inputType ) }( ${ this.valueNode.build( builder, inputType ) } )`;
7199

72100

73101
}
@@ -86,3 +114,43 @@ export default BitcastNode;
86114
* @returns {Node}
87115
*/
88116
export const bitcast = /*@__PURE__*/ nodeProxyIntent( BitcastNode ).setParameterLength( 2 );
117+
118+
/**
119+
* Bitcasts a float or a vector of floats to a corresponding integer type with the same element size.
120+
*
121+
* @tsl
122+
* @function
123+
* @param {Node<float>} value - The float or vector of floats to bitcast.
124+
* @returns {BitcastNode}
125+
*/
126+
export const floatBitsToInt = ( value ) => new BitcastNode( value, 'int', 'float' );
127+
128+
/**
129+
* Bitcasts a float or a vector of floats to a corresponding unsigned integer type with the same element size.
130+
*
131+
* @tsl
132+
* @function
133+
* @param {Node<float>} value - The float or vector of floats to bitcast.
134+
* @returns {BitcastNode}
135+
*/
136+
export const floatBitsToUint = ( value ) => new BitcastNode( value, 'uint', 'float' );
137+
138+
/**
139+
* Bitcasts an integer or a vector of integers to a corresponding float type with the same element size.
140+
*
141+
* @tsl
142+
* @function
143+
* @param {Node<int>} value - The integer or vector of integers to bitcast.
144+
* @returns {BitcastNode}
145+
*/
146+
export const intBitsToFloat = ( value ) => new BitcastNode( value, 'float', 'int' );
147+
148+
/**
149+
* Bitcast an unsigned integer or a vector of unsigned integers to a corresponding float type with the same element size.
150+
*
151+
* @tsl
152+
* @function
153+
* @param {Node<uint>} value - The unsigned integer or vector of unsigned integers to bitcast.
154+
* @returns {BitcastNode}
155+
*/
156+
export const uintBitsToFloat = ( value ) => new BitcastNode( value, 'float', 'uint' );

0 commit comments

Comments
 (0)