? ? ? ? 嗨,我是小路。今天主要和大家分享的主題是“vue+threeJs 根據屏幕調整gltf模型的大小、重心、并更換騎車整體顏色”。? ? ? ??
項目案例示意圖
1.整體更換gltf模型的顏色
定義:整體代碼如下。顏色是事先設定的
const colorAry = reactive(["rgb(216, 27, 67)", "rgb(142, 36, 170)", "rgb(81, 45, 168)", "rgb(48, 63, 159)", "rgb(30, 136, 229)", "rgb(0, 137, 123)","rgb(67, 160, 71)", "rgb(251, 192, 45)", "rgb(245, 124, 0)", "rgb(230, 74, 25)", "rgb(233, 30, 78)", "rgb(156, 39, 176)","rgb(0, 0, 0)"])
//設置車身顏色
const setCarColor = (index) => {const currentColor = new THREE.Color(colorAry[index]);scene.traverse(child => {if (child.isMesh) {console.log(child.name)if (child.name.includes('door_')) {child.material.color.set(currentColor)}}})
}
2.計算gltf模型大小,進行縮放
二、實例代碼
<template><div class="pageBox"><div class="leftBox" ref="leftRef"></div><div class="rightBox" ref="rightRef" :style="{ background: bgColor }"><div @click="setCarColor(index)" v-for="(item,index) in colorAry":style="{backgroundColor : item}">{{item}}</div></div></div>
</template>
<script setup>
import { onMounted, reactive, ref } from 'vue';
import * as THREE from 'three';
// 引入軌道控制器擴展庫OrbitControls.js
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
// 設置相機控件軌道控制器OrbitControls// 引入gltf模型加載庫GLTFLoader.js
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { getRandomColor } from '../utils/commonThree';const bgColor = ref("")
//實例化一個gui對象
// const gui = new GUI();const leftRef = ref();
const rightRef = ref()
// 定義相機輸出畫布的尺寸(單位:像素px)
let width = 800; //寬度
let height = window.innerHeight; //高度
// 創建3D場景對象Scene
const scene = new THREE.Scene();
//設置背景色
scene.background = new THREE.Color("#ffffff");// 實例化一個透視投影相機對象
const camera = new THREE.PerspectiveCamera(50, width / height, 2, 6000);//=======================================================
const spotLight = new THREE.SpotLight(0xffffff, 1.0);const clock = new THREE.Clock();//===============================================
// 創建GLTF加載器對象
const loader = new GLTFLoader();// 創建渲染器對象
const renderer = new THREE.WebGLRenderer();const modelObj = reactive({ index: 1, url: './models/3d/tesla_2018_model_3/scene.gltf' });//車身顏色數組onMounted(() => {initData()render();//添加相機空間const controls = new OrbitControls(camera, renderer.domElement);controls.maxPolarAngle = 0.9 * Math.PI / 2controls.enableZoom = true// 如果OrbitControls改變了相機參數,重新調用渲染器渲染三維場景controls.addEventListener('change', function () {renderer.render(scene, camera); //執行渲染操作});//監聽鼠標、鍵盤事件})
const initData = () => {//環境光:沒有特定方向,整體改變場景的光照明暗const ambient = new THREE.AmbientLight(0xffffff, 0.4);scene.add(ambient);scene.add(spotLight);//光源添加到場景中// 根據需要設置相機位置具體值camera.position.set(200, 200, 200);//const gridHelper = new THREE.GridHelper(1000,50,getRandomColor(),getRandomColor());scene.add(gridHelper);loadGltfData();renderer.setSize(width, height); //設置three.js渲染區域的尺寸(像素px)//將innerHTML置空,避免append重復添加渲染leftRef.value.innerHTML = ''leftRef.value.append(renderer.domElement);
}let mixer = "";const colorAry = reactive(["rgb(216, 27, 67)", "rgb(142, 36, 170)", "rgb(81, 45, 168)", "rgb(48, 63, 159)", "rgb(30, 136, 229)", "rgb(0, 137, 123)","rgb(67, 160, 71)", "rgb(251, 192, 45)", "rgb(245, 124, 0)", "rgb(230, 74, 25)", "rgb(233, 30, 78)", "rgb(156, 39, 176)","rgb(0, 0, 0)"])
//設置車身顏色
const setCarColor = (index) => {const currentColor = new THREE.Color(colorAry[index]);scene.traverse(child => {if (child.isMesh) {console.log(child.name)if (child.name.includes('door_')) {child.material.color.set(currentColor)}}})
}
//加載gltf模型
const group = new THREE.Group();
const loadGltfData = () => {modelObj.url && loader.load(modelObj.url, function (gltf) {console.log(gltf)//加載完成//設置模型的位置// 計算幾何體中心//獲取模型的長、寬、高let scale = getScale(gltf.scene)//同比例放大,模型不變形gltf.scene.scale.set(scale,scale,scale);const box = new THREE.Box3().setFromObject(gltf.scene);const center = box.getCenter(new THREE.Vector3());// 將模型幾何頂點平移到中心點位置gltf.scene.position.set(-center.x, -center.y, -center.z);gltf.scene.position.x = 10;group.add(gltf.scene);group.position.y = 50;scene.add(group);}, function (xhr) {//加載時console.log((xhr.loaded / xhr.total * 100) + '% loaded');}, function (error) {console.log('加載失敗', error);})
}
//獲取模型長寬高
const getScale = (model) => {// 計算模型的邊界框const box = new THREE.Box3().setFromObject(model);// 獲取邊界框的尺寸const size = new THREE.Vector3();box.getSize(size);//以屏幕的一般高度為放縮比例let scale = (height / 2) / size.z;return scale;
}//渲染
const render = () => {//解決加載gltf格式模型紋理貼圖和原圖不一樣問題renderer.outputEncoding = THREE.sRGBEncoding;mixer ? mixer.update(clock.getDelta()) : null;group.rotation.y += 0.01;renderer.render(scene, camera); //執行渲染操作//重復渲染requestAnimationFrame(render);//請求再次執行渲染函數render,渲染下一幀
}</script>
<style scoped lang="less">
.pageBox {width: 100%;height: 100vh;padding: 0;margin: 0;display: flex;justify-content: space-between;align-items: center;.rightBox {width: 100%;height: 100%;background: yellow;}
}
</style>
三、總結
? ? ? ?1、后面需要向更復雜的3D展廳進行調整。
? ? ? ? 2、自動計算模型和模型的重心,并調整模型的大小,已經重心的位置。自適應屏幕調整。
? ? ? ? 3、這些方法都很適合在實際項目中開發運用。
最后一句,自我勉勵:寧可十年不將軍,不可一日不拱卒!
都看到這里了,記得【點贊】+【關注】喲。