Threejs在vue中使用(场景、相机、渲染器、gltf模型添加、环境贴图等)

本文介绍了如何在Vue项目中使用Three.js创建3D场景、设置相机、渲染器、添加gltf模型和环境贴图,以及实现交互功能。内容涵盖了Three.js的安装、场景、相机类型、光照、渲染过程、模型导入和环境映射,还讨论了解决模型显示为黑色的问题。

前言

Three.js ( Javascript 3D library ) 是基于原生WebGL封装运行的三维引擎,WebGL可以看成是浏览器给我们提供的接口,在JavaScript中可以直接用这些API进行3D图形的绘制;而Three.js它封装了诸如场景、灯光、阴影、材质、贴图、空间运算等一系列功能,让你不必要再从底层WebGL开始写起。 Three.js是通过对WebGL接口的封装与简化而形成的一个易用的图形库。
Three.js开发3D应用,通常包括渲染器(Renderer)、场景(Scene)、照相机(Camera),以及在场景中创建的物体,光照等。

一、threejs的安装

1、NPM的安装

   npm install --save three

2、组件内使用

import * as THREE from "three";

二、场景

1、场景(scene)介绍

它相当于一个容器,在3d场景中要展现的所有物体、灯光、摄像机等都必须添加到这个容器里面。

2、创建场景对象Scene

Var scene = new THREE.Scene();

3、设置场景的背景色

scene.background = new THREE.Color("#F7F7F7");

三、相机

在threejs中提供了一系列的相机,其中最常用到的是 PerspectiveCamera(透视相机) 和 OrthographicCamera(正交投影相机),它们之间的区别在于透视相机在观察场景中的物体时,呈现出来的物体近大远小,最接近自然的视图。正交投影相机无论从哪个角度观察物体,大小都是一样的。

1、PerspectiveCamera创建, 确定视野范围

let camera = new THREE.PerspectiveCamera(fov, aspect, near, far);

参数说明:
fov: 视场;垂直方向的观察角度,也就是眼睛上下俯视的观察角度。
aspect: (长宽比)是照相机水平方向和竖直方向长度的比值。
near: (近面距离)相机到视景体最近的距离。
far: (远面距离)相机到视景体最远的距离。

2、确定相机的位置

this.camera.position.set(0, 10, 20);

3、操作相机

在很多场景下,我们需要移动相机来观察物体的各个角度,这时需要相机操作控件来控制相机的位置。常用的控制器有:OrbitControls(轨道控制器)、TrackballControls(轨迹球控制器)

OrbitControls:可以使用鼠标控制场景中的对象围绕场景中心旋转和平移
TrackballControls:可以使用鼠标(或控制球)来轻松移动、平移和缩放场景
Pointerlockcontrols:第一人称控制器,以第一人称视角观察室内场景

1)添加控制器

controls = new OrbitControls(camera, canvas);

2)设置控制器聚焦点

 controls.target.set(0, 5, 0);

四、光照

在场景中,如果没有光源,那所有的物体都将看不见。最常用的几种光源是AmbientLight、PointLight、SpotLight、DirectionalLight。
AmbientLight:环境光;全局均匀地照亮场景中的所有对象。
PointLight:点光源;从空间中的一点向所有方向发射光线。
SpotLight:聚光源;投射出的是类似圆锥形的光线。
DirectionalLight:平行光;比如太阳光。
例:

 {
   
   
    const color = 0xf1f1f1;  //光的颜色
    const intensity = 1;    //光的强度
    const light = new THREE.DirectionalLight(color, intensity
<think>我们在Vue2项目中使用Three.js加载PNG图片(实际上是作为纹理)并添加文字。需要注意的是,PNG通常作为纹理图片,而不是3D模型。如果用户指的是加载一个3D模型并在模型表面添加文字,那么通常3D模型会有自己的格式(如glTF、obj等),而PNG只是作为模型贴图。但根据问题描述,用户可能想加载一个PNG图片(作为平面)并在上面添加文字。 根据用户的问题,我们有两种可能的解释: 1. 将PNG图片作为纹理贴在一个平面几何体上,然后在平面几何体上添加文字(实际上文字也是纹理,可以创建为另一个平面几何体并放置在合适位置)。 2. 或者,用户可能想在一个已有的3D模型(其表面使用了PNG纹理)上添加文字,那么我们需要将文字作为纹理叠加到模型原有的纹理上,或者创建一个新的文字几何体放置在模型表面。 由于问题中明确提到“加载PNG模型”,这里我们假设用户是想将PNG图片作为纹理创建一个平面,并在该平面上添加文字。但注意,PNG本身不是模型,所以我们需要创建一个平面(PlaneGeometry)并贴上PNG纹理。 步骤: 1.Vue组件中引入Three.js库。 2. 创建场景相机渲染器等。 3. 加载PNG图片作为纹理,创建平面几何体,并将纹理应用到材质上,然后将平面添加场景中。 4. 创建文字:可以使用Three.js的文字几何体(TextGeometry),但需要加载字体文件,或者使用另一种方法:将文字绘制到Canvas上,然后将Canvas作为纹理创建精灵(Sprite)或平面。 考虑到在Vue2项目中的实现,以及字体加载的复杂性,我们可以采用Canvas纹理的方式创建文字,这样更简单且不需要额外加载字体文件。 具体步骤: 方法一(推荐):使用Canvas创建文字纹理,然后创建一个平面几何体(或精灵)来显示文字,并放置在图片平面的合适位置。 方法二:使用TextGeometry,但需要先加载字体文件(比如three.js自带的字体文件),然后创建三维文字,但这样文字是3D的,可能不符合“在表面添加”的需求(因为图片平面是2D的)。 这里我们使用方法一,因为更简单且易于控制。 实现思路: 1. 加载PNG图片,创建平面(作为背景)。 2. 创建一个Canvas,在Canvas上绘制文字,然后将Canvas作为纹理创建另一个平面(或精灵),将这个平面叠加在背景平面的前面(注意深度测试和渲染顺序)。 注意:由于两个平面都是二维的,我们需要确保文字平面在背景平面的前面(可以通过设置位置z值稍微大一点,或者设置材质depthTest=false,但要注意透明问题)。 详细步骤: 步骤1:创建场景相机渲染器 步骤2:加载背景图片纹理,创建平面几何体 步骤3:创建文字纹理 - 创建一个离屏Canvas - 在Canvas上绘制文字 - 用这个Canvas创建纹理 步骤4:用文字纹理创建平面几何体(或精灵),设置位置(在背景平面的前面一点) 步骤5:将背景平面和文字平面都添加场景中 注意:由于文字平面是透明的(如果文字背景透明),需要设置透明属性。 代码示例: 由于是在Vue2项目中,我们在组件的mounted生命周期中初始化Three.js场景。 安装Three.js:`npm install three` 示例代码: ```vue <template> <div ref="container"></div> </template> <script> import * as THREE from 'three'; export default { name: 'TextOnImage', data() { return { scene: null, camera: null, renderer: null, // 其他变量 }; }, mounted() { this.init(); this.animate(); }, methods: { init() { // 创建场景 this.scene = new THREE.Scene(); // 创建相机 this.camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); this.camera.position.z = 5; // 创建渲染器 const container = this.$refs.container; this.renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true }); this.renderer.setSize(container.clientWidth, container.clientHeight); container.appendChild(this.renderer.domElement); // 加载背景图片 const textureLoader = new THREE.TextureLoader(); textureLoader.load(require('@/assets/background.png'), (texture) => { // 替换成你的图片路径 // 创建背景平面 const bgGeometry = new THREE.PlaneGeometry(4, 3); // 根据图片比例设置 const bgMaterial = new THREE.MeshBasicMaterial({ map: texture, side: THREE.DoubleSide }); const bgPlane = new THREE.Mesh(bgGeometry, bgMaterial); this.scene.add(bgPlane); // 创建文字 this.createTextPlane(texture.image.width, texture.image.height); }); }, createTextPlane(imgWidth, imgHeight) { // 创建Canvas绘制文字 const canvas = document.createElement('canvas'); const context = canvas.getContext('2d'); canvas.width = 512; // 设置Canvas大小,根据需求调整 canvas.height = 256; // 绘制文字 context.fillStyle = '#ffffff'; // 文字颜色 context.font = 'Bold 40px Arial'; context.fillText('Hello Three.js', 50, 100); // 文字位置 // 创建纹理 const texture = new THREE.CanvasTexture(canvas); texture.needsUpdate = true; // 创建平面几何体来显示文字(也可以使用精灵,但平面更容易控制大小和位置) // 根据图片的宽高比,我们可以设置文字平面的大小和位置 // 假设我们希望文字平面在背景图片的上方居中,且宽度为背景宽度的一半 const textGeometry = new THREE.PlaneGeometry(2, 1); // 文字平面大小 const textMaterial = new THREE.MeshBasicMaterial({ map: texture, transparent: true, // 启用透明 side: THREE.DoubleSide }); const textPlane = new THREE.Mesh(textGeometry, textMaterial); // 将文字平面放置在背景平面的前面一点,避免深度冲突 textPlane.position.z = 0.1; // 稍微靠前 this.scene.add(textPlane); }, animate() { requestAnimationFrame(this.animate); this.renderer.render(this.scene, this.camera); } }, beforeDestroy() { // 清理资源 if (this.renderer) { this.renderer.dispose(); } } }; </script> <style scoped> div { width: 100%; height: 100vh; } </style> ``` 注意: 1. 图片路径:使用require加载图片,确保路径正确(根据项目结构)。 2. 文字平面的大小和位置需要根据背景图片的尺寸进行调整,这里只是一个示例。 3. 文字平面的位置可以通过设置position属性调整(如textPlane.position.set(0, 0, 0.1)),使其在背景平面的前面。 4. 如果文字需要背景色,可以在Canvas上绘制矩形作为背景。 如果用户希望在3D模型(而不是平面)上添加文字,那么方法会不同,需要将文字作为纹理叠加到模型的原有纹理上,或者使用3D文字放置在模型表面。但根据问题,我们假设是平面图片。 引用说明: 我们参考了Three.js的文档和常见做法,特别是使用Canvas创建文字纹理的方法[^1][^2][^3]。 相关问题: §§相关问题§§ 1. 如何在Three.js中加载3D模型(如glTF)并在模型表面添加文字? 2. 如何调整文字在Three.js场景中的位置和大小? 3.Vue2中使用Three.js有哪些性能优化建议?</think>在 Vue2 项目中结合 Three.js 为 PNG 模型添加文字,可以通过创建文字纹理或使用 Three.js 的文字几何体实现。以下是完整实现方案: ### 解决方案步骤 1. **创建基础场景** ```vue <template> <div ref="container"></div> </template> <script> import * as THREE from 'three'; import { TextureLoader } from 'three'; export default { mounted() { this.initScene(); }, methods: { initScene() { // 创建场景 this.scene = new THREE.Scene(); // 创建相机 this.camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 ); this.camera.position.z = 30; // 创建渲染器 this.renderer = new THREE.WebGLRenderer({ antialias: true }); this.renderer.setSize(window.innerWidth, window.innerHeight); this.$refs.container.appendChild(this.renderer.domElement); // 添加光源 const ambientLight = new THREE.AmbientLight(0xffffff, 0.6); this.scene.add(ambientLight); const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8); directionalLight.position.set(10, 20, 15); this.scene.add(directionalLight); this.loadPNGModel(); }, async loadPNGModel() { // 加载PNG纹理 const loader = new TextureLoader(); const texture = await loader.loadAsync('@/assets/model.png'); // 创建平面几何体承载纹理 const geometry = new THREE.PlaneGeometry(20, 20); const material = new THREE.MeshPhongMaterial({ map: texture, transparent: true }); this.modelMesh = new THREE.Mesh(geometry, material); this.scene.add(this.modelMesh); this.addTextToModel(); // 添加文字 this.animate(); }, animate() { requestAnimationFrame(this.animate); this.renderer.render(this.scene, this.camera); }, // 添加文字方法 ↓ } } </script> ``` 2. **添加文字的两种方法** **方法1:使用 Canvas 创建文字纹理(推荐)** ```javascript addTextToModel() { // 创建离屏Canvas绘制文字 const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); canvas.width = 512; canvas.height = 128; // 绘制文字 ctx.fillStyle = 'rgba(255, 0, 0, 0.8)'; ctx.font = 'bold 48px Arial'; ctx.fillText('Vue2 + Three.js', 20, 80); // 创建纹理 const texture = new THREE.CanvasTexture(canvas); // 创建文字平面 const textGeometry = new THREE.PlaneGeometry(15, 4); const textMaterial = new THREE.MeshBasicMaterial({ map: texture, transparent: true, side: THREE.DoubleSide }); this.textMesh = new THREE.Mesh(textGeometry, textMaterial); this.textMesh.position.set(0, -12, 0.1); // 放置在模型前方 this.scene.add(this.textMesh); } ``` **方法2:使用 TextGeometry(需加载字体)** ```javascript async addTextToModel() { // 加载字体 const fontLoader = new FontLoader(); const font = await fontLoader.loadAsync('fonts/helvetiker_regular.typeface.json'); // 创建文字几何体 const textGeometry = new TextGeometry('Hello Three.js', { font: font, size: 3, height: 0.2, }); const textMaterial = new THREE.MeshPhongMaterial({ color: 0xff0000 }); this.textMesh = new THREE.Mesh(textGeometry, textMaterial); // 定位文字(需计算位置) textGeometry.computeBoundingBox(); const textWidth = textGeometry.boundingBox.max.x - textGeometry.boundingBox.min.x; this.textMesh.position.set(-textWidth/2, -10, 5); this.scene.add(this.textMesh); } ``` ### 关键注意事项 1. **定位技巧**: - 使用 `position.set(x, y, z)` 控制文字位置 - 模型表面添加时需将 z 轴位置设为 `0.1`(略高于模型表面) - 通过 `boundingBox` 计算文字居中位置: ```javascript textGeometry.computeBoundingBox(); const centerOffset = -0.5 * (textGeometry.boundingBox.max.x - textGeometry.boundingBox.min.x); textMesh.position.x = centerOffset; ``` 2. **性能优化**: ```javascript // 组件销毁时释放资源 beforeDestroy() { this.renderer.dispose(); this.textMesh.geometry.dispose(); this.textMesh.material.dispose(); } ``` 3. **交互处理**: ```javascript // 添加点击事件 this.textMesh.userData = { clickable: true }; this.renderer.domElement.addEventListener('click', this.handleClick); // 事件处理 handleClick(event) { 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, this.camera); const intersects = raycaster.intersectObjects(this.scene.children); if (intersects.length > 0 && intersects[0].object.userData.clickable) { console.log('Text clicked!'); } } ``` ### 常见问题解决 - **文字模糊**:增加 Canvas 分辨率(设置 canvas.width 为实际显示尺寸的2倍) - **字体加载失败**:使用绝对路径加载字体文件,或将字体放入 public 目录 - **深度冲突**:通过 `textMesh.renderOrder = 1` 和 `modelMesh.renderOrder = 0` 控制渲染顺序 - **响应式适配**: ```javascript window.addEventListener('resize', () => { this.camera.aspect = window.innerWidth / window.innerHeight; this.camera.updateProjectionMatrix(); this.renderer.setSize(window.innerWidth, window.innerHeight); }); ``` ### 引用说明 Three.js 的纹理加载和文字渲染功能参考了官方文档的最佳实践[^1]。使用 Canvas 创建纹理的方法在性能敏感场景中更为高效,而 TextGeometry 则适合需要 3D 立体文字的场景[^2]。在 Vue 组件中管理 Three.js 资源生命周期可避免内存泄漏[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值