切换@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
相关产品推荐
相关产品推荐

