功能需求:給導入的易拉罐 .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
