|
@@ -25,7 +25,7 @@
|
|
<script type="module">
|
|
<script type="module">
|
|
|
|
|
|
import * as THREE from 'three';
|
|
import * as THREE from 'three';
|
|
- import { color, depth, depthTexture, normalWorld, triplanarTexture, texture, viewportSharedTexture, mx_worley_noise_float, positionWorld, timerLocal, MeshStandardNodeMaterial, MeshBasicNodeMaterial } from 'three/nodes';
|
|
|
|
|
|
+ import { color, depth, vec2, pass, depthTexture, normalWorld, triplanarTexture, texture, objectPosition, viewportTopLeft, viewportDepthTexture, viewportSharedTexture, mx_worley_noise_float, positionWorld, timerLocal, MeshStandardNodeMaterial, MeshBasicNodeMaterial } from 'three/nodes';
|
|
|
|
|
|
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
|
|
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
|
|
|
|
|
|
@@ -33,6 +33,7 @@
|
|
import WebGL from 'three/addons/capabilities/WebGL.js';
|
|
import WebGL from 'three/addons/capabilities/WebGL.js';
|
|
|
|
|
|
import WebGPURenderer from 'three/addons/renderers/webgpu/WebGPURenderer.js';
|
|
import WebGPURenderer from 'three/addons/renderers/webgpu/WebGPURenderer.js';
|
|
|
|
+ import PostProcessing from 'three/addons/renderers/common/PostProcessing.js';
|
|
|
|
|
|
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
|
|
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
|
|
|
|
|
|
@@ -43,6 +44,8 @@
|
|
let camera, scene, renderer;
|
|
let camera, scene, renderer;
|
|
let mixer, objects, clock;
|
|
let mixer, objects, clock;
|
|
let model, floor, floorPosition;
|
|
let model, floor, floorPosition;
|
|
|
|
+ let postProcessing;
|
|
|
|
+ let controls;
|
|
let stats;
|
|
let stats;
|
|
|
|
|
|
init();
|
|
init();
|
|
@@ -58,25 +61,25 @@
|
|
}
|
|
}
|
|
|
|
|
|
camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 0.25, 30 );
|
|
camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 0.25, 30 );
|
|
- camera.position.set( 3, 3, 4 );
|
|
|
|
|
|
+ camera.position.set( 3, 2, 4 );
|
|
|
|
|
|
scene = new THREE.Scene();
|
|
scene = new THREE.Scene();
|
|
- scene.fog = new THREE.Fog( 0x74ccf4, 7, 25 );
|
|
|
|
- scene.backgroundNode = normalWorld.y.mix( color( 0x74ccf4 ), color( 0x0066ff ) );
|
|
|
|
|
|
+ scene.fog = new THREE.Fog( 0x0487e2, 7, 25 );
|
|
|
|
+ scene.backgroundNode = normalWorld.y.mix( color( 0x0487e2 ), color( 0x0066ff ) );
|
|
camera.lookAt( 0, 1, 0 );
|
|
camera.lookAt( 0, 1, 0 );
|
|
|
|
|
|
const sunLight = new THREE.DirectionalLight( 0xFFE499, 5 );
|
|
const sunLight = new THREE.DirectionalLight( 0xFFE499, 5 );
|
|
sunLight.castShadow = true;
|
|
sunLight.castShadow = true;
|
|
sunLight.shadow.camera.near = .1;
|
|
sunLight.shadow.camera.near = .1;
|
|
- sunLight.shadow.camera.far = 3;
|
|
|
|
|
|
+ sunLight.shadow.camera.far = 5;
|
|
sunLight.shadow.camera.right = 2;
|
|
sunLight.shadow.camera.right = 2;
|
|
sunLight.shadow.camera.left = - 2;
|
|
sunLight.shadow.camera.left = - 2;
|
|
- sunLight.shadow.camera.top = 2;
|
|
|
|
|
|
+ sunLight.shadow.camera.top = 1;
|
|
sunLight.shadow.camera.bottom = - 2;
|
|
sunLight.shadow.camera.bottom = - 2;
|
|
sunLight.shadow.mapSize.width = 2048;
|
|
sunLight.shadow.mapSize.width = 2048;
|
|
sunLight.shadow.mapSize.height = 2048;
|
|
sunLight.shadow.mapSize.height = 2048;
|
|
sunLight.shadow.bias = - 0.001;
|
|
sunLight.shadow.bias = - 0.001;
|
|
- sunLight.position.set( 1, 3, 1 );
|
|
|
|
|
|
+ sunLight.position.set( .5, 3, .5 );
|
|
|
|
|
|
const waterAmbientLight = new THREE.HemisphereLight( 0x333366, 0x74ccf4, 5 );
|
|
const waterAmbientLight = new THREE.HemisphereLight( 0x333366, 0x74ccf4, 5 );
|
|
const skyAmbientLight = new THREE.HemisphereLight( 0x74ccf4, 0, 1 );
|
|
const skyAmbientLight = new THREE.HemisphereLight( 0x74ccf4, 0, 1 );
|
|
@@ -112,7 +115,7 @@
|
|
iceDiffuse.wrapT = THREE.RepeatWrapping;
|
|
iceDiffuse.wrapT = THREE.RepeatWrapping;
|
|
iceDiffuse.colorSpace = THREE.NoColorSpace;
|
|
iceDiffuse.colorSpace = THREE.NoColorSpace;
|
|
|
|
|
|
- const iceColorNode = triplanarTexture( texture( iceDiffuse ) ).add( color( 0x0066ff ) );
|
|
|
|
|
|
+ const iceColorNode = triplanarTexture( texture( iceDiffuse ) ).add( color( 0x0066ff ) ).mul( .8 );
|
|
|
|
|
|
const geometry = new THREE.IcosahedronGeometry( 1, 3 );
|
|
const geometry = new THREE.IcosahedronGeometry( 1, 3 );
|
|
const material = new MeshStandardNodeMaterial( { colorNode: iceColorNode } );
|
|
const material = new MeshStandardNodeMaterial( { colorNode: iceColorNode } );
|
|
@@ -137,7 +140,7 @@
|
|
|
|
|
|
objects.position.set(
|
|
objects.position.set(
|
|
( ( column - 1 ) * scale ) * - .5,
|
|
( ( column - 1 ) * scale ) * - .5,
|
|
- - .3,
|
|
|
|
|
|
+ - 1,
|
|
( ( count / column ) * scale ) * - .5
|
|
( ( count / column ) * scale ) * - .5
|
|
);
|
|
);
|
|
|
|
|
|
@@ -145,26 +148,36 @@
|
|
|
|
|
|
// water
|
|
// water
|
|
|
|
|
|
- const depthEffect = depthTexture().distance( depth ).remapClamp( 0, .05 );
|
|
|
|
-
|
|
|
|
const timer = timerLocal( .8 );
|
|
const timer = timerLocal( .8 );
|
|
const floorUV = positionWorld.xzy;
|
|
const floorUV = positionWorld.xzy;
|
|
|
|
|
|
const waterLayer0 = mx_worley_noise_float( floorUV.mul( 4 ).add( timer ) );
|
|
const waterLayer0 = mx_worley_noise_float( floorUV.mul( 4 ).add( timer ) );
|
|
const waterLayer1 = mx_worley_noise_float( floorUV.mul( 2 ).add( timer ) );
|
|
const waterLayer1 = mx_worley_noise_float( floorUV.mul( 2 ).add( timer ) );
|
|
|
|
|
|
- const waterIntensity = waterLayer0.mul( waterLayer1 ).mul( 1.4 );
|
|
|
|
- const waterColor = waterIntensity.mix( color( 0x0f5e9c ), color( 0x74ccf4 ) );
|
|
|
|
- const viewportTexture = viewportSharedTexture();
|
|
|
|
|
|
+ const waterIntensity = waterLayer0.mul( waterLayer1 );
|
|
|
|
+ const waterColor = waterIntensity.mul( 1.4 ).mix( color( 0x0487e2 ), color( 0x74ccf4 ) );
|
|
|
|
+
|
|
|
|
+ const depthWater = depthTexture( viewportDepthTexture() ).sub( depth );
|
|
|
|
+ const depthEffect = depthWater.remapClamp( - .002, .04 );
|
|
|
|
+
|
|
|
|
+ const refractionUV = viewportTopLeft.add( vec2( 0, waterIntensity.mul( .1 ) ) );
|
|
|
|
+
|
|
|
|
+ const depthTestForRefraction = depthTexture( viewportDepthTexture( refractionUV ) ).sub( depth );
|
|
|
|
+
|
|
|
|
+ const depthRefraction = depthTestForRefraction.remapClamp( 0, .1 );
|
|
|
|
+
|
|
|
|
+ const finalUV = depthTestForRefraction.lessThan( 0 ).cond( viewportTopLeft, refractionUV );
|
|
|
|
+
|
|
|
|
+ const viewportTexture = viewportSharedTexture( finalUV );
|
|
|
|
|
|
const waterMaterial = new MeshBasicNodeMaterial();
|
|
const waterMaterial = new MeshBasicNodeMaterial();
|
|
waterMaterial.colorNode = waterColor;
|
|
waterMaterial.colorNode = waterColor;
|
|
- waterMaterial.backdropNode = depthEffect.mul( 3 ).min( 1.4 ).mix( viewportTexture, viewportTexture.mul( color( 0x74ccf4 ) ) );
|
|
|
|
- waterMaterial.backdropAlphaNode = depthEffect.oneMinus();
|
|
|
|
|
|
+ waterMaterial.backdropNode = depthEffect.mix( viewportSharedTexture(), viewportTexture.mul( depthRefraction.mix( 1, waterColor ) ) );
|
|
|
|
+ waterMaterial.backdropAlphaNode = depthRefraction.oneMinus();
|
|
waterMaterial.transparent = true;
|
|
waterMaterial.transparent = true;
|
|
|
|
|
|
const water = new THREE.Mesh( new THREE.BoxGeometry( 50, .001, 50 ), waterMaterial );
|
|
const water = new THREE.Mesh( new THREE.BoxGeometry( 50, .001, 50 ), waterMaterial );
|
|
- water.position.set( 0, .8, 0 );
|
|
|
|
|
|
+ water.position.set( 0, 0, 0 );
|
|
scene.add( water );
|
|
scene.add( water );
|
|
|
|
|
|
// floor
|
|
// floor
|
|
@@ -197,20 +210,38 @@
|
|
stats = new Stats();
|
|
stats = new Stats();
|
|
document.body.appendChild( stats.dom );
|
|
document.body.appendChild( stats.dom );
|
|
|
|
|
|
- const controls = new OrbitControls( camera, renderer.domElement );
|
|
|
|
|
|
+ controls = new OrbitControls( camera, renderer.domElement );
|
|
controls.minDistance = 1;
|
|
controls.minDistance = 1;
|
|
controls.maxDistance = 10;
|
|
controls.maxDistance = 10;
|
|
controls.maxPolarAngle = Math.PI * 0.9;
|
|
controls.maxPolarAngle = Math.PI * 0.9;
|
|
- controls.target.set( 0, 1, 0 );
|
|
|
|
|
|
+ controls.autoRotate = true;
|
|
|
|
+ controls.autoRotateSpeed = 1;
|
|
|
|
+ controls.target.set( 0, .2, 0 );
|
|
controls.update();
|
|
controls.update();
|
|
|
|
|
|
// gui
|
|
// gui
|
|
|
|
|
|
const gui = new GUI();
|
|
const gui = new GUI();
|
|
|
|
|
|
- floorPosition = new THREE.Vector3( 0, 1, 0 );
|
|
|
|
|
|
+ floorPosition = new THREE.Vector3( 0, .2, 0 );
|
|
|
|
+
|
|
|
|
+ gui.add( floorPosition, 'y', - 1, 1, .001 ).name( 'position' );
|
|
|
|
|
|
- gui.add( floorPosition, 'y', 0, 2, .001 ).name( 'position' );
|
|
|
|
|
|
+ // post processing
|
|
|
|
+
|
|
|
|
+ const scenePass = pass( scene, camera );
|
|
|
|
+ const scenePassColor = scenePass.getTextureNode();
|
|
|
|
+ const scenePassDepth = scenePass.getDepthNode().remapClamp( .3, .5 );
|
|
|
|
+
|
|
|
|
+ const waterMask = objectPosition( camera ).y.greaterThan( 0 );
|
|
|
|
+
|
|
|
|
+ const scenePassColorBlurred = scenePassColor.gaussianBlur();
|
|
|
|
+ scenePassColorBlurred.directionNode = waterMask.cond( scenePassDepth, scenePass.getDepthNode().mul( 5 ) );
|
|
|
|
+
|
|
|
|
+ const vignet = viewportTopLeft.distance( .5 ).mul( 1.35 ).clamp().oneMinus();
|
|
|
|
+
|
|
|
|
+ postProcessing = new PostProcessing( renderer );
|
|
|
|
+ postProcessing.outputNode = waterMask.cond( scenePassColorBlurred, scenePassColorBlurred.mul( color( 0x74ccf4 ) ).mul( vignet ) );
|
|
|
|
|
|
//
|
|
//
|
|
|
|
|
|
@@ -231,6 +262,8 @@
|
|
|
|
|
|
stats.update();
|
|
stats.update();
|
|
|
|
|
|
|
|
+ controls.update();
|
|
|
|
+
|
|
const delta = clock.getDelta();
|
|
const delta = clock.getDelta();
|
|
|
|
|
|
floor.position.y = floorPosition.y - 5;
|
|
floor.position.y = floorPosition.y - 5;
|
|
@@ -250,7 +283,7 @@
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- renderer.render( scene, camera );
|
|
|
|
|
|
+ postProcessing.render();
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|