使用three-loader-3dtiles库时调用runtime.update触发"m is undefined"类型错误
看起来你遇到的这个m is undefined错误,大概率是参数传错和异步加载状态没处理好导致的。结合你的代码和错误信息,我整理了几个关键的修复点,你可以逐一排查:
1. 先修正runtime.update的参数传递
你现在在useFrame里给runtime.update传的第二个参数是size.height,但three-loader-3dtiles的runtime.update方法需要的是完整的视口对象(包含width、height、devicePixelRatio这三个属性),不是单独的高度值。这种参数不匹配会导致库内部试图访问参数属性时直接抛出undefined错误。
修复代码如下:
useFrame(({ size, camera, gl }, dt) => { if (runtime) { // 实时计算当前的视口信息,不要用初始化时的旧值 const currentViewport = { width: size.width, height: size.height, devicePixelRatio: gl.getPixelRatio() }; // 按库要求的参数顺序传递:deltaTime, viewport, camera runtime.update(dt, currentViewport, camera); } });
2. 确认useLoader返回的结构是否正确
你的代码里解构了{ model, runtime },但你得先确认three-loader-3dtiles的Loader3DTiles.load方法返回的结果结构是不是真的有model这个字段。很多3D tiles库返回的是tileset对象而不是model,如果这里解构错了,不仅模型渲染不出来,runtime内部状态也会出问题。
比如如果库返回的是{ tileset, runtime },那你得改成:
// 把返回的tileset别名成model,保持后续代码一致 const { tileset: model, runtime } = useLoader(Loader3DTilesBridge, props.url, (loader: Loader3DTilesBridge) => { loader.setProps(loaderProps); });
同时确保primitive组件用的是正确的对象:
<primitive object={model} />
3. 等runtime完全初始化再调用update
有时候runtime变量虽然不为undefined,但它内部的核心资源(比如tileset)还没加载完成,这时候调用update就会触发内部属性访问错误。你可以加个状态判断,等runtime真正就绪后再执行更新:
import { useState, useEffect } from 'react'; // ... 其他代码 const [isRuntimeReady, setIsRuntimeReady] = useState(false); // 监听runtime变化,判断是否初始化完成 useEffect(() => { if (runtime) { // 这里根据库的实际结构调整,比如检查是否存在tileset setIsRuntimeReady(!!runtime.tileset); } }, [runtime]); useFrame(({ size, camera, gl }, dt) => { // 只在就绪后执行update if (isRuntimeReady) { const currentViewport = { width: size.width, height: size.height, devicePixelRatio: gl.getPixelRatio() }; runtime.update(dt, currentViewport, camera); } });
4. 别忘了处理窗口Resize的情况
你在Loader3DTilesBridge里只设置了一次初始化时的视口,但窗口大小变化时,视口信息也需要同步更新到runtime。上面的useFrame代码已经实时计算了视口,这部分就已经覆盖了Resize的情况,不用额外加监听了。
额外排查点
- 检查
getViewport函数返回的结构是不是和库要求的一致,避免初始化阶段就传错了视口。 - 确认
Loader3DTilesBridge里传递的renderer是正确的threeState.gl(react-three-fiber的渲染器实例),不要传错对象。
内容来源于stack exchange

