简介
顾名思义, 通过第一视角控制器你可以像第一视角射击游戏那样控制摄像机. 鼠标用于控制视角, 键盘用于控制移动角色. 本人感觉最类似的效果就是 cs 游戏死亡后, 能够随意漂浮的感觉.
案例实现
首先, 引入相关库文件, 其中, 我们额外引入了一个处理颜色的库叫 chroma.js 库. 在这里, 就不详细介绍这个库了, 如果需要相关内容, 请查看其官方文档: https://gka.github.io/chroma.js/#color-rgba
- <script src="/lib/libs/chroma.js"></script>
- <script src="/lib/js/controls/FirstPersonControls.js"></script>
其次, 就是在实例化相机以后, 通过 camera 实例化相关对象, 然后进行相关配置:
- controls = new THREE.FirstPersonControls(camera);
- controls.lookSpeed = 0.2; // 鼠标移动查看的速度
- controls.movementSpeed = 20; // 相机移动速度
- controls.noFly = true;
- controls.constrainVertical = true; // 约束垂直
- controls.verticalMin = 1.0;
- controls.verticalMax = 2.0;
- controls.lon = -100; // 进入初始视角 x 轴的角度
- controls.lat = 0; // 初始视角进入后 y 轴的角度
最后, 需要在每次渲染里面更新控制器:
- var clock = new THREE.Clock();
- function animate() {
- render();
- // 更新性能插件
- stats.update();
- // 更新控制器
- controls.update(clock.getDelta());
- requestAnimationFrame(animate);
- }
该控件的相关控制方法:
操控 | 效果 |
---|---|
移动鼠标 | 向四周看 |
上、下、左、右方向键 | 向上、下、左、右移动 |
W | 向前移动 |
A | 向左移动 |
S | 向后移动 |
D | 向右移动 |
R | 向上移动 |
F | 向下移动 |
Q | 停止移动 |
案例代码
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>
- Title
- </title>
- <style type="text/CSS">
- html, body { margin: 0; height: 100%; } canvas { display: block; }
- </style>
- </head>
- <body onload="draw();">
- </body>
- <script src="/lib/three.js">
- </script>
- <script src="/lib/js/loaders/OBJLoader.js">
- </script>
- <script src="/lib/js/loaders/MTLLoader.js">
- </script>
- <script src="/lib/libs/chroma.js">
- </script>
- <!-- 处理颜色的库 -->
- <script src="/lib/js/controls/FirstPersonControls.js">
- </script>
- <script src="/lib/js/libs/stats.min.js">
- </script>
- <script src="/lib/js/libs/dat.gui.min.js">
- </script>
- <script src="/lib/js/Detector.js">
- </script>
- <script>
- var renderer;
- function initRender() {
- renderer = new THREE.webGLRenderer({
- antialias: true
- });
- renderer.setSize(window.innerWidth, window.innerHeight);
- renderer.sortObjects = false;
- // 告诉渲染器需要阴影效果
- document.body.appendChild(renderer.domElement);
- }
- var camera;
- function initCamera() {
- camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 10000);
- camera.position.set(0, 10, 50);
- camera.lookAt(new THREE.Vector3(0, 0, 0));
- }
- var scene;
- function initScene() {
- scene = new THREE.Scene();
- }
- // 初始化 dat.GUI 简化试验流程
- var gui;
- function initGui() {
- // 声明一个保存需求修改的相关数据的对象
- gui = {};
- var datGui = new dat.GUI();
- // 将设置属性添加到 gui 当中, gui.add(对象, 属性, 最小值, 最大值)
- }
- var light;
- function initLight() {
- scene.add(new THREE.AmbientLight(0x444444));
- light = new THREE.PointLight(0xffffff);
- light.position.set(0, 50, 0);
- // 告诉平行光需要开启阴影投射
- light.castShadow = true;
- scene.add(light);
- }
- function initModel() {
- // 辅助工具
- var helper = new THREE.AxesHelper(50);
- scene.add(helper);
- var mtlLoader = new THREE.MTLLoader();
- mtlLoader.setPath('/lib/assets/models/');
- // 加载 mtl 文件
- mtlLoader.load('city.mtl',
- function(material) {
- var objLoader = new THREE.OBJLoader();
- // 设置当前加载的纹理
- objLoader.setMaterials(material);
- objLoader.setPath('/lib/assets/models/');
- objLoader.load('city.obj',
- function(object) {
- // 设置颜色的取值范围
- var scale = chroma.scale(['yellow', '008ae5']);
- console.log(object);
- // 重新设置纹理颜色
- setRandomColors(object, scale);
- // 将模型缩放并添加到场景当中
- scene.add(object);
- })
- });
- }
- // 添加纹理的方法
- function setRandomColors(object, scale) {
- // 获取 children 数组
- var children = object.children;
- // 如果当前模型有子元素, 则遍历子元素
- if (children && children.length > 0) {
- children.forEach(function(e) {
- setRandomColors(e, scale)
- });
- } else {
- if (object instanceof THREE.Mesh) {
- // 如果当前的模型是楼层, 则设置固定的颜色, 并且透明化
- if (Array.isArray(object.material)) {
- for (var i = 0; i < object.material.length; i++) {
- var material = object.material[i];
- var color = scale(Math.random()).hex();
- if (material.name.indexOf("building") === 0) {
- material.color = new THREE.Color(color);
- material.transparent = true;
- material.opacity = 0.7;
- material.depthWrite = false;
- }
- }
- }
- // 如果不是场景组, 则给当前 mesh 添加纹理
- else {
- // 随机当前模型的颜色
- object.material.color = new THREE.Color(scale(Math.random()).hex());
- }
- }
- }
- }
- // 初始化性能插件
- var stats;
- function initStats() {
- stats = new Stats();
- document.body.appendChild(stats.dom);
- }
- var controls;
- function initControls() {
- controls = new THREE.FirstPersonControls(camera);
- controls.lookSpeed = 0.2; // 鼠标移动查看的速度
- controls.movementSpeed = 20; // 相机移动速度
- controls.noFly = true;
- controls.constrainVertical = true; // 约束垂直
- controls.verticalMin = 1.0;
- controls.verticalMax = 2.0;
- controls.lon = -100; // 进入初始视角 x 轴的角度
- controls.lat = 0; // 初始视角进入后 y 轴的角度
- }
- function render() {
- renderer.clear();
- renderer.render(scene, camera);
- }
- // 窗口变动触发的函数
- function onWindowResize() {
- camera.aspect = window.innerWidth / window.innerHeight;
- camera.updateProjectionMatrix();
- render();
- renderer.setSize(window.innerWidth, window.innerHeight);
- }
- var clock = new THREE.Clock();
- function animate() {
- // 更新控制器
- render();
- // 更新性能插件
- stats.update();
- controls.update(clock.getDelta());
- requestAnimationFrame(animate);
- }
- function draw() {
- // 兼容性判断
- if (!Detector.webgl) Detector.addGetWebGLMessage();
- initGui();
- initRender();
- initScene();
- initCamera();
- initLight();
- initModel();
- initControls();
- initStats();
- animate();
- window.onresize = onWindowResize;
- }
- </script>
- </html>
来源: https://www.2cto.com/kf/201803/734241.html