@@ -13,11 +13,17 @@ import { getFormat } from '../utils/WebGPUTextureUtils.js';
13
13
import WGSLNodeParser from './WGSLNodeParser.js' ;
14
14
import { GPUBufferBindingType , GPUStorageTextureAccess } from '../utils/WebGPUConstants.js' ;
15
15
16
- import { NoColorSpace , FloatType } from '../../../constants.js' ;
16
+ import { NoColorSpace , FloatType , RepeatWrapping , ClampToEdgeWrapping , MirroredRepeatWrapping } from '../../../constants.js' ;
17
17
18
18
// GPUShaderStage is not defined in browsers not supporting WebGPU
19
19
const GPUShaderStage = self . GPUShaderStage ;
20
20
21
+ const wrapNames = {
22
+ [ RepeatWrapping ] : 'repeat' ,
23
+ [ ClampToEdgeWrapping ] : 'clamp' ,
24
+ [ MirroredRepeatWrapping ] : 'mirror'
25
+ } ;
26
+
21
27
const gpuShaderStageLib = {
22
28
'vertex' : GPUShaderStage ? GPUShaderStage . VERTEX : 1 ,
23
29
'fragment' : GPUShaderStage ? GPUShaderStage . FRAGMENT : 2 ,
@@ -61,6 +67,8 @@ const wgslTypeLib = {
61
67
mat4 : 'mat4x4<f32>'
62
68
} ;
63
69
70
+ const wgslCodeCache = { } ;
71
+
64
72
const wgslPolyfill = {
65
73
tsl_xor : new CodeNode ( 'fn tsl_xor( a : bool, b : bool ) -> bool { return ( a || b ) && !( a && b ); }' ) ,
66
74
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 = {
71
79
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 ); }' ) ,
72
80
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 ); }' ) ,
73
81
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 ); }' ) ,
74
85
repeatWrapping : new CodeNode ( /* wgsl */ `
75
86
fn tsl_repeatWrapping( uv : vec2<f32>, dimension : vec2<u32> ) -> vec2<u32> {
76
87
@@ -81,9 +92,8 @@ fn tsl_repeatWrapping( uv : vec2<f32>, dimension : vec2<u32> ) -> vec2<u32> {
81
92
}
82
93
` ) ,
83
94
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 {
85
96
86
- let iRes = vec2i( textureDimensions( map, level ) );
87
97
let res = vec2f( iRes );
88
98
89
99
let uvScaled = coord * res;
@@ -95,10 +105,10 @@ fn tsl_biquadraticTexture( map : texture_2d<f32>, coord : vec2f, level : i32 ) -
95
105
let iuv = floor( uv );
96
106
let f = fract( uv );
97
107
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 );
102
112
103
113
return mix( mix( rg1, rg2, f.x ), mix( rg3, rg4, f.x ), f.y );
104
114
@@ -229,11 +239,94 @@ class WGSLNodeBuilder extends NodeBuilder {
229
239
230
240
}
231
241
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
+
232
322
generateFilteredTexture ( texture , textureProperty , uvSnippet , levelSnippet = '0' ) {
233
323
234
324
this . _include ( 'biquadraticTexture' ) ;
235
325
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 } ) )` ;
237
330
238
331
}
239
332
0 commit comments