5 Коміти 3ef3070762 ... adf4a950c4

Автор SHA1 Опис Дата
  Michael Herzog adf4a950c4 Object3D: Document `static`, add support in `copy()` and JSON. (#32679) 3 днів тому
  mrdoob 1a4a28a2bf Water/WaterMesh: Improve realism. (#32681) 3 днів тому
  mrdoob fea08f827d Examples: Added bloom to ocean examples. (#32680) 3 днів тому
  mrdoob 98a7dd547f Water: Use HalfFloatType for reflection render target. (#32678) 3 днів тому
  mrdoob da18e06036 Sky/SkyMesh: Remove legacy gamma correction curve. (#32677) 3 днів тому

+ 1 - 4
examples/jsm/objects/Sky.js

@@ -150,7 +150,6 @@ Sky.SkyShader = {
 	fragmentShader: /* glsl */`
 		varying vec3 vWorldPosition;
 		varying vec3 vSunDirection;
-		varying float vSunfade;
 		varying vec3 vBetaR;
 		varying vec3 vBetaM;
 		varying float vSunE;
@@ -223,9 +222,7 @@ Sky.SkyShader = {
 
 			vec3 texColor = ( Lin + L0 ) * 0.04 + vec3( 0.0, 0.0003, 0.00075 );
 
-			vec3 retColor = pow( texColor, vec3( 1.0 / ( 1.2 + ( 1.2 * vSunfade ) ) ) );
-
-			gl_FragColor = vec4( retColor, 1.0 );
+			gl_FragColor = vec4( texColor, 1.0 );
 
 			#include <tonemapping_fragment>
 			#include <colorspace_fragment>

+ 2 - 6
examples/jsm/objects/SkyMesh.js

@@ -105,7 +105,6 @@ class SkyMesh extends Mesh {
 
 		const vSunDirection = varyingProperty( 'vec3' );
 		const vSunE = varyingProperty( 'float' );
-		const vSunfade = varyingProperty( 'float' );
 		const vBetaR = varyingProperty( 'vec3' );
 		const vBetaM = varyingProperty( 'vec3' );
 
@@ -146,10 +145,9 @@ class SkyMesh extends Mesh {
 			const sunIntensity = EE.mul( max( 0.0, float( 1.0 ).sub( pow( e, cutoffAngle.sub( acos( zenithAngleCos ) ).div( steepness ).negate() ) ) ) );
 			vSunE.assign( sunIntensity );
 
-			// varying sun fade
+			// sun fade
 
 			const sunfade = float( 1.0 ).sub( clamp( float( 1.0 ).sub( exp( this.sunPosition.y.div( 450000.0 ) ) ), 0, 1 ) );
-			vSunfade.assign( sunfade );
 
 			// varying vBetaR
 
@@ -234,9 +232,7 @@ class SkyMesh extends Mesh {
 
 			const texColor = add( Lin, L0 ).mul( 0.04 ).add( vec3( 0.0, 0.0003, 0.00075 ) );
 
-			const retColor = pow( texColor, vec3( float( 1.0 ).div( float( 1.2 ).add( vSunfade.mul( 1.2 ) ) ) ) );
-
-			return vec4( retColor, 1.0 );
+			return vec4( texColor, 1.0 );
 
 		} )();
 

+ 4 - 3
examples/jsm/objects/Water.js

@@ -1,6 +1,7 @@
 import {
 	Color,
 	FrontSide,
+	HalfFloatType,
 	Matrix4,
 	Mesh,
 	PerspectiveCamera,
@@ -84,7 +85,7 @@ class Water extends Mesh {
 
 		const mirrorCamera = new PerspectiveCamera();
 
-		const renderTarget = new WebGLRenderTarget( textureWidth, textureHeight );
+		const renderTarget = new WebGLRenderTarget( textureWidth, textureHeight, { type: HalfFloatType } );
 
 		const mirrorShader = {
 
@@ -196,10 +197,10 @@ class Water extends Mesh {
 					vec3 reflectionSample = vec3( texture2D( mirrorSampler, mirrorCoord.xy / mirrorCoord.w + distortion ) );
 
 					float theta = max( dot( eyeDirection, surfaceNormal ), 0.0 );
-					float rf0 = 0.3;
+					float rf0 = 0.02;
 					float reflectance = rf0 + ( 1.0 - rf0 ) * pow( ( 1.0 - theta ), 5.0 );
 					vec3 scatter = max( 0.0, dot( surfaceNormal, eyeDirection ) ) * waterColor;
-					vec3 albedo = mix( ( sunColor * diffuseLight * 0.3 + scatter ) * getShadowMask(), ( vec3( 0.1 ) + reflectionSample * 0.9 + reflectionSample * specularLight ), reflectance);
+					vec3 albedo = mix( ( sunColor * diffuseLight * 0.3 + scatter ) * getShadowMask(), reflectionSample + specularLight, reflectance );
 					vec3 outgoingLight = albedo;
 					gl_FragColor = vec4( outgoingLight, alpha );
 

+ 2 - 2
examples/jsm/objects/WaterMesh.js

@@ -166,10 +166,10 @@ class WaterMesh extends Mesh {
 			this.add( mirrorSampler.target );
 
 			const theta = max( dot( eyeDirection, surfaceNormal ), 0.0 );
-			const rf0 = float( 0.3 );
+			const rf0 = float( 0.02 );
 			const reflectance = mul( pow( float( 1.0 ).sub( theta ), 5.0 ), float( 1.0 ).sub( rf0 ) ).add( rf0 );
 			const scatter = max( 0.0, dot( surfaceNormal, eyeDirection ) ).mul( this.waterColor );
-			const albedo = mix( this.sunColor.mul( diffuseLight ).mul( 0.3 ).add( scatter ), mirrorSampler.rgb.mul( specularLight ).add( mirrorSampler.rgb.mul( 0.9 ) ).add( vec3( 0.1 ) ), reflectance );
+			const albedo = mix( this.sunColor.mul( diffuseLight ).mul( 0.3 ).add( scatter ), mirrorSampler.rgb.add( specularLight ), reflectance );
 
 			return albedo;
 

BIN
examples/screenshots/webgl_shaders_ocean.jpg


BIN
examples/screenshots/webgl_shaders_sky.jpg


BIN
examples/screenshots/webgpu_ocean.jpg


BIN
examples/screenshots/webgpu_sky.jpg


+ 22 - 4
examples/webgl_shaders_ocean.html

@@ -32,10 +32,11 @@
 			import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
 			import { Water } from 'three/addons/objects/Water.js';
 			import { Sky } from 'three/addons/objects/Sky.js';
+			import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js';
 
 			let container, stats;
 			let camera, scene, renderer;
-			let controls, water, sun, mesh;
+			let controls, water, sun, mesh, bloomPass;
 
 			init();
 
@@ -45,14 +46,20 @@
 
 				//
 
-				renderer = new THREE.WebGLRenderer();
+				renderer = new THREE.WebGLRenderer( { outputBufferType: THREE.HalfFloatType } );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				renderer.setAnimationLoop( animate );
 				renderer.toneMapping = THREE.ACESFilmicToneMapping;
-				renderer.toneMappingExposure = 0.5;
+				renderer.toneMappingExposure = 0.1;
 				container.appendChild( renderer.domElement );
 
+				bloomPass = new UnrealBloomPass( new THREE.Vector2( window.innerWidth, window.innerHeight ) );
+				bloomPass.threshold = 0;
+				bloomPass.strength = 0.1;
+				bloomPass.radius = 0;
+				renderer.setEffects( [ bloomPass ] );
+
 				//
 
 				scene = new THREE.Scene();
@@ -105,7 +112,8 @@
 
 				const parameters = {
 					elevation: 2,
-					azimuth: 180
+					azimuth: 180,
+					exposure: 0.1
 				};
 
 				const pmremGenerator = new THREE.PMREMGenerator( renderer );
@@ -164,6 +172,11 @@
 				const folderSky = gui.addFolder( 'Sky' );
 				folderSky.add( parameters, 'elevation', 0, 90, 0.1 ).onChange( updateSun );
 				folderSky.add( parameters, 'azimuth', - 180, 180, 0.1 ).onChange( updateSun );
+				folderSky.add( parameters, 'exposure', 0, 1, 0.0001 ).onChange( function ( value ) {
+
+					renderer.toneMappingExposure = value;
+
+				} );
 				folderSky.open();
 
 				const waterUniforms = water.material.uniforms;
@@ -173,6 +186,11 @@
 				folderWater.add( waterUniforms.size, 'value', 0.1, 10, 0.1 ).name( 'size' );
 				folderWater.open();
 
+				const folderBloom = gui.addFolder( 'Bloom' );
+				folderBloom.add( bloomPass, 'strength', 0, 3, 0.01 );
+				folderBloom.add( bloomPass, 'radius', 0, 1, 0.01 );
+				folderBloom.open();
+
 				//
 
 				window.addEventListener( 'resize', onWindowResize );

+ 30 - 5
examples/webgpu_ocean.html

@@ -36,6 +36,8 @@
 		<script type="module">
 
 			import * as THREE from 'three/webgpu';
+			import { pass } from 'three/tsl';
+			import { bloom } from 'three/addons/tsl/display/BloomNode.js';
 
 			import { Inspector } from 'three/addons/inspector/Inspector.js';
 
@@ -44,8 +46,8 @@
 			import { SkyMesh } from 'three/addons/objects/SkyMesh.js';
 
 			let container;
-			let camera, scene, renderer;
-			let controls, water, sun, mesh;
+			let camera, scene, renderer, postProcessing;
+			let controls, water, sun, mesh, bloomPass;
 
 			init();
 
@@ -60,7 +62,7 @@
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				renderer.setAnimationLoop( render );
 				renderer.toneMapping = THREE.ACESFilmicToneMapping;
-				renderer.toneMappingExposure = 0.5;
+				renderer.toneMappingExposure = 0.1;
 				renderer.inspector = new Inspector();
 				container.appendChild( renderer.domElement );
 
@@ -71,6 +73,20 @@
 				camera = new THREE.PerspectiveCamera( 55, window.innerWidth / window.innerHeight, 1, 20000 );
 				camera.position.set( 30, 30, 100 );
 
+				// Post-processing
+
+				postProcessing = new THREE.PostProcessing( renderer );
+
+				const scenePass = pass( scene, camera );
+				const scenePassColor = scenePass.getTextureNode( 'output' );
+
+				bloomPass = bloom( scenePassColor );
+				bloomPass.threshold.value = 0;
+				bloomPass.strength.value = 0.1;
+				bloomPass.radius.value = 0;
+
+				postProcessing.outputNode = scenePassColor.add( bloomPass );
+
 				//
 
 				sun = new THREE.Vector3();
@@ -110,7 +126,8 @@
 
 				const parameters = {
 					elevation: 2,
-					azimuth: 180
+					azimuth: 180,
+					exposure: 0.1
 				};
 
 				const pmremGenerator = new THREE.PMREMGenerator( renderer );
@@ -164,12 +181,20 @@
 				const folderSky = gui.addFolder( 'Sky' );
 				folderSky.add( parameters, 'elevation', 0, 90, 0.1 ).onChange( updateSun );
 				folderSky.add( parameters, 'azimuth', - 180, 180, 0.1 ).onChange( updateSun );
+				folderSky.add( parameters, 'exposure', 0, 1, 0.0001 ).onChange( function ( value ) {
+
+					renderer.toneMappingExposure = value;
 
+				} );
 
 				const folderWater = gui.addFolder( 'Water' );
 				folderWater.add( water.distortionScale, 'value', 0, 8, 0.1 ).name( 'distortionScale' );
 				folderWater.add( water.size, 'value', 0.1, 10, 0.1 ).name( 'size' );
 
+				const folderBloom = gui.addFolder( 'Bloom' );
+				folderBloom.add( bloomPass.strength, 'value', 0, 3, 0.01 ).name( 'strength' );
+				folderBloom.add( bloomPass.radius, 'value', 0, 1, 0.01 ).name( 'radius' );
+
 				//
 
 				window.addEventListener( 'resize', onWindowResize );
@@ -193,7 +218,7 @@
 				mesh.rotation.x = time * 0.5;
 				mesh.rotation.z = time * 0.51;
 
-				renderer.render( scene, camera );
+				postProcessing.render();
 
 			}
 

+ 16 - 0
src/core/Object3D.js

@@ -354,6 +354,19 @@ class Object3D extends EventDispatcher {
 		 */
 		this.customDistanceMaterial = undefined;
 
+		/**
+		 * Whether the 3D object is supposed to be static or not. If set to `true`, it means
+		 * the 3D object is not going to be changed after the initial renderer. This includes
+		 * geometry and material settings. A static 3D object can be processed by the renderer
+		 * slightly faster since certain state checks can be bypassed.
+		 *
+		 * Only relevant in context of {@link WebGPURenderer}.
+		 *
+		 * @type {boolean}
+		 * @default false
+		 */
+		this.static = false;
+
 		/**
 		 * An object that can be used to store custom data about the 3D object. It
 		 * should not hold references to functions as these will not be cloned.
@@ -1267,6 +1280,7 @@ class Object3D extends EventDispatcher {
 		if ( this.visible === false ) object.visible = false;
 		if ( this.frustumCulled === false ) object.frustumCulled = false;
 		if ( this.renderOrder !== 0 ) object.renderOrder = this.renderOrder;
+		if ( this.static !== false ) object.static = this.static;
 		if ( Object.keys( this.userData ).length > 0 ) object.userData = this.userData;
 
 		object.layers = this.layers.mask;
@@ -1565,6 +1579,8 @@ class Object3D extends EventDispatcher {
 		this.frustumCulled = source.frustumCulled;
 		this.renderOrder = source.renderOrder;
 
+		this.static = source.static;
+
 		this.animations = source.animations.slice();
 
 		this.userData = JSON.parse( JSON.stringify( source.userData ) );

+ 1 - 0
src/loaders/ObjectLoader.js

@@ -1131,6 +1131,7 @@ class ObjectLoader extends Loader {
 		if ( data.visible !== undefined ) object.visible = data.visible;
 		if ( data.frustumCulled !== undefined ) object.frustumCulled = data.frustumCulled;
 		if ( data.renderOrder !== undefined ) object.renderOrder = data.renderOrder;
+		if ( data.static !== undefined ) object.static = data.static;
 		if ( data.userData !== undefined ) object.userData = data.userData;
 		if ( data.layers !== undefined ) object.layers.mask = data.layers;
 

+ 1 - 1
src/renderers/common/BundleGroup.js

@@ -44,7 +44,7 @@ class BundleGroup extends Group {
 		/**
 		 * Whether the bundle is static or not. When set to `true`, the structure
 		 * is assumed to be static and does not change. E.g. no new objects are
-		 * added to the group
+		 * added to the group.
 		 *
 		 * If a change is required, an update can still be forced by setting the
 		 * `needsUpdate` flag to `true`.

粤ICP备19079148号