当前位置: 首页 > news >正文

学习threejs,使用第一视角控制器FirstPersonControls控制相机

👨‍⚕️ 主页: gis分享者
👨‍⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅!
👨‍⚕️ 收录于专栏:threejs gis工程师


文章目录

  • 一、🍀前言
    • 1.1 ☘️第一视角控制器FirstPersonControls控制相机
  • 二、🍀利用THREE.FirstPersonControls实现第一视角控制
    • 1. ☘️实现思路
    • 2. ☘️代码样例


一、🍀前言

本文详细介绍如何基于threejs在三维场景中使用第一视角控制器FirstPersonControls控制相机,实现游戏第一人称效果,亲测可用。希望能帮助到您。一起学习,加油!加油!

1.1 ☘️第一视角控制器FirstPersonControls控制相机

THREE.FirstPersonControls 是 Three.js 的第一视角控制器,允许用户以第一人称视角进行三维场景的浏览、漫游。使用这个控制器时,用户可以通过鼠标或键盘来控制视角。
相关操控方法:
移动鼠标 向四周看
上、下、左、右方向键 向上、下、左、右移动
W 向前移动
A 向左移动
S 向后移动
D 向右移动
R 向上移动
F 向下移动
Q 停止移动
创建方法:
new THREE.FirstPersonControls(camera)
参数camera 为Threejs的相机对象
属性:
在这里插入图片描述

方法:
handleResize () : undefined 若应用程序窗口大小发生改变,则应当调用此函数。
lookAt ( vector : Vector3 ) : FirstPersonControls vector - 一个表示目标位置的向量。 或者,世界空间位置的x、y、z分量。 确保控制器将相机方向朝向到所传入的目标的位置。
lookAt ( x : Float, y : Float, z : Float ) : FirstPersonControls vector - 一个表示目标位置的向量。 或者,世界空间位置的x、y、z分量。 确保控制器将相机方向朝向到所传入的目标的位置。

二、🍀利用THREE.FirstPersonControls实现第一视角控制

1. ☘️实现思路

  • 1、初始化renderer渲染器
  • 2、初始化Scene三维场景
  • 3、初始化camera相机,定义相机位置 camera.position.set,设置相机方向camera.lookAt。
  • 4、初始化THREE.AmbientLight环境光源,scene场景加入环境光源,初始化THREE.PointLight点光源,设置点光源位置,设置点光源投影,scene添加点光源。
  • 5、加载几何模型:创建THREE.AxesHelper坐标辅助工具,创建THREE.MTLLoader加载器,调用load方法获取模型材质信息,在MTLLoader的load方法中创建THREE.OBJLoader obj模型加载器,OBJLoader 加载器设置材质为从MTLLoader获取的材质,调用OBJLoader的load方法,加载模型, 生成mesh物体,scene场景加入mesh和THREE.AxesHelper坐标辅助工具。
  • 6、创建第一视角控制器FirstPersonControls,设置控制器相关参数。加入stats监控器,监控帧数信息。

2. ☘️代码样例

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>learn44(使用第一视角控制器FIRSTPERSONCONTROLS控制相机)</title><script src="lib/threejs/127/three.js-master/build/three.js"></script><script src="lib/js/Detector.js"></script><script src="lib/js/chroma.js"></script><script src="lib/threejs/127/three.js-master/examples/js/loaders/OBJLoader.js"></script><script src="lib/threejs/127/three.js-master/examples/js/loaders/MTLLoader.js"></script><script src="lib/threejs/127/three.js-master/examples/js/controls/FirstPersonControls.js"></script><script src="lib/threejs/127/three.js-master/examples/js/libs/stats.min.js"></script><script src="lib/threejs/127/three.js-master/examples/js/libs/dat.gui.min.js"></script>
</head>
<style>html, body {margin: 0;height: 100%;}canvas {display: block;}
</style>
<body onload="draw()">
</body>
<script>var renderervar initRender = () => {renderer = new THREE.WebGLRenderer({antialias: true})renderer.setSize(window.innerWidth, window.innerHeight)renderer.sortObjects = falsedocument.body.appendChild(renderer.domElement)}var cameravar 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 scenevar initScene = () => {scene = new THREE.Scene()}var lightvar initLight = () => {scene.add(new THREE.AmbientLight)light = new THREE.PointLight(0xffffff)light.position.set(0, 50, 0)light.castShadow = truescene.add(light)}var initModel = () => {var helper = new THREE.AxesHelper(50)scene.add(helper)var mtlLoader = new THREE.MTLLoader()mtlLoader.setPath('data/model/city/')mtlLoader.load('city.mtl', material => {var objLoader = new THREE.OBJLoader()objLoader.setMaterials(material)objLoader.setPath('data/model/city/')objLoader.load('city.obj', object => {var scale = chroma.scale(['yellow', '008ae5'])setRandomColors(object, scale)scene.add(object)})})}var 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 = truematerial.opacity = 0.7material.depthWrite = false}}}// 如果不是场景组,则给当前mesh添加纹理else {//随机当前模型的颜色object.material.color = new THREE.Color(scale(Math.random()).hex())}}}}var statsvar initStats = () => {stats = new Stats()document.body.appendChild(stats.dom)}var controlsvar initControls = () => {controls = new THREE.FirstPersonControls(camera)controls.lookSpeed = 0.2 //鼠标移动查看的速度controls.movementSpeed = 20 //相机移动速度controls.noFly = truecontrols.constrainVertical = true //约束垂直controls.verticalMin = 1.0controls.verticalMax = 2.0controls.lon = -100 //进入初始视角x轴的角度controls.lat = 0 //初始视角进入后y轴的角度}var render = () => {renderer.render(scene, camera)}var onWindowResize = () => {camera.aspect = window.innerWidth / window.innerHeightcamera.updateProjectionMatrix()render()renderer.setSize(window.innerWidth, window.innerHeight)}var clock = new THREE.Clock()var animate = () => {render()stats.update()controls.update(clock.getDelta())requestAnimationFrame(animate)}var draw = () => {initRender()initScene()initCamera()initLight()initModel()initStats()initControls()animate()window.onresize = onWindowResize}
</script>
</html>

效果如下:
在这里插入图片描述

相关文章:

学习threejs,使用第一视角控制器FirstPersonControls控制相机

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️第一视角控制器FirstPerson…...

odoo17 前端 在头像下拉 dropdown 自定义菜单

odoo17 前端 在头像下拉 dropdown 自定义菜单 其实很简单, 我们先找到原来已经创建好的, 找到代码位置 使用 我的资料 为例 odoo-17.0\addons\hr\static\src\user_menu\my_profile.js /** odoo-module **/import { _t } from "web/core/l10n/translation"; import …...

如何管理好自己的LabVIEW项目

在LabVIEW项目开发中&#xff0c;项目管理对于提高开发效率、确保项目质量、减少错误和维护成本至关重要。以下从项目规划、代码管理、测试与调试、版本控制、团队协作等方面&#xff0c;分享LabVIEW项目管理的体会。 ​ 1. 项目规划与需求分析 关键步骤&#xff1a; 需求分析…...

GPT-5 要来了:抢先了解其创新突破

Microsoft 的工程师计划于 2024 年 11 月在 Azure 上部署 Orion (GPT-5)。虽然这一版本不会向公众开放&#xff0c;但其上线被视为人工智能领域的一个重要里程碑&#xff0c;并将产生深远的影响。 文章目录 GPT-5 真的要来了GPT-4 的局限性GPT-5 的创新突破与遗留挑战GPT-5 预期…...

@ComponentScan:Spring Boot中的自动装配大师

文章目录 1. 什么是ComponentScan注解&#xff1f;2. 为什么需要ComponentScan注解&#xff1f;3. 如何使用ComponentScan注解&#xff1f;4. ComponentScan注解的高级用法5. 注意事项6. 结语推荐阅读文章 在Spring Boot的世界里&#xff0c;自动装配&#xff08;Auto-wiring&a…...

uniapp 面试题总结常考

uniapp 文件详情 ├── pages # 页面文件夹 │ │── index # index文件夹 │ │ │── index.vue # index页面 ├── static # 静态资源&#xff08;类似于图片 字体图标等&#xff09; │ …...

花了36元给我的个人博客上了一道防御

前言 双11活动薅了个羊毛&#xff0c;1折的价格买了一年的EdgeOne&#xff0c;正好可以为我的个人博客站点保驾护航。本文就来看看个人博客接入EdgeOne后的效果&#xff0c;如果也想薅羊毛的&#xff0c;赶紧去双11活动页面&#xff0c;不要错过这次机会。 EdgeOne 介绍 先简…...

浅谈C++之内存管理

一、基本介绍 内存管理是C最令人切齿痛恨的问题&#xff0c;也是C最有争议的问题&#xff0c;C高手从中获得了更好的性能&#xff0c;更大的自由&#xff0c;C菜鸟的收获则是一遍一遍的检查代码和对C的痛恨&#xff0c;但内存管理在C中无处不在&#xff0c;内存泄漏几乎在每个C…...

719. 找出第 K 小的数对距离

目录 题目解法 题目 数对 (a,b) 由整数 a 和 b 组成&#xff0c;其数对距离定义为 a 和 b 的绝对差值。 给你一个整数数组 nums 和一个整数 k &#xff0c;数对由 nums[i] 和 nums[j] 组成且满足 0 < i < j < nums.length 。返回 所有数对距离中 第 k 小的数对距离。…...

【图像压缩感知】论文阅读:Self-supervised Scalable Deep Compressed Sensing

tips&#xff1a;本文为个人阅读论文的笔记&#xff0c;仅作为学习记录所用。 Title&#xff1a;Self-supervised Scalable Deep Compressed Sensing Journal&#xff1a;IJCV 2024 代码链接&#xff1a;GitHub - Guaishou74851/SCNet: Self-Supervised Scalable Deep Comp…...

Swift 宏(Macro)入门趣谈(一)

概述 苹果在去年 WWDC 23 中就为 Swift 语言新增了“其利断金”的重要小伙伴 Swift 宏&#xff08;Swift Macro&#xff09;。为此&#xff0c;苹果特地用 2 段视频&#xff08;入门和进阶&#xff09;颇为隆重的介绍了它。 那么到底 Swift 宏是什么&#xff1f;有什么用&…...

linux常见资源查询命令(持续更新)

年纪大了&#xff0c;很多命令记不住了&#xff0c;但偶尔也需要用到&#xff0c;通过搜索也需要点时间&#xff0c;特此记录。 不同操作系统命令会有所区别&#xff0c;下面是大部分时候工作的机器系统&#xff1a; CentOS release 7.5 (Final)Kernel \r on an \m 1、实时查…...

JavaWeb:文件上传1

欢迎来到“雪碧聊技术”CSDN博客&#xff01; 在这里&#xff0c;您将踏入一个专注于Java开发技术的知识殿堂。无论您是Java编程的初学者&#xff0c;还是具有一定经验的开发者&#xff0c;相信我的博客都能为您提供宝贵的学习资源和实用技巧。作为您的技术向导&#xff0c;我将…...

C++ 中的异常处理机制是怎样的?

异常处理的基本概念&#xff1a; 异常: 程序在运行时发生的错误或意外情况。 抛出异常: 使用 throw 关键字将异常传递给调用堆栈。 捕获异常: 使用 try-catch 块捕获和处理异常。 异常类型: 表示异常类别的标识符。 异常处理流程&#xff1a; 抛出异常: 当检测到错误或意…...

SwiftUI-基础入门

开发OS X 图形应用界面时有三种实现方式&#xff1a;XIB、Storyboard、SwiftUI。Storyboard基于XIB做了优化&#xff0c;但XIB基本被放弃了&#xff0c;而SwiftUI是苹果公司后来开发的一套编程语言&#xff0c;用来平替Objective-C。虽然现在Swift 6 还是有些不完善的地方&…...

C++builder中的人工智能(20):如何在C++中开发一个简单的Hopfield网络

在AI技术的发展历史中&#xff0c;模式识别模型是最伟大的AI技术之一&#xff0c;尤其是从像素图像中读取文本。其中一个是Hopfield网络&#xff08;或称为Ising模型的神经网络或Ising–Lenz–Little模型&#xff09;&#xff0c;这是一种递归神经网络形式&#xff0c;由John J…...

video2gif容器构建指南

一、介绍 1.项目概述 Video2Gif 项目旨在提供一种便捷的方式&#xff0c;让用户能够将视频中的精彩片段快速转换为 GIF 动画。GIF 动画因其循环播放、文件体积小等特点&#xff0c;在社交媒体、聊天工具中广泛应用&#xff0c;用于表达情感、分享趣事等。 2.核心功能 视频导…...

探秘Spring Boot中的@Conditional注解

文章目录 1. 什么是Conditional注解&#xff1f;2. 为什么需要Conditional注解&#xff1f;3. 如何使用Conditional注解&#xff1f;4. Conditional注解的高级用法5. 注意事项6. 结语推荐阅读文章 在Spring Boot的世界里&#xff0c;配置的灵活性和多样性是至关重要的。有时候&…...

树形dp总结

这类题型在 dp 中很常见&#xff0c;于是做一个总结吧&#xff01;&#xff01;&#xff01; 最经典的题&#xff1a;没有上司的舞会 传送门&#xff1a;没有上司的舞会 - 洛谷 状态表示&#xff1a; dp[i][0] 为 以 i 为根的子树中&#xff0c;选择 i 节点的最大欢乐值 d…...

【算法一周目】双指针(2)

目录 有效三角形的个数 解题思路 C代码实现 和为s的两个数字 解题思路 C代码实现 三数之和 解题思路 C代码实现 四数之和 解题思路 C代码实现 有效三角形的个数 题目链接&#xff1a;611. 有效三角形的个数题目描述&#xff1a;给定一个包含非负整数的数组nums&…...

地震勘探——干扰波识别、井中地震时距曲线特点

目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波&#xff1a;可以用来解决所提出的地质任务的波&#xff1b;干扰波&#xff1a;所有妨碍辨认、追踪有效波的其他波。 地震勘探中&#xff0c;有效波和干扰波是相对的。例如&#xff0c;在反射波…...

【第二十一章 SDIO接口(SDIO)】

第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...

3403. 从盒子中找出字典序最大的字符串 I

3403. 从盒子中找出字典序最大的字符串 I 题目链接&#xff1a;3403. 从盒子中找出字典序最大的字符串 I 代码如下&#xff1a; class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...

力扣-35.搜索插入位置

题目描述 给定一个排序数组和一个目标值&#xff0c;在数组中找到目标值&#xff0c;并返回其索引。如果目标值不存在于数组中&#xff0c;返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...

【前端异常】JavaScript错误处理:分析 Uncaught (in promise) error

在前端开发中&#xff0c;JavaScript 异常是不可避免的。随着现代前端应用越来越多地使用异步操作&#xff08;如 Promise、async/await 等&#xff09;&#xff0c;开发者常常会遇到 Uncaught (in promise) error 错误。这个错误是由于未正确处理 Promise 的拒绝&#xff08;r…...

第八部分:阶段项目 6:构建 React 前端应用

现在&#xff0c;是时候将你学到的 React 基础知识付诸实践&#xff0c;构建一个简单的前端应用来模拟与后端 API 的交互了。在这个阶段&#xff0c;你可以先使用模拟数据&#xff0c;或者如果你的后端 API&#xff08;阶段项目 5&#xff09;已经搭建好&#xff0c;可以直接连…...

如何在Windows本机安装Python并确保与Python.NET兼容

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…...

leetcode_69.x的平方根

题目如下 &#xff1a; 看到题 &#xff0c;我们最原始的想法就是暴力解决: for(long long i 0;i<INT_MAX;i){if(i*ix){return i;}else if((i*i>x)&&((i-1)*(i-1)<x)){return i-1;}}我们直接开始遍历&#xff0c;我们是整数的平方根&#xff0c;所以我们分两…...

CppCon 2015 学习:Reactive Stream Processing in Industrial IoT using DDS and Rx

“Reactive Stream Processing in Industrial IoT using DDS and Rx” 是指在工业物联网&#xff08;IIoT&#xff09;场景中&#xff0c;结合 DDS&#xff08;Data Distribution Service&#xff09; 和 Rx&#xff08;Reactive Extensions&#xff09; 技术&#xff0c;实现 …...

深入浅出JavaScript中的ArrayBuffer:二进制数据的“瑞士军刀”

深入浅出JavaScript中的ArrayBuffer&#xff1a;二进制数据的“瑞士军刀” 在JavaScript中&#xff0c;我们经常需要处理文本、数组、对象等数据类型。但当我们需要处理文件上传、图像处理、网络通信等场景时&#xff0c;单纯依赖字符串或数组就显得力不从心了。这时&#xff…...