Skip to content

Commit d2875f6

Browse files
authoredNov 7, 2024··
WGSLNodeBuilder: Added support for .wrap* using biquadraticTexture (#29828)
* added support for `wrap*` using `biquadraticTexture` * using `getDataFromNode` for now * cleanup * cleanup
1 parent 5d71052 commit d2875f6

File tree

1 file changed

+101
-8
lines changed

1 file changed

+101
-8
lines changed
 

‎src/renderers/webgpu/nodes/WGSLNodeBuilder.js

+101-8
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,17 @@ import { getFormat } from '../utils/WebGPUTextureUtils.js';
1313
import WGSLNodeParser from './WGSLNodeParser.js';
1414
import { GPUBufferBindingType, GPUStorageTextureAccess } from '../utils/WebGPUConstants.js';
1515

16-
import { NoColorSpace, FloatType } from '../../../constants.js';
16+
import { NoColorSpace, FloatType, RepeatWrapping, ClampToEdgeWrapping, MirroredRepeatWrapping } from '../../../constants.js';
1717

1818
// GPUShaderStage is not defined in browsers not supporting WebGPU
1919
const GPUShaderStage = self.GPUShaderStage;
2020

21+
const wrapNames = {
22+
[ RepeatWrapping ]: 'repeat',
23+
[ ClampToEdgeWrapping ]: 'clamp',
24+
[ MirroredRepeatWrapping ]: 'mirror'
25+
};
26+
2127
const gpuShaderStageLib = {
2228
'vertex': GPUShaderStage ? GPUShaderStage.VERTEX : 1,
2329
'fragment': GPUShaderStage ? GPUShaderStage.FRAGMENT : 2,
@@ -61,6 +67,8 @@ const wgslTypeLib = {
6167
mat4: 'mat4x4<f32>'
6268
};
6369

70+
const wgslCodeCache = {};
71+
6472
const wgslPolyfill = {
6573
tsl_xor: new CodeNode( 'fn tsl_xor( a : bool, b : bool ) -> bool { return ( a || b ) && !( a && b ); }' ),
6674
mod_float: new CodeNode( 'fn tsl_mod_float( x : f32, y : f32 ) -> f32 { return x - y * floor( x / y ); }' ),
@@ -71,6 +79,9 @@ const wgslPolyfill = {
7179
equals_bvec2: new CodeNode( 'fn tsl_equals_bvec2( a : vec2f, b : vec2f ) -> vec2<bool> { return vec2<bool>( a.x == b.x, a.y == b.y ); }' ),
7280
equals_bvec3: new CodeNode( 'fn tsl_equals_bvec3( a : vec3f, b : vec3f ) -> vec3<bool> { return vec3<bool>( a.x == b.x, a.y == b.y, a.z == b.z ); }' ),
7381
equals_bvec4: new CodeNode( 'fn tsl_equals_bvec4( a : vec4f, b : vec4f ) -> vec4<bool> { return vec4<bool>( a.x == b.x, a.y == b.y, a.z == b.z, a.w == b.w ); }' ),
82+
repeatWrapping_float: new CodeNode( 'fn tsl_repeatWrapping_float( coord: f32 ) -> f32 { return fract( coord ); }' ),
83+
mirrorWrapping_float: new CodeNode( 'fn tsl_mirrorWrapping_float( coord: f32 ) -> f32 { let mirrored = fract( coord * 0.5 ) * 2.0; return 1.0 - abs( 1.0 - mirrored ); }' ),
84+
clampWrapping_float: new CodeNode( 'fn tsl_clampWrapping_float( coord: f32 ) -> f32 { return clamp( coord, 0.0, 1.0 ); }' ),
7485
repeatWrapping: new CodeNode( /* wgsl */`
7586
fn tsl_repeatWrapping( uv : vec2<f32>, dimension : vec2<u32> ) -> vec2<u32> {
7687
@@ -81,9 +92,8 @@ fn tsl_repeatWrapping( uv : vec2<f32>, dimension : vec2<u32> ) -> vec2<u32> {
8192
}
8293
` ),
8394
biquadraticTexture: new CodeNode( /* wgsl */`
84-
fn tsl_biquadraticTexture( map : texture_2d<f32>, coord : vec2f, level : i32 ) -> vec4f {
95+
fn tsl_biquadraticTexture( map : texture_2d<f32>, coord : vec2f, iRes : vec2u, level : i32 ) -> vec4f {
8596
86-
let iRes = vec2i( textureDimensions( map, level ) );
8797
let res = vec2f( iRes );
8898
8999
let uvScaled = coord * res;
@@ -95,10 +105,10 @@ fn tsl_biquadraticTexture( map : texture_2d<f32>, coord : vec2f, level : i32 ) -
95105
let iuv = floor( uv );
96106
let f = fract( uv );
97107
98-
let rg1 = textureLoad( map, vec2i( iuv + vec2( 0.5, 0.5 ) ) % iRes, level );
99-
let rg2 = textureLoad( map, vec2i( iuv + vec2( 1.5, 0.5 ) ) % iRes, level );
100-
let rg3 = textureLoad( map, vec2i( iuv + vec2( 0.5, 1.5 ) ) % iRes, level );
101-
let rg4 = textureLoad( map, vec2i( iuv + vec2( 1.5, 1.5 ) ) % iRes, level );
108+
let rg1 = textureLoad( map, vec2u( iuv + vec2( 0.5, 0.5 ) ) % iRes, level );
109+
let rg2 = textureLoad( map, vec2u( iuv + vec2( 1.5, 0.5 ) ) % iRes, level );
110+
let rg3 = textureLoad( map, vec2u( iuv + vec2( 0.5, 1.5 ) ) % iRes, level );
111+
let rg4 = textureLoad( map, vec2u( iuv + vec2( 1.5, 1.5 ) ) % iRes, level );
102112
103113
return mix( mix( rg1, rg2, f.x ), mix( rg3, rg4, f.x ), f.y );
104114
@@ -229,11 +239,94 @@ class WGSLNodeBuilder extends NodeBuilder {
229239

230240
}
231241

242+
generateWrapFunction( texture ) {
243+
244+
const functionName = `tsl_coord_${ wrapNames[ texture.wrapS ] }S_${ wrapNames[ texture.wrapT ] }T`;
245+
246+
let nodeCode = wgslCodeCache[ functionName ];
247+
248+
if ( nodeCode === undefined ) {
249+
250+
let code = `fn ${ functionName }( coord : vec2f ) -> vec2f {\n\n\treturn vec2f(\n`;
251+
252+
const addWrapSnippet = ( wrap, axis ) => {
253+
254+
if ( wrap === RepeatWrapping ) {
255+
256+
this._include( 'repeatWrapping_float' );
257+
258+
code += `\t\ttsl_repeatWrapping_float( coord.${ axis } )`;
259+
260+
} else if ( wrap === ClampToEdgeWrapping ) {
261+
262+
this._include( 'clampWrapping_float' );
263+
264+
code += `\t\ttsl_clampWrapping_float( coord.${ axis } )`;
265+
266+
} else if ( wrap === MirroredRepeatWrapping ) {
267+
268+
this._include( 'mirrorWrapping_float' );
269+
270+
code += `\t\ttsl_mirrorWrapping_float( coord.${ axis } )`;
271+
272+
} else {
273+
274+
code += `\t\tcoord.${ axis }`;
275+
276+
console.warn( `WebGPURenderer: Unsupported texture wrap type "${ wrap }" for vertex shader.` );
277+
278+
}
279+
280+
};
281+
282+
addWrapSnippet( texture.wrapS, 'x' );
283+
284+
code += ',\n';
285+
286+
addWrapSnippet( texture.wrapT, 'y' );
287+
288+
code += '\n\t);\n\n}\n';
289+
290+
wgslCodeCache[ functionName ] = nodeCode = new CodeNode( code );
291+
292+
}
293+
294+
nodeCode.build( this );
295+
296+
return functionName;
297+
298+
}
299+
300+
generateTextureDimension( texture, textureProperty, levelSnippet ) {
301+
302+
const textureData = this.getDataFromNode( texture, this.shaderStage, this.globalCache );
303+
304+
if ( textureData.dimensionsSnippet === undefined ) textureData.dimensionsSnippet = {};
305+
306+
let propertyName = textureData.dimensionsSnippet[ levelSnippet ];
307+
308+
if ( textureData.dimensionsSnippet[ levelSnippet ] === undefined ) {
309+
310+
propertyName = `textureDimension_${ texture.id }_${ levelSnippet }`;
311+
312+
this.addLineFlowCode( `let ${ propertyName } = textureDimensions( ${ textureProperty }, i32( ${ levelSnippet } ) );` );
313+
314+
textureData.dimensionsSnippet[ levelSnippet ] = propertyName;
315+
316+
}
317+
318+
return propertyName;
319+
320+
}
321+
232322
generateFilteredTexture( texture, textureProperty, uvSnippet, levelSnippet = '0' ) {
233323

234324
this._include( 'biquadraticTexture' );
235325

236-
return `tsl_biquadraticTexture( ${ textureProperty }, ${ uvSnippet }, i32( ${ levelSnippet } ) )`;
326+
const wrapFunction = this.generateWrapFunction( texture );
327+
const textureDimension = this.generateTextureDimension( texture, textureProperty, levelSnippet );
328+
329+
return `tsl_biquadraticTexture( ${ textureProperty }, ${ wrapFunction }( ${ uvSnippet } ), ${ textureDimension }, i32( ${ levelSnippet } ) )`;
237330

238331
}
239332

0 commit comments

Comments
 (0)
Please sign in to comment.