/ concept-collection / mesh-converter
Sign in
concept-collection / mesh-converter
mesh-converter / src / MeshView.tsx
54 lines · 1.7 KBBlameHistoryRaw
1import { useEffect, useMemo } from 'react'
2import { Canvas } from '@react-three/fiber'
3import { OrbitControls } from '@react-three/drei'
4import * as THREE from 'three'
5import type { MeshData } from './mesh/types'
7function MeshObject({ mesh }: { mesh: MeshData }) {
8 const geometry = useMemo(() => {
9 const g = new THREE.BufferGeometry()
10 g.setAttribute('position', new THREE.Float32BufferAttribute(mesh.positions, 3))
11 g.setIndex(mesh.indices)
12 if (mesh.normals) {
13 g.setAttribute('normal', new THREE.Float32BufferAttribute(mesh.normals, 3))
14 } else {
15 g.computeVertexNormals()
16 }
17 if (mesh.colors) {
18 g.setAttribute('color', new THREE.Float32BufferAttribute(mesh.colors, 3))
19 }
20 // Center and scale to a consistent size so the fixed camera always frames it
21 g.center()
22 g.computeBoundingSphere()
23 return g
24 }, [mesh])
26 useEffect(() => () => geometry.dispose(), [geometry])
28 const scale = 1.6 / (geometry.boundingSphere?.radius || 1)
30 return (
31 <mesh geometry={geometry} scale={scale}>
32 <meshStandardMaterial
33 vertexColors={!!mesh.colors}
34 color={mesh.colors ? 'white' : '#8fb4d9'}
35 roughness={0.55}
36 metalness={0.1}
37 side={THREE.DoubleSide}
38 />
39 </mesh>
40 )
43export function MeshView({ mesh }: { mesh: MeshData }) {
44 return (
45 <Canvas camera={{ position: [2.6, 1.8, 2.6], fov: 45 }}>
46 <color attach="background" args={['#16181d']} />
47 <ambientLight intensity={0.5} />
48 <directionalLight position={[5, 8, 4]} intensity={1.6} />
49 <directionalLight position={[-4, -3, -6]} intensity={0.4} />
50 <MeshObject mesh={mesh} />
51 <OrbitControls makeDefault />
52 </Canvas>
53 )
moveopenescclose