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 175 commits into
base: master
Choose a base branch
from

Conversation

rosskevin
Copy link

@rosskevin rosskevin commented Jan 31, 2025

Temporary fork published

Temporary fork published: https://github.com/rosskevin/gltfjsx

I hope this is a temporary package and this PR is accepted, but I've got to move on and start using it in a production/published environment.

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.
  • new exposeProps option in generation API, allowing for generating component props that propagate to Object3D one to many jsx properties e.g. shadows -> [castShadow, receiveShadow] with optional matcher fn.

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.

Testing

  • I have written basic tests, previously there were none. Additional assertions have been added to support new featuers like exposeProps.
  • 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
@rosskevin
Copy link
Author

For watchers, I updated the original text, but:

Temporary fork published: https://github.com/rosskevin/gltfjsx @rosskevin/gltfjsx

I hope this is a temporary package and #286 is accepted, but I've got to move on and start using it in a production/published environment.

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