You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

切换@react-three/cannon后渲染D4触发WebGLRenderer上下文丢失错误

React Three Fiber 骰子渲染WebGL上下文丢失问题

错误信息

THREE.WebGLRenderer: Context Lost.

问题现象

从use-cannon切换到@react-three/cannon后触发问题:仅渲染D4四面骰子时会报错,盒子、圆角立方体等其他3D组件均可正常运行。

业务代码

import * as THREE from 'three'
import ReactDOM from 'react-dom'
import React, { Suspense, useMemo, useState, useEffect } from 'react'
import { Canvas, useFrame, useLoader } from '@react-three/fiber'
import { Physics, useBox, usePlane, useSphere, useConvexPolyhedron } from '@react-three/cannon'
import niceColors from 'nice-color-palettes'
import './styles.css'
import { Tetrahedron, RoundedBox } from '@react-three/drei';

import { TestDice } from './TestDice.js'

const DiceOverview = (props) => {

  function Plane({ color, ...props }) {
    const [ref, api] = usePlane(() => ({ ...props }))
    return (
      <mesh ref={ref} receiveShadow >
        <planeBufferGeometry onClick={() => api.applyImpulse([0, 20, 0], [0, 0, 0])} attach="geometry" args={[1000, 1000]} />
        <meshPhongMaterial attach="material" color={color} />
      </mesh>
    )
  }


  function Box() {
    const [ref, api] = useBox(() => ({ mass: 1, args: [4, 4, 4], isKinematic: true }))
    useFrame(state => {
      const t = state.clock.getElapsedTime()
    })
    return (
      <mesh ref={ref} castShadow receiveShadow>
        <boxBufferGeometry attach="geometry" args={[4, 4, 4]} />
        <meshLambertMaterial attach="material" color={'#3F00FF'} side={THREE.DoubleSide} />
      </mesh>
    )
  }


  const D4 = (props) => {
    console.log(props, 'what is D4 getting?')
    console.log(Tetrahedron, 'this is tetrahedron');
    console.log('hello');
    const radius = 1;
    const tetrahedronGeometry = new THREE.TetrahedronGeometry(radius);
    const [ref, api] = useConvexPolyhedron(() => {
      return {
        args: tetrahedronGeometry,
        mass: 1,
        ...props,
      };
    });
    console.log(ref, api, 'are these triggering');

    return (
  <Tetrahedron
    args={radius}
    ref={ref}
    onClick={() => api.applyImpulse([0, 20, 40], [0, 0, 0])}
    castShadow
    receiveShadow
  >
        <meshNormalMaterial attach="material" />
      </Tetrahedron>
    );
  };


  const Dtest = (props) => {
    return (
      <RoundedBox
        args={[1, 1, 1]}
        radius={0.05}
        smoothness={4}
        position={[0, 0, 10]}
      >
        <meshPhongMaterial attach="material" color="#f3f3f3" wireframe />
      </RoundedBox>
    );
  };

  const glProps = { alpha: false };
  const cameraProps = { position: [0, -12, 16] };
  return (
    <>
      <button onClick={() => { console.log('click') }}>button</button>
      <button>toss</button>
      <TestDice />
      <div style={{ position: "relative", width: 500, height: 500 }}>
        <Canvas id="myCanvas" concurrent shadowMap sRGB gl={glProps} camera={cameraProps} width={100}>
          <hemisphereLight intensity={0.35} />
          <spotLight position={[30, 0, 30]} angle={0.3} penumbra={1} intensity={2} castShadow shadow-mapSize-width={256} shadow-mapSize-height={256} />
          <pointLight position={[-30, 0, -30]} intensity={0.5} />

          <Physics className='physics' gravity={[0, 0, -60]}>
            <Plane color={niceColors[10][4]} />
            <Plane color={niceColors[10][1]} position={[-6, 0, 0]} rotation={[0, 0.9, 0]} />
            <Plane color={niceColors[10][2]} position={[6, 0, 0]} rotation={[0, -0.9, 0]} />
            <Plane color={niceColors[10][3]} position={[0, 6, 0]} rotation={[0.9, 0, 0]} />
            <Plane color={niceColors[10][0]} position={[0, -6, 0]} rotation={[-0.9, 0, 0]} />

            <D4 position={[-4, 0, 2]} rotation={[0, 1, 0]} />

            <Dtest />
            <Box />
          </Physics>
        </Canvas>
      </div>
    </>
  );
};

export default DiceOverview;

项目依赖配置

{
  "name": "basictemplate",
  "version": "1.0.0",
  "description": "template to use in future projects",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack --mode development --watch"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/jessemchung/template.git"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "bugs": {
    "url": "https://github.com/jessemchung/template/issues"
  },
  "homepage": "https://github.com/jessemchung/template#readme",
  "devDependencies": {
    "@babel/core": "^7.15.0",
    "@babel/preset-env": "^7.15.0",
    "@babel/preset-react": "^7.14.5",
    "babel-loader": "^8.2.2",
    "css-loader": "^6.2.0",
    "style-loader": "^3.2.1",
    "webpack": "^5.51.1",
    "webpack-cli": "^4.8.0"
  },
  "dependencies": {
    "@react-three/cannon": "^3.0.1",
    "@react-three/drei": "^7.5.0",
    "@react-three/fiber": "^7.0.6",
    "nice-color-palettes": "^3.0.0",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "three": "^0.132.2"
  }
}

排查结论

  • 问题触发点为useConvexPolyhedron钩子的args参数配置
  • 旧版已废弃的use-cannon支持直接传入Three.js几何体实例作为args参数,该用法在新版@react-three/cannon中已被移除,参数规则做了调整,需要按新版要求重构传参逻辑。

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 17:18:02