2
0
Эх сурвалжийг харах

WebGPURenderer: Support to AmbientLight, DirectionalLight, SpotLight (#25150)

* ShaderNode: object*( object3d )

* WebGPUNodeBuilder: Fix compiled color type

* Nodes: Rename PunctualLightNode to PointLightNode

* WebGPU: Support to AmbientLight, DirectionLight, SpotLight
sunag 2 жил өмнө
parent
commit
b07dab2889

+ 12 - 3
examples/jsm/nodes/Nodes.js

@@ -72,7 +72,10 @@ import OperatorNode from './math/OperatorNode.js';
 import CondNode from './math/CondNode.js';
 
 // lighting
-import PunctualLightNode from './lighting/PunctualLightNode.js';
+import PointLightNode from './lighting/PointLightNode.js';
+import DirectionalLightNode from './lighting/DirectionalLightNode.js';
+import SpotLightNode from './lighting/SpotLightNode.js';
+import AmbientLightNode from './lighting/AmbientLightNode.js';
 import LightsNode from './lighting/LightsNode.js';
 import LightingNode from './lighting/LightingNode.js';
 import LightingContextNode from './lighting/LightingContextNode.js';
@@ -204,7 +207,10 @@ const nodeLib = {
 	CondNode,
 
 	// lighting
-	PunctualLightNode,
+	PointLightNode,
+	DirectionalLightNode,
+	SpotLightNode,
+	AmbientLightNode,
 	LightsNode,
 	LightingNode,
 	LightingContextNode,
@@ -329,7 +335,10 @@ export {
 	CondNode,
 
 	// lighting
-	PunctualLightNode,
+	PointLightNode,
+	DirectionalLightNode,
+	SpotLightNode,
+	AmbientLightNode,
 	LightsNode,
 	LightingNode,
 	LightingContextNode,

+ 16 - 0
examples/jsm/nodes/functions/light/getDirectionVector.js

@@ -0,0 +1,16 @@
+import { Vector3 } from 'three';
+
+let vector3;
+
+const getDirectionVector = ( light, camera, directionVector ) => {
+
+	vector3 ||= new Vector3();
+
+	directionVector.setFromMatrixPosition( light.matrixWorld );
+	vector3.setFromMatrixPosition( light.target.matrixWorld );
+	directionVector.sub( vector3 );
+	directionVector.transformDirection( camera.matrixWorldInverse );
+
+}
+
+export default getDirectionVector;

+ 24 - 0
examples/jsm/nodes/lighting/AmbientLightNode.js

@@ -0,0 +1,24 @@
+import AnalyticLightNode from './AnalyticLightNode.js';
+import LightsNode from './LightsNode.js';
+
+import { AmbientLight } from 'three';
+
+class AmbientLightNode extends AnalyticLightNode {
+
+	constructor( light = null ) {
+
+		super( light );
+
+	}
+
+	construct( { context } ) {
+
+		context.irradiance.add( this.colorNode );
+
+	}
+
+}
+
+LightsNode.setReference( AmbientLight, AmbientLightNode );
+
+export default AmbientLightNode;

+ 50 - 0
examples/jsm/nodes/lighting/DirectionalLightNode.js

@@ -0,0 +1,50 @@
+import AnalyticLightNode from './AnalyticLightNode.js';
+import LightsNode from './LightsNode.js';
+import getDirectionVector from '../functions/light/getDirectionVector.js';
+import { uniform } from '../shadernode/ShaderNodeElements.js';
+
+import { Vector3, DirectionalLight } from 'three';
+
+class DirectionalLightNode extends AnalyticLightNode {
+
+	constructor( light = null ) {
+
+		super( light );
+
+		this.directionNode = uniform( new Vector3() );
+
+	}
+
+	update( frame ) {
+
+		getDirectionVector( this.light, frame.camera, this.directionNode.value );
+
+		super.update( frame );
+
+	}
+
+	construct( builder ) {
+
+		const lightDirection = this.directionNode.normalize();
+		const lightColor = this.colorNode;
+
+		const lightingModelFunctionNode = builder.context.lightingModelNode;
+		const reflectedLight = builder.context.reflectedLight;
+
+		if ( lightingModelFunctionNode?.direct ) {
+
+			lightingModelFunctionNode.direct.call( {
+				lightDirection,
+				lightColor,
+				reflectedLight
+			}, builder );
+
+		}
+
+	}
+
+}
+
+LightsNode.setReference( DirectionalLight, DirectionalLightNode );
+
+export default DirectionalLightNode;

+ 9 - 11
examples/jsm/nodes/lighting/PunctualLightNode.js → examples/jsm/nodes/lighting/PointLightNode.js

@@ -1,12 +1,11 @@
 import AnalyticLightNode from './AnalyticLightNode.js';
 import LightsNode from './LightsNode.js';
-import Object3DNode from '../accessors/Object3DNode.js';
 import getDistanceAttenuation from '../functions/light/getDistanceAttenuation.js';
-import { uniform, mul, normalize, length, sub, positionView } from '../shadernode/ShaderNodeElements.js';
+import { uniform, positionView, objectViewPosition } from '../shadernode/ShaderNodeElements.js';
 
 import { PointLight } from 'three';
 
-class PunctualLightNode extends AnalyticLightNode {
+class PointLightNode extends AnalyticLightNode {
 
 	constructor( light = null ) {
 
@@ -30,13 +29,12 @@ class PunctualLightNode extends AnalyticLightNode {
 
 	construct( builder ) {
 
-		const { colorNode, cutoffDistanceNode, decayExponentNode } = this;
+		const { colorNode, cutoffDistanceNode, decayExponentNode, light } = this;
 
-		const lightPositionViewNode = new Object3DNode( Object3DNode.VIEW_POSITION, this.light );
-		const lVector = sub( lightPositionViewNode, positionView );
+		const lVector = objectViewPosition( light ).sub( positionView );
 
-		const lightDirection = normalize( lVector );
-		const lightDistance = length( lVector );
+		const lightDirection = lVector.normalize();
+		const lightDistance = lVector.length();
 
 		const lightAttenuation = getDistanceAttenuation.call( {
 			lightDistance,
@@ -44,7 +42,7 @@ class PunctualLightNode extends AnalyticLightNode {
 			decayExponent: decayExponentNode
 		} );
 
-		const lightColor = mul( colorNode, lightAttenuation );
+		const lightColor = colorNode.mul( lightAttenuation );
 
 		const lightingModelFunctionNode = builder.context.lightingModelNode;
 		const reflectedLight = builder.context.reflectedLight;
@@ -63,6 +61,6 @@ class PunctualLightNode extends AnalyticLightNode {
 
 }
 
-LightsNode.setReference( PointLight, PunctualLightNode );
+LightsNode.setReference( PointLight, PointLightNode );
 
-export default PunctualLightNode;
+export default PointLightNode;

+ 84 - 0
examples/jsm/nodes/lighting/SpotLightNode.js

@@ -0,0 +1,84 @@
+import AnalyticLightNode from './AnalyticLightNode.js';
+import LightsNode from './LightsNode.js';
+import getDistanceAttenuation from '../functions/light/getDistanceAttenuation.js';
+import getDirectionVector from '../functions/light/getDirectionVector.js';
+import { uniform, smoothstep, positionView, objectViewPosition } from '../shadernode/ShaderNodeElements.js';
+
+import { Vector3, SpotLight } from 'three';
+
+const getSpotAttenuation = ( coneCosine, penumbraCosine, angleCosine ) => smoothstep( coneCosine, penumbraCosine, angleCosine );
+
+class SpotLightNode extends AnalyticLightNode {
+
+	constructor( light = null ) {
+
+		super( light );
+
+		this.directionNode = uniform( new Vector3() );
+
+		this.coneCosNode = uniform( 0 );
+		this.penumbraCosNode = uniform( 0 );
+
+		this.cutoffDistanceNode = uniform( 0 );
+		this.decayExponentNode = uniform( 0 );
+
+	}
+
+	update( frame ) {
+
+		super.update( frame );
+
+		const { light } = this;
+
+		getDirectionVector( light, frame.camera, this.directionNode.value );
+
+		this.coneCosNode.value = Math.cos( light.angle );
+		this.penumbraCosNode.value = Math.cos( light.angle * ( 1 - light.penumbra ) );
+
+		this.cutoffDistanceNode.value = light.distance;
+		this.decayExponentNode.value = light.decay;
+
+	}
+
+	construct( builder ) {
+
+		const { colorNode, cutoffDistanceNode, decayExponentNode, light } = this;
+
+		const lVector = objectViewPosition( light ).sub( positionView );
+
+		const lightDirection = lVector.normalize();
+		const angleCos = lightDirection.dot( this.directionNode )
+		const spotAttenuation = getSpotAttenuation( this.coneCosNode, this.penumbraCosNode, angleCos );
+
+		const lightDistance = lVector.length();
+
+		const lightAttenuation = getDistanceAttenuation.call( {
+			lightDistance,
+			cutoffDistance: cutoffDistanceNode,
+			decayExponent: decayExponentNode
+		} );
+
+		const finalColor = colorNode.mul( spotAttenuation ).mul( lightAttenuation );
+
+		const lightColor = spotAttenuation.greaterThan( 0 ).cond( finalColor, 0 );
+
+		const lightingModelFunctionNode = builder.context.lightingModelNode;
+		const reflectedLight = builder.context.reflectedLight;
+
+		if ( lightingModelFunctionNode?.direct ) {
+
+			lightingModelFunctionNode.direct.call( {
+				lightDirection,
+				lightColor,
+				reflectedLight
+			}, builder );
+
+		}
+
+	}
+
+}
+
+LightsNode.setReference( SpotLight, SpotLightNode );
+
+export default SpotLightNode;

+ 7 - 0
examples/jsm/nodes/shadernode/ShaderNodeBaseElements.js

@@ -23,6 +23,7 @@ import MaterialReferenceNode from '../accessors/MaterialReferenceNode.js';
 import ModelViewProjectionNode from '../accessors/ModelViewProjectionNode.js';
 import NormalNode from '../accessors/NormalNode.js';
 import ModelNode from '../accessors/ModelNode.js';
+import Object3DNode from '../accessors/Object3DNode.js';
 import PointUVNode from '../accessors/PointUVNode.js';
 import PositionNode from '../accessors/PositionNode.js';
 import ReferenceNode from '../accessors/ReferenceNode.js';
@@ -267,6 +268,12 @@ export const modelWorldMatrix = nodeImmutable( ModelNode, ModelNode.WORLD_MATRIX
 export const modelPosition = nodeImmutable( ModelNode, ModelNode.POSITION );
 export const modelViewPosition = nodeImmutable( ModelNode, ModelNode.VIEW_POSITION );
 
+export const objectViewMatrix = nodeProxy( Object3DNode, Object3DNode.VIEW_MATRIX );
+export const objectNormalMatrix = nodeProxy( Object3DNode, Object3DNode.NORMAL_MATRIX );
+export const objectWorldMatrix = nodeProxy( Object3DNode, Object3DNode.WORLD_MATRIX );
+export const objectPosition = nodeProxy( Object3DNode, Object3DNode.POSITION );
+export const objectViewPosition = nodeProxy( Object3DNode, Object3DNode.VIEW_POSITION );
+
 export const positionGeometry = nodeImmutable( PositionNode, PositionNode.GEOMETRY );
 export const positionLocal = nodeImmutable( PositionNode, PositionNode.LOCAL );
 export const positionWorld = nodeImmutable( PositionNode, PositionNode.WORLD );

+ 1 - 0
examples/jsm/renderers/webgpu/nodes/WebGPUNodeBuilder.js

@@ -27,6 +27,7 @@ const wgslTypeLib = {
 	int: 'i32',
 	uint: 'u32',
 	bool: 'bool',
+	color: 'vec3<f32>',
 
 	vec2: 'vec2<f32>',
 	ivec2: 'vec2<i32>',