当前位置:   article > 正文

Three.js学习6:透视相机和正交相机

正交相机

 -----------------------------华丽的分割线---------------------

相关代码均已上传到 gitee 中:myThree: 学习 Three.js ,努力加油~!

Gitee 静态演示地址:Three JS 演示页面

 -----------------------------华丽的分割线---------------------

一、相机

相机 camera,可以理解为摄像机。在拍影视剧的时候,最终用户看到的画面都是相机拍出来的内容。

Three.js 里,相机 camera 里的内容就是用户能看到的内容。从这个角度来看,相机其实就是用户的视野,就像用户的眼睛

Three.js 主要有四种不同的相机模式:

  • 透视相机 PerspectiveCamera:具有透视效果,近大远小,也是用的最多的相机。

  • 正交相机 OrthographicCamera:不具有透视效果,所有的元素的尺寸大小都是相同的,不管距离。

  • 立体相机 StereoCamera:主要做VR用的。就是让左右视觉有点点不一样的相机。

  • 立方体相机 CubeCamera:主要用作反射镜面纹理。

本文主要讨论透视相机和正交相机。

前面案例中应用到的轨道控制器,名为轨道,其实控制的就是相机的视角。

 二、透视相机

透视相机(PerspectiveCamera)中的物体具有“近大远小”的特点,是3D场景的渲染中使用得最普遍的投影模式。

1. 参数解析

const camera = new THREE.PerspectiveCamera(fov, aspect, near, far );

其参数分别为:

  1. fov :摄像机视锥体垂直视野角度,以角度来表示。默认值是50

  2. aspect :摄像机视锥体宽高比:默认值为 1,一般用渲染器到宽高比

  3. near:摄像机视锥体近截面,默认值是0.1

  4. far:摄像机视锥体远截面,默认值是2000

  1. const camera = new THREE.PerspectiveCamera( 45, width / height, 1, 1000 );
  2. scene.add( camera );

 只有在视锥体范围内,近截面和远截面之间的物体才会被渲染出来。

Three.js 编辑器里视锥体的样子:

可以通过点语法的形式修改相机视锥体的参数,但是必须调用camera.updateProjectionMatrix() 方法,让修改生效。

  1. const camera = new THREE.PerspectiveCamera(50, winW/winH,1, 10);
  2. camera.near = 5; // 修改参数
  3. camera.far = 37;
  4. camera.updateProjectionMatrix(); // 让参数修改生效

2. 修改相机坐标

因为,相机默认在原点上,物体也默认在原点上。所以,要看到物品,要把相机往后挪动位置,也既修改 z 轴位置。

  1. // 调整相机位置 x,y,z
  2. camera.position.z = 0;
  3. camera.position.x = 0;
  4. camera.position.y = 10;
  5. // 或者
  6. camera.position.set(0,0,10);

3. 镜头对准物体

不过有时候,移动相机的时候,相机必须要盯着目标物体,避免物体跑出视野之外。

camera.lookAt( Xmesh.position ); // 相机镜头盯着x物体

也可以对准某个具体的位置:

camera.lookAt(new THREE.Vector3(x,y,z));

4. 缩放镜头

  1. camera.zoom = 4;
  2. camera.updateProjectionMatrix(); // 让参数修改生效

获取或者设置摄像机的缩放倍数,其默认值为1

  • >1:镜头里的物体会被放大

  • <1:物体会被缩小

  • =1:物体正常大小

必须调用camera.updateProjectionMatrix() 方法,让修改生效。

三、正交相机

正交相机(OrthographicCamera),无论物体距离相机距离远或者近,在最终渲染物体的大小都保持不变。

主要用于渲染 2D 场景或者UI元素。如下图所示:

 1. 参数解析

  1. const camera = new THREE.OrthographicCamera(OrthographicCamera( left, right, top, bottom, near, far);
  2. scene.add( camera );

其参数依次分别为:

  • left : 摄像机视锥体左侧面

  • right : 摄像机视锥体右侧面。left 与 right 互为反数。

  • top:摄像机视锥体上侧面

  • bottom: 摄像机视锥体下侧面。top 与 bottom 互为反数。

  • near : 摄像机视锥体近截面。其默认值为0.1

  • far: 摄像机视锥体远截面。其默认值为2000

这几个参数刚好组成一个立方体。

 例如:

  1. const k = winW / winH; //canvas画布宽高比
  2. const s = 2; // 显示控制系数。
  3. const camera = new THREE.OrthographicCamera( -s*k, k*s, s, -s, 0.1, 2000 );
  4. camera.position.set(8,8,8);
  5. scene.add( camera );

为了保持照相机的横竖比例,需要保证 (right - left)(top - bottom) 的比例与 Canvas(也就是渲染器)宽度与高度的比例一致。所以才有了两个变量 k、s。

  • 变量 k:render 渲染的宽高比。因为,正交相机默认渲染的是一个正方形,但是我们渲染的范围(canvas)不一定是一个正方形。正交相机区域将被拉伸以适合我们的矩形画布,因此我们需要使用画布的宽高比。

  • 变量 S 是正交相机显示控制系数。值越小,画面越大。反之,画面越小。如果为1,画面会很大。所以,这里用“单位”的2倍。当然,也可以根据需要自行调整数据。

Three.js 编辑器里正交相机视锥体的样子:

跟透视相机一样,可以通过点语法的形式修改相机视锥体的参数,但是必须调用camera.updateProjectionMatrix() 方法,让修改生效。  

2. 正交相机例子

  1. let winW = window.innerWidth;
  2. let winH = window.innerHeight;
  3. // 场景
  4. const scene = new THREE.Scene();
  5. scene.background = new THREE.Color("#cccccc");
  6. // 网格辅助器
  7. const grid = new THREE.GridHelper(1000,10);
  8. scene.add(grid);
  9. // 物体
  10. const geometry = new THREE.BoxGeometry(100,100,100);
  11. const material = new THREE.MeshBasicMaterial({
  12. color:"#f00"
  13. });
  14. const mesh = new THREE.Mesh( geometry, material );
  15. mesh.position.set(0,0,0);
  16. scene.add( mesh );
  17. // 正投影相机案例
  18. const k = winW / winH; //canvas画布宽高比
  19. const s = 2; // 显示控制系数。网格单位*2
  20. const camera = new THREE.OrthographicCamera( -s*k, k*s, s, -s, 0.1, 2000 );
  21. camera.position.set(8,8,8);
  22. scene.add( camera );
  23. // 渲染器
  24. const renderer = new THREE.WebGLRenderer();
  25. renderer.setSize( winW, winH );
  26. document.body.appendChild( renderer.domElement );
  27. renderer.render(scene, camera);
  28. // 轨道控制器
  29. const controls = new OrbitControls(camera, renderer.domElement);
  30. controls.update();
  31. controls.addEventListener(function(){
  32. console.info( camera.position );
  33. });
  34. // 动画
  35. function aniFun(){
  36. renderer.render( scene, camera );
  37. controls.update();
  38. requestAnimationFrame( aniFun );
  39. }
  40. aniFun();

可以看到,正交相机的图像是没有近大远小的透视感的。

四、相机切换示例

 html:

  1. <div class="btns">
  2. <button type="button" id="tsBtn">透视相机</button>
  3. <button type="button" id="zjBtn">正交相机</button>
  4. <h1 id="tit">透视相机</h1>
  5. </div>
  6. <script type="importmap">
  7. {
  8. "imports":{
  9. "three":"./js/three.module.min.js",
  10. "three/addons/":"./js/jsm/"
  11. }
  12. }
  13. </script>
  14. <script type="module" src="./js/myjs5-3.js"></script>

JS:

  1. import * as THREE from "three";
  2. import { OrbitControls } from "three/addons/controls/OrbitControls.js";
  3. let scene,
  4. camera,
  5. controls, grid,
  6. renderer;
  7. let winW = window.innerWidth,
  8. winH = window.innerHeight;
  9. let tsBtn = document.getElementById("tsBtn"),
  10. zjBtn = document.getElementById("zjBtn"),
  11. tit = document.getElementById("tit");
  12. // 场景
  13. scene = new THREE.Scene();
  14. scene.background = new THREE.Color("#cccccc");
  15. // 透视相机
  16. function pCamera(){
  17. camera = new THREE.PerspectiveCamera(50, winW/winH,1, 1000);
  18. camera.position.set( 8,8,8 );
  19. camera.lookAt( scene.position );
  20. scene.add( camera );
  21. }
  22. // 正交相机
  23. function oCamera(){
  24. const k = winW / winH; //canvas画布宽高比
  25. const s = 8; // 显示控制系数。
  26. camera = new THREE.OrthographicCamera( -s*k, k*s, s, -s, 0.1, 2000 );
  27. camera.position.set(8,8,8);
  28. camera.lookAt( scene.position );
  29. scene.add( camera );
  30. }
  31. // 渲染器
  32. function renderFun(){
  33. renderer = new THREE.WebGLRenderer();
  34. renderer.setSize( winW, winH );
  35. document.body.appendChild( renderer.domElement );
  36. }
  37. // 网格辅助
  38. function gridHelperFun(){
  39. grid = new THREE.GridHelper(10,10);
  40. scene.add(grid);
  41. }
  42. // 立方体
  43. function cubeFun(){
  44. let geometry = new THREE.BoxGeometry(1,1,1);
  45. let metiral = new THREE.MeshBasicMaterial({
  46. color:"#ff3300"
  47. });
  48. let mesh = new THREE.Mesh( geometry, metiral);
  49. scene.add( mesh );
  50. }
  51. // 函数调用
  52. pCamera();
  53. renderFun();
  54. gridHelperFun();
  55. cubeFun();
  56. renderer.render(scene, camera);
  57. // 动画渲染
  58. function animateFun(){
  59. // 渲染
  60. renderer.render( scene, camera);
  61. requestAnimationFrame(animateFun);
  62. }
  63. animateFun();
  64. // 按钮事件
  65. tsBtn.addEventListener("click",function(){
  66. pCamera();
  67. renderer.render(scene, camera);
  68. tit.innerHTML = "透视相机";
  69. });
  70. zjBtn.addEventListener("click",function(){
  71. oCamera();
  72. renderer.render(scene, camera);
  73. tit.innerHTML = "正交相机";
  74. });

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小舞很执着/article/detail/921346
推荐阅读
相关标签
  

闽ICP备14008679号