使用three.js和react搭建一个3d小车模型

本文展示了如何在React应用中集成Three.js库,创建一个3D汽车模型,包括车身、车头和轮胎,并使用OrbitControls和TransformControls进行视角控制和对象操作。同时,文章还涉及了相机设置、渲染器初始化以及动态更新场景的实现方法。
摘要由CSDN通过智能技术生成

注意:该代码封装了一个子组件,使用时需要在主页面中引入 

 

import React, { useState, useEffect, useRef } from 'react';
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import { TransformControls } from 'three/examples/jsm/controls/TransformControls';
import './index.less'
const Car = () => {
  // 创建一个 ref 来引用相机对象
  const camRef = useRef();
  // 创建一个 ref 来引用渲染器对象
  const rendererRef = useRef();
  // 创建一个 ref 来引用 transform 控制器对象
  const transformRef = useRef();
  // 创建一个 ref 来引用鼠标控制器对象
  const orbitsRef = useRef();

  // 创建 state 来存储车身放大缩小比例
  const [scale, setScale] = useState(1);

  // 初始化 Three.js 场景
  useEffect(() => {
    // 获取画布容器
    const container = document.getElementById('threeContainer');

    // 创建一个 Three.js 场景
    const scene = new THREE.Scene();

    // 创建一个 Three.js 相机
    const camera = new THREE.PerspectiveCamera(
      75,
      container.offsetWidth / container.offsetHeight,
      0.1,
      1000
    );

    // 设置相机位置
    camera.position.set(-8, 2.5, 10);

    // 添加相机对象到对象列表中
    scene.add(camera);

    // 创建一个 Three.js 渲染器
    const renderer = new THREE.WebGLRenderer({ antialias: true });
    renderer.setSize(container.offsetWidth, container.offsetHeight);
    renderer.setClearColor('#fff');
    rendererRef.current = renderer;

    // 添加渲染器对象到 DOM 元素中
    container.appendChild(renderer.domElement);

    // 创建一个 Three.js 显示对象
    const carGroup = new THREE.Group();
    scene.add(carGroup);

    // 创建车身模型
    const cube = new THREE.Mesh(new THREE.BoxGeometry(2, 1, 1), new THREE.MeshLambertMaterial({
      color: 0xffffff,
    }))
    carGroup.add(cube);
    // 创建车头模型
    const headGeometry = new THREE.CylinderGeometry(0, 0.5, 1, 5);
    const headMaterial = new THREE.MeshStandardMaterial({ color: '#0000ff' });
    const head = new THREE.Mesh(headGeometry, headMaterial);
    head.position.x = 1.5;
    carGroup.add(head);
    //轮胎
    const tire1 = new THREE.Mesh(new THREE.TorusGeometry(0.2, 0.08, 8, 20), new THREE.MeshLambertMaterial({
      color: 0xffffff
    }))
    //THREE.TorusGeometry` 是用于创建圆环几何体的类,接受以下四个参数:
    //`radius`:圆环的总半径,默认值为1。
    //`tube`:圆环的管道半径,默认值为0.4。
    //`radialSegments`:圆环的弧线段数,默认值为8。
    //`tubularSegments`:圆环的管道线段数,默认值为6。
    //其中,`radius` 和 `tube` 控制圆环的外半径和内半径,`radialSegments` 和 `tubularSegments` 分别控制圆环的弧线段数和管道线段数。
    //对于 `THREE.TorusGeometry(0.2,0.08,8,20)`,它创建了一个外半径为0.2,内半径为0.08,弧线段数为8,管道线段数为20的圆环几何体。
    const tire2 = new THREE.Mesh(new THREE.TorusGeometry(0.2, 0.08, 8, 20), new THREE.MeshLambertMaterial({
      color: 0xffffff
    }))
    const tire3 = new THREE.Mesh(new THREE.TorusGeometry(0.2, 0.08, 8, 20), new THREE.MeshLambertMaterial({
      color: 0xffffff
    }))
    const tire4 = new THREE.Mesh(new THREE.TorusGeometry(0.2, 0.08, 8, 20), new THREE.MeshLambertMaterial({
      color: 0xffffff
    }))
    carGroup.add(tire1, tire2, tire3, tire4);
    tire1.position.set(0.5, -0.5, 0.5);
    tire2.position.set(-0.65, -0.5, 0.5);
    tire3.position.set(0.5, -0.5, -0.5);
    tire4.position.set(-0.65, -0.5, -0.5);

    // 创建一个灯光
    const light = new THREE.PointLight(0xffffff, 1, 100);
    light.position.set(0, 2, 2);
    scene.add(light);

    // 绑定鼠标控制器
    const orbits = new OrbitControls(camera, renderer.domElement);
    orbitsRef.current = orbits;

    // 启用防止缩放时更新对象的功能
    orbits.enableDamping = true;

    // 绑定变换控制器
    const transform = new TransformControls(camera, renderer.domElement);
    transform.attach(carGroup);
    transformRef.current = transform;
    scene.add(transform);

    // 通过 requestAnimationFrame 动态更新场景
    const animate = () => {
      requestAnimationFrame(animate);

      // 每次旋转角度增加 0.01,与防止缩放时更新对象的功能配合使用
      transform.rotateZ(0.01);

      // 将相机对象指向车身对象
      camRef.current.lookAt && camRef.current.lookAt(body.position);

      // 更新渲染器对象
      rendererRef.current.render(scene, camera);
    };
    animate();

    // 销毁场景
    const cleanup = () => {
      container.removeChild(renderer.domElement);
      scene.remove(carGroup);
      renderer.dispose();
      orbits.dispose();
      transform.dispose();
    };

    // 组件卸载时销毁场景
    return cleanup;
  }, []);

  return <div id='threeContainer' className='car_container' ref={camRef} />
};

export default Car;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值