three.jsreact-three-fiberreact-three-drei

How to keep a react three fiber canvas from scaling an object when resizing browser and always render object the same size?


I am using react fiber in one of our projects but the issue I am facing is that the GLB object gets scaled when resizing the browser or is adjusted depending on the browser's size. For example: MS Edge has less page real-estate than chrome, so it renders smaller already on page load. The model is sticky, overlaying content, for animation purposes. I have no idea how to fix this actually. Could someone maybe help me out with the math or is there another Drei helper I could use? All help would be appreciated!

So it would alway need to be an exact size, regardless of the canvas size.

Code-wise isn't much to go on but

<div
    ref={parentRef}
    className="max-w-container pointer-events-none sticky bottom-0 left-0 top-0 z-10 mx-auto -mb-[120px] hidden h-screen w-full lg:block [&>*]:!pointer-events-none"
  >
    <Canvas
      flat
      dpr={[1, 1.5]}
      gl={{
        preserveDrawingBuffer: true,
        toneMappingExposure: 1,
        outputEncoding: THREE.sRGBEncoding,
      }}
    >
      <ambientLight ref={light} color={0xffffff} intensity={0.3} />
      <Environment
        files={`${
          process.env['NEXT_PUBLIC_ASSET_PREFIX'] ?? ''
        }/pizzo_pernice_puresky_2k.hdr`}
      />
      <Element
        ref={meshRef as React.RefObject<Group<Object3DEventMap>>}
        position={position()}
        rotation={rotation()}
        scale={scale()}
        stateTextureURI={textureURI}
        onLoad={() => setIsLoaded(true)}
      />
    </Canvas>
  </div>

Solution

  • I hope it's not too late, but I just had the same issue and i solved it like this

    import { useAspect} from "@react-three/drei";
    import { useThree } from "@react-three/fiber";
    
    
    export const Component = () => {
      const { size } = useThree();
    
      const getScale = () => {
        if (size.width < size.height) {
          return useAspect(size.width, size.height, 4)[0];
        } else {
          return useAspect(size.width, size.height, 4)[1];
        }
      };
    
      return (
          <mesh scale={getScale()} />
      );
    };