three.js 04-07 之 MeshPhongMaterial 材質
阿新 • • 發佈:2019-01-22
上篇我們已經介紹了 three.js 中高階材質中的 MeshLambertMaterial 材質。本篇將要介紹的是另一種與之對應的高階材質 MeshPhongMaterial 材質。通過它可以建立一種光亮表面的材質效果。這種材質的屬性基本跟 MeshLambertMaterial 暗淡材質一樣,除此之外,我們列出 MeshPhongMaterial 材質中比較感興趣的特有屬性,如下表所示:
屬性 | 描述 |
---|---|
ambient (環境光顏色) | 同 MeshLambertMaterial 材質 |
emissive (自發光顏色) | 同 MeshLambertMaterial 材質 |
specular (鏡面反射光顏色) | 此屬性指定該材質的鏡面反射光部分的顏色。如果將它設定成跟 color 屬性相同的顏色,則會得到一種更加類似金屬的材質;如果設定成 gray 灰色,材質將變得像塑料 |
shininess (鏡面反射光強度) | 此屬性指定 specular 鏡面反射光部分的亮度。預設值是 30 |
這個示例大體上跟上一篇的基本一樣,所以不再過多嗷述,讀者可以自行參考上一篇中提到的相關引導建議去試驗。<!DOCTYPE html> <html> <head> <title>示例 04.07 - MeshPhongMaterial</title> <script src="../build/three.js"></script> <script src="../build/js/controls/OrbitControls.js"></script> <script src="../build/js/libs/stats.min.js"></script> <script src="../build/js/libs/dat.gui.min.js"></script> <script src="../jquery/jquery-3.2.1.min.js"></script> <style> body { /* 設定 margin 為 0,並且 overflow 為 hidden,來完成頁面樣式 */ margin: 0; overflow: hidden; } /* 統計物件的樣式 */ #Stats-output { position: absolute; left: 0px; top: 0px; } </style> </head> <body> <!-- 用於 WebGL 輸出的 Div --> <div id="webgl-output"></div> <!-- 用於統計 FPS 輸出的 Div --> <div id="stats-output"></div> <!-- 執行 Three.js 示例的 Javascript 程式碼 --> <script type="text/javascript"> var scene; var camera; var render; var webglRender; var canvasRender; var controls; var stats; var guiParams; var ground; var cube; var sphere; var plane; var activeMesh; var meshMaterial; var ambientLight; var spotLight; var cameraHelper; $(function() { stats = initStats(); scene = new THREE.Scene(); webglRender = new THREE.WebGLRenderer( {antialias: true, alpha: true} ); // antialias 抗鋸齒 webglRender.setSize(window.innerWidth, window.innerHeight); webglRender.setClearColor(0xeeeeee, 1.0); webglRender.shadowMap.enabled = true; // 允許陰影投射 render = webglRender; camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 30, 1000); // 2147483647 camera.position.set(-45.5, 68.2, 90.9); var target = new THREE.Vector3(10, 0 , 0); controls = new THREE.OrbitControls(camera, render.domElement); controls.target = target; camera.lookAt(target); $('#webgl-output')[0].appendChild(render.domElement); window.addEventListener('resize', onWindowResize, false); ambientLight = new THREE.AmbientLight(0x0c0c0c); scene.add(ambientLight); spotLight = new THREE.SpotLight(0xffffff); spotLight.position.set(0, 30, 60); spotLight.castShadow = true; scene.add(spotLight); cameraHelper = new THREE.CameraHelper(spotLight.shadow.camera); scene.add(cameraHelper); // 加入一個平面 var groundGeometry = new THREE.PlaneGeometry(100, 100, 4, 4); var groundMaterial = new THREE.MeshBasicMaterial({color: 0x777777}); ground = new THREE.Mesh(groundGeometry, groundMaterial); ground.rotation.set(-0.5 * Math.PI, 0, 0); // 沿著 X軸旋轉-90° scene.add(ground); // 定義 cube, sphere, plane var cubeGeometry = new THREE.BoxGeometry(15, 15, 15); var sphereGeometry = new THREE.SphereGeometry(14, 30, 30); var planeGeometry = new THREE.PlaneGeometry(14, 14, 4, 4); // 材質 meshMaterial = new THREE.MeshPhongMaterial({color: 0x7777ff, transparent: false, opacity: 1.0}); cube = new THREE.Mesh(cubeGeometry, meshMaterial); sphere = new THREE.Mesh(sphereGeometry, meshMaterial); plane = new THREE.Mesh(planeGeometry, meshMaterial); cube.castShadow = true; sphere.castShadow = true; plane.castShadow = true; cube.position.set(0, 12, 0); sphere.position.set(0, 14, 0); plane.position.set(0, 12, 0); /** 用來儲存那些需要修改的變數 */ guiParams = new function() { this.rotationSpeed = 0.02; this.opacity = meshMaterial.opacity; this.transparent = meshMaterial.transparent; this.visible = meshMaterial.visible; this.ambient = '#ffffff'; this.emissive = '#2a2a2a'; this.specular = '#ffffff'; this.shininess = 5; this.side = 'front'; this.color = '#ff000e'; this.selectedMesh = 'sphere'; this.spotLight = true; this.addMesh = function(e) { scene.remove(activeMesh); switch (e) { case "cube": activeMesh = cube; break; case "sphere": activeMesh = sphere; break; case "plane": activeMesh = plane; break; } scene.add(activeMesh); }; this.updateMaterial = function() { meshMaterial.opacity = this.opacity; meshMaterial.transparent = this.transparent; meshMaterial.visible = this.visible; meshMaterial.ambient = new THREE.Color(this.ambient); meshMaterial.emissive = new THREE.Color(this.emissive); meshMaterial.specular = new THREE.Color(this.specular); meshMaterial.shininess = this.shininess; meshMaterial.color = new THREE.Color(this.color); switch (this.side) { case "front": meshMaterial.side = THREE.FrontSide; break; case "back": meshMaterial.side = THREE.BackSide; break; case "double": meshMaterial.side = THREE.DoubleSide; break; } meshMaterial.needsUpdate = true; } } /** 定義 dat.GUI 物件,並繫結 guiParams 的幾個屬性 */ var gui = new dat.GUI(); var folder = gui.addFolder('Mesh'); folder.open(); folder.add(guiParams, 'opacity', 0.1, 1.0).onChange(function(e) { guiParams.updateMaterial(); }); folder.add(guiParams, 'transparent').onChange(function(e) { guiParams.updateMaterial(); }); folder.addColor(guiParams, 'ambient').onChange(function(e) { guiParams.updateMaterial(); }); folder.addColor(guiParams, 'emissive').onChange(function(e) { guiParams.updateMaterial(); }); folder.addColor(guiParams, 'specular').onChange(function(e) { guiParams.updateMaterial(); }); folder.add(guiParams, 'shininess', 1, 200).onChange(function(e) { guiParams.updateMaterial(); }); folder.add(guiParams, 'visible').onChange(function(e) { guiParams.updateMaterial(); }); folder.add(guiParams, 'side', ['front', 'back', 'double']).onChange(function(e) { console.log(e); guiParams.updateMaterial(); }); folder.addColor(guiParams, 'color').onChange(function(e) { guiParams.updateMaterial(); }); folder.add(guiParams, 'selectedMesh', ['cube', 'sphere', 'plane']).onChange(function(e) { guiParams.addMesh(e); }); gui.add(guiParams, 'spotLight').onChange(function(e) { scene.remove(spotLight); scene.remove(cameraHelper); if (e) { scene.add(spotLight); scene.add(cameraHelper); } }); guiParams.updateMaterial(); guiParams.addMesh(guiParams.selectedMesh); renderScene(); }); /** 渲染場景 */ function renderScene() { stats.update(); rotateMesh(); // 旋轉物體 requestAnimationFrame(renderScene); render.render(scene, camera); } /** 初始化 stats 統計物件 */ function initStats() { stats = new Stats(); stats.setMode(0); // 0 為監測 FPS;1 為監測渲染時間 $('#stats-output').append(stats.domElement); return stats; } /** 當瀏覽器視窗大小變化時觸發 */ function onWindowResize() { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); render.setSize(window.innerWidth, window.innerHeight); } /** 旋轉物體 */ function rotateMesh() { scene.traverse(function(mesh) { if (mesh instanceof THREE.Mesh && mesh != ground) { //mesh.rotation.x += guiParams.rotationSpeed; mesh.rotation.y += guiParams.rotationSpeed; //mesh.rotation.z += guiParams.rotationSpeed; } }); } </script> </body> </html>
未完待續···