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

Add Editable Materials types #486

Open
9 tasks
jo-chemla opened this issue Apr 18, 2024 · 1 comment
Open
9 tasks

Add Editable Materials types #486

jo-chemla opened this issue Apr 18, 2024 · 1 comment

Comments

@jo-chemla
Copy link

jo-chemla commented Apr 18, 2024

Add an editable component for meshBasicMaterial, standard, physical and other material flavors to defaultEditableFactoryConfig.

Threejs materials
Generic

Standard

Other

Could also extend to r3f/drei materials

@jo-chemla
Copy link
Author

jo-chemla commented Apr 18, 2024

Current workaround, adapted from api/r3f:

  • adding as a sibling to an existing editable type (like e.group)
  • a three component like meshStandardMaterial, which references the threeRef
  • and connecting one-or-many additionalProps of the theatreObject to the threejs type attributes within theatreObject.onValuesChange
// Component tree wrapped in SheetProvider
<SheetProvider sheet={demoSheet}>
  <e.mesh theatreKey="Cube">
    <boxGeometry args={[1, 1, 1]} />
      {/* <meshStandardMaterial color="orange" theatreKey="Mat" /> */}
      <MyMaterial />
  </e.mesh>
</SheetProvider>
        
        
// Custom Material or any threejs not currently supported by theatre, use an existing editable thing like group, and connect one-or-many additionalProps to the threejs type attributes
const MyMaterial = () => {
  // A reference to the THREE.js object
  const threeRef = useRef(new THREE.MeshBasicMaterial({color: 'red'}))

  const [
    // The Theatre.js object that represents our THREE.js object. It'll be initially `null`.
    theatreObject,
    setTheatreObject,
  ] =
    // Let's use `useState()` so our `useEffect()` will re-run when `theatreObject` changes
    useState(null)

  // This `useEffect()` will run when `theatreObject` changes
  useEffect(
    () => {
      // if `theatreObject` is `null`, we don't need to do anything
      if (!theatreObject) return

      const unsubscribe = theatreObject.onValuesChange((newValues) => {
        // Apply the props to our THREE.js object
        threeRef.current.color = newValues.color;
      })
      // unsubscribe from the listener when the component unmounts
      return unsubscribe
    },
    // We only want to run this `useEffect()` when `theatreObject` changes
    [theatreObject],
  )

  return (
    <>
      <e.group
        theatreKey="Material"
        // We're defining one additional property, `offset`, which is not part of THREE.js
        additionalProps={{
          color: types.rgba({ r: 255, g: 0, b: 0, a: 1 }),
        }}
        // a reference to the THREE.js object
        // ref={threeRef}
        // a reference to the Theatre.js object
        objRef={setTheatreObject}
      />
      <meshBasicMaterial 
        ref={threeRef} 
        // color={threeRef.current.offset}
      />
    </>
  )
}

Note: hurdles of this method:

  • all groups properties do appear (position etc), not only the additionalProps, which is unwanted. Having an editable, empty component might be better for selectively choosing the properties do display within the properties panel.
  • using a theatreKey='Cube/Material' or having that MyMaterial component being a child of the e.mesh component is not sufficient to have the material populate under the Cube within the Outliner tree - the Cube node gets duplicated, once for the mesh properties, and once as a parent of the the custom material.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant