Threejs创建一个可旋转拖动自动运行的小车

2023-04-22 06:12:00
pjd
原创 281
摘要:常用命令集


1、创建项目(Vite为例)


npm create vite <项目名称>
$ npm create vite threejs-1
? Select a framework: » - Use arrow-keys. Return to submit.
>   Vanilla
    Vue
    React
    Preact
    Lit
    Svelte
    Others
Done. Now run:
  cd threejs-1
  npm install
  npm run dev


2、安装依赖

npm install vite three

3、启动项目


npm run dev
> threejs-1@0.0.0 dev
> vite
  VITE v4.3.1  ready in 445 ms
  ➜  Local:   http://127.0.0.1:5173/
  ➜  Network: use --host to expose
  ➜  press h to show help

4、引入THREE 到main.js文件中


import * as THREE from "three"
console.log(THREE)


立方体示例代码:


import * as THREE from "three"
import Stat from "three/examples/jsm/libs/stats.module"
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls"
const w = window.innerWidth
const h = window.innerHeight
const stat = new Stat()
const scene = new THREE.Scene()
scene.add(new THREE.AxesHelper(2,2,2))
const g = new THREE.BoxGeometry(1,1,1)
const m = new THREE.MeshNormalMaterial()
const cube = new THREE.Mesh(g,m)
scene.add(cube)
const light = new THREE.AmbientLight()
scene.add(light)
const camera = new THREE.PerspectiveCamera(75, w/h,0.1,100)
camera.position.set(0,0,5)
camera.lookAt(0,0,0)
const renderer = new THREE.WebGLRenderer()
renderer.setSize(w,h)
document.body.append(renderer.domElement)
document.body.append(stat.dom)
const orbitControl = new OrbitControls(camera,renderer.domElement)
const clock = new THREE.Clock()
tick()
function tick() {
  //const time = clock.getElapsedTime()
  requestAnimationFrame(tick)
  renderer.render(scene,camera)
  stat.update()
  orbitControl.update()
}


效果如下:


5、小车运行示例



import * as THREE from "three";
import Stat from "three/examples/jsm/libs/stats.module";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { AxesHelper } from "three";
import * as dat from "dat.gui";
import t1 from './img/floor.jpeg'
import c1 from './img/color1.jpeg'
import c2 from './img/color2.jpg'
import black from './img/black.jpg'
let w = window.innerWidth;
let h = window.innerHeight;
const stat = new Stat();
const gui = new dat.GUI();
const scene = new THREE.Scene();
const material = new THREE.MeshNormalMaterial();
// scene.add(new AxesHelper(15, 15, 15));
//材质
const loader = new THREE.TextureLoader()
const texture = loader.load(t1)
// texture.magFilter = THREE.NearestFilter
// texture.wrapS = THREE.RepeatWrapping
// texture.wrapT = THREE.RepeatWrapping
// texture.repeat.set(10,10)
//地面
const planeG = new THREE.PlaneGeometry(30, 30);
const m = new THREE.MeshBasicMaterial({
  // color: 0xcccccc,
  map:texture,
  side: THREE.DoubleSide,
});
const plane = new THREE.Mesh(planeG, m);
plane.rotation.x = -Math.PI / 2;
plane.position.y = -1.2;
scene.add(plane);
//汽车
const car = new THREE.Group();
//前轮
const frontWheels = new THREE.Group();
const frontWheel1 = new THREE.Group();
const frontWheelG = new THREE.TorusGeometry(1, 0.2);
const wheelTexture = loader.load('black')
const wheelMaterial = new THREE.MeshStandardMaterial({
  map:wheelTexture
})
const frontWheel = new THREE.Mesh(frontWheelG, wheelMaterial);
//轮毂
const frontHubGroup = new THREE.Group();
let n = 10;
for (let i = 0; i < n; i++) {
  const frontHubG = new THREE.CylinderGeometry(0.1, 0.1, 2);
  const frontHub = new THREE.Mesh(frontHubG, material);
  frontHub.rotation.z = ((2 * Math.PI) / n) * i;
  frontHubGroup.add(frontHub);
}
//轮轴
let len = 5;
const frontAxleG = new THREE.CylinderGeometry(0.2, 0.2, len);
const frontAxle = new THREE.Mesh(frontAxleG, material);
frontAxle.rotation.x = -0.5 * Math.PI;
frontAxle.position.z = -len / 2;
frontWheel1.add(frontWheel, frontHubGroup);
const frontWheel2 = frontWheel1.clone();
frontWheel2.position.z = -len;
frontWheels.add(frontWheel1, frontWheel2, frontAxle);
frontWheels.position.z = len / 2;
frontWheels.position.x = -len / 2;
const backWheels = frontWheels.clone();
backWheels.position.x = len / 2;
// 车体
const body = new THREE.Group();
const bodyG1 = new THREE.BoxGeometry(10, 1.2, 4);
//车体材质
const bodyTexture1 = loader.load(c1)
const bodymaterial1 = new THREE.MeshStandardMaterial({
  map:bodyTexture1
})
const bodyTexture2 = loader.load(c2)
const bodymaterial2 = new THREE.MeshStandardMaterial({
  map:bodyTexture2
})
const bodyBottom = new THREE.Mesh(bodyG1, bodymaterial2);
//车顶
/////////////////////////////////////////////
const height = 4,
  width = 2;
const shape = new THREE.Shape();
shape.moveTo(0, 0);
shape.lineTo(0, width);
shape.lineTo(height, width);
shape.lineTo(height, 0);
shape.lineTo(0, 0);
const extrudeSettings = {
  steps: 2,
  depth: 0.1,
  bevelEnabled: true,
  bevelThickness: 1,
  bevelSize: 1,
  bevelOffset: 0,
  bevelSegments: 1,
};
const roofgeometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
//车顶材质
const roofmesh = new THREE.Mesh(roofgeometry, bodymaterial2);
roofmesh.rotation.x = 0.5 * Math.PI;
roofmesh.position.x = -height / 2;
roofmesh.position.z = -width / 2;
roofmesh.position.y = width / 3;
////////////////////////////////////////////
body.add(bodyBottom, roofmesh);
car.add(frontWheels, backWheels, body);
//灯光
const light = new THREE.AmbientLight();
scene.add(car, light);
//像机
const camera = new THREE.PerspectiveCamera(75, w / h, 0.1, 100);
camera.position.set(0, 2, 20);
camera.lookAt(0, 0, 0);
const guiFolder1 = gui.addFolder("相机位置");
guiFolder1.add(camera.position, "x", -20, 20, 0.01).name("相机x轴位置");
guiFolder1.add(camera.position, "y", -20, 20, 0.01).name("相机y轴位置");
guiFolder1.add(camera.position, "z", -20, 20, 0.01).name("相机z轴位置");
const guiFolder2 = gui.addFolder("汽车位置");
guiFolder2.add(car.position, "x", -20, 20, 0.01).name("汽车x轴位置");
guiFolder2.add(car.position, "y", -20, 20, 0.01).name("汽车y轴位置");
guiFolder2.add(car.position, "z", -20, 20, 0.01).name("汽车z轴位置");
//渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(w, h);
renderer.setClearColor(0x79deec);
document.body.append(renderer.domElement);
document.body.append(stat.dom);
const orbitControls = new OrbitControls(camera, renderer.domElement);
const clock = new THREE.Clock();
tick();
function tick() {
  const time = clock.getElapsedTime();
  frontWheels.rotation.z = time;
  backWheels.rotation.z = time;
  car.position.x = -time % 10;
  requestAnimationFrame(tick);
  renderer.render(scene, camera);
  // orbitControls.update();
  stat.update();
}
//窗口自适应大小
window.addEventListener("resize", () => {
  w = window.innerWidth;
  h = window.innerHeight;
  //camera
  camera.aspect = w / h;
  camera.updateProjectionMatrix();
  //renderer
  renderer.setSize(w, h);
});



效果如下: