Three.js:尝试让一个球体在一个有界的球体内移动时遇到问题。

huangapple go评论62阅读模式
英文:

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 仍然保存着上一次更新的矩阵。

不幸的事件链...

  1. 你设置了 ball.position(技术上这也更新了 ballbb.center!)
  2. 你渲染了场景(这也会自动调用 Object3D.updateMatrixWorld()
  3. 你更新了 ball.position(不会自动更新 ball.matrixWorld
  4. 你将几何体的包围球(身份位置)复制到了 ballbb
  5. 你将 ball.matrixWorld 应用于 ballbb(这与 ballbb.center 相乘)
  6. 返回第 1 步,重复

分析

第 4 步 是问题出现的地方。当你复制身份包围球到 ballbb 时,你破坏了第 1 步 中的更新,不仅对 ballbb,还对 ball!复制身份位置会重置 ballbb.center(以及相应的 ball.position)为 (0, 0, 0)。然后你应用 ball.MatrixWorld,但因为自第 2 步 以来没有 renderupdateMatrixWorld,所以 ball.matrixWorld 仍然是上一次渲染的世界矩阵,因此你基本上应用了前一帧的转换,这意味着球体不会移动。

如何修复这个问题?

你可能可以重新安排你的逻辑,以确保更新 ball.positionballbb.center 被正确应用和传播,但我能够通过改变一件事来修复它:

var ballbb = new THREE.Sphere(ball.position.clone(), 70)

注意调用 Vector3.clone()。这将确保传递给 SphereVector3ball.position 的一个副本,因此对其中一个的更新不会影响另一个。

更好的修复...

实际上,你应该能够简化你的代码,不需要进行你正在做的任何数学计算。当你创建你的 Sphere 时,确实将 ball.position 传递给它,但然后不要担心做其他任何事情。当你更新 ball.position 时,它也会更新 ballbb.centerSphere 没有 matrixWorld,它的所有数学计算都是从 centerradius 值中计算出来的,所以它将“自动”跟随 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...

  1. You set ball.position (technically this also updates ballbb.center!)
  2. You render the scene (this also automatically calls Object3D.updateMatrixWorld())
  3. You update ball.position (no auto-update to ball.matrixWorld)
  4. You copy the geometry's bsphere (identity position) into ballbb
  5. You apply ball.matrixWorld to ballbb (this multiplies is against ballbb.center)
  6. 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.

huangapple
  • 本文由 发表于 2023年5月10日 22:30:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/76219654.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定