Three.js机器人与星系动态场景(四):封装Threejs业务组件
实际在写业务的时候不会在每个组件里都写几十行的threejs的初始化工作。我们可以 将通用的threejs的场景、相机、render、轨道控制器等进行统一初始化。同时将非主体的函数提到组件外部,通过import导入进组件。将业务逻辑主体更清晰一些。下面的代码是基于react+threejs开发,感兴趣可以看看之前的博客关于这部分详细的介绍
Three.js机器人与星系动态场景:实现3D渲染与交互式控制-CSDN博客
Three.js机器人与星系动态场景(二):强化三维空间认识-CSDN博客
Three.js机器人与星系动态场景(三):如何实现动画-CSDN博客
封装ThreeTool类
在src目录下新建BasicThree文件夹,index.ts


导入相关依赖
导入three的所有方法,命名为THREE
导入轨道控制器类
性能监控库
字体加载
文本geometry
import * as THREE from "three"; // 引入Three.js库
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";import Stats from "three/examples/jsm/libs/stats.module.js"; // 引入性能监控库
import { FontLoader } from "three/examples/jsm/loaders/FontLoader";
import { TextGeometry } from "three/examples/jsm/geometries/TextGeometry";
添加属性和构造方法
export class ThreeTool {public camera: THREE.PerspectiveCamera; // 相机对象public scene: THREE.Scene; // 场景对象public renderer: THREE.WebGLRenderer; // 渲染器对象// 构造函数,初始化Three.js工具constructor() {this.renderer = this.initRenderer(); // 初始化渲染器this.scene = this.initScene(); // 初始化场景this.camera = this.initCamera(); // 初始化相机this.initOrbitControls();}
}
初始化渲染器
// 初始化渲染器的方法public initRenderer(): THREE.WebGLRenderer {const renderer = new THREE.WebGLRenderer({ antialias: true });renderer.setPixelRatio(window.devicePixelRatio);renderer.setSize(window.innerWidth, window.innerHeight);return renderer;}
初始化场景
// 初始化场景的方法public initScene(): THREE.Scene {const scene = new THREE.Scene();return scene;}
初始化渲染器
// 初始化渲染器的方法public initRenderer(): THREE.WebGLRenderer {const renderer = new THREE.WebGLRenderer({ antialias: true });renderer.setPixelRatio(window.devicePixelRatio);renderer.setSize(window.innerWidth, window.innerHeight);return renderer;}
初始化相机
// 初始化相机的方法public initCamera(): THREE.PerspectiveCamera {const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);return camera;}
初始化轨道控制器
//初始化轨道控制器public initOrbitControls() {const controls = new OrbitControls(this.camera, this.renderer.domElement);controls.update();}
初始化性能监控
// 初始化性能监控的方法public initStats(container: HTMLDivElement) {const stats = new Stats();stats.dom.style.position = "absolute";stats.dom.style.left = "0";stats.dom.style.zIndex = "100";container.appendChild(stats.dom); // 将性能监控DOM元素添加到容器中return stats;}
初始化辅助坐标系
//初始化坐标系辅助public initAxisHelper(axesLength: number = 150, showText: boolean = true) {const helper = new THREE.AxesHelper(axesLength);if (showText) {const loader = new FontLoader();let meshX = new THREE.Mesh();let meshY = new THREE.Mesh();let meshZ = new THREE.Mesh();loader.load("fonts/optimer_regular.typeface.json", (font) => {meshX = this.createText("X", font);meshY = this.createText("Y", font);meshZ = this.createText("Z", font);meshX.position.x = 12;meshY.position.y = 12;meshZ.position.z = 12;this.scene.add(meshX);this.scene.add(meshY);this.scene.add(meshZ);});}this.scene.add(helper);}
初始化文本
private createText(content: string, font: any) {const textGeometry = new TextGeometry(content, {font: font,size: 1,depth: 0.1,curveSegments: 1,});textGeometry.center();const textMaterial = new THREE.MeshPhongMaterial({ color: 0xffffff, flatShading: true }); // frontconst mesh = new THREE.Mesh(textGeometry, textMaterial);return mesh;}
完整代码
import * as THREE from "three"; // 引入Three.js库
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";import Stats from "three/examples/jsm/libs/stats.module.js"; // 引入性能监控库
import { FontLoader } from "three/examples/jsm/loaders/FontLoader";
import { TextGeometry } from "three/examples/jsm/geometries/TextGeometry";
export class ThreeTool {public camera: THREE.PerspectiveCamera; // 相机对象public scene: THREE.Scene; // 场景对象public renderer: THREE.WebGLRenderer; // 渲染器对象// 构造函数,初始化Three.js工具constructor() {this.renderer = this.initRenderer(); // 初始化渲染器this.scene = this.initScene(); // 初始化场景this.camera = this.initCamera(); // 初始化相机this.initOrbitControls();}public rendererContainer() {this.renderer.render(this.scene, this.camera); // 渲染场景和相机}// 初始化场景的方法public initScene(): THREE.Scene {const scene = new THREE.Scene();return scene;}// 初始化渲染器的方法public initRenderer(): THREE.WebGLRenderer {const renderer = new THREE.WebGLRenderer({ antialias: true });renderer.setPixelRatio(window.devicePixelRatio);renderer.setSize(window.innerWidth, window.innerHeight);return renderer;}// 初始化相机的方法public initCamera(): THREE.PerspectiveCamera {const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);return camera;}public initOrbitControls() {const controls = new OrbitControls(this.camera, this.renderer.domElement);controls.update();}// 初始化性能监控的方法public initStats(container: HTMLDivElement) {const stats = new Stats();stats.dom.style.position = "absolute";stats.dom.style.left = "0";stats.dom.style.zIndex = "100";container.appendChild(stats.dom); // 将性能监控DOM元素添加到容器中return stats;}public initAxisHelper(axesLength: number = 150, showText: boolean = true) {const helper = new THREE.AxesHelper(axesLength);if (showText) {const loader = new FontLoader();let meshX = new THREE.Mesh();let meshY = new THREE.Mesh();let meshZ = new THREE.Mesh();loader.load("fonts/optimer_regular.typeface.json", (font) => {meshX = this.createText("X", font);meshY = this.createText("Y", font);meshZ = this.createText("Z", font);meshX.position.x = 12;meshY.position.y = 12;meshZ.position.z = 12;this.scene.add(meshX);this.scene.add(meshY);this.scene.add(meshZ);});}this.scene.add(helper);}private createText(content: string, font: any) {const textGeometry = new TextGeometry(content, {font: font,size: 1,depth: 0.1,curveSegments: 1,});textGeometry.center();const textMaterial = new THREE.MeshPhongMaterial({ color: 0xffffff, flatShading: true }); // frontconst mesh = new THREE.Mesh(textGeometry, textMaterial);return mesh;}
}
代码中使用
通过new ThreeTool()形式创建一个工具类的实例
// 创建 ThreeTool 实例const instance = new ThreeTool();
通过示例的属性操作相机、场景
import { useEffect, useRef } from "react";
import * as THREE from "three";
import { generateRobot, generateStarts } from "./generate";
import { ThreeTool } from "../../BasicThree";
import Stats from "three/examples/jsm/libs/stats.module.js";/*** 创建一个Three.js场景,包括相机和渲染器*/
function Robot() {// 创建一个div容器,用于存放渲染的Three.js场景const containerRef = useRef<HTMLDivElement>(null);const statsRef = useRef<Stats>(); // 创建用于引用统计信息的 ref// 创建 ThreeTool 实例const instance = new ThreeTool();// 初始化相机位置和朝向instance.camera.position.set(15, 12, 8);instance.camera.lookAt(0, 0, 0);// 添加坐标系instance.initAxisHelper();// 生成机器人和星星const robot = generateRobot();const robot2 = generateRobot();robot2.position.x = 6;robot2.position.z = 6;const starts = generateStarts(200);// 将物体添加到场景instance.scene.add(robot, robot2, starts);// 创建并设置方向光const straightLight = new THREE.DirectionalLight(0xffffff, 5);straightLight.position.set(20, 20, 20);instance.scene.add(straightLight);// 动画函数const animate = () => {requestAnimationFrame(animate);robot.rotation.z -= 0.005;robot2.rotation.y -= 0.005;starts.rotation.y -= 0.001;starts.rotation.z += 0.001;starts.rotation.x += 0.001;instance.renderer.render(instance.scene, instance.camera);statsRef.current && statsRef.current.update(); // 更新统计信息};// 监听组件挂载和卸载useEffect(() => {if (containerRef.current) {containerRef.current.appendChild(instance.renderer.domElement);instance.renderer.render(instance.scene, instance.camera);statsRef.current = instance.initStats(containerRef.current); // 初始化统计信息// 启动动画循环animate();}}, [containerRef]);// 返回div容器,用于存放渲染的Three.js场景return <div ref={containerRef} style={{ width: "100vw", height: "100vh" }}></div>;
}// 导出Robot组件
export default Robot;
generate模型生成文件
import * as THREE from "three";
function createHead() {//SphereGeometry创建球形几何体const head = new THREE.SphereGeometry(4, 32, 16, 0, Math.PI * 2, 0, Math.PI * 0.5);const headMaterial = new THREE.MeshStandardMaterial({color: 0x43b988,roughness: 0.5,metalness: 1.0,});const headMesh = new THREE.Mesh(head, headMaterial);return headMesh;
}
//触角
function generateHorn(y: number, z: number, angle: number) {//触角 CapsuleGeometry 创建胶囊形状的几何体。胶囊形状可以看作是一个圆柱体两端加上半球体const line = new THREE.CapsuleGeometry(0.1, 2);const lineMaterial = new THREE.MeshStandardMaterial({color: 0x43b988,roughness: 0.5,metalness: 1.0,});const lineMesh = new THREE.Mesh(line, lineMaterial);lineMesh.position.y = y;lineMesh.position.z = z;lineMesh.rotation.x = angle;return lineMesh;
}
//机器人眼睛
function generateEye(x: number, y: number, z: number) {//SphereGeometry创建球形几何体const eye = new THREE.SphereGeometry(0.5, 32, 16, 0, Math.PI * 2, 0, Math.PI * 2);const eyeMaterial = new THREE.MeshStandardMaterial({color: 0x212121,roughness: 0.5,metalness: 1.0,});const eyeMesh = new THREE.Mesh(eye, eyeMaterial);eyeMesh.position.x = x;eyeMesh.position.y = y;eyeMesh.position.z = z;return eyeMesh;
}
//机器人身体
export function generateBody() {//CylinderGeometry第一个参数是上部分圆的半径,第二个参数是下部分圆的半径,第三个参数是高度,材质使用的跟腿一样const body = new THREE.CylinderGeometry(4, 4, 6);const bodyMaterial = new THREE.MeshStandardMaterial({color: 0x43b988,roughness: 0.5,metalness: 1.0,});const bodyMesh = new THREE.Mesh(body, bodyMaterial);return bodyMesh;
}
//胳膊、腿
function generateLegs(y: number, z: number) {const leg1 = new THREE.CapsuleGeometry(1, 4);const legMaterial1 = new THREE.MeshStandardMaterial({color: 0x43b988,roughness: 0.5,metalness: 1.0,});const leg1Mesh = new THREE.Mesh(leg1, legMaterial1);leg1Mesh.position.y = y;leg1Mesh.position.z = z;return leg1Mesh;
}
//创建机器人
export function generateRobot() {// 创建一个Three.js对象,用于存放机器人const robot = new THREE.Object3D();const headMesh = createHead();headMesh.position.y = 6.5;robot.add(headMesh);//眼睛const leftEye = generateEye(3, 8, -2);const rightEye = generateEye(3, 8, 2);robot.add(leftEye);robot.add(rightEye);const leftHorn = generateHorn(11, -1, (-Math.PI * 30) / 180);const rightHorn = generateHorn(11, 1, (Math.PI * 30) / 180);robot.add(leftHorn);robot.add(rightHorn);const body = generateBody();body.position.y = 4;robot.add(body);// 生成机器人左腿robot.add(generateLegs(0, -2));// 生成机器人右腿robot.add(generateLegs(0, 2));//胳膊robot.add(generateLegs(3, 5));robot.add(generateLegs(3, -5));//物体缩放robot.scale.x = 0.3;robot.scale.y = 0.3;robot.scale.z = 0.3;return robot;
}
//创建粒子星星
export function generateStarts(num: number) {//制作粒子特效const starts = new THREE.Object3D();const obj = new THREE.SphereGeometry(0.2, 3, 3);const material = new THREE.MeshStandardMaterial({color: 0x43b988,roughness: 0.5,metalness: 5,});const mesh = new THREE.Mesh(obj, material);for (let i = 0; i < num; i++) {const target = new THREE.Mesh();target.copy(mesh);target.position.x = Math.floor(Math.random() * 18 + Math.floor(Math.random() * -18));target.position.y = Math.floor(Math.random() * 18 + Math.floor(Math.random() * -18));target.position.z = Math.floor(Math.random() * 18 + Math.floor(Math.random() * -18));starts.add(target);}return starts;
}
效果图

相关文章:
Three.js机器人与星系动态场景(四):封装Threejs业务组件
实际在写业务的时候不会在每个组件里都写几十行的threejs的初始化工作。我们可以 将通用的threejs的场景、相机、render、轨道控制器等进行统一初始化。同时将非主体的函数提到组件外部,通过import导入进组件。将业务逻辑主体更清晰一些。下面的代码是基于reactthre…...
亚马逊云科技 Amazon Bedrock 构建 AI 应用体验
前言 大模型应用发展迅速,部署一套AI应用的需求也越来越多,从头部署花费时间太长,然而亚马逊科技全托管式生成式 AI 服务 Amazon Bedrock,Amazon Bedrock 简化了从基础模型到生成式AI应用构建的复杂流程,为客户铺设了…...
程序员标准简历模板
链接: https://pan.baidu.com/s/1yMXGSSNba15b9hMXjA39aA?pwdb4ev 提取码: b4ev 3年工作经验简历 链接: https://pan.baidu.com/s/1OO7n1lRL6AkhejxYC9IyDA?pwdfmvv 提取码: fmvv 优秀学员简历 链接: https://pan.baidu.com/s/106Vkw_ulOInI47_5mDySSg?pwduudc 提取码: uu...
物联网设计竞赛_10_Jetson Nano中文转汉语语音
在windows中pyttsx3可以让汉字文本输出中文语音,但是在jetson上只能用英文说话 import pyttsx3def hanyu(test):engine pyttsx3.init()rate engine.getProperty(rate)engine.setProperty(rate,125)engine.say(test)engine.runAndWait() hanyu(你好) #engine.save…...
XML Schema 指示器
XML Schema 指示器 1. 引言 XML Schema 是一种用于定义 XML 文档结构和内容的语言。它提供了一种强大的方式来描述 XML 文档中允许的元素、属性和数据类型。XML Schema 指示器是在 XML Schema 定义中使用的一些特殊元素和属性,它们用于指示 XML 处理器如何解析和验证 XML 文…...
iOS UITableView自带滑动手势和父视图添加滑动手势冲突响应机制探索
场景 我们有时候会遇到这样的一个交互场景:我们有一个UITableView 放在一个弹窗中,这个弹窗可以通过滑动进行展示和消失(跟手滑动的方式),然后这个UITableView放在弹窗中,并且可以滚动,展示一些…...
RAG实践:ES混合搜索BM25+kNN(cosine)
1 缘起 最近在研究与应用混合搜索, 存储介质为ES,ES作为大佬牌数据库, 非常友好地支持关键词检索和向量检索, 当然,支持混合检索(关键词检索向量检索), 是提升LLM响应质量RAG(Retri…...
论文去AIGC痕迹:避免AI写作被检测的技巧
在数字化时代,AI正以其卓越的能力重塑学术写作的面貌。AI论文工具的兴起,为研究者们提供了前所未有的便利,但同时也引发了关于学术诚信和原创性的热烈讨论。当AI辅助写作成为常态,如何确保论文的独创性和个人思想的体现࿰…...
C#使用异步方式调用同步方法的实现方法
使用异步方式调用同步方法,在此我们使用异步编程模型(APM)实现 1、定义异步委托和测试方法 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Task…...
【Go系列】 Go语言的入门
为什么要学习Go 从今天起,我们将一同启程探索 Go 语言的奥秘。我会用简单明了的方式,逐一讲解 Go 语言的各个知识点,帮助你从基础做起,一步步深化理解。不论你之前是否有过 Go 语言的接触经验,这个系列文章都将助你收获…...
Dify 与 Xinference 最佳组合 GPU 环境部署全流程
背景介绍 在前一篇文章 RAG 项目对比 之后,确定 Dify 目前最合适的 RAG 框架。本次就尝试在本地 GPU 设备上部署 Dify 服务。 Dify 是将模型的加载独立出去的,因此需要选择合适的模型加载框架。调研一番之后选择了 Xinference,理由如下&…...
MICCAI 2024Centerline Boundary Dice Loss for Vascular Segmentation
MICCAI 2024 Centerline Boundary Dice Loss for Vascular Segmentation MICCAI 2024Centerline Boundary Dice Loss for Vascular Segmentation中心线边界Dice损失用于血管分割**摘要**:1. 引言相关工作: 2. 方法预备知识Dice的变化 3 实验3.1 数据集3.2 设置3.3 结…...
golang验证Etherscan上的智能合约
文章目录 golang验证Etherscan上的智能合约为什么要验证智能合约如何使用golang去验证合约获取EtherscanAPI密钥Verify Source Code接口Check Source Code Verification Status接口演示示例及注意事项网络问题无法调用Etherscan接口(最重要的步骤) golan…...
Visual Studio编译优化选项
目录 /O1 和 /O2 /Ox 内联函数 虚函数优化 代码重排 循环优化 链接时间优化 代码分割 数学优化 其他优化选项 在Visual Studio中,编译优化选项是用于提高程序性能的重要工具。编译器提供了多种优化级别和选项,可以根据不同的需要进行选择。 在…...
sql业务场景分析思路参考
1、时间可以进行排序,也可以用聚合函数对时间求最大值max(时间) 例如下面的例子:取最晚入职的人,那就是将入职时间倒序排序,然后limit 1 表: 场景:查找最晚入职员工的所有信息 se…...
Django权限系统如何使用?
Django的权限系统是一个强大而灵活的特性,允许你控制不同用户对应用程序中资源的访问。以下是使用Django权限系统的几个基本步骤: 1. 定义模型权限 在你的models.py文件中,你可以为每个模型定义自定义权限。这通过在模型的Meta类里设置perm…...
基于整体学习的大幅面超高分遥感影像桥梁目标检测(含数据集下载地址)
文章摘要 在遥感图像(RSIs)中进行桥梁检测在各种应用中起着至关重要的作用,但与其他对象检测相比,桥梁检测面临独特的挑战。在RSIs中,桥梁在空间尺度和纵横比方面表现出相当大的变化。因此,为了确保桥梁的…...
逻辑回归模型(非回归问题,而是解决二分类问题)
目录: 一、Sigmoid激活函数:二、逻辑回归介绍:三、决策边界四、逻辑回归模型训练过程:1.训练目标:2.梯度下降调整参数: 一、Sigmoid激活函数: Sigmoid函数是构建逻辑回归模型的重要激活函数&am…...
QT的OpenGL渲染窗QOpenGLWidget Class
Qt - QOpenGLWidget (class) (runebook.dev) 一、说明 QOpenGLWidget 类是用于渲染 OpenGL 图形的小部件。从Qt 5.4就开始退出,它对于OpenGL有专门的配合设计。 二、QOpenGLWidget类的成员 2.1 Public类函数 QOpenGLWidget(QWidget *parent nullptr,Qt…...
单元测试和集成测试
软件测试中,单元测试和集成测试是比较常见的方法 单元测试:这是一种专注于最小可测试单元(通常是函数或方法)的测试,用于验证单个组件的行为是否符合预期。它通常由开发者自己完成,可以尽早发现问题&#…...
UE5 学习系列(二)用户操作界面及介绍
这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...
从零实现富文本编辑器#5-编辑器选区模型的状态结构表达
先前我们总结了浏览器选区模型的交互策略,并且实现了基本的选区操作,还调研了自绘选区的实现。那么相对的,我们还需要设计编辑器的选区表达,也可以称为模型选区。编辑器中应用变更时的操作范围,就是以模型选区为基准来…...
汽车生产虚拟实训中的技能提升与生产优化
在制造业蓬勃发展的大背景下,虚拟教学实训宛如一颗璀璨的新星,正发挥着不可或缺且日益凸显的关键作用,源源不断地为企业的稳健前行与创新发展注入磅礴强大的动力。就以汽车制造企业这一极具代表性的行业主体为例,汽车生产线上各类…...
大语言模型如何处理长文本?常用文本分割技术详解
为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...
HBuilderX安装(uni-app和小程序开发)
下载HBuilderX 访问官方网站:https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本: Windows版(推荐下载标准版) Windows系统安装步骤 运行安装程序: 双击下载的.exe安装文件 如果出现安全提示&…...
微信小程序云开发平台MySQL的连接方式
注:微信小程序云开发平台指的是腾讯云开发 先给结论:微信小程序云开发平台的MySQL,无法通过获取数据库连接信息的方式进行连接,连接只能通过云开发的SDK连接,具体要参考官方文档: 为什么? 因为…...
C++:多态机制详解
目录 一. 多态的概念 1.静态多态(编译时多态) 二.动态多态的定义及实现 1.多态的构成条件 2.虚函数 3.虚函数的重写/覆盖 4.虚函数重写的一些其他问题 1).协变 2).析构函数的重写 5.override 和 final关键字 1&#…...
使用LangGraph和LangSmith构建多智能体人工智能系统
现在,通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战,比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...
【Redis】笔记|第8节|大厂高并发缓存架构实战与优化
缓存架构 代码结构 代码详情 功能点: 多级缓存,先查本地缓存,再查Redis,最后才查数据库热点数据重建逻辑使用分布式锁,二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...
