目錄
項(xiàng)目搭建
初始化three.js基礎(chǔ)代碼
添加汽車模型展示
動(dòng)態(tài)修改汽車模型
今天簡(jiǎn)單實(shí)現(xiàn)一個(gè)three.js的小Demo,加強(qiáng)自己對(duì)three知識(shí)的掌握與學(xué)習(xí),只有在項(xiàng)目中才能靈活將所學(xué)知識(shí)運(yùn)用起來(lái),話不多說(shuō)直接開(kāi)始。
項(xiàng)目搭建
本案例還是借助框架書(shū)寫(xiě)three項(xiàng)目,借用vite構(gòu)建工具搭建vue項(xiàng)目,vite這個(gè)構(gòu)建工具如果有不了解的朋友,可以參考我之前對(duì)其講解的文章:vite腳手架的搭建與使用 。搭建完成之后,用編輯器打開(kāi)該項(xiàng)目,在終端執(zhí)行 npm i 安裝一下依賴,安裝完成之后終端在安裝 npm i three 即可。
因?yàn)槲掖罱ǖ氖莢ue3項(xiàng)目,為了便于代碼的可讀性,所以我將three.js代碼單獨(dú)抽離放在一個(gè)組件當(dāng)中,在App根組件中進(jìn)入引入該組件。具體如下:
<template>
<!-- 汽車展覽 -->
<autoShow></autoShow>
</template>
<script setup>
import autoShow from './components/autoShow.vue';
</script>
<style lang="less">
*{
margin: 0;
padding: 0;
}
</style>
初始化three.js基礎(chǔ)代碼
three.js開(kāi)啟必須用到的基礎(chǔ)代碼如下:
導(dǎo)入three庫(kù):
import * as THREE from 'three'
初始化場(chǎng)景:
const scene = new THREE.Scene()
初始化相機(jī):
const camera = new THREE.PerspectiveCamera(75,window.innerWidth / window.innerHeight,0.1,1000)
camera.position.set(0,2,6)
初始化渲染器:
const renderer = new THREE.WebGLRenderer({
antialias: true // 設(shè)置抗鋸齒
})
renderer.setSize(window.innerWidth,window.innerHeight)
監(jiān)聽(tīng)屏幕大小的改變,修改渲染器的寬高和相機(jī)的比例:
window.addEventListener("resize",()=>{
renderer.setSize(window.innerWidth,window.innerHeight)
camera.aspect = window.innerWidth/window.innerHeight
camera.updateProjectionMatrix()
})
導(dǎo)入控制器:
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls"
// 實(shí)例化控制器
const controls = new OrbitControls(camera,renderer.domElement)
設(shè)置渲染函數(shù):
const render = () =>{
renderer.render(scene,camera) // 渲染場(chǎng)景
requestAnimationFrame(render) // 循環(huán)渲染
}
進(jìn)行掛載:
在html代碼處創(chuàng)建一個(gè)div,然后通過(guò)ref獲取其dom元素,在頁(yè)面剛掛載的時(shí)候?qū)秩酒鞑迦氲絛om當(dāng)中去,如下:
onMounted(()=>{
// 添加控制器
const controls = new OrbitControls(camera,canvas.value)
controls.enableDamping = true
canvas.value.appendChild(renderer.domElement) // 將渲染器插入到dom中
// 初始化渲染器,渲染背景
scene.background = new THREE.Color("#ccc")
scene.environment = new THREE.Color("#ccc")
render()
})
添加汽車模型展示
在添加汽車模型之前,我們可以先創(chuàng)建一個(gè)網(wǎng)格地面,然后讓汽車模型更具有立體效果:
// 添加網(wǎng)格地面
const gridHelper = new THREE.GridHelper(10,10)
gridHelper.material.opacity = 0.2
gridHelper.material.transparent = true
scene.add(gridHelper)
接下來(lái)就可以添加汽車模型,讓汽車模型在網(wǎng)格地面上展示,如下:
// 先導(dǎo)入加載gltf模型和壓縮模型的庫(kù)
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
// 添加gltf汽車模型
const loader = new GLTFLoader()
const dracoLoader = new DRACOLoader()
dracoLoader.setDecoderPath("/draco/")
loader.setDRACOLoader(dracoLoader)
loader.load("src/assets/model/bmw01.glb",(gltf)=>{
scene.add(gltf.scene)
})
因?yàn)槠囌褂[的話,推薦平行光更具有立體效果,不建議直接使用環(huán)境光:
// 添加燈光
const light1 = new THREE.DirectionalLight(0xffffff, 0.7);
light1.position.set(0, 0, 10);
scene.add(light1);
const light2 = new THREE.DirectionalLight(0xffffff, 0.7);
light2.position.set(0, 0, -10);
scene.add(light2);
const light3 = new THREE.DirectionalLight(0xffffff, 0.7);
light3.position.set(10, 0, 0);
scene.add(light3);
const light4 = new THREE.DirectionalLight(0xffffff, 0.7);
light4.position.set(-10, 0, 0);
scene.add(light4);
const light5 = new THREE.DirectionalLight(0xffffff, 0.7);
light5.position.set(0, 10, 0);
scene.add(light5);
const light6 = new THREE.DirectionalLight(0xffffff, 0.3);
light6.position.set(5, 10, 0);
scene.add(light6);
const light7 = new THREE.DirectionalLight(0xffffff, 0.3);
light7.position.set(0, 10, 5);
scene.add(light7);
const light8 = new THREE.DirectionalLight(0xffffff, 0.3);
light8.position.set(0, 10, -5);
scene.add(light8);
const light9 = new THREE.DirectionalLight(0xffffff, 0.3);
light9.position.set(-5, 10, 0);
scene.add(light9);
動(dòng)態(tài)修改汽車模型
因?yàn)?d建模生成的gltf模型會(huì)給我們標(biāo)記好名字,所以我們只需要找到并拿來(lái)使用即可,如下:
如果想動(dòng)態(tài)修改數(shù)據(jù)的話,可以借助一個(gè)gui庫(kù),關(guān)于gui庫(kù)的講解可以參看我之前講解的文章:Gui.js庫(kù)的使用講解 ,在這里就不再贅述,這里我們?yōu)槊恳粋€(gè)汽車模型部位都創(chuàng)建一個(gè)物理材質(zhì)然后進(jìn)行動(dòng)態(tài)的修改:
將動(dòng)態(tài)修改材質(zhì)的數(shù)據(jù)添加到汽車模型材質(zhì)上去,這里我用switch動(dòng)態(tài)的去判斷各種情況,如下:
大體的思路就是上面了,ok可以簡(jiǎn)單看一下最后呈現(xiàn)的效果是啥,如下:
文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-458389.html
demo做完,給出本案例的完整代碼:(獲取素材也可以私信博主)文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-458389.html
<template>
<div class="home">
<div class="canvas-container" ref="canvas"></div>
</div>
</template>
<script setup>
import * as THREE from "three"
import { onMounted,ref } from "vue";
// 添加軌道控制器
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
// 引入gui.js庫(kù)
import { GUI } from 'three/examples/jsm/libs/lil-gui.module.min.js'
// 實(shí)例化一個(gè)gui對(duì)象
const gui = new GUI()
let canvas = ref(null)
// 創(chuàng)建場(chǎng)景
const scene = new THREE.Scene()
// 創(chuàng)建相機(jī)
const camera = new THREE.PerspectiveCamera(75,window.innerWidth / window.innerHeight,0.1,1000)
camera.position.set(0,2,6)
// 創(chuàng)建渲染器
const renderer = new THREE.WebGLRenderer({
antialias: true // 設(shè)置抗鋸齒
})
renderer.setSize(window.innerWidth,window.innerHeight)
// 設(shè)置渲染函數(shù)
const render = () =>{
renderer.render(scene,camera)
requestAnimationFrame(render)
}
// 監(jiān)聽(tīng)頁(yè)面變化
window.addEventListener("resize",()=>{
renderer.setSize(window.innerWidth,window.innerHeight)
camera.aspect = window.innerWidth/window.innerHeight
camera.updateProjectionMatrix()
})
onMounted(()=>{
// 添加控制器
const controls = new OrbitControls(camera,canvas.value)
controls.enableDamping = true
canvas.value.appendChild(renderer.domElement) // 將渲染器插入到dom中
// 初始化渲染器,渲染背景
scene.background = new THREE.Color("#ccc")
scene.environment = new THREE.Color("#ccc")
render()
})
// 添加網(wǎng)格地面
const gridHelper = new THREE.GridHelper(10,10)
gridHelper.material.opacity = 0.2
gridHelper.material.transparent = true
scene.add(gridHelper)
// 設(shè)置汽車模型部件的名稱
let wheels = [] // 汽車輪轂
let carBody,frontCar,hoodCar,glassCar // 汽車車身、汽車前列、汽車引擎、汽車擋風(fēng)玻璃
// 創(chuàng)建輪轂材質(zhì)
const wheelsMaterial = new THREE.MeshPhysicalMaterial({
color: 0xff0000,
metalness: 1,
roughness: 0.1,
});
const wheelsChange = gui.addFolder("輪轂設(shè)置")
wheelsChange.close() // 默認(rèn)關(guān)閉狀態(tài)
wheelsChange.addColor(wheelsMaterial,'color').name('前輪轂顏色').onChange(value=>{
wheelsMaterial.color.set(value)
})
wheelsChange.add(wheelsMaterial,'metalness',0,1).name('金屬度').onChange(value=>{
wheelsMaterial.metalness = value
})
wheelsChange.add(wheelsMaterial,'roughness',0,1).name('粗糙度').onChange(value=>{
wheelsMaterial.roughness = value
})
// 創(chuàng)建右后輪轂材質(zhì)
const wheelsRightMaterial = new THREE.MeshPhysicalMaterial({
color: 0xff0000,
metalness: 1,
roughness: 0.1,
});
const wheelsRightChange = wheelsChange.addFolder("右后輪轂設(shè)置")
wheelsRightChange.close() // 默認(rèn)關(guān)閉狀態(tài)
wheelsRightChange.addColor(wheelsRightMaterial,'color').name('右后輪轂顏色').onChange(value=>{
wheelsRightMaterial.color.set(value)
})
wheelsRightChange.add(wheelsRightMaterial,'metalness',0,1).name('金屬度').onChange(value=>{
wheelsRightMaterial.metalness = value
})
wheelsRightChange.add(wheelsRightMaterial,'roughness',0,1).name('粗糙度').onChange(value=>{
wheelsRightMaterial.roughness = value
})
// 創(chuàng)建輪轂材質(zhì)
const wheelsLeftMaterial = new THREE.MeshPhysicalMaterial({
color: 0xff0000,
metalness: 1,
roughness: 0.1,
});
const wheelsLeftChange = wheelsChange.addFolder("左后輪轂設(shè)置")
wheelsLeftChange.close() // 默認(rèn)關(guān)閉狀態(tài)
wheelsLeftChange.addColor(wheelsLeftMaterial,'color').name('左后輪轂顏色').onChange(value=>{
wheelsLeftMaterial.color.set(value)
})
wheelsLeftChange.add(wheelsLeftMaterial,'metalness',0,1).name('金屬度').onChange(value=>{
wheelsLeftMaterial.metalness = value
})
wheelsLeftChange.add(wheelsLeftMaterial,'roughness',0,1).name('粗糙度').onChange(value=>{
wheelsLeftMaterial.roughness = value
})
// 創(chuàng)建車身材質(zhì)
const bodyMaterial = new THREE.MeshPhysicalMaterial({
color: 0xff0000,
metalness: 1,
roughness: 0.5,
clearcoat: 1,
clearcoatRoughness: 0,
})
const carBodyChange = gui.addFolder("車身設(shè)置")
carBodyChange.close() // 默認(rèn)關(guān)閉狀態(tài)
carBodyChange.addColor(bodyMaterial,'color').name('車身顏色').onChange(value=>{
bodyMaterial.color.set(value)
})
carBodyChange.add(bodyMaterial,'metalness',0,1).name('金屬度').onChange(value=>{
bodyMaterial.metalness = value
})
carBodyChange.add(bodyMaterial,'roughness',0,1).name('粗糙度').onChange(value=>{
bodyMaterial.roughness = value
})
carBodyChange.add(bodyMaterial,'clearcoat',0,1).name('清漆').onChange(value=>{
bodyMaterial.clearcoat = value
})
carBodyChange.add(bodyMaterial,'clearcoatRoughness',0,1).name('清漆粗糙度').onChange(value=>{
bodyMaterial.clearcoatRoughness = value
})
// 創(chuàng)建車前列材質(zhì)
const frontMaterial = new THREE.MeshPhysicalMaterial({
color: 0xff0000,
metalness: 1,
roughness: 0.5,
clearcoat: 1,
clearcoatRoughness: 0,
})
const frontCarChange = gui.addFolder("車前身設(shè)置")
frontCarChange.close() // 默認(rèn)關(guān)閉狀態(tài)
frontCarChange.addColor(frontMaterial,'color').name('車前身顏色').onChange(value=>{
frontMaterial.color.set(value)
})
frontCarChange.add(frontMaterial,'metalness',0,1).name('金屬度').onChange(value=>{
frontMaterial.metalness = value
})
frontCarChange.add(frontMaterial,'roughness',0,1).name('粗糙度').onChange(value=>{
frontMaterial.roughness = value
})
frontCarChange.add(frontMaterial,'clearcoat',0,1).name('清漆').onChange(value=>{
frontMaterial.clearcoat = value
})
frontCarChange.add(frontMaterial,'clearcoatRoughness',0,1).name('清漆粗糙度').onChange(value=>{
frontMaterial.clearcoatRoughness = value
})
// 創(chuàng)建汽車引擎材質(zhì)
const hoodMaterial = new THREE.MeshPhysicalMaterial({
color: 0xff0000,
metalness: 1,
roughness: 0.5,
clearcoat: 1,
clearcoatRoughness: 0,
});
const hoodCarChange = gui.addFolder("汽車引擎設(shè)置")
hoodCarChange.close() // 默認(rèn)關(guān)閉狀態(tài)
hoodCarChange.addColor(hoodMaterial,'color').name('汽車引擎顏色').onChange(value=>{
hoodMaterial.color.set(value)
})
hoodCarChange.add(hoodMaterial,'metalness',0,1).name('金屬度').onChange(value=>{
hoodMaterial.metalness = value
})
hoodCarChange.add(hoodMaterial,'roughness',0,1).name('粗糙度').onChange(value=>{
hoodMaterial.roughness = value
})
hoodCarChange.add(hoodMaterial,'clearcoat',0,1).name('清漆').onChange(value=>{
hoodMaterial.clearcoat = value
})
hoodCarChange.add(hoodMaterial,'clearcoatRoughness',0,1).name('清漆粗糙度').onChange(value=>{
hoodMaterial.clearcoatRoughness = value
})
// 創(chuàng)建汽車擋風(fēng)玻璃材質(zhì)
const glassMaterial = new THREE.MeshPhysicalMaterial({
color: 0xffffff,
metalness: 0,
roughness: 0,
transmission: 1,
transparent: true,
});
const glassCarChange = gui.addFolder("汽車擋風(fēng)玻璃設(shè)置")
glassCarChange.close() // 默認(rèn)關(guān)閉狀態(tài)
glassCarChange.addColor(glassMaterial,'color').name('汽車擋風(fēng)玻璃顏色').onChange(value=>{
glassMaterial.color.set(value)
})
glassCarChange.add(glassMaterial,'metalness',0,1).name('金屬度').onChange(value=>{
glassMaterial.metalness = value
})
glassCarChange.add(glassMaterial,'roughness',0,1).name('粗糙度').onChange(value=>{
glassMaterial.roughness = value
})
glassCarChange.add(glassMaterial,'transmission',0,1).name('透射值').onChange(value=>{
glassMaterial.transmission = value
})
glassCarChange.add(glassMaterial,'transparent',0,1).name('是否透明').onChange(value=>{
glassMaterial.transparent = value
})
// 添加gltf汽車模型
const loader = new GLTFLoader()
const dracoLoader = new DRACOLoader()
dracoLoader.setDecoderPath("/draco/")
loader.setDRACOLoader(dracoLoader)
loader.load("src/assets/model/bmw01.glb",(gltf)=>{
// traverse函數(shù)是一種用于遍歷Object3D及其子對(duì)象的函數(shù),可以訪問(wèn)場(chǎng)景中所有的Object3D類型對(duì)象(包括Mesh、Group、Object等)
gltf.scene.traverse((child)=>{
switch(child.isMesh){
// 判斷是否為輪轂
case child.name.includes("輪轂"):
wheels.push(child)
wheels[0].material = wheelsMaterial
if(wheels.length === 3){
wheels[1].material = wheelsRightMaterial
wheels[2].material = wheelsLeftMaterial
}
break
// 判斷是否為車身
case child.name.includes("Mesh002"):
carBody = child
carBody.material = bodyMaterial
break
// 判斷是否是車前列
case child.name.includes("前臉"):
frontCar = child
frontCar.material = frontMaterial
break
// 判斷是否為引擎蓋
case child.name.includes("引擎蓋_1"):
hoodCar = child
hoodCar.material = hoodMaterial
break
// 判斷是否為擋風(fēng)玻璃
case child.name.includes("擋風(fēng)玻璃"):
glassCar = child
glassCar.material = glassMaterial
break
default:
return
}
})
scene.add(gltf.scene)
})
// 添加燈光
const light1 = new THREE.DirectionalLight(0xffffff, 0.7);
light1.position.set(0, 0, 10);
scene.add(light1);
const light2 = new THREE.DirectionalLight(0xffffff, 0.7);
light2.position.set(0, 0, -10);
scene.add(light2);
const light3 = new THREE.DirectionalLight(0xffffff, 0.7);
light3.position.set(10, 0, 0);
scene.add(light3);
const light4 = new THREE.DirectionalLight(0xffffff, 0.7);
light4.position.set(-10, 0, 0);
scene.add(light4);
const light5 = new THREE.DirectionalLight(0xffffff, 0.7);
light5.position.set(0, 10, 0);
scene.add(light5);
const light6 = new THREE.DirectionalLight(0xffffff, 0.3);
light6.position.set(5, 10, 0);
scene.add(light6);
const light7 = new THREE.DirectionalLight(0xffffff, 0.3);
light7.position.set(0, 10, 5);
scene.add(light7);
const light8 = new THREE.DirectionalLight(0xffffff, 0.3);
light8.position.set(0, 10, -5);
scene.add(light8);
const light9 = new THREE.DirectionalLight(0xffffff, 0.3);
light9.position.set(-5, 10, 0);
scene.add(light9);
</script>
到了這里,關(guān)于Three.js--》實(shí)現(xiàn)3d汽車模型展覽搭建的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!