0

I want to showcase the languages and technologies I have worked on in my portfolio. And I am using icosahedrons to display them. I have assigned all the icosahedrons an icon using decal from react-three/drei. But only 16 polygons are being rendered by the chrome on my pc and way less on my mobile. I am not able to find a way to render all of them smoothly together. I figure that as there are 20+ icosahedrons being rendered, there is some repeated work that can be optimized.

This is my tech.jsx:

import React from 'react';
import { BallCanvas } from './canvas';
import { SectionWrapper } from '../hoc';
import { technologies, languages } from '../constants';
import { styles } from '../styles';

const Tech = () => {
    return (
        <>
            <h2 className={`${styles.sectionHeadText}`}>My Tech Stack</h2>
            <p className={`${styles.sectionSubText} m-10 ml-0`}>Technical Skiils</p>
            <div className='flex flex-row flex-wrap justify-center gap-10'>
                {languages.map((language) => (
                    <div className='w-28 h-28' key={language.name}>
                        <BallCanvas icon={language.icon} />
                    </div>
                ))}
            </div>
            <p className={`${styles.sectionSubText} m-10 ml-0`}>Technologies and Frameworks</p>
            <div className='flex flex-row flex-wrap justify-center gap-10'>
                {technologies.map((technology) => (
                    <div className='w-28 h-28' key={technology.name}>
                        <BallCanvas icon={technology.icon} />
                    </div>
                ))}
            </div>
        </>
    )
}

export default SectionWrapper(Tech, '');

Here the technology and the language array contains around 10 items. And this is the component from where the ballcanvas is being called.

import React, { Suspense } from 'react';
import { Canvas } from '@react-three/fiber';
import { Decal, Float, OrbitControls, Preload, useTexture } from '@react-three/drei';
import CanvasLoader from '../Loader';


const Ball = (props) => {
    const [decal] = useTexture([props.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]} rotation={[2 * Math.PI, 0, 6.25]} flatShading map={decal} />
            </mesh>
        </Float>
    )
}

const BallCanvas = ({ icon }) => {
    return (
        <Canvas gl={{ preserveDrawingBuffer: true}}>
            <Suspense fallback={ <CanvasLoader />}>
                <OrbitControls enableZoom={false} enablePan={false}/>
                <Ball imgUrl={icon}/>
            </Suspense>
            <Preload all />
        </Canvas>
    )
}

export default BallCanvas

This is the error I am getting as my contexts are being dropped off.

WARNING: Too many active WebGL contexts. Oldest context will be lost.

I am quite new to the three js module. Any help will be appreciated. nI have come across a couple of github pages describing and overcoming this issue, but they were doing it in three js (like: instance rendering).

  • You should create only one Canvas, with multiple Meshes in it. Right now you’re creating 20+ Canvas contexts, each one with its own Mesh, which is pretty wasteful. I don’t know many devices that could handle this many, since typically you’d only need one. – M - Apr 16 '23 at 11:27

1 Answers1

1

You are creating a new canvas for every ball you are trying to display. Three.js is quite capable of handling more than 16 objects. However, the problem is that each new canvas element requires its own WebGL context. Some browsers have a limit on the number of contexts you can create (you can read more about it here).

To resolve this issue the best solution would be to render all elements in one canvas (and therefore in one WebGL context). To position all elements so that they fit the layout of your website, you can use @react-three-flex, which was created by the same authors as react-three-fiber.

Here is an example, which is linked in the @react-three-flex doucmentation page that might help you achieve your desired result.

Camillo
  • 86
  • 5