"use strict"; // 參考 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode //////////////////////////////////////////////////////////////////////////////// // 視野大小作業 //////////////////////////////////////////////////////////////////////////////// var camera, scene, renderer; var cameraControls, effectController; var clock = new THREE.Clock(); var cylinder, sphere, cube; var bevelRadius = 1.9; // TODO: 2.0 會造成幾何問題 var aspectRatio; var eyeTargetScale; // 視野大小滑桿應該寫在這個函式 // 滑桿的值應該存在全域變數:effectController.fov function setupGui() { effectController = {}; } function init() { var canvasWidth = window.innerWidth; var canvasHeight = window.innerHeight; // RENDERER renderer = new THREE.WebGLRenderer( { antialias: true } ); renderer.gammaInput = true; renderer.gammaOutput = true; renderer.setSize(canvasWidth, canvasHeight); renderer.setClearColorHex( 0x808080, 1.0 ); // 攝影機 // 長寬比為視窗寬度除以視窗高度 aspectRatio = canvasWidth/canvasHeight; camera = new THREE.PerspectiveCamera( 45, aspectRatio, 10, 10000 ); camera.position.set( -890, 600, -480 ); // 控制 cameraControls = new THREE.OrbitAndPanControls(camera, renderer.domElement); cameraControls.target.set(0,335,0); var startdir = new THREE.Vector3(); startdir.subVectors( camera.position, cameraControls.target ); eyeTargetScale = Math.tan(camera.fov*(Math.PI/180)/2)*startdir.length(); } function fillScene() { scene = new THREE.Scene(); // 光源 scene.add( new THREE.AmbientLight( 0x222222 ) ); var light = new THREE.DirectionalLight( 0xFFFFFF, 1.0 ); light.position.set( 200, 400, 500 ); scene.add( light ); light = new THREE.DirectionalLight( 0xFFFFFF, 1.0 ); light.position.set( -400, 200, -300 ); scene.add( light ); // 鳥 var bird = new THREE.Object3D(); createDrinkingBird( bird ); scene.add( bird ); // 一些方塊 var x,z; for ( x = -4500; x <= 4500; x += 1000 ) { for ( z = -4500; z <= 4500; z += 1000 ) { var blockMaterial = new THREE.MeshLambertMaterial(); // 有點隨機但重複的顏色 blockMaterial.color.setRGB( ((x+4500)%373)/373, ((x+z+9000)%283)/283, ((z+4500)%307)/307 ); blockMaterial.ambient.copy( blockMaterial.color ); var block = new THREE.Mesh( new THREE.CubeGeometry( 100, 300, 100 ), blockMaterial ); block.position.set( x, 150, z ); scene.add( block ); } } } // 鳥的支撐骨架-基底+腳掌+腿 function createSupport( bsupport ) { var legMaterial = new THREE.MeshPhongMaterial( { shininess: 4 } ); legMaterial.color.setHex( 0xAdA79b ); legMaterial.specular.setRGB( 0.5, 0.5, 0.5 ); legMaterial.ambient.copy( legMaterial.color ); var footMaterial = new THREE.MeshPhongMaterial( { color: 0x960f0b, shininess: 30 } ); footMaterial.specular.setRGB( 0.5, 0.5, 0.5 ); footMaterial.ambient.copy( footMaterial.color ); // 基底 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; // 中心在原點 bsupport.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 bsupport.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 bsupport.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 bsupport.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 bsupport.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 bsupport.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 bsupport.add( cube ); } // 鳥的身體-身體與身體到頭的連接 function createBody(bbody) { 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 ); bodyMaterial.ambient.copy( bodyMaterial.color ); var glassMaterial = new THREE.MeshPhongMaterial( { color: 0x0, specular: 0xFFFFFF, shininess: 100, opacity: 0.3, transparent: true } ); glassMaterial.ambient.copy( glassMaterial.color ); var crossbarMaterial = new THREE.MeshPhongMaterial( { color: 0x808080, specular: 0xFFFFFF, shininess: 400 } ); crossbarMaterial.ambient.copy( crossbarMaterial.color ); // 身體 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; bbody.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; bbody.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; bbody.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; bbody.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; bbody.add( cylinder ); // 橫桿 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; bbody.add( cylinder ); } // 鳥的頭-頭+帽子 function createHead(bhead) { var headMaterial = new THREE.MeshLambertMaterial( ); headMaterial.color.r = 104/255; headMaterial.color.g = 1/255; headMaterial.color.b = 5/255; headMaterial.ambient.copy( headMaterial.color ); 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 ); hatMaterial.ambient.copy( hatMaterial.color ); var eyeMaterial = new THREE.MeshPhongMaterial( { color: 0x000000, specular: 0x303030, shininess: 4 } ); eyeMaterial.ambient.copy( eyeMaterial.color ); // 頭 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; bhead.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; bhead.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; bhead.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; bhead.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; bhead.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; bhead.add( eye ); } function createDrinkingBird(bbird) { var support = new THREE.Object3D(); var body = new THREE.Object3D(); var head = new THREE.Object3D(); // 建模 // 基底+腳掌+腿 createSupport(support); // 身體+身體到頭的連接 createBody(body); // 頭+帽子 createHead(head); bbird.add(support); bbird.add(body); bbird.add(head); } function drawHelpers() { 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.render(scene, camera); } document.addEventListener("DOMContentLoaded", function () { try { init(); fillScene(); setupGui(); drawHelpers(); addToDOM(); animate(); } catch(e) { var errorReport = "你的程式遇到不可復原的錯誤,無法繪製 Canvas。錯誤是:<br/><br/>"; $('#container').append(errorReport+e); } })