Hi, I’m experiencing jank/freeze on background exr enabled in my r3f ts app, and don’t know how to preload and compile it, wish someone can give me some advice on this issue. Thanks in advance.
I have two mode for an indoor scene: orbit and first person. When entering a scene it is the default orbit mode. And in firstPerson mode, I would like to use a very large exr image for background, while in orbit mode, I want to simply use color as background .
Yet if I load and compile the exr after entering first person mode, there will be a very significant jank/freeze, with my chrome devtool performance recorded trace, there is a long blocking shader compile caused by that texture.
As can be seen from the screenshot of the performance trace, there are lots of setProgram → WebGLProgram.getUniforms → onFirstUse following the getBackground → fromEquictangularTexture(I’m setting the texture as background in my custom FirstPersonControl component which is conditionally rendered depending on mode state)
// In FirstPersonControl.tsx, the component itself is conditionally rendered depending on mode state
<Suspense>
{firstPersonModeOn && cameraInitialized && texture && <Environment
background={true} // can be true, false or "only" (which only sets the background) (default: false)
backgroundIntensity={0.5}
map={texture}
environmentIntensity={0}
/>
}
</Suspense>
So I wrote a custom hook to load and compile the texture.
export function usePreLoadFpsEnvTexture () {
const texture = useEnvironment({
files: envTextureUrl,
});
const { gl, scene, camera } = useThree();
useEffect(() => {
if (!texture) return;
texture.mapping = EquirectangularReflectionMapping;
const tempScene = scene;
// const tempScene = new Scene();
tempScene.environment = texture;
tempScene.environmentIntensity = 0.01;
// tempScene.background = texture;
gl.compile(tempScene, camera);
// tempScene.environment = null;
// tempScene.background = null;
}, [texture, gl, camera]);
return texture;
}
It works to preload the texture and compile it, now I have no jank/freeze after switching to firstperson mode. As can be seen from the trace, there is only one setProgram and onFirstUse after getBackground.
Yet, now the envmap is using this texture and the reflection of models in the scene is displaying the texture which is not desired. Yet if in this preload hook, use the texture to set background instead of the environment, the background will show up for a blink of moment and overwritten by my custom orbit mode background. Then, if switching to first person mode, it still jank for compiling the shader. I’ve also tried making a WebGLRenderTarget and only render result to it to pre compile the shader while not make the texture visible before entering firstPersonMode, yet it still jank on entering first person mode.
How may I simply preload and compile this texture to make it available in gpu before entering first person mode to use it as background, at the same time use another envmap for orbit mode.
And there is another issue:
For many of the models to be used in the scene, if using light only, even though I set light intensity to large number, the model still looks dark and not rendered with texture details.
Yet if using scene.environment(I’m using
pmremGenerator.fromScene(new RoomEnvironment()).texture for the screenshot case as in threejs editor), the detail is displayed.I wonder why the some of the details only react to environment? And in my in door scene, I’m trying to use environment(with low environmentIntensity) as well as lights( with lower intensity) to simulate lights and shadow as well as getting the details rendered. I wonder whether it is the best practice for rendering scene with these kind of models.
And at the same time, introducing environment also creates some articrafts on each frame, which makes kind of blink of noise shape in the render result. I wonder is there a way to get rid of it.
Any advice will be appreciated, thank you so much.




