THREE.js:设置球体的绝对旋转,而不是累积旋转?

发布于 2025-01-14 20:13:07 字数 1985 浏览 2 评论 0原文

我希望能够将 Three.js 球体的旋转设置为绝对值,但是每当我设置 rotateY 时,我应用的值都会从上次旋转中添加或减去,而不是变成新的绝对旋转设置。

在有关立方体的相关答案中(Three.js 设置绝对本地旋转) ,立方体有一个 rotation 属性,并且 cube.rotation.x = someValue 会产生我正在寻找的那种绝对旋转。

但是我正在使用的 SphereGeometry 对象(以世界地图作为纹理)没有旋转属性。

我想我可以跟踪以前的轮换,并仅应用差异,但我认为这最终会受到累积舍入误差的影响。

还有其他方法可以做到这一点吗?某种重置方法?

  async orient(lon: number, lat: number): Promise<void> {
    if (Globe.mapFailed)
      throw new Error('Map not available');
    else if (!Globe.mapImage)
      await new Promise<void>((resolve, reject) => Globe.waitList.push({ resolve, reject }));

    if (!this.initialized) {
      this.camera = new PerspectiveCamera(FIELD_OF_VIEW, 1);
      this.scene = new Scene();
      this.globe = new SphereGeometry(GLOBE_RADIUS, 50, 50);

      const mesh = new Mesh(
        this.globe,
        new MeshBasicMaterial({
          map: new CanvasTexture(Globe.mapCanvas)
        })
      );

      this.renderer = new WebGLRenderer({ alpha: true });
      this.renderer.setSize(GLOBE_PIXEL_SIZE, GLOBE_PIXEL_SIZE);
      this.rendererHost.appendChild(this.renderer.domElement);
      this.scene.add(mesh);
      this.camera.position.z = VIEW_DISTANCE;
      this.camera.rotation.order = 'YXZ';
      this.initialized = true;
    }

    this.globe.rotateY(PI / 20); // Just a sample value I experimented with
    this.camera.rotation.z = (lat >= 0 ? PI : 0);
    requestAnimationFrame(() => this.renderer.render(this.scene, this.camera));
  }

更新:

我现在的解决方法是:

    this.globe.rotateX(-this.lat);
    this.globe.rotateY(this.lon);
    this.lon = to_radian(lon);
    this.lat = to_radian(lat);
    this.globe.rotateY(-this.lon);
    this.globe.rotateX(this.lat);

我保存之前已完成的轮换,以便可以撤消它们,然后应用新的轮换。 (度/弧度转换以及需要反转的经度旋转的符号使该过程有点模糊。)

I'd like to be able to set the rotation of a Three.js sphere to an absolute value, but whenever I set rotateY the value I apply is added or subtracted from the last rotation, rather than becoming a new absolute rotation setting.

In a related answer about a cube (Three.js Set absolute local rotation), the cube has a rotation attribute, and cube.rotation.x = someValue results in the kind of absolute rotation that I'm looking for.

But the SphereGeometry object that I'm using (with a world map as its texture) has no rotation attribute.

I suppose I could keep track of previous rotations, and apply only the difference, but I'd think that would suffer eventually from cumulative round-off errors.

Is there another way to do this? A reset method of some sort?

  async orient(lon: number, lat: number): Promise<void> {
    if (Globe.mapFailed)
      throw new Error('Map not available');
    else if (!Globe.mapImage)
      await new Promise<void>((resolve, reject) => Globe.waitList.push({ resolve, reject }));

    if (!this.initialized) {
      this.camera = new PerspectiveCamera(FIELD_OF_VIEW, 1);
      this.scene = new Scene();
      this.globe = new SphereGeometry(GLOBE_RADIUS, 50, 50);

      const mesh = new Mesh(
        this.globe,
        new MeshBasicMaterial({
          map: new CanvasTexture(Globe.mapCanvas)
        })
      );

      this.renderer = new WebGLRenderer({ alpha: true });
      this.renderer.setSize(GLOBE_PIXEL_SIZE, GLOBE_PIXEL_SIZE);
      this.rendererHost.appendChild(this.renderer.domElement);
      this.scene.add(mesh);
      this.camera.position.z = VIEW_DISTANCE;
      this.camera.rotation.order = 'YXZ';
      this.initialized = true;
    }

    this.globe.rotateY(PI / 20); // Just a sample value I experimented with
    this.camera.rotation.z = (lat >= 0 ? PI : 0);
    requestAnimationFrame(() => this.renderer.render(this.scene, this.camera));
  }

Update:

My workaround for now is this:

    this.globe.rotateX(-this.lat);
    this.globe.rotateY(this.lon);
    this.lon = to_radian(lon);
    this.lat = to_radian(lat);
    this.globe.rotateY(-this.lon);
    this.globe.rotateX(this.lat);

I'm saving the previous rotations which have been done so that I can undo them, then apply new rotations. (Degree/radian conversions, and the sign of the longitude rotation needing to be reversed, obscures the process a bit.)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

白昼 2025-01-21 20:13:07

我认为您感到困惑 geometry.rotateY( rot)mesh.rotation.y = rot。正如文档中所解释的:

.rotateY():绕 Y 轴旋转几何体。这通常作为一次性操作完成,而不是在循环期间完成。使用 Object3D.rotation 进行典型的实时网格旋转。

geometry.rotateY(rot) 只能使用一次,因为它会更新所有顶点位置的值,因此它必须迭代每个顶点并更新它。如果您需要修改几何体的“原始状态”,例如需要开始朝下 z 轴的角色模型,这非常有用。

mesh.rotation.y = rot; 可能是您正在寻找的。这是您在实时旋转期间使用的,因此内部顶点位置保持不变,您只需将网格作为一个整体进行旋转。例如,当你的角色在地图上跑来跑去时。

this.mesh = new Mesh(geometry, material);

// Set rotation to an absolute rotation value
this.mesh.rotation.y = Math.PI / 20;

// Increment rotation a relative amount (like once per frame):
this.mesh.rotation.y += Math.PI / 20;

I think you're confusing geometry.rotateY(rot) with mesh.rotation.y = rot. As explained in the docs:

.rotateY(): Rotate the geometry about the Y axis. This is typically done as a one time operation, and not during a loop. Use Object3D.rotation for typical real-time mesh rotation.

geometry.rotateY(rot) should only be used once because it updates the values of all the vertex positions, so it has to iterate through every vertex and update it. This is useful if you need to modify the "original state" of your geometry, for example a character model that needs to start facing down the z-axis.

mesh.rotation.y = rot; is what you're probably looking for. This is what you use during realtime rotations, so the intrinsic vertex positions are left untouched, you're just rotating the mesh as a whole. For example, when your character is running all over the map.

this.mesh = new Mesh(geometry, material);

// Set rotation to an absolute rotation value
this.mesh.rotation.y = Math.PI / 20;

// Increment rotation a relative amount (like once per frame):
this.mesh.rotation.y += Math.PI / 20;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文