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>
相关推荐
是上好佳佳佳呀1 天前
【前端(十)】CSS 过渡与动画笔记
前端·css·笔记
用户新1 天前
V8引擎 精品漫游指南--Ignition篇(下 一) 动态执行前的事情
前端·javascript
阿里嘎多学长1 天前
2026-04-30 GitHub 热点项目精选
开发语言·程序员·github·代码托管
叶小鸡1 天前
Java 篇-项目实战-苍穹外卖-笔记汇总
java·开发语言·笔记
@PHARAOH1 天前
WHAT - GitLens vs Fork
前端
yqcoder1 天前
前端性能优化:如何减少重绘与重排?
前端·性能优化
AI人工智能+电脑小能手1 天前
【大白话说Java面试题】【Java基础篇】第22题:HashMap 和 HashSet 有哪些区别
java·开发语言·哈希算法·散列表·hash
时空系1 天前
第10篇:继承扩展——面向对象编程进阶 python中文编程
开发语言·python·ai编程
洋子1 天前
Yank Note 系列 13 - 让 AI Agent 进入笔记工作流
前端·人工智能
CHANG_THE_WORLD1 天前
python 批量终止进程exe
开发语言·python