Ricardo Sanchez
Ricardo Sanchez

Reputation: 5167

How to export obj file using react-three/fiber?

I'm trying to get a simple export to OBJ button working on my react app, I'm using react-three/fiber and I'm following the export example from the Threejs website

The example code pass a scene the the obj export function, but in react-three/fiber we have a Canvas component, so I naively attempt to pass a reference to that Canvas component to no avail, I'm getting the error object.traverse is not a function

Here is my code

import "./styles.css";
import { Fragment, useRef, useState } from "react";
import { Canvas, useFrame } from "@react-three/fiber";
import { OBJExporter } from "three/examples/jsm/exporters/OBJExporter";

// BOX COMPONENT
const Box = (props) => {
  const mesh = useRef();
  const [hovered, setHover] = useState(false);
  const [active, setActive] = useState(false);

  useFrame((state, delta) => (mesh.current.rotation.x += 0.01));

  return (
    <mesh
      {...props}
      ref={mesh}
      scale={active ? 1.5 : 1}
      onClick={(event) => setActive(!active)}
      onPointerOver={(event) => setHover(true)}
      onPointerOut={(event) => setHover(false)}
    >
      <boxGeometry args={[3, 3, 3]} />
      <meshStandardMaterial color={hovered ? "hotpink" : "orange"} />
    </mesh>
  );
};

// APP
export default function App() {
  const canvasRef = useRef(null);

  const link = document.createElement("a");
  link.style.display = "none";
  document.body.appendChild(link);

  function save(blob, filename) {
    link.href = URL.createObjectURL(blob);
    link.download = filename;
    link.click();
  }

  function saveString(text, filename) {
    save(new Blob([text], { type: "text/plain" }), filename);
  }

  const handleExport = () => {
    const exporter = new OBJExporter();
    const result = exporter.parse(canvasRef.current);
    saveString(result, "object.obj");
  };

  return (
    <Fragment>
      <Canvas ref={canvasRef}>
        <ambientLight />
        <pointLight position={[10, 10, 10]} />
        <Box position={[-1.2, -1, 0]} />
      </Canvas>
      <button onClick={handleExport}>Export OBJ</button>
    </Fragment>
  );
}

and a working example can be found here

Upvotes: 1

Views: 1215

Answers (1)

Jakub Kukuryk
Jakub Kukuryk

Reputation: 21

I used Your solution but I wrapped everything in the group component and moved the ref to this group, so exports work without lights and cameras. OBJExporter can export only meshes so maybe that was the origin of the issue. Works for me with react 18 @react-three/drei: "^9.40.0", @react-three/fiber: "^8.9.1",

<Canvas camera={{ position: [14, 14, 14] }}>
  <spotLight position={[0, 22, 0]} />
  <group ref={canvasRef}>{children}</group>  //use ref here
</Canvas>

Upvotes: 1

Related Questions