一、轨道控制器
拍摄画面的时候,为了保持镜头的稳定,并且能从多方位拍摄画面,往往会用到轨道(Orbit) 。
轨道控制器(Orbit controls)可以使得相机围绕目标进行轨道运动。
在 Three.js 里,轨道控制器可以通过鼠标左右键、鼠标滚动控制画面的上下左右旋转、移动、缩放,可以从多个角度观测目标物体。其效果类似 Three.js 提供的官方编辑器一样。
官方编辑器允许用鼠标左右键控制画面的旋转和移动。
http://localhost:9000/editor/
二、导入轨道控制器组件
轨道控制器(Orbit controls) 是一个附加组件,必须显式导入。
1. 拷贝附加组件文件
Three.js 的附加组件,包括轨道控制器、模型加载器等,都是放在 example/jsm
文件夹下的。因此,首先要把 jsm
文件夹的东西都拷贝到项目文件夹中。
我这里是拷贝到 js
目录下。
吐槽下:害的我找了好久,半天不知道怎么导入。
2. 页面添加 importmap 代码
<script type="importmap">{"imports": {"three" : "./js/three.module.min.js","three/addons/": "./js/jsm/"}}
</script>
来自 MDN:
导入映射(import map)是一个 JSON 对象,其允许开发者在导入 JavaScript 模块时,控制浏览器如何解析模块标识符。它提供了在 import 语句或 import() 运算符 (en-US)中用作模块标识符的文本,其会在解析标识符时与要替换的文本之间建立映射。JSON 对象必须符合导入映射 JSON 表示格式
一般我们在项目中导入模块,会调用require
方法,或者使用import
语句。导入的模块通常使用 npm 之类的包管理器进行管理。
但是,如果不用 npm 怎么管理模块?
import map
就提供了一种支持,让我们可以直接在页面上管理模块,不需要通过 npm 之类的工具。
在我们的 JS 文件里添加轨道控制器附加组件导入代码。
import * as THREE from "three";
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
注意映射的对应关系:
三、轨道控制器对象
const controls = new OrbitControls( camera, renderer.domElement );
两个参数:
-
相机对象:(必须)将要被控制的相机。该相机不允许是其他任何对象的子级,除非该对象是场景自身。
-
domElement: 用于事件监听的HTML元素。一般用渲染器DOM对象,也就是 canvas 标签。
更多的内容翻看官方文档,这里只罗列感觉常用的。
1. 常用属性
controls.enableDamping = true; // 启用阻尼效果。必须应用动画。
controls.dampingFactor = 0.01; // 设置阻尼值
controls.autoRotate = true; // 自动旋转。必须应用动画。
controls.autoRotateSpeed = 1; // 自动旋转速度controls.minDistance = 5; // 相机移动位置。用于透视相机 PerspectiveCamera
controls.maxDistance = 20;controls.minZoom = 0.5; // 最小、放大缩放比例。用于正交相机 OrthographicCamera
controls.maxZoom = 2;
2. 启用键盘控制
// 增加了键盘控制
// 当使用键盘按键的时候,相机平移的速度有多快。默认值为每次按下按键时平移7像素。
controls.keyPanSpeed = 7
// 这一对象包含了用于控制相机平移的按键代码的引用。默认值为4个箭头(方向)键。
controls.keys = {LEFT: 'ArrowLeft', //left arrowUP: 'ArrowUp', // up arrowRIGHT: 'ArrowRight', // right arrowBOTTOM: 'ArrowDown' // down arrow
}// 添加键盘事件监听。只有添加了键盘事件监听,上下左右键才能控制轨道
controls.listenToKeyEvents( window );controls.stopListenToKeyEvents(); // 取消键盘事件监听
3. 动画更新
// 更新控制器。必须在摄像机的变换发生任何手动改变后调用
// 或如果.autoRotate或.enableDamping被设置时,在update循环里调用。
controls.update();function animateFun(){controls.update(); // 现在动画里更新控制器// 渲染renderer.render( scene, camera);requestAnimationFrame(animateFun);
}
animateFun()
4. 事件
-
change:当摄像机被组件改变时触发。
-
start:初始化交互时触发。
-
end:当交互结束时触发。
// 添加 change 事件
controls.addEventListener("change",function(){console.info("change");
});
四、完整代码
在本人博文 Three.js学习3:第一个Three.js页面-CSDN博客 的基础上,修改代码。
HTML:
<!-- importmap 必须有 -->
<script type="importmap">{"imports": {"three" : "./js/three.module.min.js","three/addons/": "./js/jsm/"}}
</script>
<script src="js/myjs.js" type="module"></script>
JS:
import * as THREE from "three";
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
// 场景
const scene = new THREE.Scene();
scene.background = new THREE.Color( 0xEEEEEE); // 设置场景背景色// 物体:包含几何形 geometry 和 材质(皮肤) meterial 两部分
const geometry = new THREE.BoxGeometry(1,1,1); // 立方体
const meterial = new THREE.MeshBasicMaterial({ color: "#ff0000"
});
const mesh = new THREE.Mesh( geometry, meterial);
scene.add( mesh ); // 添加物体到场景中// 相机
const camera = new THREE.PerspectiveCamera(45, window.innerWidth/window.innerHeight, 1, 100);
camera.position.set(0,0,10); // 修改相机位置
camera.lookAt( mesh.position ); // 相机镜头盯着物体
scene.add( camera ); // 添加相机到场景中// 添加网格线
const grid = new THREE.GridHelper( 10, 10 );
scene.add( grid );// 渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight ); // 设置渲染器(canvas标签)大小
document.body.appendChild( renderer.domElement ); // 添加渲染器(canvas标签)到页面中// 轨道控制器
const controls = new OrbitControls( camera, renderer.domElement );
controls.enableDamping = true; // 启用阻尼效果。必须应用动画。
controls.dampingFactor = 0.01; // 设置阻尼值
controls.autoRotate = true; // 自动旋转。必须应用动画。
controls.autoRotateSpeed = 1; // 自动旋转速度controls.minDistance = 5; // 最小,最大缩放比例。用于透视相机 PerspectiveCamera
controls.maxDistance = 20;// 添加键盘事件监听。键盘按下的速度和按键,采用默认值。只有添加了键盘事件监听,上下左右键才能控制轨道
controls.listenToKeyEvents( window );// 更新控制器
controls.update();function animateFun(){mesh.rotation.x += 0.01;mesh.rotation.y += 0.01;controls.update(); // 现在动画里更新控制器// 渲染renderer.render( scene, camera);requestAnimationFrame(animateFun);
}
animateFun();