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>
相关推荐
木易 士心2 小时前
Vue 自定义指令详解
javascript·vue.js·ecmascript
90后的晨仔2 小时前
Vue 组件注册详解:全局注册 vs 局部注册
前端·vue.js
前端Hardy2 小时前
HTML&CSS:高颜值交互式日历,贴心记录每一天
前端·javascript·css
hnlgzb2 小时前
安卓中,kotlin如何写app界面?
android·开发语言·kotlin
一只专注做软件的湖南人3 小时前
京东商品评论接口(jingdong.ware.comment.get)技术解析:数据拉取与情感分析优化
前端·后端·api
一叶飘零_sweeeet3 小时前
极简 Go 语言教程:从 Java 开发者视角 3 小时入门实战
java·开发语言·golang
千码君20163 小时前
React Native:使用vite创建react项目并熟悉react语法
javascript·css·react native·react.js·html·vite·jsx
刺客_Andy3 小时前
React 第三十八节 Router 中useRoutes 的使用详解及注意事项
前端·react.js
刺客_Andy3 小时前
React 第三十六节 Router 中 useParams 的具体使用及详细介绍
前端·react.js