Prechádzať zdrojové kódy

Raymarching: Move `raymarchingTexture3D` to example and update `webgpu_volume_perlin` (#30531)

* examples revision

* cleanup
sunag 1 rok pred
rodič
commit
5f2b92f0be

+ 1 - 50
examples/jsm/tsl/utils/Raymarching.js

@@ -1,4 +1,4 @@
-import { varying, vec4, modelWorldMatrixInverse, cameraPosition, positionGeometry, float, Fn, Loop, max, min, vec2, vec3, smoothstep, If, Break } from 'three/tsl';
+import { varying, vec4, modelWorldMatrixInverse, cameraPosition, positionGeometry, float, Fn, Loop, max, min, vec2, vec3 } from 'three/tsl';
 
 const hitBox = /*@__PURE__*/ Fn( ( { orig, dir } ) => {
 
@@ -63,52 +63,3 @@ export const RaymarchingBox = ( steps, callback ) => {
 	} );
 
 };
-
-/**
- * Performs raymarching on the specified 3D texture.
- *
- * @tsl
- * @function
- * @param {Object} params - The parameters for the function.
- * @param {Texture|Node} params.texture - The 3D texture to sample.
- * @param {number|Node} [params.range=0.1] - The range for the smoothstep function.
- * @param {number|Node} [params.threshold=0.25] - The threshold for the smoothstep function.
- * @param {number|Node} [params.opacity=0.25] - The opacity value for the final color.
- * @param {number|Node} [params.steps=100] - The number of steps for raymarching.
- * @returns {Function} The generated function that performs raymarching on the 3D texture.
- */
-export const raymarchingTexture3D = Fn( ( {
-	texture,
-	range = float( 0.1 ),
-	threshold = float( 0.25 ),
-	opacity = float( 0.25 ),
-	steps = float( 100 )
-} ) => {
-
-	const finalColor = vec4( 0 ).toVar();
-
-	RaymarchingBox( steps, ( { positionRay } ) => {
-
-		const mapValue = float( texture.sample( positionRay.add( 0.5 ) ).r ).toVar();
-
-		mapValue.assign( smoothstep( threshold.sub( range ), threshold.add( range ), mapValue ).mul( opacity ) );
-
-		const shading = texture.sample( positionRay.add( vec3( - 0.01 ) ) ).r.sub( texture.sample( positionRay.add( vec3( 0.01 ) ) ).r );
-
-		const col = shading.mul( 3.0 ).add( positionRay.x.add( positionRay.y ).mul( 0.25 ) ).add( 0.2 );
-
-		finalColor.rgb.addAssign( finalColor.a.oneMinus().mul( mapValue ).mul( col ) );
-
-		finalColor.a.addAssign( finalColor.a.oneMinus().mul( mapValue ) );
-
-		If( finalColor.a.greaterThanEqual( 0.95 ), () => {
-
-			Break();
-
-		} );
-
-	} );
-
-	return finalColor;
-
-} );

+ 47 - 13
examples/webgpu_volume_cloud.html

@@ -26,9 +26,9 @@
 		<script type="module">
 
 			import * as THREE from 'three';
-			import { texture3D, uniform } from 'three/tsl';
+			import { float, vec3, vec4, If, Break, Fn, smoothstep, texture3D, uniform } from 'three/tsl';
 
-			import { raymarchingTexture3D } from 'three/addons/tsl/utils/Raymarching.js';
+			import { RaymarchingBox } from 'three/addons/tsl/utils/Raymarching.js';
 
 			import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
 			import { ImprovedNoise } from 'three/addons/math/ImprovedNoise.js';
@@ -111,7 +111,45 @@
 				texture.unpackAlignment = 1;
 				texture.needsUpdate = true;
 
-				// Cloud Shader
+				// Shader
+
+				const transparentRaymarchingTexture = Fn( ( {
+					texture,
+					range = float( 0.1 ),
+					threshold = float( 0.25 ),
+					opacity = float( 0.25 ),
+					steps = float( 100 )
+				} ) => {
+
+					const finalColor = vec4( 0 ).toVar();
+
+					RaymarchingBox( steps, ( { positionRay } ) => {
+
+						const mapValue = float( texture.sample( positionRay.add( 0.5 ) ).r ).toVar();
+
+						mapValue.assign( smoothstep( threshold.sub( range ), threshold.add( range ), mapValue ).mul( opacity ) );
+
+						const shading = texture.sample( positionRay.add( vec3( - 0.01 ) ) ).r.sub( texture.sample( positionRay.add( vec3( 0.01 ) ) ).r );
+
+						const col = shading.mul( 3.0 ).add( positionRay.x.add( positionRay.y ).mul( 0.25 ) ).add( 0.2 );
+
+						finalColor.rgb.addAssign( finalColor.a.oneMinus().mul( mapValue ).mul( col ) );
+
+						finalColor.a.addAssign( finalColor.a.oneMinus().mul( mapValue ) );
+
+						If( finalColor.a.greaterThanEqual( 0.95 ), () => {
+
+							Break();
+
+						} );
+
+					} );
+
+					return finalColor;
+
+				} );
+
+				// Material
 
 				const baseColor = uniform( new THREE.Color( 0x798aa0 ) );
 				const range = uniform( 0.1 );
@@ -119,26 +157,22 @@
 				const opacity = uniform( 0.25 );
 				const steps = uniform( 100 );
 
-				const cloud3d = raymarchingTexture3D( {
+				const cloud3d = transparentRaymarchingTexture( {
 					texture: texture3D( texture, null, 0 ),
-					range: range,
-					threshold: threshold,
-					opacity: opacity,
-					steps: steps
+					range,
+					threshold,
+					opacity,
+					steps
 				} );
 
 				const finalCloud = cloud3d.setRGB( cloud3d.rgb.add( baseColor ) );
 
-				//
-
-				const geometry = new THREE.BoxGeometry( 1, 1, 1 );
-
 				const material = new THREE.NodeMaterial();
 				material.colorNode = finalCloud;
 				material.side = THREE.BackSide;
 				material.transparent = true;
 
-				mesh = new THREE.Mesh( geometry, material );
+				mesh = new THREE.Mesh( new THREE.BoxGeometry( 1, 1, 1 ), material );
 				scene.add( mesh );
 
 				//

+ 33 - 28
examples/webgpu_volume_perlin.html

@@ -24,8 +24,11 @@
 		</script>
 
 		<script type="module">
+
 			import * as THREE from 'three';
-			import { Break, If, vec3, materialReference, Fn } from 'three/tsl';
+			import { Break, If, vec3, vec4, texture3D, uniform, Fn } from 'three/tsl';
+
+			import { RaymarchingBox } from 'three/addons/tsl/utils/Raymarching.js';
 
 			import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
 			import { ImprovedNoise } from 'three/addons/math/ImprovedNoise.js';
@@ -86,52 +89,54 @@
 				texture.unpackAlignment = 1;
 				texture.needsUpdate = true;
 
-				// Material
+				// Shader
 
-				const geometry = new THREE.BoxGeometry( 1, 1, 1 );
-				const material = new THREE.VolumeNodeMaterial( {
-					side: THREE.BackSide
-				} );
+				const opaqueRaymarchingTexture = Fn( ( { texture, steps, threshold } ) => {
 
-				material.base = new THREE.Color( 0x798aa0 );
-				material.map = texture;
-				material.steps = 200;
-				material.threshold = 0.6;
+					const finalColor = vec4( 0 ).toVar();
 
-				const threshold = materialReference( 'threshold', 'float' );
+					RaymarchingBox( steps, ( { positionRay } ) => {
 
-				material.testNode = Fn( ( { map, mapValue, probe, finalColor } ) => {
+						const mapValue = texture.sample( positionRay.add( 0.5 ) ).r.toVar();
 
-					If( mapValue.greaterThan( threshold ), () => {
+						If( mapValue.greaterThan( threshold ), () => {
 
-						const p = vec3( probe ).add( 0.5 );
+							const p = vec3( positionRay ).add( 0.5 );
 
-						finalColor.rgb.assign( map.normal( p ).mul( 0.5 ).add( probe.mul( 1.5 ).add( 0.25 ) ) );
-						finalColor.a.assign( 1 );
-						Break();
+							finalColor.rgb.assign( texture.normal( p ).mul( 0.5 ).add( positionRay.mul( 1.5 ).add( 0.25 ) ) );
+							finalColor.a.assign( 1 );
+							Break();
 
-					} );
+						} );
 
-				} );
+					} );
 
-				mesh = new THREE.Mesh( geometry, material );
+					return finalColor;
 
-				scene.add( mesh );
+				} );
 
 				//
 
-				const parameters = { threshold: 0.6, steps: 200 };
+				const threshold = uniform( 0.6 );
+				const steps = uniform( 200 );
 
-				function update() {
+				const material = new THREE.NodeMaterial();
+				material.colorNode = opaqueRaymarchingTexture( {
+					texture: texture3D( texture, null, 0 ),
+					steps,
+					threshold
+				} );
+				material.side = THREE.BackSide;
+				material.transparent = true;
 
-					material.threshold = parameters.threshold;
-					material.steps = parameters.steps;
+				mesh = new THREE.Mesh( new THREE.BoxGeometry( 1, 1, 1 ), material );
+				scene.add( mesh );
 
-				}
+				//
 
 				const gui = new GUI();
-				gui.add( parameters, 'threshold', 0, 1, 0.01 ).onChange( update );
-				gui.add( parameters, 'steps', 0, 300, 1 ).onChange( update );
+				gui.add( threshold, 'value', 0, 1, 0.01 ).name( 'threshold' );
+				gui.add( steps, 'value', 0, 300, 1 ).name( 'steps' );
 
 				window.addEventListener( 'resize', onWindowResize );
 

粤ICP备19079148号