Three.Camera
Camera是所有相機的抽象基類, 在構建新攝像機時,應始終繼承此類. 常見的相機有兩種型別: PerspectiveCamera(透視攝像機)或者 OrthographicCamera(正交攝像機)。
Camera子型別有ArrayCamera, CubeCamera, OrthographicCamera, PerspectiveCamera, StereoCamera, 這些相機中, 我認為比較有趣的是CubeCamera, 它包含6個PerspectiveCameras(透視攝像機)的立方攝像機, 拍出來的照片可以作為貼圖使用, 先看看它的效果吧 !
1. CubeCamera
整個環境成為了球的表面, 這個功能是不是很容易擴充套件呢. 將環境放在任意物體上, 還十分炫酷
步驟
1. 建立cubeCamera
1 //cubeCamera 2 cubeCamera = new THREE.CubeCamera(1, 10000, 128); 3 scene.add(cubeCamera);
說明: CubeCamera( near : Number, far : Number, cubeResolution : Number )
near -- 遠剪下面的距離
far -- 近剪下面的距離
cubeResolution -- 設定立方體邊緣的長度
2. 建立物體表面材質並將cubeCamera照出的環境作為材質的貼圖
1 material = new THREE.MeshBasicMaterial( { 2 envMap: cubeCamera.renderTarget.texture 3 } );
3. 建立物體, 將第二步的材質賦予物體
1 let sphere = new THREE.Mesh( new THREE.IcosahedronBufferGeometry( 20, 3 ), material ); 2 scene.add( sphere );
4. 更新材質貼圖內容
1 cubeCamera.update( renderer, scene );
那麼, 帶有環境的物體就做好了, 是不是很想試一試呀!
2. perspectiveCamera
這一投影模式被用來模擬人眼所看到的景象,它是3D場景的渲染中使用得最普遍的投影模式。
使用時需要注意: 在PerspectiveCamera大多數屬性發生改變之後,需要呼叫.updateProjectionMatrix來使得這些改變生效。
相機的使用步驟都十分類似, 第一步, 寫建構函式, 第二步, 改變位置, 第三步, 新增至場景, 第四步, 改變相機位置.
對於perspectiveCamera, 它的特點是像人眼, 距離越遠, 物體越小, 它與OrthographicCamera最大的區別就在於此, OrthographicCamera看到的物體無論距離多遠, 物體看上去的大小一樣.
使用流程
1 //1.建立相機 2 camera = new THREE.PerspectiveCamera(30, window.innerWidth / window.innerHeight, 0.1, 1000); 3 //2.新增相機至場景 4 scene.add(camera); 5 //3.改變相機位置 6 camera.position.set( 100, 50, 150); 7 //4.改變相機朝向 8 camera.lookAt(scene.position);
PerspectiveCamera( fov : Number, aspect : Number, near : Number, far : Number )
fov — 攝像機視錐體垂直視野角度
aspect — 攝像機視錐體長寬比
near — 攝像機視錐體近端面
far — 攝像機視錐體遠端面
注意點: renderer.render(scene, camera);
在渲染時, 引數選中的camera就相當於眼睛了, 選中哪個哪個就是眼睛.
效果如第一張圖片所示, 看到的是透視相機拍出來的
3. OrthographicCamera
注意它的建構函式就行, 其他與PerspectiveCamera類似
OrthographicCamera( left : Number, right : Number, top : Number, bottom : Number, near : Number, far : Number )
left — 攝像機視錐體左側面。
right — 攝像機視錐體右側面。
top — 攝像機視錐體上側面。
bottom — 攝像機視錐體下側面。
near — 攝像機視錐體近端面。
far — 攝像機視錐體遠端面。
4. ArrayCamera與StereoCamera
這兩種我還沒使用過, 這裡就簡單描述下, 後面用到了再補充
ArrayCamera 用於更加高效地使用一組已經預定義的攝像機來渲染一個場景。這將能夠更好地提升VR場景的渲染效能。
一個 ArrayCamera 的例項中總是包含著一組子攝像機,應當為每一個子攝像機定義viewport(邊界)這個屬性,這一屬性決定了由該子攝像機所渲染的視口區域的大小。
雙透視攝像機(立體相機)常被用於建立3D Anaglyph(3D立體影像)或者Parallax Barrier(視差效果)。
5. 總結
相機想使用不難, 如何靈活運用相機達到想要的效果就比較難了
6. 程式碼
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 <style> 7 body { 8 margin: 0; 9 overflow: hidden; 10 } 11 </style> 12 13 </head> 14 <body> 15 <script src="/js/three.js"></script> 16 <script src="/js/OrbitControls.js"></script> 17 <script src="/js/libs/stats.min.js"></script> 18 <script src="/js/libs/inflate.min.js"></script> 19 <script src="/js/loaders/FBXLoader.js"></script> 20 <script src="/js/exporters/GLTFExporter.js"></script> 21 <script> 22 let renderer, scene, camera, light, cubeCamera; 23 24 let container, stats; 25 26 init(); 27 animation(); 28 29 function init() { 30 //container 31 container = document.createElement("div"); 32 document.body.appendChild(container); 33 34 //status 35 stats = new Stats(); 36 container.appendChild(stats.domElement); 37 38 //renderer 39 renderer = new THREE.WebGLRenderer({ 40 antialias: true 41 }); 42 renderer.setSize(window.innerWidth, window.innerHeight); 43 renderer.setClearColor(0xffffff); 44 container.appendChild(renderer.domElement); 45 46 //scene 47 scene = new THREE.Scene(); 48 scene.background = new THREE.Color( 0xcce0ff ); 49 scene.fog = new THREE.Fog( 0xcce0ff, 500, 10000 ); 50 51 //3_相機 52 camera = new THREE.PerspectiveCamera(30, window.innerWidth / window.innerHeight); 53 scene.add(camera); 54 camera.position.set( 100, 50, 150); 55 camera.lookAt(scene.position); 56 57 //cubeCamera 58 cubeCamera = new THREE.CubeCamera(1, 10000, 128); 59 scene.add(cubeCamera); 60 61 material = new THREE.MeshBasicMaterial( { 62 envMap: cubeCamera.renderTarget.texture 63 } ); 64 65 // 66 let sphere = new THREE.Mesh( new THREE.IcosahedronBufferGeometry( 20, 3 ), material ); 67 scene.add( sphere ); 68 let geometry = new THREE.BoxGeometry( 1, 1, 1 ); 69 let meterial2 = new THREE.MeshBasicMaterial( { 70 vertexColors: THREE.VertexColors, 71 // wireframe: true 72 }); 73 let cube = new THREE.Mesh( 74 geometry, 75 meterial2 76 ); 77 geometry.faces.forEach(face => { 78 // 設定三角面face三個頂點的顏色 79 face.vertexColors = [ 80 new THREE.Color(0xffff00), 81 new THREE.Color(0x0000ff), 82 new THREE.Color(0x00ff00), 83 ] 84 }); 85 scene.add(cube); 86 87 // light 88 scene.add( new THREE.AmbientLight( 0x666666 ) ); 89 90 light = new THREE.DirectionalLight( 0xdfebff, 1 ); 91 light.position.set( 50, 200, 100 ); 92 light.position.multiplyScalar( 1.3 ); 93 94 light.castShadow = true; 95 96 light.shadow.mapSize.width = 1024; 97 light.shadow.mapSize.height = 1024; 98 99 let d = 300; 100 light.shadow.camera.left = - d; 101 light.shadow.camera.right = d; 102 light.shadow.camera.top = d; 103 light.shadow.camera.bottom = - d; 104 105 light.shadow.camera.far = 1000; 106 107 scene.add( light ); 108 109 // ground 110 var loader = new THREE.TextureLoader(); 111 var groundTexture = loader.load( '/textures/terrain/grasslight-big.jpg' ); 112 groundTexture.wrapS = groundTexture.wrapT = THREE.RepeatWrapping; 113 groundTexture.repeat.set( 25, 25 ); 114 groundTexture.anisotropy = 16; 115 116 var groundMaterial = new THREE.MeshLambertMaterial( { map: groundTexture } ); 117 118 var mesh = new THREE.Mesh( new THREE.PlaneBufferGeometry( 20000, 20000 ), groundMaterial ); 119 mesh.position.y = - 250; 120 mesh.rotation.x = - Math.PI / 2; 121 mesh.receiveShadow = true; 122 scene.add( mesh ); 123 124 //輔助工具 125 // scene.add(new THREE.AxesHelper(20)); 126 127 // controls 128 var controls = new THREE.OrbitControls( camera, renderer.domElement ); 129 // controls.maxPolarAngle = Math.PI * 0.5; 130 // controls.minDistance = 1000; 131 // controls.maxDistance = 5000; 132 133 134 } 135 136 function animation(){ 137 stats.update(); 138 cubeCamera.update( renderer, scene ); 139 render(); 140 requestAnimationFrame(animation); 141 } 142 143 function render() { 144 145 renderer.render(scene, camera); 146 147 } 148 </script> 149 </body> 150 </html>