You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

在React应用及Babylon.js中,如何获取网格对象的像素尺寸(非Vector3)

获取Babylon.js网格的屏幕像素尺寸(通用及React场景)

嘿,我来帮你搞定这个问题!你之前用meshObject.getBoundingInfo().boundingBox拿到的是3D世界空间里的包围盒尺寸,是基于场景单位的,并不是屏幕上的像素大小。要得到像素尺寸,核心是把3D坐标转换为屏幕像素坐标,再计算差值。下面分两种场景给你详细说明:

通用Babylon.js场景实现

不管是纯JS项目还是其他框架,这个核心逻辑都适用:

  1. 先拿到网格的世界空间包围盒的对角顶点(最小和最大点)
  2. 用相机的worldToScreen方法把3D坐标转成屏幕像素坐标
  3. 计算两个屏幕坐标的差值,就是网格在屏幕上的像素宽高

代码示例:

// 确保你已经获取到mesh和camera实例
const getMeshPixelSize = (mesh, camera) => {
  // 获取网格的世界空间包围盒
  const boundingBox = mesh.getBoundingInfo().boundingBox;
  const minWorldPoint = boundingBox.minimumWorld;
  const maxWorldPoint = boundingBox.maximumWorld;

  // 转换为屏幕像素坐标(注意:Babylon的屏幕坐标原点在左下角)
  const minScreenCoord = camera.worldToScreen(minWorldPoint);
  const maxScreenCoord = camera.worldToScreen(maxWorldPoint);

  // 计算像素宽高(取绝对值避免坐标顺序问题)
  const pixelWidth = Math.abs(maxScreenCoord.x - minScreenCoord.x);
  const pixelHeight = Math.abs(maxScreenCoord.y - minScreenCoord.y);

  return { width: pixelWidth, height: pixelHeight };
};

// 使用示例
const meshPixelSize = getMeshPixelSize(yourMeshInstance, yourCameraInstance);
console.log(`网格屏幕尺寸:宽${meshPixelSize.width}px,高${meshPixelSize.height}px`);

注意事项

  • 这个结果会随着相机的位置、缩放、旋转实时变化,因为是网格在屏幕上的投影尺寸
  • 如果网格不在相机的视锥体内,worldToScreen返回的坐标可能异常,建议先通过mesh.isInFrustum判断网格是否可见
  • 屏幕坐标的Y轴是从下往上计算的,所以取绝对值就能得到正确的高度差值

React + Babylon.js场景实现

React中使用Babylon.js(比如用@babylonjs/react库)时,核心逻辑和上面一致,只是要注意React组件生命周期和实例获取方式

通常我们会用ref获取mesh实例,配合useSceneuseCamera钩子拿到场景和相机,然后在useEffect中执行计算逻辑。如果需要实时更新(比如相机移动时),可以订阅场景的渲染事件。

代码示例:

import { useScene, useCamera } from '@babylonjs/react';
import { useEffect, useRef } from 'react';

// 计算网格像素尺寸的组件
function MeshPixelSizeTracker({ meshRef }) {
  const scene = useScene();
  const camera = useCamera();

  useEffect(() => {
    // 确保所有实例都初始化完成
    if (!scene || !camera || !meshRef.current) return;

    const calculatePixelSize = () => {
      const mesh = meshRef.current;
      const boundingBox = mesh.getBoundingInfo().boundingBox;
      const minWorld = boundingBox.minimumWorld;
      const maxWorld = boundingBox.maximumWorld;

      const minScreen = camera.worldToScreen(minWorld);
      const maxScreen = camera.worldToScreen(maxWorld);

      const pixelWidth = Math.abs(maxScreen.x - minScreen.x);
      const pixelHeight = Math.abs(maxScreen.y - minScreen.y);

      console.log(`React中网格像素尺寸:宽${pixelWidth}px,高${pixelHeight}px`);
    };

    // 初次计算
    calculatePixelSize();

    // 订阅场景渲染事件,实时更新尺寸(比如相机移动时)
    const renderObserver = scene.onBeforeRenderObservable.add(calculatePixelSize);

    // 组件卸载时清理订阅
    return () => {
      scene.onBeforeRenderObservable.remove(renderObserver);
    };
  }, [scene, camera, meshRef]);

  return null;
}

// 使用示例:带ref的网格组件
function My3dMesh() {
  const meshRef = useRef(null);

  return (
    <>
      <mesh ref={meshRef} name="myCustomMesh">
        <boxBlock size={2} />
      </mesh>
      <MeshPixelSizeTracker meshRef={meshRef} />
    </>
  );
}

React场景注意事项

  • 一定要在useEffect的依赖数组中加入scenecamerameshRef,确保这些实例就绪后再执行计算
  • 如果不需要实时更新,可以去掉onBeforeRenderObservable的订阅,只在初次渲染或特定事件触发时计算
  • ref获取mesh实例是React中访问Babylon原生对象的标准方式,确保能拿到真实的mesh实例

内容的提问来源于stack exchange,提问作者Elif

火山引擎 最新活动