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

学习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 renderer
  var initRender = () => {
    renderer = new THREE.WebGLRenderer({antialias: true})
    renderer.setSize(window.innerWidth, window.innerHeight)
    renderer.sortObjects = false
    document.body.appendChild(renderer.domElement)
  }
  var camera
  var 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
  var initScene = () => {
    scene = new THREE.Scene()
  }
  var light
  var initLight = () => {
    scene.add(new THREE.AmbientLight)

    light = new THREE.PointLight(0xffffff)
    light.position.set(0, 50, 0)
    light.castShadow = true
    scene.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 = true
              material.opacity = 0.7
              material.depthWrite = false
            }
          }
        }
        // 如果不是场景组,则给当前mesh添加纹理
        else {
          //随机当前模型的颜色
          object.material.color = new THREE.Color(scale(Math.random()).hex())
        }
      }
    }
  }
  var stats
  var initStats = () => {
    stats = new Stats()
    document.body.appendChild(stats.dom)
  }
  var controls
  var 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轴的角度
  }
  var render = () => {
    renderer.render(scene, camera)
  }
  var onWindowResize = () => {
    camera.aspect = window.innerWidth / window.innerHeight
    camera.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>

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


http://www.kler.cn/a/398401.html

相关文章:

  • C++11(四)---可变参数模板
  • C++学习-空指针推荐使用nullptr
  • 21.3D surface
  • 算法沉淀一:双指针
  • MySQL技巧之跨服务器数据查询:基础篇-删除语句如何写
  • xcode-select: error: tool ‘xcodebuild‘ requires Xcode, but active developer
  • GOOGLE EARTH ENGINE——利用GEE计算和下载雪的覆盖频率(SCF)和雪的消失日期(SDD)含全球除格陵兰岛外的矢量
  • 探索C++三大特性--C++ 继承详解:从概念到高级用法
  • 每日OJ题_牛客_NC114旋转字符串_C++_Java
  • STM32 | 空气净化器
  • 构建安全可靠的人工智能数据中心的关键因素
  • mac怎么看当前终端是zsh还是bash
  • 通过全球最前沿的技术解决视频拼接中时延带来的的应用缺陷,使得全景视频拼接能够真正得以大范围使用和推广的智慧地产开源了。
  • web前端开发--盒子属性
  • C++20中的概念(Concepts)到底是什么概念?
  • Android - Pixel 6a 手机OS 由 Android 15 降级到 Android 14 操作记录
  • 六:从五种架构风格推导出HTTP的REST架构
  • 2024.5 AAAiGLaM:通过邻域分区和生成子图编码对领域知识图谱对齐的大型语言模型进行微调
  • 深度学习神经网络创新点方向(具体)
  • Linux——环境基础开发工具使用1
  • React Native 全栈开发实战班 - 原生功能集成之地理位置服务
  • 常用的Anaconda Prompt命令行指令
  • 【第三课】Rust变量与数据类型(二)
  • java.sql.SQLException Parameter index out of range
  • Ubuntu下的Eigen库的安装及基本使用教程
  • 14.最长公共前缀