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.mzph.cn/news/645025.shtml

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

相关文章

扫码登录流程

扫码登录 场景 在网页版qq邮箱,微信登录账号等时候,无需输入账号和密码,只需要在手机上扫码即可完成登录 登录分析 扫码登录涉及3种角色: PC端, 手机端, 服务端 涉及围绕这三端进行,每一端…

代码随想录算法训练营第四十二天|01背包问题、01背包问题(滚动数组)、416. 分割等和子集

题目&#xff1a;01背包问题 文章链接&#xff1a;代码随想录 视频链接&#xff1a;LeetCode:背包问题 题目链接&#xff1a;卡码题目链接 图释&#xff1a; //二维dp数组实现 #include <bits/stdc.h> using namespace std;int n, bagweight;// bagweight代表行李箱空…

打 jar 包运行 在windows 平台控制台和日志 乱码解决

--拒絕鷄巴囉嗦&#xff0c;直接解決問題 我们在Windows下运行jar包时&#xff0c;常常会出现乱码&#xff0c;主要分为dos窗口输出的日志中出现乱码和程序返回数据出现乱码。 dos窗口输出的日志中出现乱码 执行如下命令&#xff0c;将控制台输出编码改为UTF8&#xff1a; ch…

Python接口自动化测试实战

接口自动化测试是指通过编写程序来模拟用户的行为&#xff0c;对接口进行自动化测试。Python是一种流行的编程语言&#xff0c;它在接口自动化测试中得到了广泛应用。下面详细介绍Python接口自动化测试实战。 1、接口自动化测试框架 在Python接口自动化测试中&#xff0c;我们…

四、Flask学习之JavaScript

四、Flask学习之JavaScript JavaScript&#xff0c;作为一种前端脚本语言&#xff0c;赋予网页生动的交互性和动态性。通过它&#xff0c;开发者能够操作DOM&#xff08;文档对象模型&#xff09;实现页面元素的动态改变、响应用户事件&#xff0c;并借助AJAX技术实现异步数据…

山西电力市场日前价格预测【2024-01-25】

日前价格预测 预测说明&#xff1a; 如上图所示&#xff0c;预测明日&#xff08;2024-01-25&#xff09;山西电力市场全天平均日前电价为274.83元/MWh。其中&#xff0c;最高日前电价为562.65元/MWh&#xff0c;预计出现在18:15。最低日前电价为0.00元/MWh&#xff0c;预计出…

《统计学习方法:李航》笔记 从原理到实现(基于python)-- 第 2章感知机

文章目录 第 2章感知机2.1 感知机模型2.2 感知机学习策略2.2.1 数据集的线性可分性2.2.2 感知机学习策略 2.3 感知机学习算法2.3.1 感知机学习算法的原始形式2.3.2 算法的收敛性2.3.3 感知机学习算法的对偶形式 实践&#xff1a;二分类模型&#xff08;iris数据集&#xff09;数…

vue3-深入组件-组件注册和props更多细节

组件注册 定义好的组件需要注册才能被使用。 注册方式有两种 全局注册 局部注册 全局注册 .component() 方法&#xff0c;让组件在当前 Vue 应用中全局可用。 在 main.ts 中 import ./assets/main.cssimport { createApp } from vue import { createPinia } from pinia i…

Nodejs前端学习Day1

妈的&#xff0c;学vue3需要15.0以上的nodejs 文章目录 前言一、学习目标二、学习目录三、为什么JavaScript可以在浏览器中被执行四、为什么JavaScript可以操作DOM和BOM五、浏览器中的JavaScript运行环境总结 前言 妈的&#xff0c;学vue3需要15.0以上的nodejs 一、学习目标 二…

递归和尾递归(用C语言解斐波那契和阶乘问题)

很多人都对递归有了解&#xff0c;但是为尾递归很少&#xff0c;所以这次来专门讲一讲关于尾递归的一些问题。 什么是尾递归 如果一个函数中所有递归形式的调用都出现在函数的末尾&#xff0c;我们称这个递归函数是尾递归的。因为在一些题目的做法中&#xff0c;我们可以发现…

解决 Git:ssh: connect to host github.com port 22: Connection timed out 问题的三种方案

1、问题描述&#xff1a; 其一、整体提示为&#xff1a; ssh: connect to host github.com port 22: Connection timed out fatal: Could not read from remote repository. 中文为&#xff1a; ssh&#xff1a;连接到主机 github.com 端口 22&#xff1a;连接超时 fatal&a…

linux服务器ssh连接慢问题处理

一、 可能导致慢的几个原因 1、网络问题&#xff1a;网络延迟、带宽限制和包丢失等网络问题都有可能导致SSH连接变慢。 2、客户端设置&#xff1a;错误的客户端设置&#xff0c;如使用过高的加密算法或不适当的密钥设置&#xff0c;可能导致SSH连接变慢。 3、服务器负载过高…

使用docker容器 将node应用程序打包成镜像

可以使得node服务应用程序可以通过流水线部署 安装docker 1、注意 我的服务器的系统是 centos7&#xff0c;所以这里写的是在centos7上按照的docker 注意&#xff1a;Docker 要求 CentOS 系统的内容版本高于3.10 uname -r打印&#xff1a;3.10.0-1160.105.1.el7.x86_64 //确定…

leetcode刷题(剑指offer) 240.搜索二维矩阵Ⅱ

240.搜索二维矩阵Ⅱ 编写一个高效的算法来搜索 *m* x *n* 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性&#xff1a; 每行的元素从左到右升序排列。每列的元素从上到下升序排列。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,4,7,11,15],[2,5,8,12,19],[3,…

27.移除元素(力扣LeetCode)

文章目录 27.移除元素&#xff08;力扣LeetCode&#xff09;题目描述方法一&#xff1a;vector成员函数&#xff1a;erase方法二&#xff1a;暴力解法方法三&#xff1a;双指针法 27.移除元素&#xff08;力扣LeetCode&#xff09; 题目描述 给你一个数组 nums 和一个值 val&…

[每日一题] 01.24 - 求三角形

求三角形 n int(input()) count1 (1 n) * n // 2 count2 n * n lis1 [str(i).zfill(2) for i in range(1,count1 1)] lis2 [str(i).zfill(2) for i in range(1,count2 1)]for i in range(0,len(lis2),n):print(.join(lis2[i:i n]))print()for i in range(1,n 1):tem…

代码中遇到的问题

编译器错误消息&#xff1a; CS1061&#xff1a; default_aspx 不包含 GridView1_SelectedIndexChanged 的定义&#xff0c;并且找不到接受类型为default_aspx的第一个参数的可访问扩展方法GridView1_SelectedIndexChanged&#xff08;是否缺少 using 指令或程序集引用&#xf…

[笔记]Spring AOP

Spring AOP&#xff08;Aspect Oriented Programming&#xff09; AOP将应用程序分为核心业务和非核心的公共功能&#xff0c;AOP的关注点是系统中的非核心的公共功能&#xff1b; AOP可以通过预编译或者运行期动态代理的方式&#xff0c;为横跨多个对象&#xff08;没有继承关…

UCAS-AOD遥感旋转目标检测数据集——基于YOLOv8obb,map50已达96.7%

1.UCAS-AOD简介 1.1数据说明 遥感图像&#xff0c;又名高分辨率遥感图像。遥感图像的分类依据是根据成像的介质不同来进行分类的。UCAS-AOD (Zhu et al.&#xff0c;2015)用于飞机和汽车的检测&#xff0c;包含飞机与汽车2类样本以及一定数量的反例样本&#xff08;背景&…

【立创EDA-PCB设计基础】6.布线铺铜实战及细节详解

前言&#xff1a;本文进行布线铺铜实战及详解布线铺铜的细节 在本专栏中【立创EDA-PCB设计基础】前面完成了布线铺铜前的设计规则的设置&#xff0c;接下来进行布线 布局原则是模块化布局&#xff08;优先布局好确定位置的器件&#xff0c;例如排针、接口、主控芯片&#xff…