threejs学习

重要概念(场景、相机、渲染器)

如下图所示,我们最终看到浏览器上生成的内容是通过虚拟场景和虚拟相机被渲染器渲染后的结果,下面首先介绍这三个概念,将贯穿所有简单复杂的threejs项目。
在这里插入图片描述

场景 Scene

虚拟的3D场景,用来表示模拟生活中的真实三维场景,或者说三维世界

    const scene = new THREE.Scene() //创建场景//添加元素如模型、灯光等scene.add(元素)

相机 Camera

透视投影相机,如果渲染远小近大–透视投影相机,不需要远小近大–正投影相机,常用透视投影相机
正投影相机:OrthographicCamera
透视投影相机:PerspectiveCamera PerspectiveCamera( fov, aspect, near, far )

  • fov:相机视锥体竖直方向视野角度 ,默认50
  • aspect:相机视锥体水平方向和竖直方向长度比,一般设置为Canvas画布宽高比width / height ,默认1
  • near:相机视锥体近裁截面相对相机距离,默认0.1
  • far:相机视锥体远裁截面相对相机距离,far-near构成了视锥体高度方向,默认2000
    在这里插入图片描述

具体使用:

      const camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 1, 1000); // 设置相机位置camera.position.set(15, 20, 50); //控制相机的拍照目标,具体说相机镜头对准哪个物体或说哪个坐标camera.lookAt(0, 0, 0)//0,0,0是坐标圆点,(x,y,z)

注意: 相机实际形成一个视锥体,在这个范围内的物体才会被渲染出来,之外的物体不会被渲染到canvas上

在我们开发的时候,如果将far设置的比较小,在放大物体的时候,可以看到部分模型消失,只渲染了一部分,那么就是模型超出视锥体了,所以不被渲染。

渲染器 WebGLRenderer

有了相机和物体,则需要完成拍照,渲染器其实可以理解为拍照。
renderer=new THREE.WebGLRenderer();进行创建 .domElement可以获取到对应的元素。
renderer.render(场景, 相机);:执行渲染的操作,类似我们按下相机快门的操作。

//创建一个渲染器,一个canvas场景
const renderer = new THREE.WebGLRenderer();renderer.setPixelRatio(window.devicePixelRatio);  //设置像素比,如果你遇到你的canvas画布输出模糊问题一定要设置renderer.setSize(window.innerWidth, window.innerHeight); //设置canvas的大小
//锯齿属性
//renderer.antialias = true//插入html中,这里即添加到id为container的标签下
const container = document.getElementById('container')
container.appendChild(renderer.domElement);//最重要的!!!!渲染
renderer.render(scene, camera); //执行渲染操作

画布自适应

   window.addEventListener("resize", this.resize);resize() {//   console.log("画面变化了");// 更新摄像头let camera = this.cameracamera.aspect = window.innerWidth / window.innerHeight;//   更新摄像机的投影矩阵,如果相机的一些属性发生了变化,需要执行updateProjectionMatrix ()方法更新相机的投影矩阵camera.updateProjectionMatrix();let renderer = this.renderer//   更新渲染器renderer.setSize(window.innerWidth, window.innerHeight);//   设置渲染器的像素比renderer.setPixelRatio(window.devicePixelRatio);},

光源和材质

首先介绍几个相关的概念:

  1. 外观-材质Material:想定义物体的外观效果,比如颜色,就需要通过材质Material相关的API实现。
    在这里插入图片描述
  2. 物体-网格模型Mesh:在threejs中可以通过网格模型Mesh (opens new window)表示一个虚拟的物体,比如一个箱子、一个鼠标。
  3. 模型位置position
const mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
//设置网格模型在三维空间中的位置坐标,默认是坐标原点
mesh.position.set(0,10,0);

光源

光源Light:影响物体的明暗效果
不同材质对光照的影响不同,如图(材质不止下图,可到官网查看)
在这里插入图片描述
光源也有很多,具体的API推荐看官网(太多啦!)
在这里插入图片描述

材质

基础介绍,具体内容看官网
在这里插入图片描述

几何体

Three.js提供了各种各样的几何体API,用来表示三维物体的几何形状。
因为太多了就不在此赘述,可以到官网去查看对应的api和属性

在这里插入图片描述

引入外部三维模型

引入glb\gltf模型

我们在实际工作中,总是需要另外的引入模型,这里介绍引入模型的方法

import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'; //加载gltf模型的加载器
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js'  //解压用,不一定需要使用它const dracoLoader = new DRACOLoader()//设置解压工具位置dracoLoader.setDecoderPath('resources/draco/') //从node_modules\three\examples\jsm\libs\draco 中复制到public下resources/draco/  注意要从自己的项目node_modules中复制,版本不对可能会报错dracoLoader.setDecoderConfig({ type: "js" });const loader = new GLTFLoader()loader.setDRACOLoader(dracoLoader)
//在vue中默认路径是public下的loader.load("model/city-v1.glb", function (gltf) {  //const model = gltf.scene //拿到模型model.name = 'city' model.position.set(0, 0, 0) //设置模型的位置model.scale.set(0.7, 0.7, 0.7)scene.add(model)//添加到场景中})

绘制天空的效果

    const loaderbox = new THREE.CubeTextureLoader() //加载CubeTexture的一个类。 内部使用ImageLoader来加载文件let path = 'night/', format = ".jpg"const cubeTexture = loaderbox.load([  //一定是六张图!!!path + 'posx' + format,path + 'negx' + format,path + 'posy' + format,path + 'negy' + format,path + 'posz' + format,path + 'negz' + format])scene.background = cubeTexture

更改引入模型的材质

        //traverse  threejs中深度遍历的方法,会遍历所有的元素model.traverse(child => {child.material = new THREE.MeshPhongMaterial({   //只能修改mesh的外观color: new THREE.Color('#123ca8'),transparent: true,opacity: 0.5,emissiveMap: Mesh.material.map,})})//或者,如果没有跟上一级有关系的,推荐用第一种model.children.forEach(item => {if (item.name !== selectTagName) {item.children.forEach(mesh => {mesh.material = new THREE.MeshPhongMaterial({color: new THREE.Color('#123ca8'),transparent: true,opacity: 0.5,emissiveMap: mesh.material.map,})})}   })

给模型添加点击事件

document.addEventListener('click', this.handleClick, false);handleClick(e){// 射线交叉计算拾取模型const raycaster = new THREE.Raycaster()const mouse = new THREE.Vector2()let tag = this.tagBoxmouse.x = (e.offsetX / this.renderer.domElement.clientWidth) * 2 - 1mouse.y = -(e.offsetY / this.renderer.domElement.clientHeight) * 2 + 1raycaster.setFromCamera(mouse, this.camera); //一定要写,不然获取的就是空// 获取点击到的模型的数组,从近到远排列const intersects = raycaster.intersectObjects(this.scene.children, true); if (intersects.length > 0) {//intersects为点击的模型数组,可以在这里写后续的逻辑}
}

添加文字标签

可以有多种方式,这里介绍css2drender渲染
在这里插入图片描述
在animate中记得要写labelRenderer.render(scene, camera)

import {CSS2DObject, CSS2DRenderer
} from "three/examples/jsm/renderers/CSS2DRenderer";// 创建一个CSS2渲染器CSS2DRenderervar labelRenderer = new CSS2DRenderer();labelRenderer.setSize(window.innerWidth, window.innerHeight);labelRenderer.domElement.style.position = 'absolute';// 相对标签原位置位置偏移大小labelRenderer.domElement.style.top = '0px';labelRenderer.domElement.style.left = '0px';// //设置.pointerEvents=none,以免模型标签HTML元素遮挡鼠标选择场景模型labelRenderer.domElement.style.pointerEvents = 'none';document.body.appendChild(labelRenderer.domElement);function animate() {// 通过相机 场景 将结果渲染出来let delta = clock.getDelta();controls.update(delta);requestAnimationFrame(animate);renderer.render(scene, camera);labelRenderer.render(scene, camera); //渲染HTML标签对象}//如果有写resize记得在resize中也要写上//labelRenderer.setSize(window.innerWidth, window.innerHeight)animate()// 创建标签function tag(name) {var div = document.createElement('div');div.innerHTML = name;div.classList.add('lable-text');//div元素包装为CSS2模型对象CSS2DObjectvar label = new CSS2DObject(div);div.style.pointerEvents = 'none';//避免HTML标签遮挡三维场景的鼠标事件gsap.to(label.position, {y: 2,repeat: -1,duration: 2,yoyo: true,ease: "Bounce.inOut",})return label;//返回CSS2模型标签}//在想要创建标签的地方var label = tag('办公楼');//把粮仓名称obj.name作为标签var pos = new THREE.Vector3();model.getWorldPosition(pos);//获取obj世界坐标label.position.copy(pos);//位置设置为posmodel.add(label); //添加到某模型中

ThreeJs内置工具

AxesHelper

辅助坐标系,THREE.AxesHelper()的参数表示坐标系坐标轴线段尺寸大小,你可以根据需要改变尺寸。
默认y轴向上,x向右,z轴正对我们
红色:x轴
绿色:y轴
蓝色:z轴

const axesHelper = new THREE.AxesHelper(150);
scene.add(axesHelper);

DirectionalLightHelper

辅助查看DirectionalLight光源的位置

 const dirHelper = new THREE.DirectionalLightHelper(dirLight, 5);  //辅助查看光源在哪里scene.add(dirHelper);

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

CameraHelper

投影相机,用于模拟相机视锥体的辅助对象.它使用 LineSegments 来模拟相机视锥体.

 //方向光,常常用来表现太阳光照的效果。(颜色,强度)const dirLight = new THREE.DirectionalLight("rgb(253,253,253)", 10);dirLight.position.set(200, 200, 10);dirLight.castShadow = true;const cam = dirLight.shadow.camera;const cameraHelper = new THREE.CameraHelper(cam);scene.add(cameraHelper);cameraHelper.visible = true;scene.add(dirLight);

在这里插入图片描述
遇到问题描述:
在设置阴影时,只显示部分模型的阴影?
答:因为剩余模型没有在光源的视锥体内,所以没显示阴影,我们可以更改视锥体的大小位置来保证所有元素都显示阴影

//不一定都设置,根据需要设置dirLight.shadow.mapSize.width = 1024; // defaultdirLight.shadow.mapSize.height = 1024; // defaultdirLight.shadow.camera.near = 0.05; // defaultdirLight.shadow.camera.far = 400; // defaultdirLight.shadow.camera.top = 50dirLight.shadow.camera.right = 50dirLight.shadow.camera.left = -50dirLight.shadow.camera.bottom = -50

OrbitControls

平时开发调试代码,或者展示模型的时候,可以通过相机控件OrbitControls实现旋转缩放预览效果。

  • 旋转:拖动鼠标左键
  • 缩放:滚动鼠标中键
  • 平移:拖动鼠标右键

通过鼠标滚轮、左右拖拽可以放大缩小、旋转查看模型,实际上是更改相机的位置
可以根据实际的需要设置,可以放大倍数,旋转的限制等。
因为在过程中一直更改模型,所以调用animate或者监听change保证更新界面

 // #引入扩展库OrbitCoimport { OrbitControls } from "three/examples/jsm/controls/OrbitControls";let controls = new OrbitControls(camera, renderer.domElement); //创建控件对象controls.target.set(0, -1, 0); //相机控件.target属性在OrbitControls.js内部表示相机目标观察点,默认0,0,0controls.enableZoom = true;controls.update()controls.maxPolarAngle = Math.PI / 2  // 最大轨道高度为Πcontrols.minPolarAngle = 0  // 最大轨道高度为Πcontrols.autoRotate = true; //是否开启自动旋转const clock = new THREE.Clock();  //初始化时钟function animate() {// 通过相机 场景 将结果渲染出来let delta = clock.getDelta();controls.update(delta);requestAnimationFrame(animate);renderer.render(scene, camera);}animate()//如果OrbitControls改变了相机参数,重新调用渲染器渲染三维场景
controls.addEventListener('change', function () {renderer.render(scene, camera); //执行渲染操作
});//监听鼠标、键盘事件

stats

监听性能,计算three.js的渲染帧率(FPS),所谓渲染帧率(FPS)

//引入
import Stats from 'three/addons/libs/stats.module.js';//创建stats对象
const stats = new Stats();
//stats.domElement:web页面上输出计算结果,一个div元素,
document.body.appendChild(stats.domElement);
// 渲染函数
function render() {//requestAnimationFrame循环调用的函数中调用方法update(),来刷新时间stats.update();renderer.render(scene, camera); //执行渲染操作requestAnimationFrame(render); //请求再次执行渲染函数render,渲染下一帧
}
render();

gui.js

就是一个前端js库,调试用,可以在gui面板更改值,具体的使用的时候可以再深入的了解,这里只是简单的介绍

import { GUI } from 'three/addons/libs/lil-gui.module.min.js';const gui = new GUI();
//改变交互界面style属性
gui.domElement.style.right = '0px';
gui.domElement.style.width = '300px';// 通过GUI改变mesh.position对象的xyz属性
gui.add(ambient, 'intensity', 0, 2.0);//更改模型位置
gui.add(mesh.position, 'x', 0, 180);
gui.add(mesh.position, 'y', 0, 180);
gui.add(mesh.position, 'z', 0, 180);

工具

模型查看

地址:gltf模型查看
可以查看图层、选中部分模型拖拽和模型一些属性值
在这里插入图片描述

在线Threejs地址

地址:国内地址
加载比官网快很多,不过是第三方培训机构的,不知道维护到什么时候,暂且用着。

gsap

地址:gsap官网
网上也有很多用tween的,看个人喜欢
动画库
例如:

   gsap.to(this.door.scale, {x: this.door.scale.x * 8, //scale拿到门的缩放值duration: 5,ease: "power1.inOut",onComplete: () => {}});

连续的动画

 const t1 = gsap.timeline();t1.to(that.door.scale, {x: that.door.scale.x / 8, //scale拿到门的缩放值duration: 5,ease: "power1.inOut",onComplete: () => {that.carMove = 'z'}});t1.to(model.position, {x: 8,y: 0,z: 24,duration: 5,ease: "linear",onComplete: () => {that.carMove = 'x'that.closeDoor()model.rotateY(Math.PI / 2) //旋转90度},})// 设置循环次数  -1为无限循环t1.repeat(-1);// 开始播放动画t1.play();

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/244606.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux中文件属性的获取(stat、chmod、Istat、fstat函数的使用)

修改文件权限 函数如下&#xff1a; chmod/fchmod函数用来修改文件的访问权限: #include <sys/stat.h> int chmod(const char *path, mode_t mode); int fchmod(int fd, mode_t mode); 成功时返回0&#xff1b;出错时返回EOF 注意&#xff1a;在vmware和windows共享的文…

【2024-01-22】某极验3流程分析-滑块验证码

声明&#xff1a;该专栏涉及的所有案例均为学习使用&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01;如有侵权&#xff0c;请私信联系本人删帖&#xff01; 文章目录 一、前言二、抓包流程分析1.刷新页面2.点击按钮进行验证…

PyTorch各种损失函数解析:深度学习模型优化的关键(2)

目录 详解pytorch中各种Loss functions mse_loss 用途 用法 使用技巧 注意事项 参数 数学理论公式 代码演示 margin_ranking_loss 用途 用法 使用技巧 注意事项 参数 数学理论公式 代码演示 multilabel_margin_loss 用途 用法 使用技巧 注意事项 参数 …

代码随想录第十五天| ● 层序遍历 10 ● 226.翻转二叉树 ● 101.对称二叉树

文章目录 层序遍历102. 二叉树的层序遍历思路一&#xff1a;递归思路二&#xff1a;层序遍历-迭代-借助队列 107. 二叉树的层序遍历 II思路&#xff1a;层序遍历后翻转数组result即可 199.二叉树的右视图思路&#xff1a;通过list数组储存每一层末尾值 637.二叉树的层平均值思路…

class_10:this关键字

this关键字是指向调用对象的指针 #include <iostream> #include <iostream> using namespace std;class Car{ public://成员数据string brand; //品牌int year; //年限//构造函数名与类名相同Car(string brand,int year){cout<<"构造函数中&#…

Element中的el-input-number+SpringBoot+mysql

1、编写模板 <el-form ref"form" label-width"100px"><el-form-item label"商品id&#xff1a;"><el-input v-model"id" disabled></el-input></el-form-item><el-form-item label"商品名称&a…

【Web前端开发基础】前端基础布局之百分比布局、flex布局

前端基础布局 目录 前端基础布局布局简介盒模型1. 标准盒模型2. 怪异盒模型3. 解决方案4. 代码示例 常见的布局单位百分比布局flex布局一、Flex布局是什么&#xff1f;二、基本概念三、容器属性flex-direction属性&#xff1a;决定主轴的方向&#xff08;即项目的排列方向&…

【数据结构】链表(单链表与双链表实现+原理+源码)

博主介绍&#xff1a;✌全网粉丝喜爱、前后端领域优质创作者、本质互联网精神、坚持优质作品共享、掘金/腾讯云/阿里云等平台优质作者、擅长前后端项目开发和毕业项目实战✌有需要可以联系作者我哦&#xff01; &#x1f345;附上相关C语言版源码讲解&#x1f345; &#x1f44…

开始学习Vue2(组件的生命周期和数据共享)

一、组件的生命周期 1. 生命周期 & 生命周期函数 生命周期&#xff08;Life Cycle&#xff09;是指一个组件从创建 -> 运行 -> 销毁的整个阶段&#xff0c;强调的是一个时间段。 生命周期函数&#xff1a;是由 vue 框架提供的内置函数&#xff0c;会伴随着 组件…

2024/1/24HTML学习:路径

路径 3.2.1路径的介绍 加载图片&#xff0c;需要找到对应的图片。 通过一定的路径 路径分两种 绝对路径&#xff08;了解&#xff09;相对路径&#xff08;常用&#xff09; 绝对路径&#xff1a;绝对位置&#xff0c;从盘符开始的路径 1.盘符开头D:\....................…

java开发——《并发编程》

目录 一.jmm 二.并发了什么 1.只有一个核&#xff08;单核&#xff09;并发还有没有意义 2.单核&#xff0c;还有什么可见性问题 3.并发和并行 三.volitaile 1.变量的可见性问题 2.原因是什么 3.本次修改的变量直接刷到主内存 4.声明其他内存对于这个地址的缓存无效 …

Addressables(2) ResourceLocation和AssetReference

IResourceLocation var op Addressables.LoadResourceLocationsAsync(key); var result op.WaitForCompletion(); 把加载的Key塞进去&#xff0c;不难看出&#xff0c;IResourceLocation可以用来获得资源的详细信息 很适合用于更新分析&#xff0c;或者一些检查工具 AssetR…

RabbitMQ中交换机的应用及原理,案例的实现

目录 一、介绍 1. 概述 2. 作用及优势 3. 工作原理 二、交换机Exchange 1. Direct 2. Topic 3. Fanout 三、代码案例 消费者代码 1. 直连direct 生产者代码 测试 2. 主题topic 生产者代码 测试 3. 扇形fanout 生产者代码 测试 每篇一获 一、介绍 1. …

MySQL定期整理磁盘碎片

MySQL定期整理磁盘碎片&#xff1a;提升数据库性能的终极指南 MySQL作为一个强大的关系型数据库管理系统&#xff0c;在长时间运行后可能会产生磁盘碎片&#xff0c;影响数据库性能。本博客将深入讨论如何定期整理MySQL磁盘碎片&#xff0c;以确保数据库的高效运行。我们将介绍…

【心得】java从CC1链入门CC链个人笔记

来劲了&#xff0c;感觉离真正的CTF又近了一步。 本文仅从一个萌新的角度去谈&#xff0c;如有纰漏&#xff0c;纯属蒟蒻。 目录 CC链概念 CC链学习前置知识 CC1链 Version1 Version2 Version3 CC链概念 CC链 Commons Collections apache组织发布的开源库 里面主要对…

计算机网络-物理层基本概念(接口特性 相关概念)

文章目录 总览物理层接口特性星火模型给出的相关概念解释&#xff08;仅供参考&#xff09; 总览 求极限传输速率&#xff1a;奈氏准则&#xff0c;香农定理&#xff08;背景环境不一样&#xff09; 编码&#xff1a;数据变成数字信号 调制&#xff1a;数字信号变成模拟信号 信…

AMIS的组件学习使用

部分代码片段 {"id": "filterForm","className": " xysd-zbkb-pubquery","labelWidth": 130,"body": [{"type": "grid","className": "xysd-grid-query-input","c…

(二)MySQL安装与部署(redhat9)

前言 MySQL仅仅是一个产品&#xff0c;Oracle旗下的小型数据库。广泛应用在中小型项目中&#xff0c;特征体积小速度快整体成本低。尤其是开源&#xff0c;所以很多中小型项目为了降低成本纷纷选用MySql作为数控存储介质 MySql的特征 底层语言使用C、C编写的。并且使用多种编…

常用芯片学习——MBI5020芯片

MBI5020 16位恒流LED驱动器 使用说明 MBI5020内建一个16位位移寄存器(Shift Register)及一个16位输出缓存器&#xff0c;可将串行式输入数据转换为并列式输出格式。在输出端&#xff0c;设计16个稳定的电流源&#xff0c;可以因应LED负载电压 (VF) 的变化&#xff0c;提供均匀…