Some of my 3d Objects are displayed and some display white image in my page

Hello guys, I’m using @react-three/drei and @react-three/fiber packages in my react app, now in my index page there are many rendered 3 objects , they’re displayed in laptop devices but my problem is with mobile , some of them are displayed and some were displayed but after adding new one 3d object they are not displayed (actually there are displayed but in some mobiles)…

It’s is not a problem with code of course ,cause there is not a problem with that and as i said in laptop there are displayed completely fine but they are not in mobile (some devices)


i have tried to use website to make an optimzation for my gltf and texture optimization web but i used it but the same problem …

this my website u can try to open it in both website and mobile if u wanna see portfolio

if each square is a canvas, then that’s not going to work. browsers limit the amount of open webgl contexts to a very small number. drei has a solution for this: GitHub - pmndrs/drei: 🥉 useful helpers for react-three-fiber

you can also look into GitHub - pmndrs/uikit: 🎨 user interfaces for react-three-fiber you can design the whole scroll container in threejs, you don’t even have to use dom/html.

for example this my code of generating tech section in my website

"use client";
import { technologies } from "@/constants";
import React from "react";
import { BallCanvas } from "../canvas";
import { TechnologiesParams } from "@/types";
import SectionWrapper from "@/app/(root)/SectionWrapper";

const Tech: React.FC = (): React.ReactNode => {
  return (
    <div className="flex flex-wrap justify-center gap-10">
      {technologies.map((technology: TechnologiesParams) => (
        <div className="w-28 h-28" key={technology.name}>
          <BallCanvas icon={technology.icon.src} />
        </div>
      ))}
    </div>
  );
};

export default SectionWrapper(Tech, "Tech");
"use client";
import {
  Decal,
  Float,
  OrbitControls,
  Preload,
  useTexture,
} from "@react-three/drei";
import { Canvas } from "@react-three/fiber";
import React, { Suspense } from "react";
import CanvasLoader from "../sections/Loader";

const Ball = ({ imgUrl }: { imgUrl: string }): React.ReactNode => {
  const [decal] = useTexture([imgUrl]);

  return (
    <Float speed={1.75} rotationIntensity={1} floatIntensity={2}>
      <ambientLight intensity={0.25} />
      <directionalLight position={[0, 0, 0.05]} />
      <mesh castShadow receiveShadow scale={2.75}>
        <icosahedronGeometry args={[1, 1]} />
        <meshStandardMaterial
          color={"#fff8eb"}
          polygonOffset
          polygonOffsetFactor={-5}
          flatShading
        />
        <Decal
          position={[0, 0, 1]}
          map={decal}
          rotation={[2 * Math.PI, 0, 6.25]}
        />
      </mesh>
    </Float>
  );
};

const BallCanvas = ({ icon }: { icon: string }): React.ReactNode => {
  return (
    <Canvas
      className="top-20"
      frameloop="demand"
      gl={{ preserveDrawingBuffer: false }}
    >
      <Suspense fallback={<CanvasLoader />}>
        <OrbitControls enableZoom={false} />
        <Ball imgUrl={icon} />
      </Suspense>
      <Preload all />
    </Canvas>
  );
};

export default BallCanvas;

I inspect white square as u said and yeah like im using canvas for each one . i didnt understand how can i solve my problem , second why it happening only in some mobile not in laptop or some mobiles too

like i said, browsers arbitrarily limit the amount of open webgl context, i.e. <canvas> elements. the number may vary from browser to browser, or desktop and mobile. let it be 5, or 10. if you cross over it will start to crash.

it would not even make sense to have 3 canvas, or 2, you should only ever have one single canvas because the memory overhead and performance hit of having multiple is not feasible.

the good news is that this is what drei/view is for, and the rewrite would be simple. it creates a single full screen canvas that is cut into pieces, each piece is isolated into its own scene, camera, controls, etc, this “view” is in your regular dom component graph.

https://codesandbox.io/p/sandbox/view-tracking-bp6tmc

1 Like

i got u , it like create one canvas for all the dom , whole page and instead of displaying each 3d object in canvas i will use View component instead right?

ok what about this one here , im not using a gltf file for rendering ball

"use client";
import { technologies } from "@/constants";
import React from "react";
import { BallCanvas } from "../canvas";
import { TechnologiesParams } from "@/types";
import SectionWrapper from "@/app/(root)/SectionWrapper";

const Tech: React.FC = (): React.ReactNode => {
  return (
    <div className="flex flex-wrap justify-center gap-10">
      {technologies.map((technology: TechnologiesParams) => (
        <div className="w-28 h-28" key={technology.name}>
          <BallCanvas icon={technology.icon.src} />
        </div>
      ))}
    </div>
  );
};

export default SectionWrapper(Tech, "Tech");
"use client";
import {
  Decal,
  Float,
  OrbitControls,
  Preload,
  useTexture,
} from "@react-three/drei";
import { Canvas } from "@react-three/fiber";
import React, { Suspense } from "react";
import CanvasLoader from "../sections/Loader";

const Ball = ({ imgUrl }: { imgUrl: string }): React.ReactNode => {
  const [decal] = useTexture([imgUrl]);

  return (
    <Float speed={1.75} rotationIntensity={1} floatIntensity={2}>
      <ambientLight intensity={0.25} />
      <directionalLight position={[0, 0, 0.05]} />
      <mesh castShadow receiveShadow scale={2.75}>
        <icosahedronGeometry args={[1, 1]} />
        <meshStandardMaterial
          color={"#fff8eb"}
          polygonOffset
          polygonOffsetFactor={-5}
          flatShading
        />
        <Decal
          position={[0, 0, 1]}
          map={decal}
          rotation={[2 * Math.PI, 0, 6.25]}
        />
      </mesh>
    </Float>
  );
};

const BallCanvas = ({ icon }: { icon: string }): React.ReactNode => {
  return (
    <Canvas
      className="top-20"
      frameloop="demand"
      gl={{ preserveDrawingBuffer: false }}
    >
      <Suspense fallback={<CanvasLoader />}>
        <OrbitControls enableZoom={false} />
        <Ball imgUrl={icon} />
      </Suspense>
      <Preload all />
    </Canvas>
  );
};

export default BallCanvas;

it isn’t about gltf, but webgl. you can feasibly have one, single webgl canvas. everything on top is a waste of memory and performance, more than a few will crash guaranteed due to arbitrary browser limitations.

import { Canvas, addEffect } from '@react-three/fiber'
import { View } from '@react-three/drei'
import Lenis from '@studio-freight/lenis'

// Use lenis smooth scroll
const lenis = new Lenis({ syncTouch: true })
// Integrate into fibers own raf loop instead of opening another
addEffect((t) => lenis.raf(t))

const Tech: React.FC = (): React.ReactNode => {
  return (
    <>
      <div className="flex flex-wrap justify-center gap-10">
        {technologies.map((technology: TechnologiesParams) => (
          <div className="w-28 h-28" key={technology.name}>
            <BallCanvas icon={technology.icon.src} />
          </div>
        ))}
      </div>
      <Canvas
        frameloop="demand" gl={{ preserveDrawingBuffer: false }}
        style={{ pointerEvents: "none", position: 'fixed', top: 0, bottom: 0, left: 0, right: 0, overflow: 'hidden' }}
        eventSource={document.getElementById('root')}
      >
        <View.Port />
        <Preload all />
      </Canvas>
    </>
  )
}


const Ball = ({ imgUrl }: { imgUrl: string }): React.ReactNode => {
  const [decal] = useTexture([imgUrl])
  return (
    <Float speed={1.75} rotationIntensity={1} floatIntensity={2}>
      <ambientLight intensity={0.25} />
      <directionalLight position={[0, 0, 0.05]} />
      <mesh castShadow receiveShadow scale={2.75}>
        <icosahedronGeometry args={[1, 1]} />
        <meshStandardMaterial color={'#fff8eb'} polygonOffset polygonOffsetFactor={-5} flatShading />
        <Decal position={[0, 0, 1]} map={decal} rotation={[2 * Math.PI, 0, 6.25]} />
      </mesh>
    </Float>
  )
}

const BallCanvas = ({ icon }: { icon: string }): React.ReactNode => {
  return (
    <View className="top-20">      
      <OrbitControls enableZoom={false} />
      <Ball imgUrl={icon} />
    </View>
  )
}

i make the body element as the root , and i did what u said

"use client";

import { technologies } from "@/constants";
import { TechnologiesParams } from "@/types";
import { Canvas } from "@react-three/fiber";
import { Preload, View } from "@react-three/drei";
import React, { useEffect, useState } from "react";

import SectionWrapper from "@/app/(root)/SectionWrapper";
import { BallCanvas } from "../canvas";

const Tech: React.FC = () => {
  const [eventSource, setEventSource] = useState<HTMLElement | undefined>(
    undefined
  );

  useEffect(() => {
    const rootElement = document.getElementById("root");
    if (rootElement) {
      setEventSource(rootElement);
    }
  }, []);

  return (
    <>
      <div className="flex flex-wrap justify-center gap-10">
        {technologies.map((technology: TechnologiesParams) => (
          <div className="w-28 h-28" key={technology.name}>
            <BallCanvas icon={technology.icon.src} />
          </div>
        ))}
      </div>
      <Canvas
        frameloop="demand"
        gl={{ preserveDrawingBuffer: false }}
        style={{
          position: "fixed",
          top: 0,
          bottom: 0,
          left: 0,
          right: 0,
          overflow: "hidden",
        }}
        eventSource={eventSource}
      >
        <View.Port />
        <Preload all />
      </Canvas>
    </>
  );
};

export default SectionWrapper(Tech, "Tech");
"use client";

import {
  Decal,
  Float,
  OrbitControls,
  useTexture,
  View,
} from "@react-three/drei";
import React from "react";

interface BallProps {
  imgUrl: string;
}

const Ball: React.FC<BallProps> = ({ imgUrl }) => {
  const [decal] = useTexture([imgUrl]);
  return (
    <Float speed={1.75} rotationIntensity={1} floatIntensity={2}>
      <ambientLight intensity={0.25} />
      <directionalLight position={[0, 0, 0.05]} />
      <mesh castShadow receiveShadow scale={2.75}>
        <icosahedronGeometry args={[1, 1]} />
        <meshStandardMaterial
          color={"#fff8eb"}
          polygonOffset
          polygonOffsetFactor={-5}
          flatShading
        />
        <Decal
          position={[0, 0, 1]}
          map={decal}
          rotation={[2 * Math.PI, 0, 6.25]}
        />
      </mesh>
    </Float>
  );
};

interface BallCanvasProps {
  icon: string;
}

const BallCanvas: React.FC<BallCanvasProps> = ({ icon }) => {
  return (
    <View className="top-20">
      <OrbitControls enableZoom={false} />
      <Ball imgUrl={icon} />
    </View>
  );
};

export default BallCanvas;

here is github repo

github repo

Hi Man.
I don´t know if you already fixed your problem. I had the same problem that you and I could fix it.
The first problem rendering the hero page (the gamer setup) I had to change the model for another lighter due to that one used in that project is very heavy. Then I use a timeout to render it 2 seconds after the application had loaded.
The second part (the spheres) I fixed that rendering a View instead multiple canvas. Using view reduces the load since you are using one single Canvas for all those elements.
As you can imagine I customize my project so it is different to the initial one that I supose you watched in JSM channel.
If you want I can share some fragments of my final project with you so you can have an idea of what I did.

1 Like

Yeah plz share it , actually I tried to remove canvas and use view component as u said and it worked but the problem is when you deploy your Website, did u try to deploy it ? Then the problem will be related to hosting itself I think… cause I’m hosting it in free plans so it doesn’t offer that CPU, memory…to display all threed objects without crashing

Yes I deploy it. It is actually my current portfolio :slight_smile:
www.alejodev.com

This is what I did with the spheres.

const BallCanvas = ({ container }) => {
  return (
    <>
      {
        technologies.map((tech, index) => (
          <View 
          key={tech.name} 
          index={index}
          className="m-2"
          style={{cursor: 'grab', width: "110px", height: "110px", position: 'relative'}}>
            <OrbitControls 
              maxPolarAngle={Math.PI / 2}
              minPolarAngle={Math.PI / 2}
              enableZoom={false}
            />
            <ambientLight intensity={0.5} />
            <PerspectiveCamera makeDefault position={[0, 0, 5]}/>
            <Ball imgUrl={tech.icon} />
          </View>
        ))
      }

      <Canvas 
        eventSource={container}
        style={{ inset: 0, position: "fixed"}}>
          <View.Port/>
      </Canvas>
    </>
  );
};


const Ball = ({ imgUrl }) => {
  const texture = useTexture(imgUrl);
  return (
    <Float 
      rotationIntensity={1.5}
      speed={1} 
      floatIntensity={3}>

      <directionalLight position={[0.5, -1, 0.5]} intensity={0.7}/>
      <mesh scale={2}>
        <dodecahedronGeometry args={[1, 1]} />
        <meshStandardMaterial
          color='#fff'
          // polygonOffset
          // polygonOffsetFactor={-5}
          flatShading
        />
        <Decal
          position={[0, 0, 1]}
          rotation={[2 * Math.PI, 0, 6.25]}
          scale={1}
          map={texture}
        />
      </mesh>
    </Float>
  );
};


...


function Tech() {

  const container = useRef();

  return (
    <div ref={container} className="w-full h-full relative flex flex-wrap justify-center gap-2 max-w-2xl mx-auto">
      <BallCanvas container={container}/>
    </div>
  );
}

And this is the timeout that I mentioned I did in the hero section.
After that delay I render the setup model

  const [renderModel, setRenderModel] = useState(false);

  useEffect(() => {
      setTimeout(() => {
        setRenderModel(true);
      }, 2000);
  }, []);

...
{renderModel ? <Computer/> : <LoadingModel/>}

Sorry to tell u but your portfolio has been crashed :sweat_smile:

It’s weird. I can see it working well on my cellphone and and also try it in 2 different browsers.
What kind of cellphone do you have? Specs?
Because what I also read is that 3D models are heavy and it takes a lot of resources in a mobile

I don’t know actually what’s happening :smiling_face_with_tear:, I have k40 gaming, (12 Ram) , but as I said it doesn’t depends on your mobile resources, it depends on host resources…