import * as THREE from 'three/webgpu'; import type { MeshPhysicalNodeMaterialParameters } from 'three/webgpu'; import type { GUIController, GUIFolder } from '../Utils/guiUtils.cjs'; import type { TSLFloatNode, TSLMat4Node, TSLNode, TSLVec2Node, TSLVec3Node, TSLVec4Node } from '../types/tsl.cjs'; /** How the refraction ray continues once it exits the volume (only matters with `backdropDistance > 0`). */ export type MeshTransmissionRefractionMode = 'volume' | 'slab'; /** Coordinate domain the stochastic dither is anchored to. */ export type MeshTransmissionDitherAnchor = 'world' | 'screen'; /** Sampled texel chain returned by a transmission viewport source (`sample(uv).level(lod)`). */ export interface MeshTransmissionViewportSampleNode extends TSLVec4Node { level(levelNode: TSLNode): TSLVec4Node; } /** Sampleable, mip-aware vec4 source used for viewport/backdrop transmission lookups. */ export interface MeshTransmissionViewportBufferNode extends TSLVec4Node { sample(uvNode: TSLVec2Node): MeshTransmissionViewportSampleNode; size(levelNode: TSLNode): TSLNode; } /** Constructor options for {@link MeshTransmissionNodeMaterial}. */ export interface MeshTransmissionNodeMaterialParameters extends MeshPhysicalNodeMaterialParameters { chromaticAberration?: number | undefined; anisotropicBlur?: number | undefined; time?: number | undefined; distortion?: number | undefined; surfaceDistortion?: number | undefined; distortionScale?: number | undefined; temporalDistortion?: number | undefined; ditherStrength?: number | undefined; ditherScale?: number | undefined; edgeFade?: number | undefined; blurScale?: number | undefined; backdropDistance?: number | undefined; samples?: number | undefined; refractionMode?: MeshTransmissionRefractionMode | undefined; ditherAnchor?: MeshTransmissionDitherAnchor | undefined; viewportBuffer?: MeshTransmissionViewportBufferNode | null | undefined; } /** Development setters exposed through `material.userData.set` (legacy shim — plain property assignment is now live). */ export interface MeshTransmissionUniformSetters { chromaticAberration(value: number): void; anisotropicBlur(value: number): void; time(value: number): void; distortion(value: number): void; surfaceDistortion(value: number): void; distortionScale(value: number): void; temporalDistortion(value: number): void; ditherStrength(value: number): void; ditherScale(value: number): void; edgeFade(value: number): void; blurScale(value: number): void; backdropDistance(value: number): void; } /** Material user-data contract containing the development uniform setters. */ export type MeshTransmissionUserData = THREE.MeshPhysicalNodeMaterial['userData'] & { set: MeshTransmissionUniformSetters; }; /** Numeric controller returned by a compatible transmission debug folder. */ export interface MeshTransmissionGUIController extends GUIController { name(label: string): this; } /** Folder surface shared by lil-gui, dat.gui, and the Three.js Inspector. */ export interface MeshTransmissionGUIFolder extends GUIFolder { add, TKey extends Extract>(state: TState, property: TKey, minimum: number, maximum: number, step: number): MeshTransmissionGUIController; close(): unknown; } /** GUI root capable of creating the transmission material's debug folder. */ export interface MeshTransmissionGUI { addFolder(name: string): MeshTransmissionGUIFolder; } /** Inputs for world-anchored biplanar stochastic sampling (vec4 of decorrelated IGN channels). */ export type MeshTransmissionBiplanarNoiseArguments = [ positionWorld: TSLVec3Node, normal: TSLVec3Node, scale: TSLFloatNode ]; /** Inputs for Beer–Lambert volume attenuation. */ export type MeshTransmissionAttenuationArguments = [ radiance: TSLVec3Node, transmissionDistance: TSLFloatNode, attenuationColor: TSLVec3Node, attenuationDistance: TSLFloatNode ]; /** Inputs for projecting a world-space position to viewport UV + clip depth (`vec4(uv, 0, clipW)`). */ export type MeshTransmissionScreenPointArguments = [ worldPosition: TSLVec3Node, viewMatrix: TSLMat4Node, projectionMatrix: TSLMat4Node ]; /** Inputs for remapping normalized UVs into the active camera viewport. */ export type MeshTransmissionViewportRemapArguments = [ uv: TSLVec2Node, viewport: TSLVec4Node, screen: TSLVec2Node ]; /** * @classdesc Physically based transmissive node material — a drop-in upgrade for the * built-in transmission of `MeshPhysicalMaterial`, rendering the same class of glass at * higher visual quality for less GPU work. It replaces the stock refraction shader with * its own while keeping the official semantics: `transmission`/`transmissionMap`, * `thickness`/`thicknessMap`, `ior`, `dispersion`, `attenuationColor`/`attenuationDistance`, * and base `color` all behave exactly as they do on the standard material, Fresnel splits * the transmitted and reflected energy the same way, and the mesh draws in the same * transparent-bucket order. No extra scene passes are added — like the built-in * transmission it refracts a viewport snapshot, shared by every instance of this material. * * Where it goes beyond the built-in transmission: * * - Physically scaled roughness blur. The official shader blurs a fixed amount per * roughness value regardless of the scene; here the blur footprint is the refracted * ray's spread projected to actual pixels, so it grows with thickness, with proximity * to the camera, and with `backdropDistance` — thick glass near the lens frosts more * than a thin sliver in the distance, as it should. * - Half the texture fetches for equal smoothness: a single-level 4-tap bicubic with a * noise-dithered LOD fraction replaces the official two-level 8-tap filter (12 vs 24 * fetches with dispersion active). Measured roughly 20% faster frames at dispersion * parity, and parity on plain glass while doing strictly more. * - Chromatic control without recompiles: the physical `dispersion` property is honored * (same Abbe-style `(ior − 1)` scaling as three core) and the artistic * `chromaticAberration` adds drei-style fringing on top; both fold into a uniform * branch, so the extra refraction rays cost nothing while the controls sit at 0. * - Screen-edge-safe refraction: offsets fade out near the viewport border instead of * smearing clamped edge pixels, and UV remapping is per-viewport (ArrayCamera/XR * correct, which the official refraction is not). * - Looks the built-in cannot produce: world-anchored stochastic grain that sticks to * the surface (reads as frosted material, not screen noise), directional * `anisotropicBlur` along the refraction flow, animated `distortion`, `'slab'` exit * refraction with `backdropDistance` for true window parallax, and a stochastic * `samples` gather for hero-quality frost. * * Requires the WebGPU renderer entry points `three/webgpu` and TSL (`three/tsl`). * * An extension of {@link MeshPhysicalNodeMaterial}: * * - Uses the node-material pipeline so you can override nodes like `iorNode`, `roughnessNode`, etc. * - All controls are live properties — `material.chromaticAberration = 0.8` works at any time. * - Pass a custom `viewportBuffer` to refract something other than the scene snapshot. * * ```js * import { MeshTransmissionNodeMaterial } from 'three-blocks/transmission'; * import * as THREE from 'three/webgpu'; * * // Create transmission material * const mat = new MeshTransmissionNodeMaterial({ * color: new THREE.Color('#ffffff'), * roughness: 0.2, * thickness: 0.5, * ior: 1.5, * chromaticAberration: 0.4, * anisotropicBlur: 0.1, * distortion: 0.0, * attenuationDistance: 0.5, * attenuationColor: new THREE.Color('#ffffff') * }); * * const geometry = new THREE.TorusKnotGeometry(1, 0.4, 128, 32); * const mesh = new THREE.Mesh(geometry, mat); * scene.add(mesh); * ``` * * @extends THREE.MeshPhysicalNodeMaterial * @short Drop-in upgrade for MeshPhysicalMaterial transmission — physically scaled blur, Abbe dispersion, and frosted-glass effects, smoother and faster than the built-in refraction. * @demo docs/demos/mesh-transmission.html * @tags WebGPU, WebGL * @category Materials */ export declare class MeshTransmissionNodeMaterial extends THREE.MeshPhysicalNodeMaterial { static get type(): string; /** * Constructs a new transmission node material. * Use `setValues(parameters)` to override properties; see property docs below. * * @param {MeshTransmissionNodeMaterialParameters} [parameters={}] Optional material parameters. * @param {number} [parameters.transmission=1] Mix between diffuse shading (0) and transmitted backdrop (1); multiplied by `transmissionMap`. * @param {number} [parameters.chromaticAberration=0.4] Artistic per-channel dispersion strength (Abbe-scaled by `ior − 1`). * @param {number} [parameters.anisotropicBlur=0] Directional smear along the refraction flow (0 disables the extra taps). * @param {number} [parameters.time=0] Offset added to the built-in clock driving temporal distortion. * @param {number} [parameters.distortion=0] Distortion amount applied to the refraction normal via noise; scales amplitude, 0 disables. * @param {number} [parameters.surfaceDistortion=0] Distortion amplitude applied to the shading normal, so the ripple shows in reflections too. * @param {number} [parameters.distortionScale=0] Distortion noise frequency, in gradient-noise cells per object-space unit. * @param {number} [parameters.temporalDistortion=0] Strength of time-based distortion animation. * @param {number} [parameters.ditherStrength=0.5] Blue-noise jitter strength for sampling stability. * @param {number} [parameters.ditherScale=128] Blue-noise tiling frequency for the world anchor (higher values tile smaller). * @param {number} [parameters.edgeFade=0.1] Viewport-border width over which refraction offsets fade to straight-through. * @param {number} [parameters.blurScale=1] Artistic multiplier on the physically scaled blur footprint. * @param {number} [parameters.backdropDistance=0] Assumed distance from the exit surface to the refracted scene, in world units. * @param {number} [parameters.samples=1] Stochastic gather taps per channel (structural; >1 switches to a golden-angle cone gather). * @param {'volume'|'slab'} [parameters.refractionMode='volume'] Post-exit ray model used with `backdropDistance` ('slab' re-refracts at the exit interface). * @param {'world'|'screen'} [parameters.ditherAnchor='world'] Dither domain: 'world' sticks the grain to the surface, 'screen' is cheapest. * @param {THREE.Color|string|number} [parameters.color=0xffffff] Base albedo color (tints the transmitted light, like official three). * @param {MeshTransmissionViewportBufferNode|null} [parameters.viewportBuffer=null] Optional sampleable TSL viewport node; defaults to a mip snapshot shared by all instances. */ readonly isMeshTransmissionNodeMaterial: true; chromaticAberration: number; anisotropicBlur: number; time: number; distortion: number; surfaceDistortion: number; distortionScale: number; temporalDistortion: number; ditherStrength: number; ditherScale: number; edgeFade: number; blurScale: number; backdropDistance: number; _debug: MeshTransmissionGUIFolder | null | undefined; private _samples; private _refractionMode; private _ditherAnchor; private _viewportBuffer; private _backdropBuilt; constructor(parameters?: MeshTransmissionNodeMaterialParameters); /** * Keeps the official physical transmission out of the compiled lighting model — * `transmission > 0` is still honored by the renderer for transparent-bucket * ordering, but the refraction itself is this material's backdrop graph. */ get useTransmission(): boolean; /** * Perturbs the shading normal with the distortion noise, so the ripple shows in * reflections as well as through the glass. Composes with `normalNode` and normal * maps rather than replacing them. * @override */ setupNormal(): TSLVec3Node; /** * Stochastic gather taps per channel. `1` (default) uses a dithered single-level * bicubic; higher values switch to a golden-angle cone gather one octave sharper. * Structural: changing it rebuilds the shader. * @type {number} * @default 1 */ get samples(): number; set samples(value: number); /** * Post-exit ray model used with `backdropDistance`: 'volume' keeps the bent ray * (official-compatible), 'slab' re-refracts at the exit interface — physically * correct parallel offset for flat panes. Structural: changing it rebuilds the shader. * @type {'volume'|'slab'} * @default 'volume' */ get refractionMode(): MeshTransmissionRefractionMode; set refractionMode(value: MeshTransmissionRefractionMode); /** * Dither domain: 'world' anchors the grain to the surface (reads as material, * signature look), 'screen' uses a single Hilbert walk on pixel coordinates * (cheapest). Structural: changing it rebuilds the shader. * @type {'world'|'screen'} * @default 'world' */ get ditherAnchor(): MeshTransmissionDitherAnchor; set ditherAnchor(value: MeshTransmissionDitherAnchor); /** * Sampleable TSL texture node used for the scene/backdrop. Defaults to a viewport * mip snapshot shared by every instance; assign a custom node to refract something * else (an FBO, a video texture, …). Structural: changing it rebuilds the shader. * @type {MeshTransmissionViewportBufferNode|null} */ get viewportBuffer(): MeshTransmissionViewportBufferNode | null; set viewportBuffer(value: MeshTransmissionViewportBufferNode | null); /** * Rebuilds the backdrop refraction graph from the current structural options and * flags the material for recompilation. Called automatically by the structural setters. * @returns {void} */ private _rebuildBackdrop; copy(source: THREE.Material): this; /** * Attaches a debug UI for tuning transmission parameters. * Compatible with lil-gui, dat.gui, and Three.js Inspector. * @param {MeshTransmissionGUI|null} gui - A lil-gui instance or folder. * @returns {void} */ attachGUI(gui: MeshTransmissionGUI | null | undefined): void; /** * Destroys and clears the debug folder if attached. * @returns {this} */ disposeGUI(): this; /** * Disposes material resources and detaches the debug UI. * @override */ dispose(): void; } export interface MeshTransmissionNodeMaterial { backdropNode: TSLVec3Node; backdropAlphaNode: TSLFloatNode; userData: MeshTransmissionUserData; }