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

在Vue项目中使用three.js在前端页面展示PLY文件或STL文件

前言:这是一个3d打印局域网管理系统的需求

一、安装three.js

three.js官网:https://threejs.org/docs/#manual/en/introduction/Installation

我用的是yarn,官网用的是npm

二、使用three.js

1.在script部分导入three.js

import * as THREE from 'three';

2.基础使用

=》创建场景:场景是three.js中用于存储所有3D对象的容器。它相当于一个虚拟的3D空间,所有对象(如几何体、灯光等)都会被添加到场景中。

const scene = new THREE.Scene();//创建场景

=》创建相机:相机用于定义用户观察场景的视角。这里使用的是PerspectiveCamera,它模拟了真实世界的透视效果。

//创建相机
const camera = new THREE.PerspectiveCamera(75,window.innerWidth/window.innerHeight,0.1,1000);

它的参数分别是:

->FOV(Field of View):视野角度,单位是度。这里设置为75,表示相机能看到的范围。

->宽高比(Aspect Ratio):通常是容器的宽度除以高度。这里使用window.innerWidth / window.innerHeight,确保在场景不同屏幕尺寸下不会变形。

->近裁剪面(Near Clipping Plane):距离相机最近的渲染范围,小于这个值的物体不会被渲染。这里设置为0.1。

->远裁剪面(Far Clipping Plane):距离相机最远的渲染范围,大于这个值的物体不会被渲染。这里设置为1000。

=》创建渲染器:渲染器的作用是将场景渲染到屏幕上。这里使用的是WebGLRenderer,它利用WebGL技术在浏览器中渲染3D图形。setSize方法设置了渲染器的尺寸,通常与浏览器窗口的大小一致。最后,将渲染器的domElement(一个<canvas>元素)添加到HTML文档中。

//创建渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth,window.innerHeight);
document.body.appendChild(renderer.domElement);

=》创建立方体:

//创建立方体
const geometry = new THREE.BoxGeometry(1,1,1);
const material = new THREE.MeshBasicMaterial({color:0x00ff00});
const cube = new THREE.Mesh(geometry,material);
scene.add(cube); 

->几何体(Geometry):定义了对象的形状。这里使用BoxGeometry创建了一个边长为1的立方体。

->材质(Material):定义了对象的外观。这里使用MeshBasicMaterial,并设置颜色为绿色(0x00ff00)。

->网格(Mesh):将几何体和材质组合在一起,形成一个可渲染的对象。最后,将立方体添加到场景中。

=》调整相机位置:默认情况下,相机和立方体都在场景的原点(0, 0, 0)。为了避免它们重叠,将相机沿Z轴向后移动5个单位。

//调整相机位置
camera.position.z = 5;

=》动画循环:

//动画循环
function animate(){cube.rotation.x += 0.01;cube.rotation.y += 0.01;renderer.render(scene,camera);}
renderer.setAnimationLoop(animate);

->动画逻辑:在animate函数中,每帧更新立方体的旋转角度(rotation.x和rotation.y),使其围绕X轴和Y轴旋转。

->渲染场景:调用renderer.render(scene, camera)将场景渲染到屏幕上。

->循环调用:renderer.setAnimationLoop(animate)会自动调用animate函数,并在浏览器刷新时重新渲染场景,通常每秒60次。

3.综合使用

这里创建一个文件名为Three.vue的vue文件

<template><div ref="threeJsContainer" class="three-js-container"></div></template><script>import * as THREE from 'three';export default {name: 'ThreeJsComponent',mounted() {this.initThreeJs();},methods: {initThreeJs() {// 创建场景const scene = new THREE.Scene();// 创建相机const camera = new THREE.PerspectiveCamera(75,window.innerWidth / window.innerHeight,0.1,1000);camera.position.z = 5;// 创建渲染器const renderer = new THREE.WebGLRenderer();renderer.setSize(window.innerWidth, window.innerHeight);// 将渲染器的 canvas 添加到 Vue 组件的 div 中this.$refs.threeJsContainer.appendChild(renderer.domElement);// 创建立方体const geometry = new THREE.BoxGeometry(1, 1, 1);const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });const cube = new THREE.Mesh(geometry, material);scene.add(cube);// 动画循环const animate = () => {cube.rotation.x += 0.01;cube.rotation.y += 0.01;renderer.render(scene, camera);};renderer.setAnimationLoop(animate);}}};</script><style scoped>.three-js-container {width: 100vw;height: 100vh;}</style>

在App组件中导入并使用这个组件,不出意外就可看到一个旋转的绿色正方体

4.展示ply文件

我下载了blender软件,导出了一个ply文件,这个ply文件放在项目的public文件夹

先导入所需的文件

import * as THREE from 'three';
import { PLYLoader } from 'three/examples/jsm/loaders/PLYLoader.js';
<template><h1>我是PLY</h1><div ref="threeContainer" class="three-container"></div><h1>你呢</h1>
</template><script>
import * as THREE from 'three';
import { PLYLoader } from 'three/examples/jsm/loaders/PLYLoader.js';export default {name: 'PLY',mounted() {this.initThree();},methods: {initThree() {console.log("ply");// 创建场景const scene = new THREE.Scene();// 创建相机const camera = new THREE.PerspectiveCamera(75,window.innerWidth / window.innerHeight,0.1,1000);camera.position.set(0, 0, 10); // 调整相机位置camera.lookAt(scene.position); // 让相机朝向场景中心// 添加光源const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);scene.add(ambientLight);const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);directionalLight.position.set(1, 1, 1);scene.add(directionalLight);// 创建渲染器const renderer = new THREE.WebGLRenderer();renderer.setSize(window.innerWidth, window.innerHeight);// 将渲染器的 canvas 添加到 Vue 组件的 div 中this.$refs.threeContainer.appendChild(renderer.domElement);// 加载 .ply 文件let mesh; // 声明一个变量用于存储加载的网格const loader = new PLYLoader();loader.load('/2.ply', function (geometry) {// 计算顶点法线geometry.computeVertexNormals();const material = new THREE.MeshStandardMaterial({ color: 0xffffff });mesh = new THREE.Mesh(geometry, material); // 将加载的网格存储到变量中scene.add(mesh);});// 动画循环const animate = () => {if (mesh) {// 每帧让物体绕 x 轴和 y 轴旋转mesh.rotation.x += 0.01;mesh.rotation.y += 0.01;}renderer.render(scene, camera);};renderer.setAnimationLoop(animate);}}
};
</script>
<style scoped>
.three-container {width: 100%;height: 100%;
}
</style>

5.展示stl文件

文件是一个同学发给我的,一个城堡

其实这个是和ply同理的,只是导入的文件不同

import * as THREE from 'three';import { STLLoader } from 'three/examples/jsm/loaders/STLLoader.js';
<template><h1>我是STL</h1><div ref="threeContainer" class="three-container"></div><h1>你呢</h1></template><script>import * as THREE from 'three';import { STLLoader } from 'three/examples/jsm/loaders/STLLoader.js';export default {name: 'STL',mounted() {this.initThree();},methods: {initThree() {console.log("stl");// 创建场景const scene = new THREE.Scene();// 创建相机const camera = new THREE.PerspectiveCamera(75,window.innerWidth / window.innerHeight,0.1,1000);camera.position.set(0, 0, 10); // 调整相机位置camera.lookAt(scene.position); // 让相机朝向场景中心// 添加光源const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);scene.add(ambientLight);const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);directionalLight.position.set(1, 1, 1);scene.add(directionalLight);// 创建渲染器const renderer = new THREE.WebGLRenderer();renderer.setSize(window.innerWidth, window.innerHeight);// 将渲染器的 canvas 添加到 Vue 组件的 div 中this.$refs.threeContainer.appendChild(renderer.domElement);// 加载 .stl 文件let mesh; // 用于存储加载的模型const loader = new STLLoader(); // 使用 STLLoader 加载 STL 文件loader.load('/chengbao.stl', function (geometry) {// STL 文件通常不需要计算顶点法线,因为它们是三角形网格// 居中几何体(确保模型的几何中心在原点)geometry.center();// 创建渐变材质const uniforms = {iTime: { value: 0 },iResolution: { value: new THREE.Vector2(window.innerWidth, window.innerHeight) }};const material = new THREE.ShaderMaterial({uniforms: uniforms,vertexShader: `varying vec2 vUv;void main() {vUv = uv;gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);}`,fragmentShader: `precision highp float;uniform float iTime;uniform vec2 iResolution;varying vec2 vUv;// 渐变颜色定义const vec3 colors[5] = vec3[](vec3(0., 0., 0.6),vec3(0., 1., 1.),vec3(0.0, 1.0, 0.),vec3(1.0, 1.0, 0.),vec3(1.0, 0.0, 0.));const float points[5] = float[](0.0, 0.15, 0.5, 0.65, 1.0);vec3 gradian(vec3 c1, vec3 c2, float a) {return mix(c1, c2, a);}vec3 heat4(float weight) {if (weight <= points[0]) return colors[0];if (weight >= points[4]) return colors[4];for (int i = 1; i < 5; i++) {if (weight < points[i]) {float a = (weight - points[i - 1]) / (points[i] - points[i - 1]);return gradian(colors[i - 1], colors[i], a);}}return vec3(0.0);}void main() {float weight = (vUv.x + vUv.y + iTime) / 10.0; // 根据时间动态调整权重vec3 color = heat4(weight);float alpha = sin(iTime) * 0.5 + 0.5; // 透明度在 0 到 1 之间变化gl_FragColor = vec4(color, alpha);}`,transparent: true // 启用透明度});mesh = new THREE.Mesh(geometry, material); // 创建网格mesh.position.set(0, 0, 0); // 确保模型在场景中心mesh.scale.set(0.1, 0.1, 0.1); // 调整模型大小(根据需要)scene.add(mesh); // 将模型添加到场景中});// 鼠标滑动控制渐变速度和模型旋转let lastTime = performance.now();let lastMouseX = 0;let lastMouseY = 0;renderer.domElement.addEventListener('mousemove', (event) => {const now = performance.now();const deltaTime = (now - lastTime) / 1000; // 时间差(秒)const mouseX = event.clientX;const mouseY = event.clientY;const deltaX = mouseX - lastMouseX;const deltaY = mouseY - lastMouseY;const speed = Math.sqrt(deltaX * deltaX + deltaY * deltaY); // 鼠标滑动速度const speedFactor = speed * deltaTime; // 速度因子if (mesh) {mesh.material.uniforms.iTime.value += speedFactor; // 根据鼠标滑动速度调整时间mesh.rotation.y += deltaX * 0.001; // 水平旋转mesh.rotation.x -= deltaY * 0.001; // 垂直旋转}lastTime = now;lastMouseX = mouseX;lastMouseY = mouseY;});// 动画循环const animate = () => {renderer.render(scene, camera); // 渲染场景};renderer.setAnimationLoop(animate); // 设置动画循环}}};</script><style scoped>.three-container {width: 100%;height: 100%;}</style>

我这个做了更花哨的效果,可以渐变

相关文章:

在Vue项目中使用three.js在前端页面展示PLY文件或STL文件

前言&#xff1a;这是一个3d打印局域网管理系统的需求 一、安装three.js three.js官网&#xff1a;https://threejs.org/docs/#manual/en/introduction/Installation 我用的是yarn,官网用的是npm 二、使用three.js 1.在script部分导入three.js import * as THREE from thr…...

DeepSeek笔记(二):DeepSeek局域网访问

如果有多台电脑&#xff0c;可以通过远程访问&#xff0c;实现在局域网环境下多台电脑共享使用DeepSeek模型。在本笔记中&#xff0c;首先介绍设置局域网多台电脑访问DeepSeek-R1模型。 一、启动Ollama局域网访问 1.配置环境变量 此处本人的操作系统是Windows11&#xff0c;…...

【LeetCode Hot100 矩阵】矩阵置零、螺旋矩阵、旋转图像、搜索二维矩阵II

矩阵 1. 矩阵置零&#xff08;Set Matrix Zeroes&#xff09;解题思路步骤&#xff1a; 代码实现 2. 螺旋矩阵&#xff08;Spiral Matrix&#xff09;解题思路具体步骤&#xff1a; 代码实现 3. 旋转矩阵 90 度解决思路代码实现 5. 搜索二维矩阵中的目标值解决思路代码实现 1. …...

【设计模式】【创建型模式】建造者模式(Builder)

&#x1f44b;hi&#xff0c;我不是一名外包公司的员工&#xff0c;也不会偷吃茶水间的零食&#xff0c;我的梦想是能写高端CRUD &#x1f525; 2025本人正在沉淀中… 博客更新速度 &#x1f44d; 欢迎点赞、收藏、关注&#xff0c;跟上我的更新节奏 &#x1f3b5; 当你的天空突…...

如何利用国内镜像从huggingface上下载项目

1、利用镜像快速下载项目 在huggingface上下载模型时速度太慢&#xff0c;可以用下面的方法 pip install -U huggingface_hub pip install huggingface-cliexport HF_ENDPOINThttps://hf-mirror.comhuggingface-cli download --resume-download shenzhi-wang/Llama3-8B-Chine…...

pandas常用操作

pandas是Python中用于数据操作和分析的强大库。以下是一些常用的操作&#xff1a; ### 1. 读取数据 - **从CSV文件读取**&#xff1a; python import pandas as pd df pd.read_csv(path/to/file.csv) - **从Excel文件读取**&#xff1a; python df pd.read_exc…...

linux使用

文章目录 前言操作系统的作用组成二、安装linux系统安装VMware Workstation安装ubuntu图形化&#xff0c;命令行finalshell快照目录理解命令执行命令格式常用命令lscdmkdir 前言 本文讲解认识与使用linux操作系统 操作系统的作用 操作系统是用户和计算机的桥梁。比如我们输入…...

基于豆瓣2025电影数据可视化分析系统的设计与实现

✔️本项目旨在通过对豆瓣电影数据进行综合分析与可视化展示&#xff0c;构建一个基于Python的大数据可视化系统。通过数据爬取收集、清洗、分析豆瓣电影数据&#xff0c;我们提供了一个全面的电影信息平台&#xff0c;为用户提供深入了解电影产业趋势、影片评价与演员表现的工…...

基于Python的深度学习音乐推荐系统(有配套论文)

音乐推荐系统 提供实时音乐推荐功能&#xff0c;根据用户行为和偏好动态调整推荐内容 Python、Django、深度学习、卷积神经网络 、算法 数据库&#xff1a;MySQL 系统包含角色&#xff1a;管理员、用户 管理员功能&#xff1a;用户管理、系统设置、音乐管理、音乐推荐管理、系…...

远程计算机无conda情况下配置python虚拟环境

1. 按照正常流程&#xff0c;根据远程计算机的IP地址/用户名/密码&#xff0c;通过pycharm进行部署 部署流程为: pycharm主菜单--> 工具-->部署 -->配置 **注意&#xff0c;pycharm的远程部署必须是专业版 2. 配置远程python解释器 上图是配置SSH解释器的截图&…...

强化学习-价值学习算法

Sarsa 理论解释 Sarsa是基于时序差分算法的&#xff0c;它的公式非常简单且易理解&#xff0c;不像策略梯度算法那样需要复杂的推导过程。 Sarsa的核心函数是 Q ( s , a ) Q(s, a) Q(s,a)&#xff0c;它的含义是在状态 s s s下执行 a a a&#xff0c;在后续轨迹中获取的期望…...

Golang深度学习

前言 在2009年&#xff0c;Google公司发布了一种新的编程语言&#xff0c;名为Go&#xff08;或称为Golang&#xff09;&#xff0c;旨在提高编程效率、简化并发编程&#xff0c;并提供强大的标准库支持。Go语言的设计者们希望通过Go语言能够解决软件开发中的一些长期存在的问…...

基于推荐算法的在线课程推荐系统设计与实现

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…...

es和kibana安装

es安装 安装 wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.17.1-linux-x86_64.tar.gz 参考&#xff1a; https://www.cnblogs.com/shamo89/p/18504053 https://blog.csdn.net/u012899618/article/details/130383429 解压 tar -zxvf elastic…...

本地部署Anything LLM+Ollama+DeepSeek R1打造AI智能知识库教程

文章目录 前言1. 本地部署OllamaDeepSeek2. 本地安装Anything LLM3. 配置与使用演示4. 远程调用大模型5. 安装内网穿透6. 配置固定公网地址 前言 本文主要介绍如何在Windows电脑上本地部署Ollama并接入DeepSeek R1大模型&#xff0c;然后使用强大的开源AI工具Anything LLM结合…...

zyNo.25

SSRF漏洞 在了解ssrf漏洞前先了解curl命令的使用 1.curl命令的使用 基本格式&#xff1a;curl<参数值>请求地址 get请求&#xff1a;curl http://127.0.0.1 post请求&#xff1a;curl -X POST -d "a1&b2" http://127.0.0.1/(其中&#xff0c;使用-X参…...

Spring框架基本使用(Maven详解)

前言&#xff1a; 当我们创建项目的时候&#xff0c;第一步少不了搭建环境的相关准备工作。 那么如果想让我们的项目做起来方便快捷&#xff0c;应该引入更多的管理工具&#xff0c;帮我们管理。 Maven的出现帮我们大大解决了管理的难题&#xff01;&#xff01; Maven&#xf…...

关于前后端分离跨域问题——使用DeepSeek分析查错

我前端使用ant design vue pro框架&#xff0c;后端使用kratos框架开发。因为之前也解决过跨域问题&#xff0c;正常是在后端的http请求中加入中间件&#xff0c;设置跨域需要通过的字段即可&#xff0c;代码如下所示&#xff1a; func NewHTTPServer(c *conf.Server, s *conf…...

三层渗透测试-DMZ区域 二三层设备区域

DMZ区域渗透 信息收集 首先先进行信息收集&#xff0c;这里我们可以选择多种的信息收集方式&#xff0c;例如nmap如此之类的&#xff0c;我的建议是&#xff0c;可以通过自己现有的手里小工具&#xff0c;例如无影&#xff0c;密探这种工具&#xff0c;进行一个信息收集。以免…...

领航Linux UDP:构建高效网络新纪元

欢迎来到 破晓的历程的 博客 ⛺️不负时光&#xff0c;不负己✈️ 文章目录 引言Udp和Tcp的异同相同点不同点总结 1.1、socket1.2、bind1.3、recvfrom1.4、sendto2.1、代码2.1、说明3.1、代码3.2、说明 引言 在前几篇博客中&#xff0c;我们学习了Linux网络编程中的一些概念。…...

[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解

突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 ​安全措施依赖问题​ GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...

【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)

服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...

unix/linux,sudo,其发展历程详细时间线、由来、历史背景

sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...

【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)

要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况&#xff0c;可以通过以下几种方式模拟或触发&#xff1a; 1. 增加CPU负载 运行大量计算密集型任务&#xff0c;例如&#xff1a; 使用多线程循环执行复杂计算&#xff08;如数学运算、加密解密等&#xff09;。运行图…...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心

当仓库学会“思考”&#xff0c;物流的终极形态正在诞生 想象这样的场景&#xff1a; 凌晨3点&#xff0c;某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径&#xff1b;AI视觉系统在0.1秒内扫描包裹信息&#xff1b;数字孪生平台正模拟次日峰值流量压力…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)

Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败&#xff0c;具体原因是客户端发送了密码认证请求&#xff0c;但Redis服务器未设置密码 1.为Redis设置密码&#xff08;匹配客户端配置&#xff09; 步骤&#xff1a; 1&#xff09;.修…...

有限自动机到正规文法转换器v1.0

1 项目简介 这是一个功能强大的有限自动机&#xff08;Finite Automaton, FA&#xff09;到正规文法&#xff08;Regular Grammar&#xff09;转换器&#xff0c;它配备了一个直观且完整的图形用户界面&#xff0c;使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...

零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)

本期内容并不是很难&#xff0c;相信大家会学的很愉快&#xff0c;当然对于有后端基础的朋友来说&#xff0c;本期内容更加容易了解&#xff0c;当然没有基础的也别担心&#xff0c;本期内容会详细解释有关内容 本期用到的软件&#xff1a;yakit&#xff08;因为经过之前好多期…...

STM32HAL库USART源代码解析及应用

STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...

4. TypeScript 类型推断与类型组合

一、类型推断 (一) 什么是类型推断 TypeScript 的类型推断会根据变量、函数返回值、对象和数组的赋值和使用方式&#xff0c;自动确定它们的类型。 这一特性减少了显式类型注解的需要&#xff0c;在保持类型安全的同时简化了代码。通过分析上下文和初始值&#xff0c;TypeSc…...