# WGSL Integration TSL allows embedding raw WGSL (WebGPU Shading Language) code when you need direct GPU control. ## wgslFn - Custom WGSL Functions ### Basic Usage ```javascript import { wgslFn, float, vec3 } from 'three/tsl'; // Define WGSL function const gammaCorrect = wgslFn(` fn gammaCorrect(color: vec3, gamma: f32) -> vec3 { return pow(color, vec3(1.0 / gamma)); } `); // Use in TSL material.colorNode = gammaCorrect(inputColor, float(2.2)); ``` ### Function with Multiple Parameters ```javascript const blendColors = wgslFn(` fn blendColors(a: vec3, b: vec3, t: f32) -> vec3 { return mix(a, b, t); } `); material.colorNode = blendColors(colorA, colorB, blendFactor); ``` ### Advanced Math Functions ```javascript const fresnelSchlick = wgslFn(` fn fresnelSchlick(cosTheta: f32, F0: vec3) -> vec3 { return F0 + (vec3(1.0) - F0) * pow(1.0 - cosTheta, 5.0); } `); const GGX = wgslFn(` fn distributionGGX(N: vec3, H: vec3, roughness: f32) -> f32 { let a = roughness * roughness; let a2 = a * a; let NdotH = max(dot(N, H), 0.0); let NdotH2 = NdotH * NdotH; let num = a2; let denom = (NdotH2 * (a2 - 1.0) + 1.0); denom = 3.14159265359 * denom * denom; return num / denom; } `); ``` ### Noise Functions ```javascript const simplexNoise = wgslFn(` fn mod289(x: vec3) -> vec3 { return x - floor(x * (1.0 / 289.0)) * 289.0; } fn permute(x: vec3) -> vec3 { return mod289(((x * 34.0) + 1.0) * x); } fn snoise(v: vec2) -> f32 { let C = vec4( 0.211324865405187, 0.366025403784439, -0.577350269189626, 0.024390243902439 ); var i = floor(v + dot(v, C.yy)); let x0 = v - i + dot(i, C.xx); var i1: vec2; if (x0.x > x0.y) { i1 = vec2(1.0, 0.0); } else { i1 = vec2(0.0, 1.0); } var x12 = x0.xyxy + C.xxzz; x12 = vec4(x12.xy - i1, x12.zw); i = mod289(vec3(i, 0.0)).xy; let p = permute(permute(i.y + vec3(0.0, i1.y, 1.0)) + i.x + vec3(0.0, i1.x, 1.0)); var m = max(vec3(0.5) - vec3(dot(x0, x0), dot(x12.xy, x12.xy), dot(x12.zw, x12.zw)), vec3(0.0)); m = m * m; m = m * m; let x = 2.0 * fract(p * C.www) - 1.0; let h = abs(x) - 0.5; let ox = floor(x + 0.5); let a0 = x - ox; m = m * (1.79284291400159 - 0.85373472095314 * (a0 * a0 + h * h)); let g = vec3( a0.x * x0.x + h.x * x0.y, a0.y * x12.x + h.y * x12.y, a0.z * x12.z + h.z * x12.w ); return 130.0 * dot(m, g); } `); // Use noise const noiseValue = simplexNoise(uv().mul(10.0)); ``` ### FBM (Fractal Brownian Motion) ```javascript const fbm = wgslFn(` fn fbm(p: vec2, octaves: i32) -> f32 { var value = 0.0; var amplitude = 0.5; var frequency = 1.0; var pos = p; for (var i = 0; i < octaves; i = i + 1) { value = value + amplitude * snoise(pos * frequency); amplitude = amplitude * 0.5; frequency = frequency * 2.0; } return value; } `); ``` ## WGSL Types Reference ### Scalar Types ```wgsl bool // Boolean i32 // 32-bit signed integer u32 // 32-bit unsigned integer f32 // 32-bit float f16 // 16-bit float (if enabled) ``` ### Vector Types ```wgsl vec2 // 2D float vector vec3 // 3D float vector vec4 // 4D float vector vec2 // 2D integer vector vec2 // 2D unsigned integer vector ``` ### Matrix Types ```wgsl mat2x2 // 2x2 matrix mat3x3 // 3x3 matrix mat4x4 // 4x4 matrix mat2x3 // 2 columns, 3 rows ``` ### Texture Types ```wgsl texture_2d texture_3d texture_cube texture_storage_2d ``` ## WGSL Syntax Reference ### Variables ```wgsl let x = 1.0; // Immutable var y = 2.0; // Mutable const PI = 3.14159; // Compile-time constant ``` ### Control Flow ```wgsl // If-else if (condition) { // ... } else if (other) { // ... } else { // ... } // For loop for (var i = 0; i < 10; i = i + 1) { // ... } // While loop while (condition) { // ... } // Switch switch (value) { case 0: { /* ... */ } case 1, 2: { /* ... */ } default: { /* ... */ } } ``` ### Built-in Functions ```wgsl // Math abs(x), sign(x), floor(x), ceil(x), round(x) fract(x), trunc(x) min(a, b), max(a, b), clamp(x, lo, hi) mix(a, b, t), step(edge, x), smoothstep(lo, hi, x) sin(x), cos(x), tan(x), asin(x), acos(x), atan(x), atan2(y, x) pow(x, y), exp(x), log(x), exp2(x), log2(x) sqrt(x), inverseSqrt(x) // Vector length(v), distance(a, b) dot(a, b), cross(a, b) normalize(v), faceForward(n, i, nref) reflect(i, n), refract(i, n, eta) // Matrix transpose(m), determinant(m) // Texture textureSample(t, s, coord) textureLoad(t, coord, level) textureStore(t, coord, value) textureDimensions(t) ``` ## Combining TSL and WGSL ### TSL Wrapper for WGSL ```javascript import { Fn, wgslFn, float, vec2, vec3 } from 'three/tsl'; // WGSL implementation const wgslNoise = wgslFn(` fn noise2d(p: vec2) -> f32 { return fract(sin(dot(p, vec2(12.9898, 78.233))) * 43758.5453); } `); // TSL wrapper with nice API const noise = Fn(([position, scale = 1.0]) => { return wgslNoise(position.xy.mul(scale)); }); // Use material.colorNode = vec3(noise(positionWorld, 10.0)); ``` ### Hybrid Approach ```javascript // Complex math in WGSL const complexMath = wgslFn(` fn complexOperation(a: vec3, b: vec3, t: f32) -> vec3 { let blended = mix(a, b, t); let rotated = vec3( blended.x * cos(t) - blended.y * sin(t), blended.x * sin(t) + blended.y * cos(t), blended.z ); return normalize(rotated); } `); // Simple logic in TSL const finalColor = Fn(() => { const base = texture(diffuseMap).rgb; const processed = complexMath(base, vec3(1, 0, 0), time); return mix(base, processed, oscSine(time)); }); material.colorNode = finalColor(); ``` ## Performance Tips ### Avoid Branching When Possible ```wgsl // Instead of: if (x > 0.5) { result = a; } else { result = b; } // Use: result = mix(b, a, step(0.5, x)); ``` ### Use Local Variables ```wgsl fn compute(p: vec2) -> f32 { // Cache repeated calculations let p2 = p * p; let p4 = p2 * p2; return p2.x + p2.y + p4.x * p4.y; } ``` ### Minimize Texture Samples ```wgsl // Sample once, use multiple times let sample = textureSample(tex, sampler, uv); let r = sample.r; let g = sample.g; let b = sample.b; ```