fog.html 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. <!DOCTYPE html><html lang="en"><head>
  2. <meta charset="utf-8">
  3. <title>Fog</title>
  4. <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
  5. <meta name="twitter:card" content="summary_large_image">
  6. <meta name="twitter:site" content="@threejs">
  7. <meta name="twitter:title" content="Three.js – Fog">
  8. <meta property="og:image" content="https://threejs.org/files/share.png">
  9. <link rel="shortcut icon" href="../../files/favicon_white.ico" media="(prefers-color-scheme: dark)">
  10. <link rel="shortcut icon" href="../../files/favicon.ico" media="(prefers-color-scheme: light)">
  11. <link rel="stylesheet" href="../resources/lesson.css">
  12. <link rel="stylesheet" href="../resources/lang.css">
  13. <!-- Import maps polyfill -->
  14. <!-- Remove this when import maps will be widely supported -->
  15. <script async src="https://unpkg.com/[email protected]/dist/es-module-shims.js"></script>
  16. <script type="importmap">
  17. {
  18. "imports": {
  19. "three": "../../build/three.module.js"
  20. }
  21. }
  22. </script>
  23. </head>
  24. <body>
  25. <div class="container">
  26. <div class="lesson-title">
  27. <h1>Fog</h1>
  28. </div>
  29. <div class="lesson">
  30. <div class="lesson-main">
  31. <p>This article is part of a series of articles about three.js. The
  32. first article is <a href="fundamentals.html">three.js fundamentals</a>. If
  33. you haven't read that yet and you're new to three.js you might want to
  34. consider starting there. If you haven't read about cameras you might
  35. want to start with <a href="cameras.html">this article</a>.</p>
  36. <p>Fog in a 3D engine is generally a way of fading to a specific color
  37. based on the distance from the camera. In three.js you add fog by
  38. creating <a href="/docs/#api/en/scenes/Fog"><code class="notranslate" translate="no">Fog</code></a> or <a href="/docs/#api/en/scenes/FogExp2"><code class="notranslate" translate="no">FogExp2</code></a> object and setting it on the scene's
  39. <a href="/docs/#api/en/scenes/Scene#fog"><code class="notranslate" translate="no">fog</code></a> property.</p>
  40. <p><a href="/docs/#api/en/scenes/Fog"><code class="notranslate" translate="no">Fog</code></a> lets you choose <code class="notranslate" translate="no">near</code> and <code class="notranslate" translate="no">far</code> settings which are distances
  41. from the camera. Anything closer than <code class="notranslate" translate="no">near</code> is unaffected by fog.
  42. Anything further than <code class="notranslate" translate="no">far</code> is completely the fog color. Parts between
  43. <code class="notranslate" translate="no">near</code> and <code class="notranslate" translate="no">far</code> fade from their material color to the fog color.</p>
  44. <p>There's also <a href="/docs/#api/en/scenes/FogExp2"><code class="notranslate" translate="no">FogExp2</code></a> which grows exponentially with distance from the camera.</p>
  45. <p>To use either type of fog you create one and and assign it to the scene as in</p>
  46. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">const scene = new THREE.Scene();
  47. {
  48. const color = 0xFFFFFF; // white
  49. const near = 10;
  50. const far = 100;
  51. scene.fog = new THREE.Fog(color, near, far);
  52. }
  53. </pre>
  54. <p>or for <a href="/docs/#api/en/scenes/FogExp2"><code class="notranslate" translate="no">FogExp2</code></a> it would be</p>
  55. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">const scene = new THREE.Scene();
  56. {
  57. const color = 0xFFFFFF;
  58. const density = 0.1;
  59. scene.fog = new THREE.FogExp2(color, density);
  60. }
  61. </pre>
  62. <p><a href="/docs/#api/en/scenes/FogExp2"><code class="notranslate" translate="no">FogExp2</code></a> is closer to reality but <a href="/docs/#api/en/scenes/Fog"><code class="notranslate" translate="no">Fog</code></a> is used
  63. more commonly since it lets you choose a place to apply
  64. the fog so you can decide to show a clear scene
  65. up to a certain distance and then fade out to some color
  66. past that distance.</p>
  67. <div class="spread">
  68. <div>
  69. <div data-diagram="fog" style="height: 300px;"></div>
  70. <div class="code">THREE.Fog</div>
  71. </div>
  72. <div>
  73. <div data-diagram="fogExp2" style="height: 300px;"></div>
  74. <div class="code">THREE.FogExp2</div>
  75. </div>
  76. </div>
  77. <p>It's important to note that the fog is applied to <em>things that are rendered</em>.
  78. It is part of the calculation of each pixel of the color of the object.
  79. What that means is if you want your scene to fade to a certain color you
  80. need to set the fog <strong>and</strong> the background color to the same color.
  81. The background color is set using the
  82. <a href="/docs/#api/en/scenes/Scene#background"><code class="notranslate" translate="no">scene.background</code></a>
  83. property. To pick a background color you attach a <a href="/docs/#api/en/math/Color"><code class="notranslate" translate="no">THREE.Color</code></a> to it. For example</p>
  84. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">scene.background = new THREE.Color('#F00'); // red
  85. </pre>
  86. <div class="spread">
  87. <div>
  88. <div data-diagram="fogBlueBackgroundRed" style="height: 300px;" class="border"></div>
  89. <div class="code">fog blue, background red</div>
  90. </div>
  91. <div>
  92. <div data-diagram="fogBlueBackgroundBlue" style="height: 300px;" class="border"></div>
  93. <div class="code">fog blue, background blue</div>
  94. </div>
  95. </div>
  96. <p>Here is one of our previous examples with fog added. The only addition
  97. is right after setting up the scene we add the fog and set the scene's
  98. background color</p>
  99. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">const scene = new THREE.Scene();
  100. +{
  101. + const near = 1;
  102. + const far = 2;
  103. + const color = 'lightblue';
  104. + scene.fog = new THREE.Fog(color, near, far);
  105. + scene.background = new THREE.Color(color);
  106. +}
  107. </pre>
  108. <p>In the example below the camera's <code class="notranslate" translate="no">near</code> is 0.1 and its <code class="notranslate" translate="no">far</code> is 5.
  109. The camera is at <code class="notranslate" translate="no">z = 2</code>. The cubes are 1 unit large and at Z = 0.
  110. This means with a fog setting of <code class="notranslate" translate="no">near = 1</code> and <code class="notranslate" translate="no">far = 2</code> the cubes
  111. will fade out right around their center.</p>
  112. <p></p><div translate="no" class="threejs_example_container notranslate">
  113. <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/fog.html"></iframe></div>
  114. <a class="threejs_center" href="/manual/examples/fog.html" target="_blank">click here to open in a separate window</a>
  115. </div>
  116. <p></p>
  117. <p>Let's add an interface so we can adjust the fog. Again we'll use
  118. <a href="https://github.com/georgealways/lil-gui">lil-gui</a>. lil-gui takes
  119. an object and a property and automagically makes an interface
  120. for that type of property. We could just simply let it manipulate
  121. the fog's <code class="notranslate" translate="no">near</code> and <code class="notranslate" translate="no">far</code> properties but it's invalid to have
  122. <code class="notranslate" translate="no">near</code> be greater than <code class="notranslate" translate="no">far</code> so let's make a helper so lil-gui
  123. can manipulate a <code class="notranslate" translate="no">near</code> and <code class="notranslate" translate="no">far</code> property but we'll make sure <code class="notranslate" translate="no">near</code>
  124. is less than or equal to <code class="notranslate" translate="no">far</code> and <code class="notranslate" translate="no">far</code> is greater than or equal <code class="notranslate" translate="no">near</code>.</p>
  125. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">// We use this class to pass to lil-gui
  126. // so when it manipulates near or far
  127. // near is never &gt; far and far is never &lt; near
  128. class FogGUIHelper {
  129. constructor(fog) {
  130. this.fog = fog;
  131. }
  132. get near() {
  133. return this.fog.near;
  134. }
  135. set near(v) {
  136. this.fog.near = v;
  137. this.fog.far = Math.max(this.fog.far, v);
  138. }
  139. get far() {
  140. return this.fog.far;
  141. }
  142. set far(v) {
  143. this.fog.far = v;
  144. this.fog.near = Math.min(this.fog.near, v);
  145. }
  146. }
  147. </pre>
  148. <p>We can then add it like this</p>
  149. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">{
  150. const near = 1;
  151. const far = 2;
  152. const color = 'lightblue';
  153. scene.fog = new THREE.Fog(color, near, far);
  154. scene.background = new THREE.Color(color);
  155. +
  156. + const fogGUIHelper = new FogGUIHelper(scene.fog);
  157. + gui.add(fogGUIHelper, 'near', near, far).listen();
  158. + gui.add(fogGUIHelper, 'far', near, far).listen();
  159. }
  160. </pre>
  161. <p>The <code class="notranslate" translate="no">near</code> and <code class="notranslate" translate="no">far</code> parameters set the minimum and maximum values
  162. for adjusting the fog. They are set when we setup the camera.</p>
  163. <p>The <code class="notranslate" translate="no">.listen()</code> at the end of the last 2 lines tells lil-gui to <em>listen</em>
  164. for changes. That way when we change <code class="notranslate" translate="no">near</code> because of an edit to <code class="notranslate" translate="no">far</code>
  165. or we change <code class="notranslate" translate="no">far</code> in response to an edit to <code class="notranslate" translate="no">near</code> lil-gui will update
  166. the other property's UI for us.</p>
  167. <p>It might also be nice to be able to change the fog color but like was
  168. mentioned above we need to keep both the fog color and the background
  169. color in sync. So, let's add another <em>virtual</em> property to our helper
  170. that will set both colors when lil-gui manipulates it.</p>
  171. <p>lil-gui can manipulate colors in 4 ways, as a CSS 6 digit hex string (eg: <code class="notranslate" translate="no">#112233</code>). As an hue, saturation, value, object (eg: <code class="notranslate" translate="no">{h: 60, s: 1, v: }</code>).
  172. As an RGB array (eg: <code class="notranslate" translate="no">[255, 128, 64]</code>). Or, as an RGBA array (eg: <code class="notranslate" translate="no">[127, 200, 75, 0.3]</code>).</p>
  173. <p>It's easiest for our purpose to use the hex string version since that way
  174. lil-gui is only manipulating a single value. Fortunately <a href="/docs/#api/en/math/Color"><code class="notranslate" translate="no">THREE.Color</code></a>
  175. as a <a href="/docs/#api/en/math/Color#getHexString"><code class="notranslate" translate="no">getHexString</code></a> method
  176. we get use to easily get such a string, we just have to prepend a '#' to the front.</p>
  177. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">// We use this class to pass to lil-gui
  178. // so when it manipulates near or far
  179. // near is never &gt; far and far is never &lt; near
  180. +// Also when lil-gui manipulates color we'll
  181. +// update both the fog and background colors.
  182. class FogGUIHelper {
  183. * constructor(fog, backgroundColor) {
  184. this.fog = fog;
  185. + this.backgroundColor = backgroundColor;
  186. }
  187. get near() {
  188. return this.fog.near;
  189. }
  190. set near(v) {
  191. this.fog.near = v;
  192. this.fog.far = Math.max(this.fog.far, v);
  193. }
  194. get far() {
  195. return this.fog.far;
  196. }
  197. set far(v) {
  198. this.fog.far = v;
  199. this.fog.near = Math.min(this.fog.near, v);
  200. }
  201. + get color() {
  202. + return `#${this.fog.color.getHexString()}`;
  203. + }
  204. + set color(hexString) {
  205. + this.fog.color.set(hexString);
  206. + this.backgroundColor.set(hexString);
  207. + }
  208. }
  209. </pre>
  210. <p>We then call <code class="notranslate" translate="no">gui.addColor</code> to add a color UI for our helper's virtual property.</p>
  211. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">{
  212. const near = 1;
  213. const far = 2;
  214. const color = 'lightblue';
  215. scene.fog = new THREE.Fog(color, near, far);
  216. scene.background = new THREE.Color(color);
  217. * const fogGUIHelper = new FogGUIHelper(scene.fog, scene.background);
  218. gui.add(fogGUIHelper, 'near', near, far).listen();
  219. gui.add(fogGUIHelper, 'far', near, far).listen();
  220. + gui.addColor(fogGUIHelper, 'color');
  221. }
  222. </pre>
  223. <p></p><div translate="no" class="threejs_example_container notranslate">
  224. <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/fog-gui.html"></iframe></div>
  225. <a class="threejs_center" href="/manual/examples/fog-gui.html" target="_blank">click here to open in a separate window</a>
  226. </div>
  227. <p></p>
  228. <p>You can see setting <code class="notranslate" translate="no">near</code> to like 1.9 and <code class="notranslate" translate="no">far</code> to 2.0 gives
  229. a very sharp transition between un-fogged and completely fogged.
  230. where as <code class="notranslate" translate="no">near</code> = 1.1 and <code class="notranslate" translate="no">far</code> = 2.9 should just about be
  231. the smoothest given our cubes are spinning 2 units away from the camera.</p>
  232. <p>One last thing, there is a boolean <a href="/docs/#api/en/materials/Material#fog"><code class="notranslate" translate="no">fog</code></a>
  233. property on a material for whether or not objects rendered
  234. with that material are affected by fog. It defaults to <code class="notranslate" translate="no">true</code>
  235. for most materials. As an example of why you might want
  236. to turn the fog off, imagine you're making a 3D vehicle
  237. simulator with a view from the driver's seat or cockpit.
  238. You probably want the fog off for everything inside the vehicle when
  239. viewing from inside the vehicle.</p>
  240. <p>A better example might be a house
  241. and thick fog outside house. Let's say the fog is set to start
  242. 2 meters away (near = 2) and completely fogged out at 4 meters (far = 4).
  243. Rooms are longer than 2 meters and the house is probably longer
  244. than 4 meters so you need to set the materials for the inside
  245. of the house to not apply fog otherwise when standing inside the
  246. house looking outside the wall at the far end of the room will look
  247. like it's in the fog.</p>
  248. <div class="spread">
  249. <div>
  250. <div data-diagram="fogHouseAll" style="height: 300px;" class="border"></div>
  251. <div class="code">fog: true, all</div>
  252. </div>
  253. </div>
  254. <p>Notice the walls and ceiling at the far end of the room are getting fog applied.
  255. By turning fog off on the materials for the house we can fix that issue.</p>
  256. <div class="spread">
  257. <div>
  258. <div data-diagram="fogHouseInsideNoFog" style="height: 300px;" class="border"></div>
  259. <div class="code">fog: true, only outside materials</div>
  260. </div>
  261. </div>
  262. <p><canvas id="c"></canvas></p>
  263. <script type="module" src="../resources/threejs-fog.js"></script>
  264. </div>
  265. </div>
  266. </div>
  267. <script src="../resources/prettify.js"></script>
  268. <script src="../resources/lesson.js"></script>
  269. </body></html>