Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor to CLI+API, typescript, and more #286

Open
wants to merge 152 commits into
base: master
Choose a base branch
from

Conversation

rosskevin
Copy link

@rosskevin rosskevin commented Jan 31, 2025

Goal

  • Allow for external reuse via API (load, transform, analyze, generate)
  • Allow for customization of analyze/duplicates/pruning
  • Allow external users to generate non-r3f components through direct api access
  • Allow for customization of generated code

Included

  • Added eslint
  • Removed rollup for simpler tsup config
  • Converted to typescript
  • Updated all dependencies
  • Integrated auto for automatic releases (NEED a committer to work with me or commit access to complete setup)
  • Separate generate code from analyze, simplifying and reducing some duplicate logic with better maintainability
  • Allow pluggable pruning strategies for the analyze phase
  • Allow subclassing for analyze and generate phases.
  • Integrated ts-morph for AST access or string building, whichever is easiest. API consumer can direct access and modify the AST. Allows for easy tsx | jsx stringification.
  • Removed copied loaders src and instead use community maintained node-three-gltf
  • Add tests (just the start, but it's a start!)
  • Resolution is nodenext, so this is an ESM build with top-level await for node 16+
  • Optimized npm package via ignores
  • Better naming in generated code for typescript types.

Motivation

We have three CAD models that have continuous development. We are building online configurators, and we effectively need a way to customize gltfjsx to instrument the code with our additions in a continuous integration way.

Status on testing

  • I have written basic tests, previously there were none.
  • I have performed some comparison generations that look good.
  • I have npm linked locally and used this new code to create a model that loads identically to the code on master

TL;DR

I need this, and I spent a lot of time on it. I'll be moving forward with it regardless, but I think it belongs here. I hope to have this PR reconciled and merged so that the entire community can collaborate.

Samples

GLTF r3f
/*
  FOO header 
*/

import {
  useAnimations,
  useGLTF,
  Merged,
  PerspectiveCamera,
  OrthographicCamera,
} from '@react-three/drei'
import { GroupProps, MeshProps, useGraph } from '@react-three/fiber'
import * as React from 'react'
import { AnimationClip, Mesh, MeshPhysicalMaterial, MeshStandardMaterial } from 'three'
import { GLTF, SkeletonUtils } from 'three-stdlib'

interface FlightHelmetGLTF extends GLTF {
  nodes: {
    Hose_low: Mesh
    RubberWood_low: Mesh
    GlassPlastic_low: Mesh
    MetalParts_low: Mesh
    LeatherParts_low: Mesh
    Lenses_low: Mesh
  }
  materials: {
    HoseMat: MeshStandardMaterial
    RubberWoodMat: MeshStandardMaterial
    GlassPlasticMat: MeshStandardMaterial
    MetalPartsMat: MeshStandardMaterial
    LeatherPartsMat: MeshStandardMaterial
    LensesMat: MeshPhysicalMaterial
  }
}

export interface FlightHelmetProps extends GroupProps {}

const modelLoadPath = '/FlightHelmet.gltf'
const draco = false

export function FlightHelmet(props: FlightHelmetProps) {
  const { nodes, materials } = useGLTF(modelLoadPath, draco) as FlightHelmetGLTF

  return (
    <group {...props} dispose={null}>
      <mesh
        name="Hose_low"
        castShadow
        receiveShadow
        geometry={nodes.Hose_low.geometry}
        material={materials.HoseMat}
      />
      <mesh
        name="RubberWood_low"
        castShadow
        receiveShadow
        geometry={nodes.RubberWood_low.geometry}
        material={materials.RubberWoodMat}
      />
      <mesh
        name="GlassPlastic_low"
        castShadow
        receiveShadow
        geometry={nodes.GlassPlastic_low.geometry}
        material={materials.GlassPlasticMat}
      />
      <mesh
        name="MetalParts_low"
        castShadow
        receiveShadow
        geometry={nodes.MetalParts_low.geometry}
        material={materials.MetalPartsMat}
      />
      <mesh
        name="LeatherParts_low"
        castShadow
        receiveShadow
        geometry={nodes.LeatherParts_low.geometry}
        material={materials.LeatherPartsMat}
      />
      <mesh
        name="Lenses_low"
        castShadow
        receiveShadow
        geometry={nodes.Lenses_low.geometry}
        material={materials.LensesMat}
      />
    </group>
  )
}

useGLTF.preload(modelLoadPath, draco)
Draco instanceall r3f
/*
  FOO header 
*/

import {
  useAnimations,
  useGLTF,
  Merged,
  PerspectiveCamera,
  OrthographicCamera,
} from '@react-three/drei'
import { GroupProps, MeshProps, useGraph } from '@react-three/fiber'
import * as React from 'react'
import { AnimationClip, Mesh, MeshPhysicalMaterial, MeshStandardMaterial } from 'three'
import { GLTF, SkeletonUtils } from 'three-stdlib'

interface FlightHelmetGLTF extends GLTF {
  nodes: {
    GlassPlastic_low: Mesh
    Hose_low: Mesh
    Lenses_low: Mesh
    RubberWood_low: Mesh
    MetalParts_low: Mesh
    LeatherParts_low: Mesh
  }
  materials: {
    GlassPlasticMat: MeshStandardMaterial
    HoseMat: MeshStandardMaterial
    LensesMat: MeshPhysicalMaterial
    RubberWoodMat: MeshStandardMaterial
    MetalPartsMat: MeshStandardMaterial
    LeatherPartsMat: MeshStandardMaterial
  }
}

export interface FlightHelmetProps extends GroupProps {}

const modelLoadPath = '/FlightHelmet-transformed.glb'
const draco = true

type ContextType = Record<string, React.ForwardRefExoticComponent<MeshProps>>

const context = React.createContext<ContextType>({})

export function FlightHelmetInstances({ children, ...props }: FlightHelmetProps) {
  const { nodes } = useGLTF(modelLoadPath, draco) as FlightHelmetGLTF
  const instances = React.useMemo(
    () => ({
      GlassPlastic_low: nodes.GlassPlastic_low,
      Hose_low: nodes.Hose_low,
      Lenses_low: nodes.Lenses_low,
      RubberWood_low: nodes.RubberWood_low,
      MetalParts_low: nodes.MetalParts_low,
      LeatherParts_low: nodes.LeatherParts_low,
    }),
    [nodes],
  )
  return (
    <Merged meshes={instances} {...props}>
      {(instances: ContextType) => <context.Provider value={instances} children={children} />}
    </Merged>
  )
}

export function FlightHelmet(props: FlightHelmetProps) {
  const instances = React.useContext(context)

  return (
    <group {...props} dispose={null}>
      <instances.GlassPlastic_low name="GlassPlastic_low" />
      <instances.Hose_low name="Hose_low" />
      <instances.Lenses_low name="Lenses_low" />
      <instances.RubberWood_low name="RubberWood_low" />
      <instances.MetalParts_low name="MetalParts_low" />
      <instances.LeatherParts_low name="LeatherParts_low" />
    </group>
  )
}

useGLTF.preload(modelLoadPath, draco)

Closes/supercedes PRs

This closes the majority of open PRs through fixes or through reuse of external loaders that are maintained:

Closes issues

This PR allows-for/solves/obsoletes/no longer present the following issues:

hichemfantar and others added 30 commits September 11, 2024 01:44
…mpty leaf nodes

The code changes introduce two new options to the CLI tool:
- `--pruneKeepAttributes`: Determines whether to keep unused vertex attributes, such as UVs without an assigned texture.
- `--pruneKeepLeaves`: Determines whether to keep empty leaf nodes.

These options provide more control over the pruning process, allowing users to optimize the resulting glTF files based on their specific requirements.
…e I think we can import these, so try that before continuing on these
@hichemfantar
Copy link

Awesome work! 🚀

@rosskevin
Copy link
Author

@donmccurdy @drcmda I have performed a cursory review of all PRs and issues that I believe this closes, and linked them so the merging of this PR will auto close them. There are many solved/closeable/unrelated issues, but I didn't link those.

If you would, please review and let me know what changes you'd like to see to be merged. Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment