-
Notifications
You must be signed in to change notification settings - Fork 37
Description
Hi, really appreciate the project, I'm trying to get this to work with an expo project and react-three-fiber
for web I got an error that I could get around by just creating a FiberCanvas.web.tsx and just use the regular Canvas from fiber.
but on ios when I try following the guide in the readme, I get this error
(NOBRIDGE) WARN THREE.Renderer: .render() called before the backend is initialized. Try using .renderAsync() instead
I dug into the threejs code and changed the state.gl.render to renderAsync, which did remove the warning but rendered nothing.
so I found this pmndrs/react-three-fiber#3403 issue, and the suggested fix does not work because I never get past
await state.gl.init();
when modifying a bit to try to do the fix like this
import type { ReconcilerRoot, RootState } from "@react-three/fiber";
import {
createRoot,
events,
extend,
unmountComponentAtNode,
} from "@react-three/fiber";
import React, { useRef, useState } from "react";
import type { ViewProps } from "react-native";
import { PixelRatio } from "react-native";
import { useCanvasEffect, Canvas as WCanvas } from "react-native-wgpu";
import * as THREE from "three";
import {
makeWebGPURenderer,
ReactNativeCanvas,
} from "@/utils/makeWebGPURenderer";
//global.THREE = global.THREE || THREE;
interface FiberCanvasProps {
children: React.ReactNode;
style?: ViewProps["style"];
camera?: THREE.PerspectiveCamera;
scene?: THREE.Scene;
}
export const Canvas = ({
children,
style,
scene,
camera,
}: FiberCanvasProps) => {
const root = useRef<ReconcilerRoot<OffscreenCanvas>>(null!);
React.useMemo(() => extend(THREE), []);
const [frameloop, setFrameloop] = useState<"always" | "never">("never");
const canvasRef = useCanvasEffect(async () => {
const context = canvasRef.current!.getContext("webgpu")!;
const renderer = makeWebGPURenderer(context);
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
const canvas = new ReactNativeCanvas(context.canvas) as HTMLCanvasElement;
canvas.width = canvas.clientWidth * PixelRatio.get();
canvas.height = canvas.clientHeight * PixelRatio.get();
const size = {
top: 0,
left: 0,
width: canvas.clientWidth,
height: canvas.clientHeight,
};
if (!root.current) {
root.current = createRoot(canvas);
}
root.current.configure({
size,
events,
scene,
camera,
gl: (context) => {
const renderer = new THREE.WebGPURenderer({
antialias: true,
canvas,
context,
});
renderer.init().then(() => setFrameloop("always"));
renderer.xr = { addEventListener: () => {} };
return renderer;
},
frameloop,
dpr: 1, //PixelRatio.get(),
onCreated: async (state: RootState) => {
//@ts-ignore
await state.gl.init();
const renderFrame = state.gl.render.bind(state.gl);
state.gl.render = (s: THREE.Scene, c: THREE.Camera) => {
renderFrame(s, c);
context?.present();
};
},
});
root.current.render(children);
return () => {
if (canvas != null) {
unmountComponentAtNode(canvas!);
}
};
});
return <WCanvas ref={canvasRef} style={style} />;
};
I get this
(NOBRIDGE) WARN THREE.WebGPURenderer: WebGPU is not available, running under WebGL2 backend.
And also, I don't think the useCanvasEffect will rerun if I change the component state.
Any help would be appreciated
PS. sometimes it does render but it is not consistent