英文:
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.matrixWorld
toballbb
(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
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论