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>