import * as THREE from 'three'; import { GLTFLoader } from '../../examples/jsm/loaders/GLTFLoader.js'; import { threejsLessonUtils } from './threejs-lesson-utils.js'; { const darkColors = { background: '#333', }; const lightColors = { background: '#FFF', }; const darkMatcher = window.matchMedia( '(prefers-color-scheme: dark)' ); function fogExample( scene, fog, update ) { scene.fog = fog; const width = 4; const height = 3; const depth = 10; const geometry = new THREE.BoxGeometry( width, height, depth ); const material = new THREE.MeshPhongMaterial( { color: 'hsl(130,50%,50%)' } ); return { obj3D: new THREE.Mesh( geometry, material ), update, }; } function houseScene( props, fogInHouse ) { const { scene, camera } = props; scene.background = new THREE.Color( '#FFF' ); camera.far = 200; const loader = new GLTFLoader(); const settings = { shininess: 0, roughness: 1, metalness: 0, }; loader.load( '/manual/examples/resources/models/simple_house_scene/scene.gltf', ( gltf ) => { const hackGeometry = new THREE.CircleGeometry( 0.5, 32 ); const box = new THREE.Box3(); const size = new THREE.Vector3(); const center = new THREE.Vector3(); const materials = new Set(); gltf.scene.traverse( ( node ) => { const material = node.material; if ( material ) { // hack in the bottom of the trees since I don't have // the model file if ( node.name === 'mesh_11' || node.name === 'mesh_6' ) { node.updateWorldMatrix( true, false ); box.setFromObject( node ); box.getSize( size ); box.getCenter( center ); const hackMesh = new THREE.Mesh( hackGeometry, node.material ); scene.add( hackMesh ); hackMesh.position.copy( center ); hackMesh.rotation.x = Math.PI * 0.5; hackMesh.position.y -= size.y / 2; hackMesh.scale.set( size.x, size.z, 1 ); } ( Array.isArray( material ) ? material : [ material ] ).forEach( ( material ) => { if ( ! materials.has( material ) ) { materials.add( material ); for ( const [ key, value ] of Object.entries( settings ) ) { if ( material[ key ] !== undefined ) { material[ key ] = value; } } if ( ! fogInHouse && material.name.startsWith( 'fogless' ) ) { material.fog = false; } } } ); } } ); scene.add( gltf.scene ); } ); camera.fov = 45; camera.position.set( 0.4, 1, 1.7 ); camera.lookAt( 1, 1, 0.7 ); const color = 0xFFFFFF; const near = 1.5; const far = 5; scene.fog = new THREE.Fog( color, near, far ); const light = new THREE.PointLight( 0xFFFFFF, 1 ); light.position.copy( camera.position ); light.position.y += 0.2; scene.add( light ); const target = [ 1, 1, 0.7 ]; return { trackball: false, obj3D: new THREE.Object3D(), update: ( time ) => { camera.lookAt( target[ 0 ] + Math.sin( time * .25 ) * .5, target[ 1 ], target[ 2 ] ); }, }; } function createLightDarkFogUpdater( fog ) { return function () { const isDarkMode = darkMatcher.matches; const colors = isDarkMode ? darkColors : lightColors; fog.color.set( colors.background ); }; } threejsLessonUtils.addDiagrams( { fog: { create( props ) { const { scene } = props; const color = 0xFFFFFF; const near = 12; const far = 18; const fog = new THREE.Fog( color, near, far ); return fogExample( scene, fog, createLightDarkFogUpdater( fog ) ); }, }, fogExp2: { create( props ) { const { scene } = props; const color = 0xFFFFFF; const density = 0.1; const fog = new THREE.FogExp2( color, density ); return fogExample( scene, fog, createLightDarkFogUpdater( fog ) ); }, }, fogBlueBackgroundRed: { create( props ) { const { scene } = props; scene.background = new THREE.Color( '#F00' ); const color = '#00F'; const near = 12; const far = 18; return fogExample( scene, new THREE.Fog( color, near, far ) ); }, }, fogBlueBackgroundBlue: { create( props ) { const { scene } = props; scene.background = new THREE.Color( '#00F' ); const color = '#00F'; const near = 12; const far = 18; return fogExample( scene, new THREE.Fog( color, near, far ) ); }, }, fogHouseAll: { create( props ) { return houseScene( props, true ); }, }, fogHouseInsideNoFog: { create( props ) { return houseScene( props, false ); }, }, } ); }