three.js基础案例day13——模型的物理特性

这个案例主要是使用three.js中的物理引擎插件(OimoPhysics),使用OimoPhysics可以使three.js中的物体具有更真实的物理效果,例如重力、自由落体、弹簧等。具体效果如下:

 首先需要搭建基础环境,场景、相机、渲染器和控制器。若不清楚的可以查看three.js基础案例day01。

 1.创建多个立方体

boxes = new THREE.InstancedMesh(
    new THREE.BoxGeometry(0.1, 0.1, 0.1),
    new THREE.MeshLambertMaterial(),
    200,
  )
  const matrix = new THREE.Matrix4()
  const color = new THREE.Color()
  for (let i = 0; i < boxes.count; i++) {
    matrix.setPosition(
      Math.random() - 0.5,
      Math.random() * 2,
      Math.random() - 0.5,
    )
    boxes.setMatrixAt(i, matrix)
    boxes.setColorAt(i, color.setHex(Math.random() * 0xffffff))
  }
  scene.add(boxes)

2.创建多个小球

spheres = new THREE.InstancedMesh(
    new THREE.SphereGeometry(0.075, 32, 16),
    new THREE.MeshLambertMaterial(),
    200,
  )
  for (let i = 0; i < spheres.count; i++) {
    matrix.setPosition(
      Math.random() - 0.5,
      Math.random() * 2,
      Math.random() - 0.5,
    )
    spheres.setMatrixAt(i, matrix)
    spheres.setColorAt(i, color.setHex(Math.random() * 0xffffff))
  }
  scene.add(spheres)

3.创建平面 并设置阴影

// 平面 
plane = new THREE.Mesh(
    new THREE.BoxGeometry(10, 1, 10),
    new THREE.ShadowMaterial({ color: 0x111111 }), // 影子的颜色
  )
  plane.position.y = -1
  scene.add(plane)
// 设置阴影
function enableShadow() {
  renderer.shadowMap.enabled = true
  dirLight.castShadow = true
  plane.receiveShadow = true
  boxes.castShadow = true
  boxes.receiveShadow = true
}

4. 导入OimoPhysics插件并使用

// 导入
import { OimoPhysics } from 'three/examples/jsm/physics/OimoPhysics'
// 使用
physics = await OimoPhysics()
physics.addMesh(plane)
physics.addMesh(boxes, 1)
physics.addMesh(spheres, 1)

5.设置物体不断的落下

let index = Math.floor(Math.random() * boxes.count)
  position.set(0, Math.random() + 1, 0)
  physics.setMeshPosition(boxes, position, index)

  index = Math.floor(Math.random() * spheres.count)
  position.set(0, Math.random() + 1, 0)
  physics.setMeshPosition(spheres, position, index)
  controls.update()

全部代码

<template>
  <div id="threeId" ref="elementRef"></div>
</template>

<script setup>
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import { OimoPhysics } from 'three/examples/jsm/physics/OimoPhysics'
import { ref, onMounted } from 'vue'

let width, height, scene, camera, renderer, controls
let dirLight
let boxes, plane, spheres
let physics
let position = new THREE.Vector3()
const elementRef = ref(null)
onMounted(() => {
  const element = elementRef.value
  width = element.offsetWidth
  height = element.offsetHeight
  initScene()
  initLights()
  initMeshes()
  enableShadow()
  enablePhysics()
  
})

function initScene() {
  // 初始化场景: 创建场景,相机,物体,渲染器
  scene = new THREE.Scene()
  scene.background = new THREE.Color(0x808080)

  camera = new THREE.PerspectiveCamera(60, width / height, 1, 1000)
  camera.position.set(2, 1, 2)
  scene.add(camera)

  // const axesHelper = new THREE.AxesHelper(40)
  // scene.add(axesHelper)

  renderer = new THREE.WebGLRenderer()
  renderer.setSize(width, height)
  elementRef.value.appendChild(renderer.domElement)
  renderer.outputEncoding = THREE.sRGBEncoding
  controls = new OrbitControls(camera, renderer.domElement)
  controls.update()
}
function initLights() {
  // 环境光
  const hesLight = new THREE.HemisphereLight() // 白色光
  hesLight.intensity = 0.3
  scene.add(hesLight)
  // 平行光
  dirLight = new THREE.DirectionalLight()
  dirLight.position.set(5, 5, -5)
  scene.add(dirLight)
}
function initMeshes() {
  // plane
  plane = new THREE.Mesh(
    new THREE.BoxGeometry(10, 1, 10),
    new THREE.ShadowMaterial({ color: 0x111111 }), // 影子的颜色
  )
  plane.position.y = -1
  scene.add(plane)
  // 立方体 材质:如木头,镜面反色差
  boxes = new THREE.InstancedMesh(
    new THREE.BoxGeometry(0.1, 0.1, 0.1),
    new THREE.MeshLambertMaterial(),
    200,
  )
  const matrix = new THREE.Matrix4()
  const color = new THREE.Color()
  for (let i = 0; i < boxes.count; i++) {
    matrix.setPosition(
      Math.random() - 0.5,
      Math.random() * 2,
      Math.random() - 0.5,
    )
    boxes.setMatrixAt(i, matrix)
    boxes.setColorAt(i, color.setHex(Math.random() * 0xffffff))
  }
  scene.add(boxes)

  // 球体
  spheres = new THREE.InstancedMesh(
    new THREE.SphereGeometry(0.075, 32, 16),
    new THREE.MeshLambertMaterial(),
    200,
  )
  for (let i = 0; i < spheres.count; i++) {
    matrix.setPosition(
      Math.random() - 0.5,
      Math.random() * 2,
      Math.random() - 0.5,
    )
    spheres.setMatrixAt(i, matrix)
    spheres.setColorAt(i, color.setHex(Math.random() * 0xffffff))
  }
  scene.add(spheres)
}
function enableShadow() {
  renderer.shadowMap.enabled = true
  dirLight.castShadow = true
  plane.receiveShadow = true
  boxes.castShadow = true
  boxes.receiveShadow = true
}
async function enablePhysics() {
  physics = await OimoPhysics()
  physics.addMesh(plane)
  physics.addMesh(boxes, 1)
  physics.addMesh(spheres, 1)
  render()
}
function render() {
  requestAnimationFrame(render)

  let index = Math.floor(Math.random() * boxes.count)
  position.set(0, Math.random() + 1, 0)
  physics.setMeshPosition(boxes, position, index)

  index = Math.floor(Math.random() * spheres.count)
  position.set(0, Math.random() + 1, 0)
  physics.setMeshPosition(spheres, position, index)
  controls.update()
  renderer.render(scene, camera)
}
</script>

<style lang="scss" scoped>
#threeId {
  width: 100%;
  height: 100%;
}
</style>

  • 9
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值