Re-render of the custom BufferGeometry crashes in react-three-fiber

Hi, guys.
I have already asked this question here:

But nobody has answered yet.
It seems the problem is the following:
I get proper data from the server, but do not know how to update the buffer, and the app crashes.
How do you change your mesh to another set of coordinates and normals and then display it with react managing component update?

The full message of the StackOverflow question:
I have a react-three-fiber app, which renders custom BufferGeometry cone.
On the frontend I got some user inputs for setting parameters like height, radius etc.
Then I send this data to the server via post request and the server sends back coordinates and normals arrays.
At first request, all works fine.
But then, when a user for example changes height a little - the app crashes with:

[.WebGL-0000704C00336700] GL_INVALID_OPERATION: Vertex buffer is not big enough for the draw call

When I console.log these new data arrays, they are as expected.
Apparently, something wrong with my React implementation.

The code follows:

function App() {
  const [coneData, setConeData] = useState({});
  const [height, setHeight] = useState(5);
  const [radius, setRadius] = useState(3);
  const [segments, setSegments] = useState(3);

  const sendConeParams = useCallback(async () => {
    const config = {
      headers: {
        "Content-Type": "application/json",
      },
    };
    const { data } = await axios.post(
      `/api`,
      { height, radius, segments },
      config
    );
    setConeData(data);
  }, [height, radius, segments]);

  useEffect(() => {
    sendConeParams();
  }, [sendConeParams]);

  return (
    <>
      <div id="canvas-container">
        <Canvas>
          <ambientLight intensity={0.5} />
          <spotLight position={[10, 10, 10]} angle={0.15} penumbra={1} />
          <pointLight position={[-10, -10, -10]} />
          {coneData.conePositions && coneData.coneNormals ? (
            <Cone
              position={[0, 0, 0]}
              triangulation={coneData.conePositions}
              normals={coneData.coneNormals}
            />
          ) : (
            ""
          )}

          <OrbitControls />
        </Canvas>
      </div>
      <Controls
        height={height}
        radius={radius}
        segments={segments}
        setHeight={setHeight}
        setRadius={setRadius}
        setSegments={setSegments}
      />
    </>
  );
}

Your issue mixes up heavily with other libraries. Please copy your full question just as posted on SO in your post so it is not necessary to view the SO question (but keep the link to it).

Why do you need the server to construct the geometry rather than the client? Unless there is a special algorithm you want to protect from public, but i don’t think that’s the case for a cone.

[.WebGL-0000704C00336700] GL_INVALID_OPERATION: Vertex buffer is not big enough for the draw call

Like is said your example code is heavily abstracted with react (and aframe?), when using custom data rather than built-in primitives you also should rather use Geometry (previously called BufferGeometry) and make sure that the attributes sizes match the actual provided array buffers, the error comes from.

1 Like

Thanks for the answer.
Making this app is a test assignment from some company.
So a user enters cone parameters on the frontend (in Controls component), then the server calculates normals and coordinates and sends them back for the frontend to render.
Yes, it is react and react-three-fiber, but I didn’t use aframe.
The server is on node.js and it just calculates and returns data object with JS-arrays conePositions and coneNormals.
The code of the Cone.js is like so:

import React, { useRef, useState, useEffect, useLayoutEffect } from "react";
import { useFrame } from "@react-three/fiber";
import { BufferAttribute } from "three";
import * as THREE from "three";

function Cone({ positions, normals }) {
  const mesh = useRef();
  const geom = useRef();

  positions = new Float32Array(positions);
  normals = new Float32Array(normals);

  return (
    <mesh ref={mesh}>
      <bufferGeometry ref={geom} attach="geometry">
        <bufferAttribute
          attachObject={["attributes", "position"]}
          count={positions.length / 3}
          array={positions}
          itemSize={3}
        />
        <bufferAttribute
          attachObject={["attributes", "normal"]}
          count={normals.length / 3}
          array={normals}
          itemSize={3}
        />
      </bufferGeometry>
      <meshPhongMaterial
        attach="material"
        color="grey"
      />
    </mesh>
  );
}

export default Cone;

May be I need to dispose of the old geometry or set some flag needUpdate to true or just create new BufferGeometry imperatively?
And the sizes of positions and normals change when parameters are changed. But even if I only set another height, for example, the array size remains, but the app crashes anyway.

I made a simpler example, without server.
Here is a component, which is rendered in React.
It gets coneData from external js-file, then renders a mesh.
It works fine first time, but then, after I change some parameter in the ui, the app eigther crashes or nothing happens or if I change the number of segments to a lower value, the geometry changes and a hole appears, where a side was.

import { useRef, useState, useEffect } from "react";
import getConeData from "../utils";

export default function Cone({ height, radius, segments }) {
  const mesh = useRef();
  const [myData, setMyData] = useState(false);
  useEffect(() => {
    setMyData(getConeData(height, radius, segments));
  }, [height, radius, segments]);

  return (
    <>
      {myData ? (
        <mesh ref={mesh} rotation-x={-0.7} position-y={-0.5} position-x={-2}>
          <bufferGeometry attach="geometry">
            <bufferAttribute
              attachObject={["attributes", "position"]}
              count={myData.conePositions.length / 3}
              array={new Float32Array(myData.conePositions)}
              itemSize={3}
            />
          </bufferGeometry>
          <meshPhongMaterial attach="material" color="grey" />
        </mesh>
      ) : (
        ""
      )}
    </>
  );
}