fog.html 8.8 KB

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