Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 48 additions & 31 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/nodes/functions/BSDF/BRDF_Sheen.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const D_Charlie = /*@__PURE__*/ Fn( ( { roughness, dotNH } ) => {
const V_Neubelt = /*@__PURE__*/ Fn( ( { dotNV, dotNL } ) => {

// Neubelt and Pettineo 2013, "Crafting a Next-gen Material Pipeline for The Order: 1886"
return float( 1.0 ).div( float( 4.0 ).mul( dotNL.add( dotNV ).sub( dotNL.mul( dotNV ) ) ) );
return float( 1.0 ).div( float( 4.0 ).mul( dotNL.add( dotNV ).sub( dotNL.mul( dotNV ) ) ) ).clamp();

} ).setLayout( {
name: 'V_Neubelt',
Expand Down
36 changes: 31 additions & 5 deletions src/nodes/utils/LoopNode.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import { error } from '../../utils.js';
*
* } );
* ```
* The module also provides `Break()` and `Continue()` TSL expression for loop control.
* The module also provides `Break()` and `Continue()` TSL expressions for loop control.
* @augments Node
*/
class LoopNode extends Node {
Expand All @@ -50,7 +50,7 @@ class LoopNode extends Node {
/**
* Constructs a new loop node.
*
* @param {Array<any>} params - Depending on the loop type, array holds different parameterization values for the loop.
* @param {Array<LoopNode~Params|loopBodyCallback>} params - Any number of loop parameters followed by the loop body.
*/
constructor( params = [] ) {

Expand Down Expand Up @@ -340,13 +340,13 @@ export default LoopNode;
*
* @tsl
* @function
* @param {...any} params - A list of parameters.
* @param {...(LoopNode~Params|loopBodyCallback)} params - Any number of loop parameters followed by the loop body.
* @returns {LoopNode}
*/
export const Loop = ( ...params ) => new LoopNode( nodeArray( params, 'int' ) ).toStack();

/**
* TSL function for creating a `Continue()` expression.
* TSL function for inserting a `continue` expression into the shader.
*
* @tsl
* @function
Expand All @@ -355,10 +355,36 @@ export const Loop = ( ...params ) => new LoopNode( nodeArray( params, 'int' ) ).
export const Continue = () => expression( 'continue' ).toStack();

/**
* TSL function for creating a `Break()` expression.
* TSL function for inserting a `break` expression into the shader.
*
* @tsl
* @function
* @returns {ExpressionNode}
*/
export const Break = () => expression( 'break' ).toStack();

/**
* The parameters of a loop. A number or int/uint node defines the loop's end value,
* a bool node defines a `while` loop and an object allows a more detailed configuration.
*
* @typedef {number|Node<int>|Node<uint>|Node<bool>|LoopNode~ObjectParams} LoopNode~Params
*/

/**
* A detailed loop configuration.
*
* @typedef {Object} LoopNode~ObjectParams
* @property {number|Node<int>|Node<uint>} [start=0] - The initial value of the loop variable.
* @property {number|Node<int>|Node<uint>} [end] - The value the loop variable is compared against. If omitted, the loop counts down from `start - 1` to `0`.
* @property {string} [name] - The name of the loop variable. Defaults to `i`, `j`, `k` and so on.
* @property {string} [type='int'] - The data type of the loop variable.
* @property {('<'|'<='|'>'|'>=')} [condition] - The comparison operator. The loop runs as long as the comparison is true. Inferred from `start` and `end` if not set.
* @property {string|number|Function|Node} [update] - Defines how the loop variable is updated after each iteration. Inferred from `condition` and `type` if not set.
*/

/**
* The loop body.
*
* @callback loopBodyCallback
* @param {Object<string, Node>} inputs - The loop variables of the current `Loop()` call, keyed by their name.
*/
18 changes: 13 additions & 5 deletions src/renderers/webgl-fallback/nodes/GLSLNodeBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ import { DataTexture } from '../../../textures/DataTexture.js';
import { error } from '../../../utils.js';

const glslPolyfills = {
bitcast_int_uint: new CodeNode( /* glsl */'uint tsl_bitcast_int_to_uint ( int x ) { return floatBitsToUint( intBitsToFloat ( x ) ); }' ),
bitcast_uint_int: new CodeNode( /* glsl */'int tsl_bitcast_uint_to_int ( uint x ) { return floatBitsToInt( uintBitsToFloat ( x ) ); }' ),
textureGather: new CodeNode( /* glsl */`
vec4 tsl_textureGather( const int comp, sampler2D map, vec2 coord, ivec2 offset, bool flipY ) {
if ( flipY ) offset.y = - offset.y;
Expand Down Expand Up @@ -84,8 +82,6 @@ const glslMethods = {
bitcast_int_float: 'intBitsToFloat',
bitcast_uint_float: 'uintBitsToFloat',
bitcast_float_uint: 'floatBitsToUint',
bitcast_uint_int: 'tsl_bitcast_uint_to_int',
bitcast_int_uint: 'tsl_bitcast_int_to_uint',
floatpack_snorm_2x16: 'packSnorm2x16',
floatpack_unorm_2x16: 'packUnorm2x16',
floatpack_float16_2x16: 'packHalf2x16',
Expand Down Expand Up @@ -277,7 +273,19 @@ class GLSLNodeBuilder extends NodeBuilder {
*/
getBitcastMethod( type, inputType ) {

return this.getMethod( `bitcast_${ inputType }_${ type }` );
const inputComponentType = this.getComponentType( inputType );
const componentType = this.getComponentType( type );

// integer types support bitcast implicitly via the type constructor

if ( inputComponentType !== 'float' && componentType !== 'float' &&
this.getTypeLength( inputType ) === this.getTypeLength( type ) ) {

return this.getType( type );

}

return this.getMethod( `bitcast_${ inputComponentType }_${ componentType }` );

}

Expand Down
4 changes: 2 additions & 2 deletions src/renderers/webgl/WebGLAnimation.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ function WebGLAnimation() {

function onAnimationFrame( time, frame ) {

animationLoop( time, frame );

requestId = context.requestAnimationFrame( onAnimationFrame );

animationLoop( time, frame );

}

return {
Expand Down
22 changes: 21 additions & 1 deletion test/unit/addons/tsl/TSLBitOps.tests.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { float, int, uint, bitcast, countLeadingZeros, countOneBits, countTrailingZeros, inversesqrt } from 'three/tsl';
import { float, int, uint, ivec4, uvec4, bitcast, countLeadingZeros, countOneBits, countTrailingZeros, inversesqrt } from 'three/tsl';
import { gpuTest } from './gpu-test-utils.js';

// Coverage for the generic bitcast() constructor (src/nodes/math/BitcastNode.js
Expand Down Expand Up @@ -37,6 +37,26 @@ export default QUnit.module( 'TSL', () => {

} );

gpuTest( 'bitcast() reinterprets bits between ivec4 and uvec4', ( { assert } ) => {

// Each component's two's-complement bit pattern read as unsigned:
// -1 -> 0xFFFFFFFF, -2 -> 0xFFFFFFFE, positive values unchanged.
assert.eq(
bitcast( ivec4( - 1, 1, 2, - 2 ), 'uvec4' ),
uvec4( 4294967295, 1, 2, 4294967294 ),
'bitcast(ivec4, "uvec4") reinterprets each component'
);

// Round trip: bitcast is lossless reinterpretation, so converting
// out and back must recover the exact original vector.
assert.eq(
bitcast( bitcast( ivec4( - 1, 1, 2, - 2 ), 'uvec4' ), 'ivec4' ),
ivec4( - 1, 1, 2, - 2 ),
'bitcast round trip recovers the exact ivec4'
);

} );

} );

QUnit.module( 'bit counting', () => {
Expand Down