Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WebGPURenderer: Volumetric lighting #1544

Merged
merged 15 commits into from
Feb 23, 2025
101 changes: 99 additions & 2 deletions examples-testing/changes.patch
Original file line number Diff line number Diff line change
Expand Up @@ -16378,7 +16378,7 @@ index f20978b8..46c08191 100644
init();

diff --git a/examples-testing/examples/webgpu_postprocessing_ao.ts b/examples-testing/examples/webgpu_postprocessing_ao.ts
index 1957d7a9..d76a7142 100644
index 1957d7a9..b38fb89f 100644
--- a/examples-testing/examples/webgpu_postprocessing_ao.ts
+++ b/examples-testing/examples/webgpu_postprocessing_ao.ts
@@ -1,7 +1,7 @@
Expand Down Expand Up @@ -16410,7 +16410,7 @@ index 1957d7a9..d76a7142 100644
+ denoisePass: ShaderNodeObject<DenoiseNode>,
+ blendPassAO: ShaderNodeObject<THREE.Node>,
+ blendPassDenoise: ShaderNodeObject<THREE.Node>,
+ scenePassColor: ShaderNodeObject<THREE.Node>;
+ scenePassColor: ShaderNodeObject<THREE.TextureNode>;

const params = {
distanceExponent: 1,
Expand Down Expand Up @@ -17896,6 +17896,103 @@ index 679ce01a..50b5dadf 100644

// Material

diff --git a/examples-testing/examples/webgpu_volume_lighting.ts b/examples-testing/examples/webgpu_volume_lighting.ts
index feff77f6..ca2a596b 100644
--- a/examples-testing/examples/webgpu_volume_lighting.ts
+++ b/examples-testing/examples/webgpu_volume_lighting.ts
@@ -1,5 +1,5 @@
-import * as THREE from 'three';
-import { vec3, Fn, time, texture3D, screenUV, uniform, screenCoordinate, pass } from 'three/tsl';
+import * as THREE from 'three/webgpu';
+import { vec3, Fn, time, texture3D, screenUV, uniform, screenCoordinate, pass, ShaderNodeObject } from 'three/tsl';

import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { ImprovedNoise } from 'three/addons/math/ImprovedNoise.js';
@@ -12,10 +12,10 @@ import Stats from 'three/addons/libs/stats.module.js';

import { GUI } from 'three/addons/libs/lil-gui.module.min.js';

-let renderer, scene, camera;
-let volumetricMesh, teapot, pointLight, spotLight;
-let postProcessing;
-let stats;
+let renderer: THREE.WebGPURenderer, scene: THREE.Scene, camera: THREE.PerspectiveCamera;
+let volumetricMesh: THREE.Mesh, teapot: THREE.Mesh, pointLight: THREE.PointLight, spotLight: THREE.SpotLight;
+let postProcessing: THREE.PostProcessing;
+let stats: Stats;

init();

@@ -91,12 +91,12 @@ function init() {
const volumetricMaterial = new THREE.VolumeNodeMaterial();
volumetricMaterial.steps = 12;
volumetricMaterial.offsetNode = bayer16(screenCoordinate); // Add dithering to reduce banding
- volumetricMaterial.scatteringNode = Fn(({ positionRay }) => {
+ volumetricMaterial.scatteringNode = Fn(({ positionRay }: { positionRay: ShaderNodeObject<THREE.Node> }) => {
// Return the amount of fog based on the noise texture

const timeScaled = vec3(time, 0, time.mul(0.3));

- const sampleGrain = (scale, timeScale = 1) =>
+ const sampleGrain = (scale: number, timeScale = 1) =>
texture3D(noiseTexture3D, positionRay.add(timeScaled.mul(timeScale)).mul(scale).mod(1), 0).r.add(0.5);

let density = sampleGrain(0.1);
diff --git a/examples-testing/examples/webgpu_volume_lighting_rectarea.ts b/examples-testing/examples/webgpu_volume_lighting_rectarea.ts
index 23ec92a0..876c0299 100644
--- a/examples-testing/examples/webgpu_volume_lighting_rectarea.ts
+++ b/examples-testing/examples/webgpu_volume_lighting_rectarea.ts
@@ -1,5 +1,5 @@
-import * as THREE from 'three';
-import { vec3, Fn, time, texture3D, screenUV, uniform, screenCoordinate, pass } from 'three/tsl';
+import * as THREE from 'three/webgpu';
+import { vec3, Fn, time, texture3D, screenUV, uniform, screenCoordinate, pass, ShaderNodeObject } from 'three/tsl';

import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { ImprovedNoise } from 'three/addons/math/ImprovedNoise.js';
@@ -12,12 +12,12 @@ import Stats from 'three/addons/libs/stats.module.js';

import { GUI } from 'three/addons/libs/lil-gui.module.min.js';

-let renderer, scene, camera;
-let volumetricMesh, meshKnot;
-let rectLight1, rectLight2, rectLight3;
-let clock;
-let postProcessing;
-let stats;
+let renderer: THREE.WebGPURenderer, scene: THREE.Scene, camera: THREE.PerspectiveCamera;
+let volumetricMesh: THREE.Mesh, meshKnot: THREE.Mesh;
+let rectLight1: THREE.RectAreaLight, rectLight2: THREE.RectAreaLight, rectLight3: THREE.RectAreaLight;
+let clock: THREE.Clock;
+let postProcessing: THREE.PostProcessing;
+let stats: Stats;

init();

@@ -93,12 +93,12 @@ function init() {
const volumetricMaterial = new THREE.VolumeNodeMaterial();
volumetricMaterial.steps = 12;
volumetricMaterial.offsetNode = bayer16(screenCoordinate); // Add dithering to reduce banding
- volumetricMaterial.scatteringNode = Fn(({ positionRay }) => {
+ volumetricMaterial.scatteringNode = Fn(({ positionRay }: { positionRay: ShaderNodeObject<THREE.Node> }) => {
// Return the amount of fog based on the noise texture

const timeScaled = vec3(time, 0, time.mul(0.3));

- const sampleGrain = (scale, timeScale = 1) =>
+ const sampleGrain = (scale: number, timeScale = 1) =>
texture3D(noiseTexture3D, positionRay.add(timeScaled.mul(timeScale)).mul(scale).mod(1), 0).r.add(0.5);

let density = sampleGrain(0.1);
@@ -134,7 +134,7 @@ function init() {

//

- const createRectLightMesh = rectLight => {
+ const createRectLightMesh = (rectLight: THREE.RectAreaLight) => {
const geometry = new THREE.PlaneGeometry(4, 10);
const frontMaterial = new THREE.MeshBasicMaterial({ color: rectLight.color, side: THREE.BackSide });
const backMaterial = new THREE.MeshStandardMaterial({ color: 0x111111 });
diff --git a/examples-testing/examples/webgpu_water.ts b/examples-testing/examples/webgpu_water.ts
index 76e09f1f..edefce0e 100644
--- a/examples-testing/examples/webgpu_water.ts
Expand Down
12 changes: 7 additions & 5 deletions src-testing/changes.patch
Original file line number Diff line number Diff line change
Expand Up @@ -3139,7 +3139,7 @@ index 1fe2dbbd..a431897f 100644
+export const shaderStages: NodeShaderStage[] = [...defaultShaderStages, 'compute'];
export const vectorComponents = ['x', 'y', 'z', 'w'];
diff --git a/src-testing/src/nodes/lighting/LightingContextNode.ts b/src-testing/src/nodes/lighting/LightingContextNode.ts
index e5cac583..821c3c48 100644
index ee5cf92a..c58f0886 100644
--- a/src-testing/src/nodes/lighting/LightingContextNode.ts
+++ b/src-testing/src/nodes/lighting/LightingContextNode.ts
@@ -1,5 +1,23 @@
Expand Down Expand Up @@ -3186,20 +3186,22 @@ index e5cac583..821c3c48 100644
/**
* Constructs a new lighting context node.
*
@@ -21,7 +45,12 @@ class LightingContextNode extends ContextNode {
@@ -21,8 +45,13 @@ class LightingContextNode extends ContextNode {
* @param {?Node<vec3>} [backdropNode=null] - A backdrop node.
* @param {?Node<float>} [backdropAlphaNode=null] - A backdrop alpha node.
*/
- constructor(node, lightingModel = null, backdropNode = null, backdropAlphaNode = null) {
- constructor(lightsNode, lightingModel = null, backdropNode = null, backdropAlphaNode = null) {
- super(lightsNode);
+ constructor(
+ node: Node,
+ lightsNode: Node,
+ lightingModel: LightingModel | null = null,
+ backdropNode: Node | null = null,
+ backdropAlphaNode: Node | null = null,
+ ) {
super(node);
+ super(node);

/**
* The current lighting model.
@@ -79,7 +108,7 @@ class LightingContextNode extends ContextNode {
indirectSpecular,
};
Expand Down
2 changes: 1 addition & 1 deletion three.js
Submodule three.js updated 33 files
+2 −0 examples/files.json
+4 −4 examples/jsm/tsl/lighting/TiledLightsNode.js
+18 −0 examples/jsm/tsl/math/Bayer.js
+ examples/screenshots/webgpu_volume_lighting.jpg
+ examples/screenshots/webgpu_volume_lighting_rectarea.jpg
+307 −0 examples/webgpu_volume_lighting.html
+320 −0 examples/webgpu_volume_lighting_rectarea.html
+4 −0 src/Three.TSL.js
+2 −3 src/materials/nodes/MeshSSSNodeMaterial.js
+26 −11 src/materials/nodes/NodeMaterial.js
+17 −127 src/materials/nodes/VolumeNodeMaterial.js
+1 −0 src/nodes/TSL.js
+6 −13 src/nodes/accessors/Lights.js
+8 −0 src/nodes/accessors/ModelNode.js
+32 −0 src/nodes/accessors/Object3DNode.js
+17 −17 src/nodes/core/LightingModel.js
+56 −2 src/nodes/display/PassNode.js
+45 −1 src/nodes/functions/BSDF/LTC.js
+5 −8 src/nodes/functions/BasicLightingModel.js
+4 −6 src/nodes/functions/PhongLightingModel.js
+21 −23 src/nodes/functions/PhysicalLightingModel.js
+5 −6 src/nodes/functions/ToonLightingModel.js
+183 −0 src/nodes/functions/VolumetricLightingModel.js
+33 −0 src/nodes/lighting/AnalyticLightNode.js
+2 −11 src/nodes/lighting/DirectionalLightNode.js
+1 −3 src/nodes/lighting/LightUtils.js
+3 −3 src/nodes/lighting/LightingContextNode.js
+58 −14 src/nodes/lighting/LightsNode.js
+11 −26 src/nodes/lighting/PointLightNode.js
+3 −8 src/nodes/lighting/RectAreaLightNode.js
+5 −5 src/nodes/lighting/ShadowBaseNode.js
+15 −1 src/nodes/lighting/ShadowNode.js
+7 −18 src/nodes/lighting/SpotLightNode.js
4 changes: 4 additions & 0 deletions types/three/examples/jsm/tsl/math/Bayer.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { ShaderNodeObject } from "three/tsl";
import { Node } from "three/webgpu";

export const bayer16: (uv: Node) => ShaderNodeObject<Node>;
4 changes: 4 additions & 0 deletions types/three/src/Three.TSL.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@ export const modInt: typeof TSL.modInt;
export const modelDirection: typeof TSL.modelDirection;
export const modelNormalMatrix: typeof TSL.modelNormalMatrix;
export const modelPosition: typeof TSL.modelPosition;
export const modelRadius: typeof TSL.modelRadius;
export const modelScale: typeof TSL.modelScale;
export const modelViewMatrix: typeof TSL.modelViewMatrix;
export const modelViewPosition: typeof TSL.modelViewPosition;
Expand Down Expand Up @@ -336,6 +337,7 @@ export const numWorkgroups: typeof TSL.numWorkgroups;
export const objectDirection: typeof TSL.objectDirection;
export const objectGroup: typeof TSL.objectGroup;
export const objectPosition: typeof TSL.objectPosition;
export const objectRadius: typeof TSL.objectRadius;
export const objectScale: typeof TSL.objectScale;
export const objectViewPosition: typeof TSL.objectViewPosition;
export const objectWorldMatrix: typeof TSL.objectWorldMatrix;
Expand Down Expand Up @@ -380,6 +382,7 @@ export const range: typeof TSL.range;
export const rangeFog: typeof TSL.rangeFog;
export const rangeFogFactor: typeof TSL.rangeFogFactor;
export const reciprocal: typeof TSL.reciprocal;
export const lightProjectionUV: typeof TSL.lightProjectionUV;
export const reference: typeof TSL.reference;
export const referenceBuffer: typeof TSL.referenceBuffer;
export const reflect: typeof TSL.reflect;
Expand Down Expand Up @@ -416,6 +419,7 @@ export const select: typeof TSL.select;
export const setCurrentStack: typeof TSL.setCurrentStack;
export const shaderStages: typeof TSL.shaderStages;
export const shadow: typeof TSL.shadow;
export const pointShadow: typeof TSL.pointShadow;
export const shadowPositionWorld: typeof TSL.shadowPositionWorld;
export const sharedUniformGroup: typeof TSL.sharedUniformGroup;
export const shapeCircle: typeof TSL.shapeCircle;
Expand Down
3 changes: 2 additions & 1 deletion types/three/src/materials/nodes/NodeMaterial.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ declare class NodeMaterial extends Material {

depthNode: Node | null;
shadowPositionNode: Node | null;
receivedShadowNode: Node | null;
receivedShadowNode: () => Node | null;
castShadowNode: Node | null;

outputNode: Node | null;
Expand Down Expand Up @@ -89,6 +89,7 @@ declare class NodeMaterial extends Material {
setupOutgoingLight(): Node;
setupLightingModel(builder: NodeBuilder): LightingModel;
setupLighting(builder: NodeBuilder): Node;
setupFog(builder: NodeBuilder, outputNode: Node): Node;
setupOutput(builder: NodeBuilder, outputNode: Node): Node;

setDefaultValues(material: Material): void;
Expand Down
16 changes: 14 additions & 2 deletions types/three/src/materials/nodes/VolumeNodeMaterial.d.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,22 @@
import FunctionNode from "../../nodes/code/FunctionNode.js";
import Node from "../../nodes/core/Node.js";
import { ShaderNodeObject } from "../../nodes/tsl/TSLCore.js";
import NodeMaterial, { NodeMaterialParameters } from "./NodeMaterial.js";

export interface VolumeNodeMaterialParameters extends NodeMaterialParameters {
steps?: number | undefined;

scatteringNode?: Node | null | undefined;
}

export default class VolumeNodeMaterial extends NodeMaterial {
lights: boolean;
readonly isVolumeNodeMaterial: true;
testNode: Node | null;

steps: number;

scatteringNode: (params: { positionRay: ShaderNodeObject<Node> }) => Node | null;

offsetNode?: Node | undefined;

constructor(parameters?: NodeMaterialParameters);
}
3 changes: 1 addition & 2 deletions types/three/src/nodes/Nodes.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ export {
default as LightingModel,
LightingModelDirectInput,
LightingModelDirectRectAreaInput,
LightingModelIndirectInput,
LightingModelReflectedLight,
} from "./core/LightingModel.js";
export { default as MRTNode } from "./core/MRTNode.js";
Expand Down Expand Up @@ -134,7 +133,7 @@ export { default as EnvironmentNode } from "./lighting/EnvironmentNode.js";
export { default as HemisphereLightNode } from "./lighting/HemisphereLightNode.js";
export { default as IESSpotLightNode } from "./lighting/IESSpotLightNode.js";
export { default as IrradianceNode } from "./lighting/IrradianceNode.js";
export { default as LightingContextNode } from "./lighting/LightingContextNode.js";
export { default as LightingContextNode, LightingContext } from "./lighting/LightingContextNode.js";
export { default as LightingNode } from "./lighting/LightingNode.js";
export { default as LightProbeNode } from "./lighting/LightProbeNode.js";
export { default as LightsNode } from "./lighting/LightsNode.js";
Expand Down
1 change: 1 addition & 0 deletions types/three/src/nodes/TSL.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ export * from "./accessors/Lights.js";
export * from "./lighting/LightingContextNode.js";
export * from "./lighting/LightsNode.js";
export * from "./lighting/PointLightNode.js";
export * from "./lighting/PointShadowNode.js";
export * from "./lighting/ShadowBaseNode.js";
export * from "./lighting/ShadowNode.js";

Expand Down
2 changes: 1 addition & 1 deletion types/three/src/nodes/accessors/Lights.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { ShaderNodeObject } from "../tsl/TSLCore.js";

export function lightShadowMatrix(light: Light): ShaderNodeObject<Node>;

export function lightProjectionUV(light: Light): ShaderNodeObject<Node>;
export function lightProjectionUV(light: Light, position?: Node): ShaderNodeObject<Node>;

export function lightPosition(light: Light): ShaderNodeObject<Node>;

Expand Down
1 change: 1 addition & 0 deletions types/three/src/nodes/accessors/ModelNode.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export const modelWorldMatrix: ShaderNodeObject<ModelNode>;
export const modelPosition: ShaderNodeObject<ModelNode>;
export const modelScale: ShaderNodeObject<ModelNode>;
export const modelViewPosition: ShaderNodeObject<ModelNode>;
export const modelRadius: ShaderNodeObject<ModelNode>;
export const modelNormalMatrix: ShaderNodeObject<Node>;
export const modelWorldMatrixInverse: ShaderNodeObject<UniformNode<Matrix4>>;

Expand Down
12 changes: 7 additions & 5 deletions types/three/src/nodes/accessors/Object3DNode.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@ export default class Object3DNode extends Node {
static SCALE: "scale";
static VIEW_POSITION: "viewPosition";
static DIRECTION: "direction";
static RADIUS: "radius";
}

export const objectDirection: (object3d: Object3D) => ShaderNodeObject<Object3DNode>;
export const objectWorldMatrix: (object3d: Object3D) => ShaderNodeObject<Object3DNode>;
export const objectPosition: (object3d: Object3D) => ShaderNodeObject<Object3DNode>;
export const objectScale: (object3d: Object3D) => ShaderNodeObject<Object3DNode>;
export const objectViewPosition: (object3d: Object3D) => ShaderNodeObject<Object3DNode>;
export const objectDirection: (object3d?: Object3D | null) => ShaderNodeObject<Object3DNode>;
export const objectWorldMatrix: (object3d?: Object3D | null) => ShaderNodeObject<Object3DNode>;
export const objectPosition: (object3d?: Object3D | null) => ShaderNodeObject<Object3DNode>;
export const objectScale: (object3d?: Object3D | null) => ShaderNodeObject<Object3DNode>;
export const objectViewPosition: (object3d?: Object3D | null) => ShaderNodeObject<Object3DNode>;
export const objectRadius: (object3d?: Object3D | null) => ShaderNodeObject<Object3DNode>;
41 changes: 13 additions & 28 deletions types/three/src/nodes/core/LightingModel.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { DirectLightData, DirectRectAreaLightData } from "../lighting/LightsNode.js";
import Node from "./Node.js";
import NodeBuilder from "./NodeBuilder.js";
import StackNode from "./StackNode.js";

export interface LightingModelReflectedLight {
directDiffuse: Node;
Expand All @@ -9,38 +9,23 @@ export interface LightingModelReflectedLight {
indirectSpecular: Node;
}

export interface LightingModelDirectInput {
lightDirection: Node;
lightColor: Node;
export interface LightingModelDirectInput extends DirectLightData {
lightNode: Node;
reflectedLight: LightingModelReflectedLight;
}

export interface LightingModelDirectRectAreaInput {
lightColor: Node;
lightPosition: Node;
halfWidth: Node;
halfHeight: Node;
export interface LightingModelDirectRectAreaInput extends DirectRectAreaLightData {
lightNode: Node;
reflectedLight: LightingModelReflectedLight;
ltc_1: Node;
ltc_2: Node;
}

export interface LightingModelIndirectInput {
radiance: Node;
irradiance: Node;
iblIrradiance: Node;
ambientOcclusion: Node;
reflectedLight: LightingModelReflectedLight;
backdrop: Node;
backdropAlpha: Node;
outgoingLight: Node;
declare class LightingModel {
start(builder: NodeBuilder): void;
finish(builder: NodeBuilder): void;
direct(lightData: LightingModelDirectInput, builder: NodeBuilder): void;
directRectArea(lightData: LightingModelDirectRectAreaInput, builder: NodeBuilder): void;
indirect(builder: NodeBuilder): void;
ambientOcclusion(builder: NodeBuilder): void;
}

export default class LightingModel {
start(input: LightingModelIndirectInput, stack: StackNode, builder: NodeBuilder): void;
finish(input: LightingModelIndirectInput, stack: StackNode, builder: NodeBuilder): void;
direct(input: LightingModelDirectInput, stack: StackNode, builder: NodeBuilder): void;
directRectArea(input: LightingModelDirectRectAreaInput, stack: StackNode, builder: NodeBuilder): void;
indirect(input: LightingModelIndirectInput, stack: StackNode, builder: NodeBuilder): void;
ambientOcclusion(input: LightingModelIndirectInput, stack: StackNode, builder: NodeBuilder): void;
}
export default LightingModel;
11 changes: 10 additions & 1 deletion types/three/src/nodes/display/PassNode.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Camera } from "../../cameras/Camera.js";
import { Layers } from "../../core/Layers.js";
import { RenderTarget, RenderTargetOptions } from "../../core/RenderTarget.js";
import { Scene } from "../../scenes/Scene.js";
import { Texture } from "../../textures/Texture.js";
Expand Down Expand Up @@ -34,6 +35,14 @@ declare class PassNode extends TempNode {

constructor(scope: PassNodeScope, scene: Scene, camera: Camera, options?: RenderTargetOptions);

setResolution(resolution: number): this;

getResolution(): number;

setLayers(layers: Layers): this;

getLayers(): Layers;

setMRT(mrt: MRTNode | null): this;

getMRT(): MRTNode | null;
Expand All @@ -44,7 +53,7 @@ declare class PassNode extends TempNode {

toggleTexture(name: string): void;

getTextureNode(name?: string): ShaderNodeObject<Node>;
getTextureNode(name?: string): ShaderNodeObject<TextureNode>;

getPreviousTextureNode(name?: string): ShaderNodeObject<Node>;

Expand Down
6 changes: 5 additions & 1 deletion types/three/src/nodes/functions/BSDF/LTC.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,8 @@ declare const LTC_Evaluate: (
args: { N: Node; V: Node; P: Node; mInv: Node; p0: Node; p1: Node; p2: Node; p3: Node },
) => Node;

export { LTC_Evaluate, LTC_Uv };
declare const LTC_Evaluate_Volume: (
args: { P: Node; p0: Node; p1: Node; p2: Node; p3: Node },
) => Node;

export { LTC_Evaluate, LTC_Evaluate_Volume, LTC_Uv };
Loading
Loading