功能需求:給導入的易拉罐 .obj 元素實現換膚。
附件材料:3d模型制作軟件導出的 .obj 文件 和 需要換膚的紋理圖片。
代碼實現:
css:

* { margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } html, body, #content { width: 100%; height: 100%; overflow: hidden; } ul, li { list-style-type: none; } .skin-btn { position: absolute; display: flex; } .skin-btn li { width: 40px; height: 40px; margin: 15px 10px; } .skin-btn--red { background-color: #c11d24; } .skin-btn--orange { background-color: #ff7800; } .skin-btn--blue { background-color: #00d2ff; }
js:

import React, { useEffect } from 'react'; import * as THREE from 'three'; import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'; import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader'; import fileObj from 'static/media/coca/file.obj'; import cocaRed from 'static/media/coca/coca_red.jpg'; import cocaOrange from 'static/media/coca/coca_orange.jpg'; import cocaBlue from 'static/media/coca/coca_blue.jpg'; import './index.css'; function Skin() { // obj對象需貼圖的面,為數據對象 let objLoaderMaterialArr = []; // 更換皮膚 const changeSkin = (color) => { // 紋理設置 let TextureLoader = null; switch (color) { case 'red': TextureLoader = new THREE.TextureLoader().load(cocaRed); break; case 'orange': TextureLoader = new THREE.TextureLoader().load(cocaOrange); break; case 'blue': TextureLoader = new THREE.TextureLoader().load(cocaBlue); break; default: } // 給第一個紋理面設置相關圖片 objLoaderMaterialArr[0] = new THREE.MeshLambertMaterial({ map: TextureLoader, }); }; const init = () => { // dom元素生成 const contentEl = document.getElementById('content'); const winWidth = window.innerWidth; const winHeight = window.innerHeight; contentEl.style.cssText = `width:${winWidth}px;height:${winHeight}px`; // 場景 const scene = new THREE.Scene(); // obj 元素加載器 const objLoader = new OBJLoader(); objLoader.load(fileObj, (obj) => { obj.scale.set(0.1, 0.1, 0.1); obj.traverse((child) => { if (child instanceof THREE.Mesh) { // 獲取需貼紙的材質列表 objLoaderMaterialArr = child.material; // 給第一個紋理面設置相關圖片 objLoaderMaterialArr[0] = new THREE.MeshLambertMaterial({ map: new THREE.TextureLoader().load(cocaRed), }); } }); scene.add(obj); }); // ------------------------------------------------------------------------------------------ // 相機 const camera = new THREE.PerspectiveCamera(45, winWidth / winHeight, 0.1, 1000); // 設置相機坐標 camera.position.set(10, 30, 100); // 渲染器 const renderer = new THREE.WebGLRenderer({ antialias: true, }); // 設置渲染器的顏色和大小 renderer.setClearColor('#000'); renderer.setSize(winWidth, winHeight); const canvas = renderer.domElement; document.body.appendChild(canvas); contentEl.append(canvas); // 鼠標控制旋轉 const orbitControls = new OrbitControls(camera, canvas); // 設置自動旋轉及旋轉速度 orbitControls.autoRotate = true; orbitControls.autoRotateSpeed = 10; // 設置光源 const light = new THREE.DirectionalLight(0xffffff, 0.5); light.position.setScalar(100); scene.add(light); scene.add(new THREE.AmbientLight(0xffffff, 0.5)); // 執行實時刷新 function render() { // 動畫循環渲染 requestAnimationFrame(render); // 渲染到頁面上 renderer.render(scene, camera); orbitControls.update(); } render(); }; useEffect(() => { init(); }); return ( <div id="content"> <ul className="skin-btn"> <li className="skin-btn--red" onClick={() => { changeSkin('red'); }} ></li> <li className="skin-btn--orange" onClick={() => { changeSkin('orange'); }} ></li> <li className="skin-btn--blue" onClick={() => { changeSkin('blue'); }} ></li> </ul> </div> ); } export default Skin;
運行截圖:
代碼地址:https://github.com/Zion0707/threejs/tree/master/src/pages/skin