materials.html 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. Title: Three.js Materials
  2. Description: Materials in Three.js
  3. TOC: Materials
  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.
  8. Three.js provides several types of materials.
  9. They define how objects will appear in the scene.
  10. Which materials you use really depends on what you're trying to
  11. accomplish.
  12. There are 2 ways to set most material properties. One at creation time which
  13. we've seen before.
  14. ```js
  15. const material = new THREE.MeshPhongMaterial({
  16. color: 0xFF0000, // red (can also use a CSS color string here)
  17. flatShading: true,
  18. });
  19. ```
  20. The other is after creation
  21. ```js
  22. const material = new THREE.MeshPhongMaterial();
  23. material.color.setHSL(0, 1, .5); // red
  24. material.flatShading = true;
  25. ```
  26. note that properties of type `THREE.Color` have multiple ways to be set.
  27. ```js
  28. material.color.set(0x00FFFF); // same as CSS's #RRGGBB style
  29. material.color.set(cssString); // any CSS color, eg 'purple', '#F32',
  30. // 'rgb(255, 127, 64)',
  31. // 'hsl(180, 50%, 25%)'
  32. material.color.set(someColor) // some other THREE.Color
  33. material.color.setHSL(h, s, l) // where h, s, and l are 0 to 1
  34. material.color.setRGB(r, g, b) // where r, g, and b are 0 to 1
  35. ```
  36. And at creation time you can pass either a hex number or a CSS string
  37. ```js
  38. const m1 = new THREE.MeshBasicMaterial({color: 0xFF0000}); // red
  39. const m2 = new THREE.MeshBasicMaterial({color: 'red'}); // red
  40. const m3 = new THREE.MeshBasicMaterial({color: '#F00'}); // red
  41. const m4 = new THREE.MeshBasicMaterial({color: 'rgb(255,0,0)'}); // red
  42. const m5 = new THREE.MeshBasicMaterial({color: 'hsl(0,100%,50%)'); // red
  43. ```
  44. So let's go over three.js's set of materials.
  45. The `MeshBasicMaterial` is not affected by lights.
  46. The `MeshLambertMaterial` computes lighting only at the vertices vs the `MeshPhongMaterial` which computes lighting at every pixel. The `MeshPhongMaterial`
  47. also supports specular highlights.
  48. <div class="spread">
  49. <div>
  50. <div data-diagram="MeshBasicMaterial" ></div>
  51. <div class="code">Basic</div>
  52. </div>
  53. <div>
  54. <div data-diagram="MeshLambertMaterial" ></div>
  55. <div class="code">Lambert</div>
  56. </div>
  57. <div>
  58. <div data-diagram="MeshPhongMaterial" ></div>
  59. <div class="code">Phong</div>
  60. </div>
  61. </div>
  62. <div class="spread">
  63. <div>
  64. <div data-diagram="MeshBasicMaterialLowPoly" ></div>
  65. </div>
  66. <div>
  67. <div data-diagram="MeshLambertMaterialLowPoly" ></div>
  68. </div>
  69. <div>
  70. <div data-diagram="MeshPhongMaterialLowPoly" ></div>
  71. </div>
  72. </div>
  73. <div class="threejs_center code">low-poly models with same materials</div>
  74. The `shininess` setting of the `MeshPhongMaterial` determines the *shininess* of the specular highlight. It defaults to 30.
  75. <div class="spread">
  76. <div>
  77. <div data-diagram="MeshPhongMaterialShininess0" ></div>
  78. <div class="code">shininess: 0</div>
  79. </div>
  80. <div>
  81. <div data-diagram="MeshPhongMaterialShininess30" ></div>
  82. <div class="code">shininess: 30</div>
  83. </div>
  84. <div>
  85. <div data-diagram="MeshPhongMaterialShininess150" ></div>
  86. <div class="code">shininess: 150</div>
  87. </div>
  88. </div>
  89. Note that setting the `emissive` property to a color on either a
  90. `MeshLambertMaterial` or a `MeshPhongMaterial` and setting the `color` to black
  91. (and `shininess` to 0 for phong) ends up looking just like the `MeshBasicMaterial`.
  92. <div class="spread">
  93. <div>
  94. <div data-diagram="MeshBasicMaterialCompare" ></div>
  95. <div class="code">
  96. <div>Basic</div>
  97. <div>color: 'purple'</div>
  98. </div>
  99. </div>
  100. <div>
  101. <div data-diagram="MeshLambertMaterialCompare" ></div>
  102. <div class="code">
  103. <div>Lambert</div>
  104. <div>color: 'black'</div>
  105. <div>emissive: 'purple'</div>
  106. </div>
  107. </div>
  108. <div>
  109. <div data-diagram="MeshPhongMaterialCompare" ></div>
  110. <div class="code">
  111. <div>Phong</div>
  112. <div>color: 'black'</div>
  113. <div>emissive: 'purple'</div>
  114. <div>shininess: 0</div>
  115. </div>
  116. </div>
  117. </div>
  118. Why have all 3 when `MeshPhongMaterial` can do the same things as `MeshBasicMaterial`
  119. and `MeshLambertMaterial`? The reason is the more sophisticated material
  120. takes more GPU power to draw. On a slower GPU like say a mobile phone
  121. you might want to reduce the GPU power needed to draw your scene by
  122. using one of the less complex materials. It also follows that if you
  123. don't need the extra features then use the simplest material. If you don't
  124. need the lighting and the specular highlight then use the `MeshBasicMaterial`.
  125. The `MeshToonMaterial` is similar to the `MeshPhongMaterial`
  126. with one big difference. Rather than shading smoothly it uses a gradient map
  127. (an X by 1 texture) to decide how to shade. The default uses a gradient map
  128. that is 70% brightness for the first 70% and 100% after but you can supply your
  129. own gradient map. This ends up giving a 2 tone look that looks like a cartoon.
  130. <div class="spread">
  131. <div data-diagram="MeshToonMaterial"></div>
  132. </div>
  133. Next up there are 2 *physically based rendering* materials. Physically Based
  134. Rendering is often abbreviated PBR.
  135. The materials above use simple math to make materials that look 3D but they
  136. aren't what actually happens in real world. The 2 PBR materials use much more
  137. complex math to come close to what actually happens in the real world.
  138. The first one is `MeshStandardMaterial`. The biggest difference between
  139. `MeshPhongMaterial` and `MeshStandardMaterial` is it uses different parameters.
  140. `MeshPhongMaterial` had a `shininess` setting. `MeshStandardMaterial` has 2
  141. settings `roughness` and `metalness`.
  142. At a basic level [`roughness`](MeshStandardMaterial.roughness) is the opposite
  143. of `shininess`. Something that has a high roughness, like a baseball doesn't
  144. have hard reflections whereas something that's not rough, like a billiard ball,
  145. is very shiny. Roughness goes from 0 to 1.
  146. The other setting, [`metalness`](MeshStandardMaterial.metalness), says
  147. how metal the material is. Metals behave differently than non-metals. 0
  148. for non-metal and 1 for metal.
  149. Here's a quick sample of `MeshStandardMaterial` with `roughness` from 0 to 1
  150. across and `metalness` from 0 to 1 down.
  151. <div data-diagram="MeshStandardMaterial" style="min-height: 400px"></div>
  152. The `MeshPhysicalMaterial` is same as the `MeshStandardMaterial` but it
  153. adds a `clearcoat` parameter that goes from 0 to 1 for how much to
  154. apply a clearcoat gloss layer and a `clearCoatRoughness` parameter
  155. that specifies how rough the gloss layer is.
  156. Here's the same grid of `roughness` by `metalness` as above but with
  157. `clearcoat` and `clearCoatRoughness` settings.
  158. <div data-diagram="MeshPhysicalMaterial" style="min-height: 400px"></div>
  159. The various standard materials progress from fastest to slowest
  160. `MeshBasicMaterial` ➡ `MeshLambertMaterial` ➡ `MeshPhongMaterial` ➡
  161. `MeshStandardMaterial` ➡ `MeshPhysicalMaterial`. The slower materials
  162. can make more realistic looking scenes but you might need to design
  163. your code to use the faster materials on low powered or mobile machines.
  164. There are 3 materials that have special uses. `ShadowMaterial`
  165. is used to get the data created from shadows. We haven't
  166. covered shadows yet. When we do we'll use this material
  167. to take a peek at what's happening behind the scenes.
  168. The `MeshDepthMaterial` renders the depth of each pixel where
  169. pixels at negative [`near`](PerspectiveCamera.near) of the camera are 0 and negative [`far`](PerspectiveCamera.far) are 1. Certain special effects can use this data which we'll
  170. get into at another time.
  171. <div class="spread">
  172. <div>
  173. <div data-diagram="MeshDepthMaterial"></div>
  174. </div>
  175. </div>
  176. The `MeshNormalMaterial` will show you the *normals* of geometry.
  177. *Normals* are the direction a particular triangle or pixel faces.
  178. `MeshNormalMaterial` draws the view space normals (the normals relative to the camera).
  179. <span style="background: red;" class="color">x is red</span>,
  180. <span style="background: green;" class="dark-color">y is green</span>, and
  181. <span style="background: blue;" class="dark-color">z is blue</span> so things facing
  182. to the right will be <span style="background: #FF7F7F;" class="color">pink</span>,
  183. to the left will be <span style="background: #007F7F;" class="dark-color">aqua</span>,
  184. up will be <span style="background: #7FFF7F;" class="color">light green</span>,
  185. down will be <span style="background: #7F007F;" class="dark-color">purple</span>,
  186. and toward the screen will be <span style="background: #7F7FFF;" class="color">lavender</span>.
  187. <div class="spread">
  188. <div>
  189. <div data-diagram="MeshNormalMaterial"></div>
  190. </div>
  191. </div>
  192. `ShaderMaterial` is for making custom materials using the three.js shader
  193. system. `RawShaderMaterial` is for making entirely custom shaders with
  194. no help from three.js. Both of these topics are large and will be
  195. covered later.
  196. Most materials share a bunch of settings all defined by `Material`.
  197. [See the docs](Material)
  198. for all of them but let's go over two of the most commonly used
  199. properties.
  200. [`flatShading`](Material.flatShading):
  201. whether or not the object looks faceted or smooth. default = `false`.
  202. <div class="spread">
  203. <div>
  204. <div data-diagram="smoothShading"></div>
  205. <div class="code">flatShading: false</div>
  206. </div>
  207. <div>
  208. <div data-diagram="flatShading"></div>
  209. <div class="code">flatShading: true</div>
  210. </div>
  211. </div>
  212. [`side`](Material.side): which sides of triangles to show. The default is `THREE.FrontSide`.
  213. Other options are `THREE.BackSide` and `THREE.DoubleSide` (both sides).
  214. Most 3D objects drawn in three are probably opaque solids so the back sides
  215. (the sides facing inside the solid) do not need to be drawn. The most common
  216. reason to set `side` is for planes or other non-solid objects where it is
  217. common to see the back sides of triangles.
  218. Here are 6 planes drawn with `THREE.FrontSide` and `THREE.DoubleSide`.
  219. <div class="spread">
  220. <div>
  221. <div data-diagram="sideDefault" style="height: 250px;"></div>
  222. <div class="code">side: THREE.FrontSide</div>
  223. </div>
  224. <div>
  225. <div data-diagram="sideDouble" style="height: 250px;"></div>
  226. <div class="code">side: THREE.DoubleSide</div>
  227. </div>
  228. </div>
  229. There's really a lot to consider with materials and we actually still
  230. have a bunch more to go. In particular we've mostly ignored textures
  231. which open up a whole slew of options. Before we cover textures though
  232. we need to take a break and cover
  233. [setting up your development environment](threejs-setup.html)
  234. <div class="threejs_bottombar">
  235. <h3>material.needsUpdate</h3>
  236. <p>
  237. This topic rarely affects most three.js apps but just as an FYI...
  238. Three.js applies material settings when a material is used where "used"
  239. means "something is rendered that uses the material". Some material settings are
  240. only applied once as changing them requires lots of work by three.js.
  241. In those cases you need to set <code>material.needsUpdate = true</code> to tell
  242. three.js to apply your material changes. The most common settings
  243. that require you to set <code>needsUpdate</code> if you change the settings after
  244. using the material are:
  245. </p>
  246. <ul>
  247. <li><code>flatShading</code></li>
  248. <li>adding or removing a texture
  249. <p>
  250. Changing a texture is ok, but if want to switch from using no texture
  251. to using a texture or from using a texture to using no texture
  252. then you need to set <code>needsUpdate = true</code>.
  253. </p>
  254. <p>In the case of going from texture to no-texture it is often
  255. just better to use a 1x1 pixel white texture.</p>
  256. </li>
  257. </ul>
  258. <p>As mentioned above most apps never run into these issues. Most apps
  259. do not switch between flat shaded and non flat shaded. Most apps also
  260. either use textures or a solid color for a given material, they rarely
  261. switch from using one to using the other.
  262. </p>
  263. </div>
  264. <canvas id="c"></canvas>
  265. <script type="module" src="resources/threejs-materials.js"></script>