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); }, }, }); }