英文:
Three,js: Problem when trying to make a sphere move with a bounded sphere
问题
I am new to three.js and having trouble when trying to animate a sphere to move through a space.
我是新手使用 three.js,在尝试让一个球体在空间中移动时遇到了问题。
I am creating a new Sphere and using new THREE.Vector3().randomDirection(); to make it move.
我创建了一个新的球体,并使用 new THREE.Vector3().randomDirection() 使其移动。
The sphere is supposed to be moving in a bounded sphere for collision detection.
这个球体应该在一个有界的球体内移动,用于碰撞检测。
When I add ballbb.copy(ball.geometry.boundingSphere).applyMatrix4(ball.matrixWorld) to the code to make the bounded Sphere move with the sphere, the sphere stops moving.
当我将 ballbb.copy(ball.geometry.boundingSphere).applyMatrix4(ball.matrixWorld) 添加到代码中,以使有界球体与球体一起移动时,球体停止移动。
英文:
I am new to three.js and having trouble when trying to animate a sphere to move through a space.
I am creating a new Sphere and using new THREE.Vector3().randomDirection(); to make it move. The sphere is supposed to be moving in a bounded sphere for collision detection. When I add ballbb.copy(ball.geometry.boundingSphere).applyMatrix4(ball.matrixWorld) to the code to make the bounded Sphere move with the sphere, the sphere stops moving.
const sphere = new THREE.SphereGeometry(70);
const sphereMaterial = new THREE.MeshStandardMaterial
var ball = new THREE.Mesh(sphere,sphereMaterial)
ball.position.x = (Math.random() - 0.5) * 1000;
ball.position.y = (Math.random() - 0.5) * 1000;
ball.position.z = (Math.random() - 0.5) * 1000;
ball.userData.vel = new THREE.Vector3().randomDirection();
var ballbb = new THREE.Sphere(ball.position, 70)
scene.add(ball)
function animate() {
requestAnimationFrame(animate)
controls.update()
render()
ballbb.copy(ball.geometry.boundingSphere).applyMatrix4(ball.matrixWorld)
console.log(ball.position)
}
function render() {
renderer.render(scene, camera)
ball.position.add(ball.userData.vel)
}
答案1
得分: 0
I got some time to debug this and figured out the problem. It's a twisting tale, so hold on...
Sphere 构造函数 (r152 源代码) 接受一个 Vector3 作为中心位置,以及一个 Number 作为所定义球体的半径。问题出在中心的 Vector3 没有被复制到 Sphere.center,而是直接被赋值给了属性。这意味着 Sphere.center 将是对传递给它的 Vector3 的引用。
但是,等等,还有更多!
在 three.js 中,当你改变 Mesh.position 时,除非你使用 Object3D.updatematrixWorld() 或调用 render,否则 matrixWorld 不会立即更新。因此,在这之前,ball.matrixWorld 仍然保存着上一次更新的矩阵。
不幸的事件链...
- 你设置了
ball.position(技术上这也更新了ballbb.center!) - 你渲染了场景(这也会自动调用
Object3D.updateMatrixWorld()) - 你更新了
ball.position(不会自动更新ball.matrixWorld) - 你将几何体的包围球(身份位置)复制到了
ballbb - 你将
ball.matrixWorld应用于ballbb(这与ballbb.center相乘) - 返回第 1 步,重复
分析
第 4 步 是问题出现的地方。当你复制身份包围球到 ballbb 时,你破坏了第 1 步 中的更新,不仅对 ballbb,还对 ball!复制身份位置会重置 ballbb.center(以及相应的 ball.position)为 (0, 0, 0)。然后你应用 ball.MatrixWorld,但因为自第 2 步 以来没有 render 或 updateMatrixWorld,所以 ball.matrixWorld 仍然是上一次渲染的世界矩阵,因此你基本上应用了前一帧的转换,这意味着球体不会移动。
如何修复这个问题?
你可能可以重新安排你的逻辑,以确保更新 ball.position 或 ballbb.center 被正确应用和传播,但我能够通过改变一件事来修复它:
var ballbb = new THREE.Sphere(ball.position.clone(), 70)
注意调用 Vector3.clone()。这将确保传递给 Sphere 的 Vector3 是 ball.position 的一个副本,因此对其中一个的更新不会影响另一个。
更好的修复...
实际上,你应该能够简化你的代码,不需要进行你正在做的任何数学计算。当你创建你的 Sphere 时,确实将 ball.position 传递给它,但然后不要担心做其他任何事情。当你更新 ball.position 时,它也会更新 ballbb.center。Sphere 没有 matrixWorld,它的所有数学计算都是从 center 和 radius 值中计算出来的,所以它将“自动”跟随 ball。
英文:
I got some time to debug this and figured out the problem. It's a twisting tale, so hold on...
The Sphere constructor (r152 source code) takes a Vector3 as the center position, and a Number as the radius of the sphere being defined. The quirk comes in that the center Vector3 isn't copied into Sphere.center, but is instead assigned to the property. This means Sphere.center will be a reference to the Vector3 passed to it.
But wait, there's more!
In three.js, when you change Mesh.position, it won't update the matrixWorld right away unless you tell it to with Object3D.updatematrixWorld() or a call to render. So until that happens, ball.matrixWorld still holds the matrix from the previous update.
An unfortunate chain of events...
- You set
ball.position(technically this also updatesballbb.center!) - You render the scene (this also automatically calls
Object3D.updateMatrixWorld()) - You update
ball.position(no auto-update toball.matrixWorld) - You copy the geometry's bsphere (identity position) into
ballbb - You apply
ball.matrixWorldtoballbb(this multiplies is againstballbb.center) - Goto 1, repeat
Analysis
Step 4 is where things go sideways. When you copy the identity bounding sphere into ballbb, you destroy the update made in Step 1, not only for ballbb, but also for ball! Copying the identity resets ballbb.center (and, in turn, ball.position) to (0, 0, 0). You then apply the ball.MatrixWorld, but because there hasn't been a render or updateMatrixWorld since Step 2, ball.matrixWorld is still the world matrix from the last render, so you're basically applying the transformation from the previous frame, meaning the ball doesn't move.
How do you fix this?
You could probably rearrange your logic to ensure updating ball.position or ballbb.center are applied and propagated correctly, but I was able to fix it by changing one thing:
var ballbb = new THREE.Sphere(ball.position.clone(), 70)
Notice the call to Vector3.clone(). This will ensure the Vector3 given to the Sphere is a copy of ball.position, so that updates to one won't affect the other.
A better fix...
Really, you should be able to simplify your code and not do any of the math you're doing. When you create your Sphere, do give it ball.position, but then don't worry about doing anything else. When you update ball.position, it will also update ballbb.center. A Sphere doesn't have a matrixWorld, and all of its math is computed from the center and radius values, so it will "automatically" follow ball.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论