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>
相关推荐
Wenweno0o18 小时前
0基础Go语言Eino框架智能体实战-chatModel
开发语言·后端·golang
于慨18 小时前
Lambda 表达式、方法引用(Method Reference)语法
java·前端·servlet
石小石Orz18 小时前
油猴脚本实现生产环境加载本地qiankun子应用
前端·架构
从前慢丶18 小时前
前端交互规范(Web 端)
前端
@yanyu66619 小时前
07-引入element布局及spring boot完善后端
javascript·vue.js·spring boot
CHU72903519 小时前
便捷约玩,沉浸推理:线上剧本杀APP功能版块设计详解
前端·小程序
chenjingming66619 小时前
jmeter线程组设置以及串行和并行设置
java·开发语言·jmeter
GISer_Jing19 小时前
Page-agent MCP结构
前端·人工智能
王霸天19 小时前
💥别再抄网上的Scale缩放代码了!50行源码教你写一个永不翻车的大屏适配
前端·vue.js·数据可视化
小领航19 小时前
用 Three.js + Vue 3 打造炫酷的 3D 行政地图可视化组件
前端·github