"use strict"; // 參考 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode //////////////////////////////////////////////////////////////////////////////// // 建立四個視埠作業 //////////////////////////////////////////////////////////////////////////////// var camera, topCam, sideCam, frontCam; var scene, renderer; var cameraControls; var clock = new THREE.Clock(); var canvasWidth; var canvasHeight; function fillScene() { scene = new THREE.Scene(); scene.fog = new THREE.Fog( 0xDDDDDD, 2000, 4000 ); // 光源 scene.add( new THREE.AmbientLight( 0x222222 ) ); var light = new THREE.DirectionalLight( 0xFFFFFF, 0.7 ); light.position.set( 200, 500, 500 ); scene.add( light ); light = new THREE.DirectionalLight( 0xFFFFFF, 0.9 ); light.position.set( -200, -100, -400 ); scene.add( light ); // 材質 var headMaterial = new THREE.MeshLambertMaterial( ); headMaterial.color.r = 104/255; headMaterial.color.g = 1/255; headMaterial.color.b = 5/255; var hatMaterial = new THREE.MeshPhongMaterial( { shininess: 100 } ); hatMaterial.color.r = 24/255; hatMaterial.color.g = 38/255; hatMaterial.color.b = 77/255; hatMaterial.specular.setRGB( 0.5, 0.5, 0.5 ); var bodyMaterial = new THREE.MeshPhongMaterial( { shininess: 100 } ); bodyMaterial.color.setRGB( 31/255, 86/255, 169/255 ); bodyMaterial.specular.setRGB( 0.5, 0.5, 0.5 ); var glassMaterial = new THREE.MeshPhongMaterial( { color: 0x0, specular: 0xFFFFFF, shininess: 100, opacity: 0.3, transparent: true } ); var legMaterial = new THREE.MeshPhongMaterial( { shininess: 4 } ); legMaterial.color.setHex( 0xAdA79b ); legMaterial.specular.setRGB( 0.5, 0.5, 0.5 ); var footMaterial = new THREE.MeshPhongMaterial( { color: 0x960f0b, shininess: 30 } ); footMaterial.specular.setRGB( 0.5, 0.5, 0.5 ); var sphere, cylinder, cube; var bevelRadius = 1.9; // TODO: 2.0 會造成幾何問題 // 建模 // 基底 cube = new THREE.Mesh( new THREE.BeveledBlockGeometry( 20+64+110, 4, 2*77+12, bevelRadius ), footMaterial ); cube.position.x = -45; // (20+32) - 寬度的一半 (20+64+110)/2 cube.position.y = 4/2; // 高的的一半 cube.position.z = 0; // 中心在原點 scene.add( cube ); // 腳掌 cube = new THREE.Mesh( new THREE.BeveledBlockGeometry( 20+64+110, 52, 6, bevelRadius ), footMaterial ); cube.position.x = -45; // (20+32) - 寬度的一半 (20+64+110)/2 cube.position.y = 52/2; // 高的的一半 cube.position.z = 77 + 6/2; // 偏移 77 + 深度的一半 6/2 scene.add( cube ); cube = new THREE.Mesh( new THREE.BeveledBlockGeometry( 20+64+110, 52, 6, bevelRadius ), footMaterial ); cube.position.x = -45; // (20+32) - 寬度的一半 (20+64+110)/2 cube.position.y = 52/2; // 高的的一半 cube.position.z = -(77 + 6/2); // 負的偏移 77 + 深度的一半 6/2 scene.add( cube ); cube = new THREE.Mesh( new THREE.BeveledBlockGeometry( 64, 104, 6, bevelRadius ), footMaterial ); cube.position.x = 0; // X 方向在原點 cube.position.y = 104/2; cube.position.z = 77 + 6/2; // 負的偏移 77 + 深度的一半 6/2 scene.add( cube ); cube = new THREE.Mesh( new THREE.BeveledBlockGeometry( 64, 104, 6, bevelRadius ), footMaterial ); cube.position.x = 0; // X 方向在原點 cube.position.y = 104/2; cube.position.z = -(77 + 6/2); // 負的偏移 77 + 深度的一半 6/2 scene.add( cube ); // 腳 cube = new THREE.Mesh( new THREE.BeveledBlockGeometry( 60, 282+4, 4, bevelRadius ), legMaterial ); cube.position.x = 0; // X 方向在原點 cube.position.y = 104 + 282/2 - 2; cube.position.z = 77 + 6/2; // 負的偏移 77 + 深度的一半 6/2 scene.add( cube ); cube = new THREE.Mesh( new THREE.BeveledBlockGeometry( 60, 282+4, 4, bevelRadius ), legMaterial ); cube.position.x = 0; // X 方向在原點 cube.position.y = 104 + 282/2 - 2; cube.position.z = -(77 + 6/2); // 負的偏移 77 + 深度的一半 6/2 scene.add( cube ); // 身體 sphere = new THREE.Mesh( new THREE.SphereGeometry( 104/2, 32, 16, 0, Math.PI * 2, Math.PI/2, Math.PI ), bodyMaterial ); sphere.position.x = 0; sphere.position.y = 160; sphere.position.z = 0; scene.add( sphere ); // 半球的上蓋 cylinder = new THREE.Mesh( new THREE.CylinderGeometry( 104/2, 104/2, 0, 32 ), bodyMaterial ); cylinder.position.x = 0; cylinder.position.y = 160; cylinder.position.z = 0; scene.add( cylinder ); cylinder = new THREE.Mesh( new THREE.CylinderGeometry( 12/2, 12/2, 390 - 100, 32 ), bodyMaterial ); cylinder.position.x = 0; cylinder.position.y = 160 + 390/2 - 100; cylinder.position.z = 0; scene.add( cylinder ); // 玻璃 sphere = new THREE.Mesh( new THREE.SphereGeometry( 116/2, 32, 16 ), glassMaterial ); sphere.position.x = 0; sphere.position.y = 160; sphere.position.z = 0; scene.add( sphere ); cylinder = new THREE.Mesh( new THREE.CylinderGeometry( 24/2, 24/2, 390, 32 ), glassMaterial ); cylinder.position.x = 0; cylinder.position.y = 160 + 390/2; cylinder.position.z = 0; scene.add( cylinder ); // 頭 sphere = new THREE.Mesh( new THREE.SphereGeometry( 104/2, 32, 16 ), headMaterial ); sphere.position.x = 0; sphere.position.y = 160 + 390; sphere.position.z = 0; scene.add( sphere ); // 帽子 cylinder = new THREE.Mesh( new THREE.CylinderGeometry( 142/2, 142/2, 10, 32 ), hatMaterial ); cylinder.position.x = 0; cylinder.position.y = 160 + 390 + 40 + 10/2; cylinder.position.z = 0; scene.add( cylinder ); cylinder = new THREE.Mesh( new THREE.CylinderGeometry( 80/2, 80/2, 70, 32 ), hatMaterial ); cylinder.position.x = 0; cylinder.position.y = 160 + 390 + 40 + 10 + 70/2; cylinder.position.z = 0; scene.add( cylinder ); var crossbarMaterial = new THREE.MeshPhongMaterial( { color: 0x808080, specular: 0xFFFFFF, shininess: 400 } ); var eyeMaterial = new THREE.MeshPhongMaterial( { color: 0x000000, specular: 0x303030, shininess: 4 } ); // 橫桿 cylinder = new THREE.Mesh( new THREE.CylinderGeometry( 5, 5, 200, 32 ), crossbarMaterial ); cylinder.position.set( 0, 360, 0 ); cylinder.rotation.x = 90 * Math.PI / 180.0; scene.add( cylinder ); // 鼻子 cylinder = new THREE.Mesh( new THREE.CylinderGeometry( 6, 14, 70, 32 ), headMaterial ); cylinder.position.set( -70, 530, 0 ); cylinder.rotation.z = 90 * Math.PI / 180.0; scene.add( cylinder ); // 眼睛 var sphGeom = new THREE.SphereGeometry( 10, 32, 16 ); // 左眼 sphere = new THREE.Mesh( sphGeom, eyeMaterial ); sphere.position.set( -48, 560, 0 ); var eye = new THREE.Object3D(); eye.add( sphere ); eye.rotation.y = 20 * Math.PI / 180.0; scene.add( eye ); // 右眼 sphere = new THREE.Mesh( sphGeom, eyeMaterial ); sphere.position.set( -48, 560, 0 ); eye = new THREE.Object3D(); eye.add( sphere ); eye.rotation.y = -20 * Math.PI / 180.0; scene.add( eye ); } function init() { canvasWidth = window.innerWidth; canvasHeight = window.innerHeight; var aspectRatio = canvasWidth/canvasHeight; // RENDERER renderer = new THREE.WebGLRenderer( { antialias: true } ); renderer.gammaInput = true; renderer.gammaOutput = true; renderer.setSize(canvasWidth, canvasHeight); renderer.setClearColorHex( 0xDDDDDD, 1.0 ); // 繪製多個視埠時不要清除畫面 renderer.autoClear = false; var container = document.getElementById('container'); container.appendChild( renderer.domElement ); // 攝影機 camera = new THREE.PerspectiveCamera( 45, canvasWidth / canvasHeight, 1, 4000 ); camera.position.set( -1160, 310, -600 ); // OrthographicCamera( left, right, top, bottom, near, far ) var viewSize = 1100; topCam = new THREE.OrthographicCamera( -aspectRatio*viewSize / 2, aspectRatio*viewSize / 2, viewSize / 2, -viewSize / 2, -1000, 1000 ); // 將 X 設為 Up 向量 topCam.up.set( 1, 0, 0 ); // 控制 cameraControls = new THREE.OrbitAndPanControls(camera, renderer.domElement); cameraControls.target.set(0,310,0); } function drawHelpers() { Coordinates.drawGround({size:10000}); Coordinates.drawGrid({size:10000,scale:0.01}); } function addToDOM() { var container = document.getElementById('container'); var canvas = container.getElementsByTagName('canvas'); if (canvas.length>0) { container.removeChild(canvas[0]); } container.appendChild( renderer.domElement ); } function animate() { window.requestAnimationFrame(animate); render(); } function render() { var delta = clock.getDelta(); cameraControls.update(delta); // 用適當的顏色清除螢幕 renderer.clear(); // 透視攝影機 renderer.setViewport( 0, 0, 0.5*canvasWidth, 0.5*canvasHeight ); renderer.render( scene, camera ); // 俯視角 topCam.position.copy( cameraControls.target ); // 往上移然後往下看向鳥 topCam.position.y +=1 ; topCam.lookAt( cameraControls.target ); renderer.setViewport( 0.5*canvasWidth, 0.5*canvasHeight, 0.5*canvasWidth, 0.5*canvasHeight ); renderer.render( scene, topCam ); } document.addEventListener("DOMContentLoaded", function () { try { init(); fillScene(); drawHelpers(); addToDOM(); animate(); } catch(e) { var errorReport = "你的程式遇到不可復原的錯誤,無法繪製 Canvas。錯誤是:<br/><br/>"; $('#container').append(errorReport+e); } })