ThreeJs中场景(scene)、 相机(camera)、渲染器(renderer)等方法类使用

news2024/11/13 23:27:16

ThreeJs笔记

简介

WebGL(Web Graphics Library,Web图形库),是一个JavaScript API,可在任何兼容的Web浏览器中渲染高性能的交互式3D和2D图形,而无需使用插件 。 WebGL通过引入一个与OpenGL ES 2.0非常一致的API来做到这一点,该API可以在HTML5 元素中使用。 这种一致性使API可以利用用户设备提供的硬件图形加速。通过这些接口,开发者可以直接跟GPU进行通信。

WebGL 程序分为两部分:

  • 使用 Javascript 编写的运行在CPU的程序
  • 使用 GLSL 编写的运行在GPU的着色器程序

着色器程序接收CPU传过来的数据,并进行一定处理,最终渲染成丰富多彩的应用样式。着色器程序如下:

// 顶点着色器
var vertex_shader_source =
    'void main() {' +
    '   gl_Position = vec4(0.0, 0.0, 0.0, 1.0);' + // 设置顶点坐标
    '   gl_PointSize = 10.0;' + // 设置顶点的大小
    '' +
    '}';
 
// 片元着色器
var fragment_shader_source =
    'void main(){' +
    '   gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);' + //设置顶点颜色
    '}';

原生WebGL 能绘制的基本图元只有 3 种,分别是点、线段、三角形,对应了物理世界中的点线面。所有复杂的图形或者立方体,都是先用点组成基本结构,然后用三角形将这些点构成的平面填充起来,最后由多个平面组成几何体。但现实情况是,如果想生成满足各种应用场景的复杂形状,几何结构会非常复杂,代码写起来也会非常复杂。所以我们选择借助一些3d渲染框架来实现应用场景的复杂形状。

例如threeJs(Three.js是国内文档资料最多、使用最广泛的三维引擎)

ThreeJs,是一个基于原生WebGL,轻量级,跨平台的Javascript库,可以在浏览器上结合HTML5的canvas,SVG或者WebGL,创建和展示3D模型和动画。允许我们在不依赖任何浏览器插件的情况下,创建一个GPU加速的3D动画场景,这可能得益于WebGL的出现,因为WebGL的底层实现是基于OpenGL。

  • Three.js官网

ThreeJs入门使用

原生创建一个WebGL程序,一般需要4个步骤:

  • 初始化WebGL绘图上下文
  • 初始化着色器程序
  • 建立模型和数据缓存
  • 完成绘制和动画

但是对于Treee.js却有所不同,其使用面向对象的方式来构建程序,包含3个基本对象:场景(scene)、 相机(camera)、渲染器(renderer)。

一、获取three.js

demo版本控制

"node": "v16.18.1",
"three": "0.156.1", 
"vue": "3.3.4",

下载依赖

npm install three

项目中引入

import * as THREE from 'three'; //导入全部核心包
import { Scene } from 'three'; //按需导入
// 引入附加组件,附加组件,必须显式导入,例如轨道控制OrbitControls
import { OrbitControls } from ' three/examples/jsm/controls/OrbitControl 

注:附加组件以及其他需要单独引入依赖three内置在examples文件夹下

二、创建场景、摄像机、渲染器(画布)

  • 场景(scene) :用于把创建完成的模型 添加到 画布中。
  • 摄像机 (camera): 相当于人眼所在的位置 ;
  • 渲染器(renderer):相当于canvas 画布元素。
  • 创建三个元素之后 ,把画布 插入到html 元素中
const scene = new THREE.Scene();
// 设置场景背景
const textureLoader = new THREE.TextureLoader()
// scene.background = new THREE.Color(0xaaaaaa)
scene.background = textureLoader.load('src/assets/images/t2.png', () => {
  renderer.render(scene, camera)
})

// 创建摄像机
const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 2000); // (角度  , 长宽比  , 最近看到的距离, 最远)
camera.position.x = -30;
camera.position.y = 40;
camera.position.z = 30;
camera.lookAt(scene.position); //将相机指向场景

//创建webgl渲染器 (画布)
const renderer = new THREE.WebGLRenderer();
renderer.setClearColor(0xeeeeee); //canvas画布颜色 会被scene.background覆盖
renderer.setSize(window.innerWidth, window.innerHeight);  //canvas 画布大小	
	
// 将这个canvas元素插入到 html中
document.getElementById('chartlet-box').appendChild(renderer.domElement);
renderer.render(scene, camera);	

创建摄像机 PerspectiveCamera参数图解

在这里插入图片描述

三、创建辅助坐标系

  • 更直观的去设置元素的位置
  • 用scene.add 去添加元素到画布
  • 必须在appendChild 插入前
// 辅助坐标系
const axesHelper = new THREE.AxesHelper(200) //参数200标示坐标系大小,可以根据场景大小去设置
scene.add(axesHelper)

展示效果:

在这里插入图片描述

四、平面、立方体、球、线的创建

  • 平面的创建,需要大小(PlaneGeometry)和材质(MeshStandardMaterial) 两个对象;
  • THREE.Mesh 创建一个网格模型对象 几何体是不能被渲染的,只有几何体和材质结合成网格才能被渲染到屏幕上
  • scene.add 添加到画布中
//底坐
const planeGeometry = new THREE.PlaneGeometry(200, 200)
const planeMaterial = new THREE.MeshLambertMaterial({ color: 0xaaaaaa, opacity: 1 })
const plane = new THREE.Mesh(planeGeometry, planeMaterial)
plane.rotation.x = -0.5 * Math.PI
plane.position.y = -25
//告诉底部平面需要接收阴影
plane.receiveShadow = true
scene.add(plane)

// 长方体模型
const geometry = new THREE.BoxGeometry(200, 20, 200)

// 模型材质
const material = new THREE.MeshLambertMaterial({
  color: 'rgb(39, 148, 177)'
})

// 模型材质图片
const texture = textureLoader.load('src/assets/images/t1.png', () => {
  renderer.render(scene, camera)
})
const material1 = new THREE.MeshLambertMaterial({
  map: texture
})
const mesh = new THREE.Mesh(geometry, [material, material, material, material, material1, material])
mesh.castShadow = true
scene.add(mesh)

// 画线
const myLineMaterial = new THREE.LineBasicMaterial({ color: 'red' })
const geometryBuffer = new THREE.BufferGeometry()
const points: any[] = []
points.push(new THREE.Vector3(50, 0, 101))
points.push(new THREE.Vector3(50, -100, 101))
geometryBuffer.setFromPoints(points)
const line = new THREE.Line(geometryBuffer, myLineMaterial)
scene.add(line)

// 画圆
const geometryCircle = new THREE.CircleGeometry(5)
const materialCircle = new THREE.MeshBasicMaterial({ color: 0xffff00 })
const circle = new THREE.Mesh(geometryCircle, materialCircle)
circle.position.x = 50
circle.position.y = -25
circle.position.z = 102
circle.name = 'test'
scene.add(circle)

展示效果:此时我们可以看到,地面,立方体都没有颜色,是因为没有光源 ,下面添加光源。

在这里插入图片描述

五、光源的创建

  • 创建灯光的类型,和颜色(光源的种类可以在官方文档中去查看)
  • 设置光源的位置
  • 设置光源,投影的长度
  • scene.add添加到画布
// 光源 环境光会均匀的照亮场景中的所有物体
const ambient = new THREE.AmbientLight(0x404040, 16)
scene.add(ambient)

// 平行光可以投射阴影 显示阴影纹路
const directionalLight = new THREE.DirectionalLight()
directionalLight.position.set(200, 200, 200)
directionalLight.shadow.camera.near = 20 //产生阴影的最近距离
directionalLight.shadow.camera.far = 200 //产生阴影的最远距离
directionalLight.shadow.camera.left = -50 //产生阴影距离位置的最左边位置
directionalLight.shadow.camera.right = 50 //最右边
directionalLight.shadow.camera.top = 50 //最上边
directionalLight.shadow.camera.bottom = -50 //最下面
//这两个值决定使用多少像素生成阴影 默认512
directionalLight.shadow.mapSize.height = 1024
directionalLight.shadow.mapSize.width = 1024
//告诉平行光需要开启阴影投射
directionalLight.castShadow = true
scene.add(directionalLight)

效果展示:

在这里插入图片描述

六、鼠标操控三维场景

  • 鼠标操控三维场景 需要引入OrbitControls规定控制插件来实现鼠标缩放与拖拽画布
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'

// 轨道控件
const controls = new OrbitControls(camera, renderer.domElement)
controls.addEventListener('change', () => {
  renderer.render(scene, camera)
})
  • 通过OrbitControls来控制某个模型始终面向相机
controls.addEventListener('change', () => {
  const { x, y, z } = camera.position
  scene.traverse((child) => {
    if (child.name === 'test') {
      child.lookAt(x, y, z)
    }
  })
  renderer.render(scene, camera)
})

七、添加点击事件

  • 画布的生成dom通过addEventListener添加点击事件
  • 结合Raycaster类进行鼠标拾取,计算鼠标或触摸点的位置
  • 根据射线计算与所有对象的交点获取到点击的对象数组
renderer.domElement.addEventListener('click', (event: any) => {
  const raycaster = new THREE.Raycaster() // 光线投射用于进行鼠标拾取
  const mouse = new THREE.Vector2()
  // 计算鼠标或触摸点的位置
  mouse.x = (event.clientX / window.innerWidth) * 2 - 1
  mouse.y = -(event.clientY / window.innerHeight) * 2 + 1
  // 更新射线
  raycaster.setFromCamera(mouse, camera)
  // 计算与所有对象的交点
  const intersects = raycaster.intersectObjects(scene.children, true)
  if (intersects.length > 0) {
    // 处理点击事件
    // intersects[0] 包含了第一个交点
    const clickedObject: any = intersects[0].object
    //通过点击到该模型用名字匹配
    if (clickedObject.name === 'test') {
      console.log('获取的当前模型信息:', clickedObject)
      clickedObject.material.color.set('pink')
      renderer.render(scene, camera)
    }
  }
})

ThreeJs其他辅助类介绍

一、加载3D模型文件glb

  • 需要单独引入对应的载入程序
  • 解决报错: THREE.GLTFLoader: No DRACOLoader instance provided
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader'
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader'

const loader = new GLTFLoader()
/* 报错: THREE.GLTFLoader: No DRACOLoader instance provided */
/* 
解决办法:

在node_modules安装的包中获取three版本对应的draco,路径为node_modules\three\examples\js\libs\draco

将该文件夹复制到public文件夹下并在DRACOLoader.setDecoderPath时候设置该对应路径即可
————————————————
版权声明:本文为CSDN博主「早日退休!」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_48894212/article/details/127241897 
*/
const dracoLoader = new DRACOLoader()
dracoLoader.setDecoderPath('/public/draco/') // 设置public下的解码路径,注意最后面的/
loader.setDRACOLoader(dracoLoader)
loader.load(
  '/src/assets/glb/LittlestTokyo.glb',
  function (gltf: any) {
    scene.add(gltf.scene)
  },
  undefined,
  function (error: any) {
    console.error(error)
  }
)

二、创建css3D渲染器

  • ThreeJs提供的CSS3DObject把一个文档dom对象转化成ThreeJs可用的Object3D对象,CSS3DRenderer就是负责渲染这个CSS3DObject的渲染器
  • 创建方式渲染器方式与webgl渲染器一致、需要单独设置渲染器dom的定位样式,才能在webgl的画布上面显示
  • webgl渲染器和css3D渲染器同时存在时,css3D渲染器设置了样式position在顶层显示
  • 在轨道控制以及事件处理方面直接通过3d渲染器去传递下去。如果加载在webgl渲染器上会导致无法操作
const createTag = (obj: any) => {
  const element = document.createElement('div')
  element.className = 'tag'
  element.innerHTML = `<p>名称:${obj.name}</p><p>温度:22°</p><p>湿度:29%</p>`
  // css3d添加点击事件
  element.addEventListener('pointerdown', () => {
    console.log('click')
  })
  const object = new CSS3DObject(element)
  object.visible = true
  //缩放比例
  object.scale.set(0.2, 0.2, 0.2)
  //指定摆放位置
  object.position.copy(obj.position)
  return object
}
const tags: any[] = []
scene.traverse((child) => {
  if (child.isObject3D && child.children.length === 0) {
    //添加标签文字
    const tag = createTag(child)
    tags.push(tag)
    scene.add(tag) //添加到指定的场景里
  }
})

const render3D = new CSS3DRenderer()
//设置渲染器大小
render3D.setSize(width, height)
//需要设置位置---------------------- 重点 ---------------------------
render3D.domElement.style.position = 'absolute'
render3D.domElement.style.top = '0'
//该渲染器也要加上同样的控制器
const controls1 = new OrbitControls(camera, render3D.domElement)
render3D.render(scene, camera)

scene.tarverse: 该方法接受一个函数作为参数,遍历调用者和它的所有后代,都执行该function

三、关于材质与贴图

  • 材质种类参考官网文档或者推荐博客
// 颜色
const material = new THREE.MeshLambertMaterial({
  color: 'rgb(39, 148, 177)'
})
// 图片
const textureLoader = new THREE.TextureLoader()
const texture = textureLoader.load('src/assets/images/t1.png', () => {
  // 加载完成图片后刷新页面显示材质
  renderer.render(scene, camera)
})
const material1 = new THREE.MeshLambertMaterial({
  map: texture
})

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

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

相关文章

学编程,为什么优先推荐学Python?

编程&#xff0c;也就是用计算机语言来控制计算机的过程&#xff0c;是当今社会中一项非常重要和有用的技能。无论你是想从事科学研究、工程设计、商业管理、教育传播、艺术创作&#xff0c;还是其他任何领域&#xff0c;学习编程都可以给你带来很多好处。 本文将从以下几个方…

Maven 构建生命周期

目录 构建阶段由插件目标构成 Clean 生命周期 Default (Build) 生命周期 命令行调用 Site 生命周期 Maven 构建生命周期定义了一个项目构建跟发布的过程。 一个典型的 Maven 构建&#xff08;build&#xff09;生命周期是由以下几个阶段的序列组成的&#xff1a; 阶段 处…

express-generator快速构建node后端项目

express-generator是express官方团队开发者准备的一个快速生成工具&#xff0c;可以非常快速的生成一个基于express开发的框架基础应用。 npm安装 npm install express-generator -g初始化应用 express my_node_test 创建了一个名为 my_node_test 的express骨架项目通过 Exp…

Session 机制

一、Session 会话机制原理 Session&#xff08;会话&#xff09;机制是一种在 Web 应用程序中用来跟踪用户状态的技术。它通过在服务器端存储和管理用户信息&#xff0c;为每个用户分配一个唯一的会话标识符&#xff08;Session ID/Token&#xff09;&#xff0c;并将该标识符…

CMS难题待解?头部企业已领跑前装量产与集成趋势

对汽车智能化来说&#xff0c;又一项智能交互的科技新配置已经兴起。 今年9月初&#xff0c;阿维塔12在德国慕尼黑车展上全球首发亮相&#xff0c;作为一款纯电智能豪华轿跑&#xff0c;新车采用电子外后视镜&#xff08;CMS&#xff09;取代了传统外后视镜&#xff0c;为这款…

提供电商API接口,点击获取API文档及测试

提供电商API接口&#xff0c;点击获取API文档及测试&#xff0c;一键对接各大主流电商平台 随着电子商务的飞速发展&#xff0c;电商API接口在业务运营中发挥着越来越重要的作用。它们提供了高效、便捷的连接方式&#xff0c;使得不同系统之间能够无缝协同工作&#xff0c;提升…

iPhone删除的照片怎么找回?总有一个方法适合你

大家都知道&#xff0c;手机使用久了就会产生很多垃圾文件。特别是占内存最大的照片&#xff0c;女生应该深有体会。对于相册里那些已经用不到的照片以及拍摄失败的“废片”&#xff0c;我们通常会选择将其一键删除。 但是如果在清理的过程中将一些重要的照片误删了该怎么办&a…

设计PCB时天线区域不想涂绿油怎么办?

摘要&#xff1a;本文以嘉立创EDA为例介绍一下如何将天线区域的绿油去掉。 设计制作带有PCB天线的电路板时&#xff0c;为了提升天线性能&#xff0c;最好是将天线金属部分裸露&#xff0c;不要盖上绿油。处理的方式有三种&#xff1a;第一种是将天线部分的一个小矩形区域开窗&…

【深蓝学院】手写VIO第6章--视觉前端--笔记

第5章相关内容&#xff0c;还是CSDN的传统Markdown编辑器好用。 视觉前段在14讲课程中已经讲过&#xff0c;这里再简单复习一下。 1. 前端工作的定性比较&#xff0c;分析 这一节讲了很多关于前端的方法框架的对比讨论&#xff0c;后面看完了相关的论文之后强烈建议再回来听一…

如何在Firefox中配置HTTP?

在浏览器中配置HTTP是一个常见的需求&#xff0c;它可以让我们轻松访问需要的网站或保护个人隐私。本文将为您详细介绍如何在Firefox浏览器中配置HTTP应用&#xff0c;帮助您实现无缝的HTTP体验。无论您是初次接触HTTP还是有一定经验的用户&#xff0c;本文都能为您提供实用的操…

ParCNetV2: Oversized Kernel with Enhanced Attention(超大的内核,增强了注意力)

贡献&#xff1a; 提出了超大卷积&#xff0c;用于CNN中长距离特征相互作用的有效建模。与ParCNetV1相比&#xff0c;它能够在所有空间位置上进行均匀卷积&#xff0c;同时消除了对额外位置编码的需求。提出了两个分叉门单元(空间BGU和通道BGU)&#xff0c;它们是紧凑而强大的…

阿里云服务器计算型规格族18个实例规格性能特点和适用场景汇总

阿里云服务器ECS计算型规格族属于独享型云服务器&#xff0c;在高负载不会出现计算资源争夺现象&#xff0c;因为每一个vCPU都对应一个Intel Xeon 处理器核心的超线程&#xff0c;具有性能稳定且资源独享的特点。本文介绍阿里云服务器ECS计算型实例规格族18个具体实例规格的性…

力扣第113题 路径总和 || 树 深度优先搜索 回溯 二叉树

题目 113. 路径总和 II 中等 给你二叉树的根节点 root 和一个整数目标和 targetSum &#xff0c;找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。 叶子节点 是指没有子节点的节点。 示例 1&#xff1a; 输入&#xff1a;root [5,4,8,11,null,13,4,7,2,null,n…

Maven系列第3篇:详解maven解决依赖问题

maven系列目标&#xff1a;从入门开始开始掌握一个高级开发所需要的maven技能。 这是maven系列第3篇。 我们先来回顾一下什么是maven&#xff1f; maven是apache软件基金会组织维护的一款自动化构件工具&#xff0c;专注服务于java平台的项目构件和依赖管理。 本文主要内容…

高频时序数据仓库

天软课堂将在本周四添加新主题--天软超高频行情数据。针对市场上高频行情数据处理业务的相关痛点&#xff0c;直观的在线演示如何通过天软高频数仓及高性能计算能力&#xff0c;将其逐个击破&#xff0c;期待各位老师的参会。

不吹不黑,网络安全工程师年薪30万是真的吗?

近几年&#xff0c;网络安全愈演愈烈&#xff0c;很多人都开始重视网络安全&#xff0c;有些公司为了招聘网安人才主动给出去30万甚至更高的年薪&#xff0c;那么&#xff0c;今天就来说一下网络安全工程师的那些事&#xff0c;看看他们真的是有这么厉害吗&#xff1f;他们又凭…

如何处理前端路由?

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…

【Redis】Redis性能优化:理解与使用Redis Pipeline

原创不易&#xff0c;注重版权。转载请注明原作者和原文链接 文章目录 Pipeline介绍原生批命令(MSET, MGET) VS PipelinePipeline的优缺点一些疑问Pipeline代码实现 当我们谈论Redis数据处理和存储的优化方法时&#xff0c;「 Redis Pipeline」无疑是一个不能忽视的重要技术。…

06-Zookeeper选举Leader源码剖析

上一篇&#xff1a;05-Zookeeper典型使用场景实战 一、为什么要看源码 提升技术功底&#xff1a;学习源码里的优秀设计思想&#xff0c;比如一些疑难问题的解决思路&#xff0c;还有一些优秀的设计模式&#xff0c;整体提升自己的技术功底深度掌握技术框架&#xff1a;源码看多…

文献检索技巧收集

在进行文献阅读之前最重要的工作就是文献检索&#xff0c;筛选出有价值的文献进行阅读。在写作的时候直接plain text&#xff0c;少用标题 文献检索–>文献阅读–>文献整理–>… 一、搜索技巧 加不加引号&#xff0c;在搜索中文时不会有这个烦恼&#xff0c;中文分词时…