MeshPhongMaterial
Video Lecture
Description
In this lecture we experiment with the Three.js MeshPhongMaterial.
It uses the Blinn–Phong reflection model,
It is useful for simulating shiny objects such as polished wood.
It is more computationally-expensive to use than the MeshLambertMaterial, MeshNormalMaterial and MeshBasicMaterial so if performance need to be considered, then one option you have is to only use it when necessary.
Start Code
./src/client/client.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | // If using Relative Import References import * as THREE from '/build/three.module.js' import { OrbitControls } from '/jsm/controls/OrbitControls' import Stats from '/jsm/libs/stats.module' import { GUI } from '/jsm/libs/dat.gui.module' // If using Module Specifiers //import * as THREE from 'three' //import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls' //import Stats from 'three/examples/jsm/libs/stats.module' //import { GUI } from 'three/examples/jsm/libs/dat.gui.module' const scene: THREE.Scene = new THREE.Scene() //scene.background = new THREE.Color(0xff0000) const axesHelper = new THREE.AxesHelper(5) scene.add(axesHelper) const light = new THREE.PointLight(0xffffff, 2); light.position.set(10, 10, 10); scene.add(light); const camera: THREE.PerspectiveCamera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000) const renderer: THREE.WebGLRenderer = new THREE.WebGLRenderer() renderer.setSize(window.innerWidth, window.innerHeight) document.body.appendChild(renderer.domElement) const controls = new OrbitControls(camera, renderer.domElement) //controls.addEventListener('change', render) const boxGeometry: THREE.BoxGeometry = new THREE.BoxGeometry() const sphereGeometry: THREE.SphereGeometry = new THREE.SphereGeometry() const icosahedronGeometry: THREE.IcosahedronGeometry = new THREE.IcosahedronGeometry(1, 0) const planeGeometry: THREE.PlaneGeometry = new THREE.PlaneGeometry() const torusKnotGeometry: THREE.TorusKnotGeometry = new THREE.TorusKnotGeometry() const material: THREE.MeshPhongMaterial = new THREE.MeshPhongMaterial() // const texture = new THREE.TextureLoader().load("img/grid.png") // material.map = texture // const envTexture = new THREE.CubeTextureLoader().load(["img/px_50.png", "img/nx_50.png", "img/py_50.png", "img/ny_50.png", "img/pz_50.png", "img/nz_50.png"]) // envTexture.mapping = THREE.CubeReflectionMapping // envTexture.mapping = THREE.CubeRefractionMapping // material.envMap = envTexture const cube: THREE.Mesh = new THREE.Mesh(boxGeometry, material) cube.position.x = 5 scene.add(cube) const sphere: THREE.Mesh = new THREE.Mesh(sphereGeometry, material) sphere.position.x = 3 scene.add(sphere) const icosahedron: THREE.Mesh = new THREE.Mesh(icosahedronGeometry, material) icosahedron.position.x = 0 scene.add(icosahedron) const plane: THREE.Mesh = new THREE.Mesh(planeGeometry, material) plane.position.x = -2 scene.add(plane) const torusKnot: THREE.Mesh = new THREE.Mesh(torusKnotGeometry, material) torusKnot.position.x = -5 scene.add(torusKnot) camera.position.z = 3 window.addEventListener('resize', onWindowResize, false) function onWindowResize() { camera.aspect = window.innerWidth / window.innerHeight camera.updateProjectionMatrix() renderer.setSize(window.innerWidth, window.innerHeight) render() } const stats = Stats() document.body.appendChild(stats.dom) var options = { side: { "FrontSide": THREE.FrontSide, "BackSide": THREE.BackSide, "DoubleSide": THREE.DoubleSide, }, combine: { "MultiplyOperation": THREE.MultiplyOperation, "MixOperation": THREE.MixOperation, "AddOperation": THREE.AddOperation }, } const gui = new GUI() const materialFolder = gui.addFolder('THREE.Material') materialFolder.add(material, 'transparent') materialFolder.add(material, 'opacity', 0, 1, 0.01) materialFolder.add(material, 'depthTest') materialFolder.add(material, 'depthWrite') materialFolder.add(material, 'alphaTest', 0, 1, 0.01).onChange(() => updateMaterial()) materialFolder.add(material, 'visible') materialFolder.add(material, 'side', options.side).onChange(() => updateMaterial()) materialFolder.open() var data = { color: material.color.getHex(), emissive: material.emissive.getHex(), //specular: material.specular.getHex() }; var meshPhongMaterialFolder = gui.addFolder('THREE.MeshPhongMaterial'); meshPhongMaterialFolder.addColor(data, 'color').onChange(() => { material.color.setHex(Number(data.color.toString().replace('#', '0x'))) }); meshPhongMaterialFolder.addColor(data, 'emissive').onChange(() => { material.emissive.setHex(Number(data.emissive.toString().replace('#', '0x'))) }); //meshPhongMaterialFolder.addColor(data, 'specular').onChange(() => { material.specular.setHex(Number(data.specular.toString().replace('#', '0x'))) }); //meshPhongMaterialFolder.add(material, 'shininess', 0, 1024); meshPhongMaterialFolder.add(material, 'wireframe'); meshPhongMaterialFolder.add(material, 'wireframeLinewidth', 0, 10); meshPhongMaterialFolder.add(material, 'flatShading').onChange(() => updateMaterial()) meshPhongMaterialFolder.add(material, 'combine', options.combine).onChange(() => updateMaterial()) meshPhongMaterialFolder.add(material, 'reflectivity', 0, 1); meshPhongMaterialFolder.add(material, 'refractionRatio', 0, 1); meshPhongMaterialFolder.open() function updateMaterial() { material.side = Number(material.side) material.combine = Number(material.combine) material.needsUpdate = true } var animate = function () { requestAnimationFrame(animate) render() stats.update() }; function render() { renderer.render(scene, camera) } animate(); |
Final Code
./src/client/client.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | // If using Relative Import References import * as THREE from '/build/three.module.js' import { OrbitControls } from '/jsm/controls/OrbitControls' import Stats from '/jsm/libs/stats.module' import { GUI } from '/jsm/libs/dat.gui.module' // If using Module Specifiers //import * as THREE from 'three' //import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls' //import Stats from 'three/examples/jsm/libs/stats.module' //import { GUI } from 'three/examples/jsm/libs/dat.gui.module' const scene: THREE.Scene = new THREE.Scene() //scene.background = new THREE.Color(0xff0000) const axesHelper = new THREE.AxesHelper(5) scene.add(axesHelper) const light = new THREE.PointLight(0xffffff, 2); light.position.set(10, 10, 10); scene.add(light); const light2 = new THREE.PointLight(0xffffff, 2); light2.position.set(-10, -10, -10); scene.add(light2); const camera: THREE.PerspectiveCamera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000) const renderer: THREE.WebGLRenderer = new THREE.WebGLRenderer() renderer.setSize(window.innerWidth, window.innerHeight) document.body.appendChild(renderer.domElement) const controls = new OrbitControls(camera, renderer.domElement) //controls.addEventListener('change', render) const boxGeometry: THREE.BoxGeometry = new THREE.BoxGeometry() const sphereGeometry: THREE.SphereGeometry = new THREE.SphereGeometry() const icosahedronGeometry: THREE.IcosahedronGeometry = new THREE.IcosahedronGeometry(1, 0) const planeGeometry: THREE.PlaneGeometry = new THREE.PlaneGeometry() const torusKnotGeometry: THREE.TorusKnotGeometry = new THREE.TorusKnotGeometry() const material: THREE.MeshPhongMaterial = new THREE.MeshPhongMaterial() const texture = new THREE.TextureLoader().load("img/grid.png") material.map = texture const envTexture = new THREE.CubeTextureLoader().load(["img/px_50.png", "img/nx_50.png", "img/py_50.png", "img/ny_50.png", "img/pz_50.png", "img/nz_50.png"]) envTexture.mapping = THREE.CubeReflectionMapping //envTexture.mapping = THREE.CubeRefractionMapping material.envMap = envTexture const cube: THREE.Mesh = new THREE.Mesh(boxGeometry, material) cube.position.x = 5 scene.add(cube) const sphere: THREE.Mesh = new THREE.Mesh(sphereGeometry, material) sphere.position.x = 3 scene.add(sphere) const icosahedron: THREE.Mesh = new THREE.Mesh(icosahedronGeometry, material) icosahedron.position.x = 0 scene.add(icosahedron) const plane: THREE.Mesh = new THREE.Mesh(planeGeometry, material) plane.position.x = -2 scene.add(plane) const torusKnot: THREE.Mesh = new THREE.Mesh(torusKnotGeometry, material) torusKnot.position.x = -5 scene.add(torusKnot) camera.position.z = 3 window.addEventListener('resize', onWindowResize, false) function onWindowResize() { camera.aspect = window.innerWidth / window.innerHeight camera.updateProjectionMatrix() renderer.setSize(window.innerWidth, window.innerHeight) render() } const stats = Stats() document.body.appendChild(stats.dom) var options = { side: { "FrontSide": THREE.FrontSide, "BackSide": THREE.BackSide, "DoubleSide": THREE.DoubleSide, }, combine: { "MultiplyOperation": THREE.MultiplyOperation, "MixOperation": THREE.MixOperation, "AddOperation": THREE.AddOperation }, } const gui = new GUI() const materialFolder = gui.addFolder('THREE.Material') materialFolder.add(material, 'transparent') materialFolder.add(material, 'opacity', 0, 1, 0.01) materialFolder.add(material, 'depthTest') materialFolder.add(material, 'depthWrite') materialFolder.add(material, 'alphaTest', 0, 1, 0.01).onChange(() => updateMaterial()) materialFolder.add(material, 'visible') materialFolder.add(material, 'side', options.side).onChange(() => updateMaterial()) materialFolder.open() var data = { color: material.color.getHex(), emissive: material.emissive.getHex(), specular: material.specular.getHex() }; var meshPhongMaterialFolder = gui.addFolder('THREE.MeshPhongMaterial'); meshPhongMaterialFolder.addColor(data, 'color').onChange(() => { material.color.setHex(Number(data.color.toString().replace('#', '0x'))) }); meshPhongMaterialFolder.addColor(data, 'emissive').onChange(() => { material.emissive.setHex(Number(data.emissive.toString().replace('#', '0x'))) }); meshPhongMaterialFolder.addColor(data, 'specular').onChange(() => { material.specular.setHex(Number(data.specular.toString().replace('#', '0x'))) }); meshPhongMaterialFolder.add(material, 'shininess', 0, 1024); meshPhongMaterialFolder.add(material, 'wireframe'); meshPhongMaterialFolder.add(material, 'wireframeLinewidth', 0, 10); meshPhongMaterialFolder.add(material, 'flatShading').onChange(() => updateMaterial()) meshPhongMaterialFolder.add(material, 'combine', options.combine).onChange(() => updateMaterial()) meshPhongMaterialFolder.add(material, 'reflectivity', 0, 1); meshPhongMaterialFolder.add(material, 'refractionRatio', 0, 1); meshPhongMaterialFolder.open() function updateMaterial() { material.side = Number(material.side) material.combine = Number(material.combine) material.needsUpdate = true } var animate = function () { requestAnimationFrame(animate) render() stats.update() }; function render() { renderer.render(scene, camera) } animate(); |