three.js

需求一:导入3D模型车,修改车身的颜色

package.json

javascript 复制代码
{
  "name": "car",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview"
  },
  "dependencies": {
    "three": "^0.180.0",
    "vue": "^3.5.21"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^6.0.1",
    "vite": "^7.1.7"
  }
}

CarScene.vue

javascript 复制代码
<script setup lang='ts'>
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
import * as THREE from "three";
import { onMounted, ref } from "vue";

const container = ref()
let carBody;
const initScene = () => {
    //创建场景
    const scene = new THREE.Scene();
    //创建camera
    const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000)

    //创建渲染器
    const renderer = new THREE.WebGLRenderer()
    //设置渲染器的大小
    renderer.setSize(window.innerWidth / 2, window.innerHeight / 2)
    renderer.setClearColor(0x87CEEB)
    //将渲染器append
    container.value.appendChild(renderer.domElement)

    camera.position.set(0, 500, 150)
    const loader = new GLTFLoader()
    let model
    loader.load('/src/assets/models/red_car.glb', (gltf) => {
        console.log('gltf', gltf);
        model = gltf.scene
        model.scale.set(3, 3, 3)
        // model旋转 60°
        model.rotation.y =  Math.PI / 3
        scene.add(model)
        carBody = model.getObjectByName('carobjcleanermaterialmergergles')
    }, function (xhr) {

    },
        function (error) {
            console.log('An error happened');
        })
    const directionalLight = new THREE.DirectionalLight(0xffffff, 0.9);
    scene.add(directionalLight)



    //轨道
    const controls = new OrbitControls(camera, renderer.domElement)
    controls.update()

    function animate() {
        controls.update()
        renderer.render(scene, camera)
    }

    renderer.setAnimationLoop(animate)
}


onMounted(() => {
    initScene()
})


const colors = [
    { value: '#000', name: '黑色' },
    { value: '#fff', name: '白色' },
    { value: '#1B6EF3', name: '蓝色' },
    { value: '#41B883', name: '绿色' },
]
const changeColor = (color) => {
    if (!carBody) return;
    carBody.traverse((child) => {
        if (child.isMesh && child.material) {
            // 创建新材质或修改现有材质
            if (Array.isArray(child.material)) {
                // 处理材质数组
                child.material.forEach(material => {
                    if (material instanceof THREE.MeshStandardMaterial) {
                        material.color.set(color);
                        material.needsUpdate = true;
                    }
                });
            } else if (child.material.color) {
                //如果有贴图,那么修改颜色只会修改透明部分,所以需要为null
                if (child.material.map) {
                    child.material.map = null;
                }
                // 处理单个材质
                child.material.color.set(color);
                child.material.needsUpdate = true;
            }
        }
    });
}

</script>
<template>
    <div class="car-wrap">
        <div class="btn-color" v-for="(item, index) in colors" :key="index" @click="changeColor(item.value)"
            :style="{ 'backgroundColor': item.value }"></div>
        <div ref="container" class="three-container"></div>
    </div>
</template>
<style scoped>
.car-wrap {
    background: #ccc;
}

.btn-color {
    width: 50px;
    height: 30px;
    margin: 10px auto;
}
</style>

需求二:添加GridHelper,无线循环移动GridHelper,视角效果是车在移动。

MoveScene.vue

javascript 复制代码
<script setup lang='ts'>
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
import * as THREE from "three";
import { onMounted, ref  } from "vue";

const container = ref()
let carBody;
//网格大小
const gridSize = 1000;
const initScene = () => {
    //创建场景
    const scene = new THREE.Scene();
    //创建camera
    const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000)

    //创建渲染器
    const renderer = new THREE.WebGLRenderer({antialias: true})
    //设置渲染器的大小
    renderer.setSize(window.innerWidth / 2, window.innerHeight / 2)
    renderer.setClearColor(0xffffff)

    // Grid
    const divisions = 50; //网格被分割成多少份
    const gridHelper = new THREE.GridHelper(gridSize, divisions);
    scene.add(gridHelper);

    //  camera.position.set(0, 500, 150)
    camera.position.set(0, 500, 150);

    //将渲染器append
    container.value.appendChild(renderer.domElement)


    const loader = new GLTFLoader()
    let model
    loader.load('/src/assets/models/red_car.glb', (gltf) => {
        console.log('gltf', gltf);
        model = gltf.scene
        model.scale.set(3, 3, 3)
        // model旋转 90°
        model.rotation.y = Math.PI / 2
        scene.add(model)
        carBody = model.getObjectByName('carobjcleanermaterialmergergles')
    }, function (xhr) {

    },
        function (error) {
            console.log('An error happened');
        })
    const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
    scene.add(directionalLight)

    //轨道
    const controls = new OrbitControls(camera, renderer.domElement)
    controls.update()

    function animate() {
        controls.update()
        gridHelper.position.x += 5
        //当网格移出屏幕时,让网格重新出现做屏幕左侧,实现无线循环
        if (gridHelper.position.x > gridSize) {
            gridHelper.position.x = -gridSize
        }
        renderer.render(scene, camera)
    }

    renderer.setAnimationLoop(animate)
}


onMounted(() => {
    initScene()
})


const colors = [
    { value: '#000', name: '黑色' },
    { value: '#fff', name: '白色' },
    { value: '#1B6EF3', name: '蓝色' },
    { value: '#41B883', name: '绿色' },
]
const changeColor = (color) => {
    if (!carBody) return;
    carBody.traverse((child) => {
        if (child.isMesh && child.material) {
            // 创建新材质或修改现有材质
            if (Array.isArray(child.material)) {
                // 处理材质数组
                child.material.forEach(material => {
                    if (material instanceof THREE.MeshStandardMaterial) {
                        material.color.set(color);
                        material.needsUpdate = true;
                    }
                });
            } else if (child.material.color) {
                //如果有贴图,那么修改颜色只会修改透明部分,所以需要为null
                if (child.material.map) {
                    child.material.map = null;
                }
                // 处理单个材质
                child.material.color.set(color);
                child.material.needsUpdate = true;
            }
        }
    });
}

</script>
<template>
    <div class="car-wrap">
        <div class="btn-color" v-for="(item, index) in colors" :key="index" @click="changeColor(item.value)"
            :style="{ 'backgroundColor': item.value }"></div>
        <div ref="container" class="three-container"></div>
    </div>
</template>
<style scoped>
.car-wrap {
    background: #ccc;
}

.btn-color {
    width: 50px;
    height: 30px;
    margin: 10px auto;
}
</style>
相关推荐
子兮曰3 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰3 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
小羊没烦恼!3 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
前端小万3 天前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝3 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
三十而立洋3 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
伞伞悦读3 天前
【第38期】Python 模块与包详解:import、from、模块搜索路径、包结构和 __init__
开发语言·python
卡布鲁3 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
C语言小火车3 天前
C/C++ 为什么需要编译器?
开发语言·c++
李少兄3 天前
JavaScript 隐式全局变量解析
javascript