添加 Cannon.js Body 到 Three.js 网格导致组和多个形状的 Vec3 错误
Adding Cannon.js Body to Three.js Mesh causing Vec3 error with groups and multiple shapes
基本上,我在 Three.js 中创建了一组 2 个网格,在 Cannon 中创建了一个包含 2 个形状的 Body。
它们单独看起来很好,但是当我将 Body 位置复制到网格以添加物理时,代码中断,屏幕上没有任何显示,并且在记录位置时,对于 Body 一切正常,但是网格显示为未定义。
(最终目标是用模型替换网格)
任何帮助都会很棒,这里是有问题的代码:
import './style.css'
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js'
import * as dat from 'lil-gui'
import * as CANNON from 'cannon-es'
/**
* Base
*/
// Debug
const gui = new dat.GUI()
// Canvas
const canvas = document.querySelector('canvas.webgl')
// Scene
const scene = new THREE.Scene()
/**
* Models
*/
const dracoLoader = new DRACOLoader()
dracoLoader.setDecoderPath('/draco/')
const gltfLoader = new GLTFLoader()
gltfLoader.setDRACOLoader(dracoLoader)
let mixer = null
let gunModel = null
gltfLoader.load(
'/models/hamburger.glb',
(gltf) =>
{
gltf.scene.position.set(0, 4, 0)
gunModel = gltf.scene
scene.add(gunModel)
console.log(gunModel.position)
}
)
/**
* test wireframe cubes
*/
const YGeo = new THREE.BoxBufferGeometry(2, 6, 2);
const YMat = new THREE.MeshBasicMaterial({
color: 'green',
wireframe: true
})
const gun = new THREE.Group();
const blockY = new THREE.Mesh(YGeo, YMat);
blockY.position.x = 4;
const XGeo = new THREE.BoxBufferGeometry(6,2,2);
const XMat = new THREE.MeshBasicMaterial({
color: 'green',
wireframe: true
})
const blockX = new THREE.Mesh(XGeo, XMat);
blockX.position.y = 2
gun.add(blockY)
gun.add(blockX)
gui.add(gun.position, 'y', 0, 5, 0.01);
gui.add(gun.position, 'x', -3, 4, 0.01)
gui.add(gun.position, 'z', -3, 3, 0.01)
scene.add(gun)
/**
* Floor
*/
const floor = new THREE.Mesh(
new THREE.PlaneGeometry(50, 50),
new THREE.MeshStandardMaterial({
color: '#444444',
metalness: 0,
roughness: 0.5
})
)
floor.receiveShadow = true
floor.rotation.x = - Math.PI * 0.5
scene.add(floor)
/**
* Lights
*/
const ambientLight = new THREE.AmbientLight(0xffffff, 0.8)
scene.add(ambientLight)
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.6)
directionalLight.castShadow = true
directionalLight.shadow.mapSize.set(1024, 1024)
directionalLight.shadow.camera.far = 15
directionalLight.shadow.camera.left = - 7
directionalLight.shadow.camera.top = 7
directionalLight.shadow.camera.right = 7
directionalLight.shadow.camera.bottom = - 7
directionalLight.position.set(5, 5, 5)
scene.add(directionalLight)
/**
* Sizes
*/
const sizes = {
width: window.innerWidth,
height: window.innerHeight
}
window.addEventListener('resize', () =>
{
// Update sizes
sizes.width = window.innerWidth
sizes.height = window.innerHeight
// Update camera
camera.aspect = sizes.width / sizes.height
camera.updateProjectionMatrix()
// Update renderer
renderer.setSize(sizes.width, sizes.height)
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
})
/**
* Camera
*/
// Base camera
const camera = new THREE.PerspectiveCamera(75, sizes.width / sizes.height, 0.1, 100)
camera.position.set(- 8, 4, 8)
scene.add(camera)
// Controls
const controls = new OrbitControls(camera, canvas)
controls.target.set(0, 1, 0)
controls.enableDamping = true
/**
* Renderer
*/
const renderer = new THREE.WebGLRenderer({
canvas: canvas
})
renderer.shadowMap.enabled = true
renderer.shadowMap.type = THREE.PCFSoftShadowMap
renderer.setSize(sizes.width, sizes.height)
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
/**
* Physics
*/
const world = new CANNON.World({
gravity: new CANNON.Vec3(0, -9.81, 0)
});
const floorBody = new CANNON.Body({
shape: new CANNON.Plane(),
mass: 0
})
world.addBody(floorBody)
const shapeY = new CANNON.Box(new CANNON.Vec3(1,3,1))
const shapeX = new CANNON.Box(new CANNON.Vec3(3,1,1))
const boxBody = new CANNON.Body({
mass: 1
})
boxBody.addShape(shapeY, new CANNON.Vec3(3, 0, 0), new CANNON.Quaternion())
boxBody.addShape(shapeX, new CANNON.Vec3(0,2,0), new CANNON.Quaternion())
world.addBody(boxBody)
boxBody.position.set(-0.56, 4.13, -0.02)
console.log(boxBody.position)
gui.add(boxBody.position, 'y', 0, 10, 0.01);
/**
* Animate
*/
const clock = new THREE.Clock()
let previousTime = 0
const tick = () =>
{
const elapsedTime = clock.getElapsedTime()
const deltaTime = elapsedTime - previousTime
previousTime = elapsedTime
world.step(1/60, deltaTime, 3)
floor.position.copy(floorBody.position);
floorBody.quaternion.copy(floor.quaternion);
// if(gunModel) {
// gunModel.position.copy(boxBody);
// gunModel.quaternion.copy(boxBody)
// console.log(gunModel.position)
// }
gun.position.copy(boxBody);
gun.quaternion.copy(boxBody)
console.log(gun.position.x)
if(mixer)
{
mixer.update(deltaTime)
}
// Update controls
controls.update()
// Render
renderer.render(scene, camera)
// Call tick again on the next frame
window.requestAnimationFrame(tick)
}
tick()
// access boxBody attributes?
gun.position.copy(boxBody.position);
gun.quaternion.copy(boxBody.quaternion);
console.log(gun.position.x)
基本上,我在 Three.js 中创建了一组 2 个网格,在 Cannon 中创建了一个包含 2 个形状的 Body。
它们单独看起来很好,但是当我将 Body 位置复制到网格以添加物理时,代码中断,屏幕上没有任何显示,并且在记录位置时,对于 Body 一切正常,但是网格显示为未定义。
(最终目标是用模型替换网格)
任何帮助都会很棒,这里是有问题的代码:
import './style.css'
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js'
import * as dat from 'lil-gui'
import * as CANNON from 'cannon-es'
/**
* Base
*/
// Debug
const gui = new dat.GUI()
// Canvas
const canvas = document.querySelector('canvas.webgl')
// Scene
const scene = new THREE.Scene()
/**
* Models
*/
const dracoLoader = new DRACOLoader()
dracoLoader.setDecoderPath('/draco/')
const gltfLoader = new GLTFLoader()
gltfLoader.setDRACOLoader(dracoLoader)
let mixer = null
let gunModel = null
gltfLoader.load(
'/models/hamburger.glb',
(gltf) =>
{
gltf.scene.position.set(0, 4, 0)
gunModel = gltf.scene
scene.add(gunModel)
console.log(gunModel.position)
}
)
/**
* test wireframe cubes
*/
const YGeo = new THREE.BoxBufferGeometry(2, 6, 2);
const YMat = new THREE.MeshBasicMaterial({
color: 'green',
wireframe: true
})
const gun = new THREE.Group();
const blockY = new THREE.Mesh(YGeo, YMat);
blockY.position.x = 4;
const XGeo = new THREE.BoxBufferGeometry(6,2,2);
const XMat = new THREE.MeshBasicMaterial({
color: 'green',
wireframe: true
})
const blockX = new THREE.Mesh(XGeo, XMat);
blockX.position.y = 2
gun.add(blockY)
gun.add(blockX)
gui.add(gun.position, 'y', 0, 5, 0.01);
gui.add(gun.position, 'x', -3, 4, 0.01)
gui.add(gun.position, 'z', -3, 3, 0.01)
scene.add(gun)
/**
* Floor
*/
const floor = new THREE.Mesh(
new THREE.PlaneGeometry(50, 50),
new THREE.MeshStandardMaterial({
color: '#444444',
metalness: 0,
roughness: 0.5
})
)
floor.receiveShadow = true
floor.rotation.x = - Math.PI * 0.5
scene.add(floor)
/**
* Lights
*/
const ambientLight = new THREE.AmbientLight(0xffffff, 0.8)
scene.add(ambientLight)
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.6)
directionalLight.castShadow = true
directionalLight.shadow.mapSize.set(1024, 1024)
directionalLight.shadow.camera.far = 15
directionalLight.shadow.camera.left = - 7
directionalLight.shadow.camera.top = 7
directionalLight.shadow.camera.right = 7
directionalLight.shadow.camera.bottom = - 7
directionalLight.position.set(5, 5, 5)
scene.add(directionalLight)
/**
* Sizes
*/
const sizes = {
width: window.innerWidth,
height: window.innerHeight
}
window.addEventListener('resize', () =>
{
// Update sizes
sizes.width = window.innerWidth
sizes.height = window.innerHeight
// Update camera
camera.aspect = sizes.width / sizes.height
camera.updateProjectionMatrix()
// Update renderer
renderer.setSize(sizes.width, sizes.height)
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
})
/**
* Camera
*/
// Base camera
const camera = new THREE.PerspectiveCamera(75, sizes.width / sizes.height, 0.1, 100)
camera.position.set(- 8, 4, 8)
scene.add(camera)
// Controls
const controls = new OrbitControls(camera, canvas)
controls.target.set(0, 1, 0)
controls.enableDamping = true
/**
* Renderer
*/
const renderer = new THREE.WebGLRenderer({
canvas: canvas
})
renderer.shadowMap.enabled = true
renderer.shadowMap.type = THREE.PCFSoftShadowMap
renderer.setSize(sizes.width, sizes.height)
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
/**
* Physics
*/
const world = new CANNON.World({
gravity: new CANNON.Vec3(0, -9.81, 0)
});
const floorBody = new CANNON.Body({
shape: new CANNON.Plane(),
mass: 0
})
world.addBody(floorBody)
const shapeY = new CANNON.Box(new CANNON.Vec3(1,3,1))
const shapeX = new CANNON.Box(new CANNON.Vec3(3,1,1))
const boxBody = new CANNON.Body({
mass: 1
})
boxBody.addShape(shapeY, new CANNON.Vec3(3, 0, 0), new CANNON.Quaternion())
boxBody.addShape(shapeX, new CANNON.Vec3(0,2,0), new CANNON.Quaternion())
world.addBody(boxBody)
boxBody.position.set(-0.56, 4.13, -0.02)
console.log(boxBody.position)
gui.add(boxBody.position, 'y', 0, 10, 0.01);
/**
* Animate
*/
const clock = new THREE.Clock()
let previousTime = 0
const tick = () =>
{
const elapsedTime = clock.getElapsedTime()
const deltaTime = elapsedTime - previousTime
previousTime = elapsedTime
world.step(1/60, deltaTime, 3)
floor.position.copy(floorBody.position);
floorBody.quaternion.copy(floor.quaternion);
// if(gunModel) {
// gunModel.position.copy(boxBody);
// gunModel.quaternion.copy(boxBody)
// console.log(gunModel.position)
// }
gun.position.copy(boxBody);
gun.quaternion.copy(boxBody)
console.log(gun.position.x)
if(mixer)
{
mixer.update(deltaTime)
}
// Update controls
controls.update()
// Render
renderer.render(scene, camera)
// Call tick again on the next frame
window.requestAnimationFrame(tick)
}
tick()
// access boxBody attributes?
gun.position.copy(boxBody.position);
gun.quaternion.copy(boxBody.quaternion);
console.log(gun.position.x)