Skip to content

Commit

Permalink
Merge pull request #26 from tscircuit/jscad-three-mesh
Browse files Browse the repository at this point in the history
Add JSCadThreeMesh component
  • Loading branch information
r-bt authored Jul 22, 2024
2 parents 1545c7a + 4c7e39a commit 3066fcb
Show file tree
Hide file tree
Showing 8 changed files with 847 additions and 23 deletions.
14 changes: 7 additions & 7 deletions examples/custom.fixture.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { Custom } from "../lib";
import { JsCadFixture } from "../lib/components/jscad-fixture";
import { primitives, booleans } from "@jscad/modeling";
import { Custom } from "../lib"
import { JsCadFixture } from "../lib/components/jscad-fixture"
import { primitives, booleans } from "@jscad/modeling"

const cube = primitives.cube({ size: 10 });
const sphere = primitives.sphere({ radius: 6, segments: 32 });
const cube = primitives.cube({ size: 10 })
const sphere = primitives.sphere({ radius: 6, segments: 32 })

const intersected = booleans.subtract(cube, sphere);
const intersected = booleans.subtract(cube, sphere)

export default () => (
<JsCadFixture>
<Custom geometry={intersected} />
</JsCadFixture>
);
)
20 changes: 20 additions & 0 deletions examples/jscad-three-mesh.fixture.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Canvas } from "@react-three/fiber"
import { OrbitControls } from "@react-three/drei"
import { JSCadThreeMesh } from "../lib/components/jscad-three-mesh"
import { Cube } from "../lib"

export default () => (
<div
style={{
width: "100%",
height: "100vh",
}}
>
<Canvas>
<JSCadThreeMesh>
<Cube size={10} />
</JSCadThreeMesh>
<OrbitControls />
</Canvas>
</div>
)
15 changes: 15 additions & 0 deletions lib/components/jscad-three-mesh.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { useJSCADRenderer } from "../useJSCADRenderer"

export function JSCadThreeMesh({
children,
}: {
children: any
}) {
const mesh = useJSCADRenderer(children)

if (!mesh) {
return null
}

return <primitive object={mesh} />
}
6 changes: 3 additions & 3 deletions lib/create-host-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import type {
TorusProps,
} from "./jscad-fns"
import type { JSCADModule, JSCADPrimitive } from "./jscad-primitives"
import type { Geom3 } from "@jscad/modeling/src/geometries/types";
import type { Geom3 } from "@jscad/modeling/src/geometries/types"

export function createHostConfig(jscad: JSCADModule) {
const createInstance = (
Expand Down Expand Up @@ -214,9 +214,9 @@ export function createHostConfig(jscad: JSCADModule) {
}

case "custom": {
const { geometry } = props as { geometry: Geom3 };
const { geometry } = props as { geometry: Geom3 }

return geometry;
return geometry
}

default:
Expand Down
8 changes: 4 additions & 4 deletions lib/jscad-fns/custom.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import type { Geom3 } from "@jscad/modeling/src/geometries/types";
import type { Geom3 } from "@jscad/modeling/src/geometries/types"

export type CustomProps = {
geometry: Geom3;
};
geometry: Geom3
}

export function Custom({ geometry }: CustomProps) {
return <custom geometry={geometry} />;
return <custom geometry={geometry} />
}
65 changes: 65 additions & 0 deletions lib/useJSCADRenderer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import ReactReconciler from "react-reconciler"
import { useEffect, useMemo, useState } from "react"
import * as jscad from "@jscad/modeling"
import { createHostConfig } from "./create-host-config"
import convertCSGToThreeGeom from "./convert-csg-to-three-geom"
import * as THREE from "three"

const hostConfig = createHostConfig(jscad as any)
const reconciler = ReactReconciler(hostConfig)

/**
* React Hook that initalizes the JSCAD root to render 3D objects
*/
export function useJSCADRenderer(children) {
const container = useMemo<any[]>(() => [], [])

const root = useMemo(() => {
const root = reconciler.createContainer(
container,
0,
null,
false,
null,
"",
(error) => console.error(error),
null,
)

return root
}, [container])

const [mesh, setMesh] = useState<THREE.Scene | null>(null)

useEffect(() => {
reconciler.updateContainer(children, root, null, () => {})

const scene = new THREE.Scene()

container.map((csg) => {
const geometry = convertCSGToThreeGeom(csg)

if (csg.sides) {
// 2D shape
const material = new THREE.LineBasicMaterial({
vertexColors: true,
linewidth: 2, // Note: linewidth > 1 only works in WebGL 2
})
const lineLoop = new THREE.LineLoop(geometry, material)
scene.add(lineLoop)
} else {
// 3D shape
const material = new THREE.MeshStandardMaterial({
vertexColors: true,
side: THREE.DoubleSide, // Ensure both sides are visible
})
const mesh = new THREE.Mesh(geometry, material)
scene.add(mesh)
}
})

setMesh(scene)
}, [reconciler, children])

return mesh
}
Loading

0 comments on commit 3066fcb

Please sign in to comment.