threejs-fog.js 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. import * as THREE from 'three';
  2. import {GLTFLoader} from '../../examples/jsm/loaders/GLTFLoader.js';
  3. import {threejsLessonUtils} from './threejs-lesson-utils.js';
  4. {
  5. const darkColors = {
  6. background: '#333',
  7. };
  8. const lightColors = {
  9. background: '#FFF',
  10. };
  11. const darkMatcher = window.matchMedia('(prefers-color-scheme: dark)');
  12. function fogExample(scene, fog, update) {
  13. scene.fog = fog;
  14. const width = 4;
  15. const height = 3;
  16. const depth = 10;
  17. const geometry = new THREE.BoxGeometry(width, height, depth);
  18. const material = new THREE.MeshPhongMaterial({color: 'hsl(130,50%,50%)'});
  19. return {
  20. obj3D: new THREE.Mesh(geometry, material),
  21. update,
  22. };
  23. }
  24. function houseScene(props, fogInHouse) {
  25. const {scene, camera} = props;
  26. scene.background = new THREE.Color('#FFF');
  27. camera.far = 200;
  28. const loader = new GLTFLoader();
  29. const settings = {
  30. shininess: 0,
  31. roughness: 1,
  32. metalness: 0,
  33. };
  34. loader.load('/manual/examples/resources/models/simple_house_scene/scene.gltf', (gltf) => {
  35. const hackGeometry = new THREE.CircleGeometry(0.5, 32);
  36. const box = new THREE.Box3();
  37. const size = new THREE.Vector3();
  38. const center = new THREE.Vector3();
  39. const materials = new Set();
  40. gltf.scene.traverse((node) => {
  41. const material = node.material;
  42. if (material) {
  43. // hack in the bottom of the trees since I don't have
  44. // the model file
  45. if (node.name === 'mesh_11' || node.name === 'mesh_6') {
  46. node.updateWorldMatrix(true, false);
  47. box.setFromObject(node);
  48. box.getSize(size);
  49. box.getCenter(center);
  50. const hackMesh = new THREE.Mesh(hackGeometry, node.material);
  51. scene.add(hackMesh);
  52. hackMesh.position.copy(center);
  53. hackMesh.rotation.x = Math.PI * 0.5;
  54. hackMesh.position.y -= size.y / 2;
  55. hackMesh.scale.set(size.x, size.z, 1);
  56. }
  57. (Array.isArray(material) ? material : [material]).forEach((material) => {
  58. if (!materials.has(material)) {
  59. materials.add(material);
  60. for (const [key, value] of Object.entries(settings)) {
  61. if (material[key] !== undefined) {
  62. material[key] = value;
  63. }
  64. }
  65. if (!fogInHouse && material.name.startsWith('fogless')) {
  66. material.fog = false;
  67. }
  68. }
  69. });
  70. }
  71. });
  72. scene.add(gltf.scene);
  73. });
  74. camera.fov = 45;
  75. camera.position.set(0.4, 1, 1.7);
  76. camera.lookAt(1, 1, 0.7);
  77. const color = 0xFFFFFF;
  78. const near = 1.5;
  79. const far = 5;
  80. scene.fog = new THREE.Fog(color, near, far);
  81. const light = new THREE.PointLight(0xFFFFFF, 1);
  82. light.position.copy(camera.position);
  83. light.position.y += 0.2;
  84. scene.add(light);
  85. const target = [1, 1, 0.7];
  86. return {
  87. trackball: false,
  88. obj3D: new THREE.Object3D(),
  89. update: (time) => {
  90. camera.lookAt(target[0] + Math.sin(time * .25) * .5, target[1], target[2]);
  91. },
  92. };
  93. }
  94. function createLightDarkFogUpdater(fog) {
  95. return function() {
  96. const isDarkMode = darkMatcher.matches;
  97. const colors = isDarkMode ? darkColors : lightColors;
  98. fog.color.set(colors.background);
  99. };
  100. }
  101. threejsLessonUtils.addDiagrams({
  102. fog: {
  103. create(props) {
  104. const {scene} = props;
  105. const color = 0xFFFFFF;
  106. const near = 12;
  107. const far = 18;
  108. const fog = new THREE.Fog(color, near, far);
  109. return fogExample(scene, fog, createLightDarkFogUpdater(fog));
  110. },
  111. },
  112. fogExp2: {
  113. create(props) {
  114. const {scene} = props;
  115. const color = 0xFFFFFF;
  116. const density = 0.1;
  117. const fog = new THREE.FogExp2(color, density);
  118. return fogExample(scene, fog, createLightDarkFogUpdater(fog));
  119. },
  120. },
  121. fogBlueBackgroundRed: {
  122. create(props) {
  123. const {scene} = props;
  124. scene.background = new THREE.Color('#F00');
  125. const color = '#00F';
  126. const near = 12;
  127. const far = 18;
  128. return fogExample(scene, new THREE.Fog(color, near, far));
  129. },
  130. },
  131. fogBlueBackgroundBlue: {
  132. create(props) {
  133. const {scene} = props;
  134. scene.background = new THREE.Color('#00F');
  135. const color = '#00F';
  136. const near = 12;
  137. const far = 18;
  138. return fogExample(scene, new THREE.Fog(color, near, far));
  139. },
  140. },
  141. fogHouseAll: {
  142. create(props) {
  143. return houseScene(props, true);
  144. },
  145. },
  146. fogHouseInsideNoFog: {
  147. create(props) {
  148. return houseScene(props, false);
  149. },
  150. },
  151. });
  152. }