You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

349 lines
9.2 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js webgl - watch</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<link type="text/css" rel="stylesheet" href="main.css">
</head>
<body>
<div id="container"></div>
<div id="info">
<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> - Rolex + aomap - 610 ko
</div>
<script type="importmap">
{
"imports": {
"three": "../build/three.module.js",
"three/addons/": "./jsm/",
"tween": "./jsm/libs/tween.module.js"
}
}
</script>
<script type="module">
import * as THREE from 'three';
import * as TWEEN from 'tween';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { RGBELoader } from 'three/addons/loaders/RGBELoader.js';
import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js';
import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js';
import { OutputPass } from 'three/addons/postprocessing/OutputPass.js';
import { ShaderPass } from 'three/addons/postprocessing/ShaderPass.js';
import { FXAAShader } from 'three/addons/shaders/FXAAShader.js';
let composer, camera, scene, renderer;
let gui, dirLight, pointLight, controls, bloomPass, fxaaPass;
let ready = false;
const meshs = {};
const materials = {};
const torad = Math.PI / 180;
const setting = {
roughness: 0.09,
metalness: 1.0,
opacity: 0.4,
threshold: 0,
strength: 0.08,
radius: 0.0,
postProcess: false
};
init();
function init() {
const container = document.getElementById( 'container' );
camera = new THREE.PerspectiveCamera( 55, window.innerWidth / window.innerHeight, 0.1, 20 );
camera.position.set( 0.8, 0.5, - 1.5 );
scene = new THREE.Scene();
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setAnimationLoop( animate );
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 0.7;
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.VSMShadowMap;
container.appendChild( renderer.domElement );
new RGBELoader()
.setPath( 'textures/equirectangular/' )
.load( 'lobe.hdr', function ( texture ) {
texture.mapping = THREE.EquirectangularReflectionMapping;
scene.background = texture;
scene.environment = texture;
scene.backgroundBlurriness = 0.5;
scene.backgroundIntensity = 1.0;
scene.environmentIntensity = 1.5;
// model
const loader = new GLTFLoader().setPath( 'models/gltf/' );
loader.setDRACOLoader( new DRACOLoader().setDecoderPath( 'jsm/libs/draco/gltf/' ) );
loader.load( 'rolex.glb', function ( gltf ) {
gltf.scene.rotation.x = Math.PI * 0.25;
gltf.scene.traverse( ( child ) => {
if ( child.isMesh || child.isGroup ) {
if ( child.isMesh ) {
child.material.vertexColors = false;
materials[ child.material.name ] = child.material;
if ( child.name !== 'glass' ) {
child.receiveShadow = true;
child.castShadow = true;
}
}
meshs[ child.name ] = child;
}
} );
scene.add( gltf.scene );
meshs.glass.material = new THREE.MeshPhysicalMaterial( {
color: 0x020205,
transparent: true, opacity: setting.opacity,
metalness: 0, roughness: 0,
iridescence: 0.3,
clearcoat: 1.0,
blending: THREE.AdditiveBlending
} );
ready = true;
createGUI();
} );
} );
controls = new OrbitControls( camera, renderer.domElement );
controls.minDistance = 0.3;
controls.maxDistance = 10;
controls.target.set( 0, - 0.1, 0 );
controls.enableDamping = true;
controls.dampingFactor = 0.05;
controls.update();
dirLight = new THREE.DirectionalLight( 0xFFFFFF, 6 );
dirLight.position.set( - 0.1, 0.6, 0.4 );
dirLight.castShadow = true;
scene.add( dirLight );
const shadow = dirLight.shadow;
shadow.mapSize.width = shadow.mapSize.height = 1024;
shadow.radius = 8;
shadow.bias = - 0.0005;
const shadowCam = shadow.camera, s = 0.5;
shadowCam.near = 0.1;
shadowCam.far = 2;
shadowCam.right = shadowCam.top = s;
shadowCam.left = shadowCam.bottom = - s;
// debug shadow
//scene.add( new THREE.CameraHelper(shadowCam) );
pointLight = new THREE.PointLight( 0x7b8cad, 1, 0, 2 );
pointLight.position.set( 0.3, - 0.2, - 0.2 );
scene.add( pointLight );
window.addEventListener( 'resize', onWindowResize );
moveCamera();
}
function moveCamera() {
controls.enabled = false;
controls.enableDamping = false;
const sph = new THREE.Spherical();
const target = controls.target;
const tmp = {
distance: controls.getDistance(),
phi: controls.getPolarAngle(),
theta: controls.getAzimuthalAngle()
};
new TWEEN.Tween( tmp )
.to( { distance: 1, theta: - Math.PI * 0.2 }, 6000 )
.easing( TWEEN.Easing.Quadratic.Out )
.onUpdate( function ( n ) {
sph.set( n.distance, n.phi, n.theta );
camera.position.setFromSpherical( sph ).add( target );
camera.lookAt( target );
} )
.onComplete( function () {
controls.enabled = true;
controls.enableDamping = true;
} )
.start();
}
function postProcess( b ) {
if ( b ) {
if ( composer ) return;
const renderPass = new RenderPass( scene, camera );
const outputPass = new OutputPass();
bloomPass = new UnrealBloomPass( new THREE.Vector2( window.innerWidth, window.innerHeight ), 1.5, 0.4, 0.85 );
bloomPass.threshold = setting.threshold;
bloomPass.strength = setting.strength;
bloomPass.radius = setting.radius;
fxaaPass = new ShaderPass( FXAAShader );
const pixelRatio = renderer.getPixelRatio();
fxaaPass.material.uniforms[ 'resolution' ].value.set( 1 / ( window.innerWidth * pixelRatio ), 1 / ( window.innerHeight * pixelRatio ) );
composer = new EffectComposer( renderer );
composer.setPixelRatio( pixelRatio );
composer.addPass( renderPass );
composer.addPass( bloomPass );
composer.addPass( fxaaPass );
composer.addPass( outputPass );
composer.addPass( fxaaPass );
composer.addPass( fxaaPass );
} else {
if ( ! composer ) return;
composer.dispose();
composer = null;
bloomPass = null;
fxaaPass = null;
}
}
function createGUI() {
gui = new GUI();
gui.add( setting, 'roughness', 0, 1, 0.01 ).onChange( upMaterial );
gui.add( setting, 'metalness', 0, 1, 0.01 ).onChange( upMaterial );
gui.add( setting, 'opacity', 0, 1, 0.01 ).onChange( upMaterial );
//
gui.add( setting, 'postProcess' ).onChange( postProcess );
gui.add( setting, 'threshold', 0, 1, 0.01 ).onChange( upBloom );
gui.add( setting, 'strength', 0, 3, 0.01 ).onChange( upBloom );
gui.add( setting, 'radius', 0, 1, 0.01 ).onChange( upBloom );
}
function upMaterial() {
materials.Gold.metalness = materials.Silver.metalness = setting.metalness;
materials.Gold.roughness = materials.Silver.roughness = setting.roughness;
meshs.glass.material.opacity = setting.opacity;
}
function upBloom() {
if ( ! bloomPass ) return;
bloomPass.threshold = setting.threshold;
bloomPass.strength = setting.strength;
bloomPass.radius = setting.radius;
}
function getTime() {
const currentDate = new Date();
let hour = currentDate.getHours();
const minute = currentDate.getMinutes();
const second = currentDate.getSeconds();
let day = currentDate.getDay();
const month = currentDate.getMonth();
const milli = currentDate.getMilliseconds();
if ( hour >= 12 ) hour -= 12;
if ( day > 30 ) day = 30;
meshs.hour.rotation.y = - hour * 30 * torad;
meshs.minute.rotation.y = - minute * 6 * torad;
meshs.second.rotation.y = - second * 6 * torad;
meshs.mini_03.rotation.y = - day * 12 * torad;
meshs.mini_02.rotation.y = - month * 30 * torad;
meshs.mini_01.rotation.y = - milli * 0.36 * torad;
}
function onWindowResize() {
const width = window.innerWidth;
const height = window.innerHeight;
camera.aspect = width / height;
camera.updateProjectionMatrix();
renderer.setSize( width, height );
if ( composer ) {
composer.setSize( width, height );
if ( fxaaPass ) {
const pr = renderer.getPixelRatio();
fxaaPass.material.uniforms[ 'resolution' ].value.set( 1 / ( width * pr ), 1 / ( height * pr ) );
}
}
}
//
function animate() {
controls.update();
TWEEN.update();
if ( composer ) composer.render();
else renderer.render( scene, camera );
if ( ready ) getTime();
}
</script>
</body>
</html>