vue3+three.js的理解與簡單使用示例代碼
一、tres.js的安裝
npm i @tresjs/core @tresjs/cientos three
二、three.js的一些基本概念
1、Scene(場景,可以想象成一個空房間。):(這里介紹的是three.js的手動創(chuàng)建)
2、Camera(相機)? - 觀眾的眼睛
3、 Renderer(渲染器)? - 攝影師
4、Object(物體)? - 演員
// 手動創(chuàng)建一切 ?? const scene = new THREE.Scene() // 手動造房間 const camera = new THREE.PerspectiveCamera() // 手動買相機 const renderer = new THREE.WebGLRenderer() // 手動雇攝影師 // 手動組合所有東西 scene.add(mesh) // 手動放家具 scene.add(light) // 手動裝電燈 renderer.render(scene, camera) // 手動拍照
記?。簺]有 Scene(房間),你的 3D 東西就飄在空中,看不見也摸不著!
三、tres.js的簡單示例(自動化創(chuàng)建thrss.js的關(guān)鍵要素):
<template>
<!-- 主容器,確保3D場景充滿整個視口 -->
<div style="width: 100%; height: 100vh">
<!--
TresCanvas 是 3D 場景的根容器,可以理解成一個工地,它自動創(chuàng)建了:
1. Scene(場景/空房間)
2. Renderer(渲染器)
3. Canvas(畫布)
4. 自動渲染循環(huán)
window-size: 自動填充整個窗口大小
clear-color: 背景顏色,這里設(shè)置為青綠色
-->
<TresCanvas window-size clear-color="#82DBC5">
<!--
透視相機,模擬人眼視角
:position="[3, 3, 3]": 相機在3D空間中的位置 [x, y, z]
:look-at="[0, 0, 0]": 相機看向的點 [x, y, z],這里設(shè)置為世界原點
-->
<TresPerspectiveCamera :position="[3, 3, 3]" :look-at="[0, 0, 0]" />
<!--
?? 軌道控制器,提供用戶交互功能:
- 左鍵拖拽:旋轉(zhuǎn)場景
- 右鍵拖拽:平移場景
- 滾輪縮放:縮放場景
無需額外配置,開箱即用
-->
<OrbitControls />
<!--
?? 立方體網(wǎng)格
TresMesh可以理解成工地的某一棟房子,包含幾何體和材質(zhì)
-->
<TresMesh>
<!--
?? 立方體幾何體,定義形狀
:args="[1, 1, 1]": 定義立方體的尺寸 [寬度, 高度, 深度]
-->
<TresBoxGeometry :args="[1, 1, 1]" />
<!--
?? 基礎(chǔ)網(wǎng)格材質(zhì),為幾何體添加外觀屬性
color="red": 基礎(chǔ)顏色設(shè)置為紅色
:wireframe="true": 啟用線框模式,只顯示邊框
-->
<TresMeshBasicMaterial color="red" :wireframe="true" />
</TresMesh>
<!--
?? 環(huán)境光,模擬環(huán)境反射光
:intensity="0.8": 光照強度為0.8
環(huán)境光無方向性,為整個場景提供均勻的基礎(chǔ)照明
-->
<TresAmbientLight :intensity="0.8" />
<!--
?? 坐標(biāo)軸輔助工具,幫助理解3D空間方向
:args="[5]": 坐標(biāo)軸長度為5個單位
紅色=X軸,綠色=Y軸,藍色=Z軸
-->
<TresAxesHelper :args="[5]" />
</TresCanvas>
</div>
</template>
<script setup>
// 導(dǎo)入Tres.js核心組件
import { TresCanvas } from "@tresjs/core";
// 導(dǎo)入軌道控制器組件
import { OrbitControls } from "@tresjs/cientos";
</script>
四、效果圖:

五、tres.js實現(xiàn)iphone手機3D模型組件展示:
<template>
<div class="iphone-showcase">
<!--
TresCanvas是Tres.js的根組件,相當(dāng)于Three.js的WebGL渲染器
window-size: 自動填充整個窗口大小
:clear-color: 綁定背景顏色,使用Vue的響應(yīng)式數(shù)據(jù)
-->
<TresCanvas window-size :clear-color="currentColor">
<!--
透視相機組件
:position: 相機在3D空間中的位置 [x, y, z]
:look-at: 相機看向的點 [x, y, z],這里設(shè)置為世界原點
:fov: 視野角度,60度是接近人眼的自然視角
-->
<TresPerspectiveCamera
:position="[cameraPosition.x, cameraPosition.y, cameraPosition.z]"
:look-at="[0, 0, 0]"
:fov="60"
/>
<!--
軌道控制器,提供用戶交互功能:
- 左鍵拖拽:旋轉(zhuǎn)場景
- 右鍵拖拽:平移場景
- 鼠標(biāo)滾輪:縮放場景
enable-damping: 啟用阻尼效果,使移動更平滑
damping-factor: 阻尼系數(shù),值越小移動越平滑
:auto-rotate: 綁定自動旋轉(zhuǎn)狀態(tài)
auto-rotate-speed: 自動旋轉(zhuǎn)的速度
-->
<OrbitControls
enable-damping
damping-factor="0.05"
:auto-rotate="autoRotate"
auto-rotate-speed="1"
/>
<!-- 光源系統(tǒng) -->
<!-- 平行光:模擬太陽光,有明確的方向性,產(chǎn)生陰影 -->
<TresDirectionalLight :position="[5, 5, 5]" :intensity="1.5" />
<!-- 環(huán)境光:模擬環(huán)境反射光,無方向,提供基礎(chǔ)照明 -->
<TresAmbientLight :intensity="0.8" />
<!-- 點光源:模擬燈泡,從點向四周發(fā)射光線 -->
<TresPointLight :position="[2, 3, -2]" :intensity="0.8" color="#4ecdc4" />
<!-- iPhone模型組件 -->
<IPhoneModel />
<!-- 輔助工具(主要用于調(diào)試) -->
<!-- 坐標(biāo)軸輔助:紅色=X軸,綠色=Y軸,藍色=Z軸,幫助理解3D空間方向 -->
<TresAxesHelper :args="[3]" />
<!-- 網(wǎng)格輔助:10x10的網(wǎng)格,幫助定位和觀察場景比例 -->
<TresGridHelper :args="[10, 10]" :position="[0, -1.5, 0]" />
</TresCanvas>
<!-- 控制面板 -->
<div class="controls">
<button @click="toggleAutoRotate">
{{ autoRotate ? "?? 暫停" : "?? 旋轉(zhuǎn)" }}
</button>
<button @click="changeColor">?? 換色</button>
</div>
</div>
</template>
<script setup>
import {
ref,
reactive,
onMounted,
onUnmounted,
watch,
h,
shallowRef,
} from "vue";
import { TresCanvas } from "@tresjs/core";
import { OrbitControls } from "@tresjs/cientos";
import * as THREE from "three";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
//自動旋轉(zhuǎn)控制,初始值為true(啟用自動旋轉(zhuǎn))
const autoRotate = ref(true);
/**
* 相機位置
* reactive用于對象類型數(shù)據(jù),初始位置為[0, 0.5, 3]
* - x: 水平位置
* - y: 垂直位置
* - z: 深度位置
*/
const cameraPosition = reactive({ x: 0, y: 0.5, z: 3 });
//背景顏色
const currentColor = ref("#1a1a2e");
/**
* iPhone模型引用
* 使用shallowRef優(yōu)化性能,只對.value的變化做出響應(yīng)
*/
const iphoneModel = shallowRef(null);
// ========== 動畫循環(huán)控制 ==========
// 動畫幀ID,用于控制動畫循環(huán)
let animationId = null;
// ========== 用戶交互方法 ==========
//旋轉(zhuǎn)、暫停
const toggleAutoRotate = () => {
autoRotate.value = !autoRotate.value;
};
//換色
const changeColor = () => {
const colors = ["#1a1a2e", "#0f3460", "#533483", "#16213e"];
const currentIndex = colors.indexOf(currentColor.value);
currentColor.value = colors[(currentIndex + 1) % colors.length];
};
// ========== 模型加載邏輯 ==========
//加載iPhone模型
const loadIPhoneModel = () => {
// 創(chuàng)建GLTF加載器實例(GLTFLoader是加載GLTF格式的3D模型文件)
const loader = new GLTFLoader();
// 模型文件路徑(需要放在public/models/目錄下)
const modelPath = "/models/scene.gltf";
/**
* 加載GLTF模型
* 參數(shù)1: 模型文件路徑
* 參數(shù)2: 加載成功回調(diào)函數(shù)
* 參數(shù)3: 加載進度回調(diào)函數(shù)
* 參數(shù)4: 加載失敗回調(diào)函數(shù)
*/
loader.load(
modelPath,
// 加載成功回調(diào)
// const gltf = {
// scene: THREE.Group, // 整個3D場景(最重要的部分)
// scenes: Array, // 場景數(shù)組(通常只有一個場景)
// cameras: Array, // 相機數(shù)組
// animations: Array, // 動畫數(shù)據(jù)數(shù)組
// asset: Object, // 資源信息(作者、版本等)
// userData: Object // 用戶自定義數(shù)據(jù)
// };
(gltf) => {
// 檢查場景是否有效
if (gltf.scene) {
// 克隆模型,避免直接修改原始數(shù)據(jù)
const model = gltf.scene.clone();
//確保模型正確顯示。網(wǎng)格(Mesh):3D模型的基本組成單位,包含幾何體(形狀)和材質(zhì)(外觀)
model.traverse((child) => {
if (child.isMesh) {
child.visible = true;
}
});
//創(chuàng)建一個剛好能完全包圍這個3D模型的矩形邊界框,用于獲取模型的精確尺寸和位置信息,以便進行居中、縮放等標(biāo)準(zhǔn)化處理。
const box = new THREE.Box3().setFromObject(model);
// 獲取模型尺寸
const size = box.getSize(new THREE.Vector3());
// 獲取模型中心點
const center = box.getCenter(new THREE.Vector3());
// 將模型移動到世界原點(0,0,0)
model.position.x -= center.x;
model.position.y -= center.y;
model.position.z -= center.z;
// 根據(jù)最大尺寸縮放模型到合適大小
const maxSize = Math.max(size.x, size.y, size.z);
// 縮放到0.8單位大小,確保模型不會太大或太小
const scale = maxSize > 0 ? 0.8 / maxSize : 1;
model.scale.setScalar(scale);
// 更新模型引用
iphoneModel.value = model;
}
},
// 加載進度回調(diào)
// const progress = {
// loaded: 1024000, // 已加載的字節(jié)數(shù) (bytes)
// total: 5120000, // 總字節(jié)數(shù) (bytes)
// lengthComputable: true // 是否知道總大小
// };
(progress) => {
// 在控制臺顯示加載進度,便于調(diào)試
console.log(
`加載進度: ${((progress.loaded / progress.total) * 100).toFixed(2)}%`
);
},
// 加載失敗回調(diào)
(error) => {
console.error("模型加載失敗:", error);
}
);
};
// ========== iPhone模型組件 ==========
const IPhoneModel = () => {
if (iphoneModel.value) {
// 模型已加載:渲染3D模型
return h("primitive", { object: iphoneModel.value });
}
// 模型未加載:不渲染內(nèi)容
return null;
};
// ========== 動畫系統(tǒng) ==========
const animate = () => {
// 1. 動畫函數(shù)定義
if (autoRotate.value) {
// 2. 動畫條件控制
const time = Date.now() * 0.001; // 3. 時間變量
cameraPosition.x = Math.sin(time) * 3; // 4. 屬性變化(動畫核心)
cameraPosition.z = Math.cos(time) * 3;
}
animationId = requestAnimationFrame(animate); // 5. 循環(huán)機制
};
//開始動畫循環(huán)
const startAnimation = () => {
if (!animationId) {
animationId = requestAnimationFrame(animate);
}
};
//停止動畫循環(huán)
const stopAnimation = () => {
if (animationId) {
cancelAnimationFrame(animationId);
animationId = null; // 重置ID
}
};
// ========== 響應(yīng)式監(jiān)聽和生命周期 ==========
//監(jiān)聽旋轉(zhuǎn)還是暫停
watch(autoRotate, (newVal) => {
if (newVal) {
startAnimation(); // 開始動畫循環(huán)
} else {
stopAnimation(); // 停止動畫循環(huán)
}
});
onMounted(() => {
if (autoRotate.value) {
startAnimation(); // 開始動畫循環(huán)
}
// 加載iPhone模型
loadIPhoneModel();
});
onUnmounted(() => {
stopAnimation(); // 停止動畫循環(huán),避免內(nèi)存泄漏
});
</script>
<style scoped>
/* 主容器樣式 */
.iphone-showcase {
width: 100%;
height: 100vh;
position: relative;
}
/* 控制面板樣式 */
.controls {
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 10px;
z-index: 100;
}
/* 控制按鈕樣式 */
.controls button {
padding: 10px 20px;
background: rgba(255, 255, 255, 0.9);
border: none;
border-radius: 25px;
color: #333;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
}
/* 按鈕懸停效果 */
.controls button:hover {
background: rgba(255, 255, 255, 1);
transform: translateY(-2px);
}
</style>
六、iphone手機3D模型組件下載:
這里使用的是Sketchfab下載的3D模型文件,這里使用的是gltf文件(下載后需要解壓,然后將全部的解壓文件放到public/models中即可)

七、效果圖:

總結(jié)
到此這篇關(guān)于vue3+three.js理解與簡單使用的文章就介紹到這了,更多相關(guān)vue3 three.js簡單使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
關(guān)于Vue 消除Token過期時刷新頁面的重復(fù)提示問題
很多朋友在token過期時刷新頁面,頁面長時間未操作,再刷新頁面時,第一次彈出“token失效,請重新登錄!”提示,針對這個問題該怎么處理呢,下面小編給大家?guī)碓蚍治黾敖鉀Q方法,一起看看吧2021-07-07
vuex中遇到的坑,vuex數(shù)據(jù)改變,組件中頁面不渲染操作
這篇文章主要介紹了vuex中遇到的坑,vuex數(shù)據(jù)改變,組件中頁面不渲染操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-11-11
Cookbook組件形式:優(yōu)化 Vue 組件的運行時性能
本文仿照Vue Cookbook 組織形式,對優(yōu)化 Vue 組件的運行時性能進行闡述。通過基本的示例代碼給大家講解,需要的朋友參考下2018-11-11
element-ui使用導(dǎo)航欄跳轉(zhuǎn)路由的用法詳解
今天小編就為大家分享一篇element-ui使用導(dǎo)航欄跳轉(zhuǎn)路由的用法詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-08-08

