"use client"
import { Canvas, useFrame, useThree } from '@react-three/fiber'
import { useHelper, OrbitControls, BakeShadows, SoftShadows, Sky, Environment, Lightformer, Outlines, Line, Cone, Text, Billboard } from '@react-three/drei'
import { Leva, useControls } from 'leva'
import { StrictMode, useEffect, useRef, useMemo, useLayoutEffect } from 'react'
import * as THREE from 'three'

export default function App() {
  return (
    <StrictMode>
      <Leva flat />
      <Canvas camera={{ fov: 50, near: 0.1, far: 200, position: [- 50, 50, 50] }} shadows>
        <Experience />
      </Canvas>
    </StrictMode>
  )
}

export function Experience() {
  const { start, end, thickness } = useControls('Geometry', { start: { value: [0, 0], step: 0.25 }, end: { value: [10, 10], step: 0.25 }, thickness: { value: 0.15, min: 0, max: 1 } })

  return <>
    <OrbitControls makeDefault />
    <directionalLight position={[1, 2, 3]} intensity={1.5} />
    <ambientLight intensity={0.5} />
    <Sky />
    <Arrow color='black' thickness={thickness} start={[start[0], 0, start[1]]} end={[end[0], 0, end[1]]} />
    <axesHelper />

    <mesh rotation-x={- Math.PI * 0.5} scale={1}>
      <planeGeometry args={[10, 10, 1, 1]} />
      <meshStandardMaterial color="greenyellow" />
    </mesh>

  </>
}

export function Arrow({ start = [0, 0, 0], end = [20, 0, 0], color = 'black', thickness = 0.15, text = { content: 'Hello World', color: 'black', fontSize: 2, fontWeight: 'normal', fontStyle: 'normal', anchorY: 'bottom' }, ...props }) {
  const length = Math.sqrt((start[0] - end[0]) ** 2 + (start[1] - end[1]) ** 2 + (start[2] - end[2]) ** 2)
  const headLength = 10 * thickness
  const headWidth = 3 * thickness

  const end3 = useMemo(() => new THREE.Vector3(...end), [end])
  const refgroup = useRef()

  useLayoutEffect(() => {
    refgroup.current.lookAt(end3)
  }, [end3])

  return (
    <group ref={refgroup} position={start} {...props}>
      <mesh position={[0, 0, (length - headLength) / 2]} scale={[thickness, length - headLength, thickness]} rotation-x={Math.PI / 2}>
        <cylinderGeometry args={[1, 1, 1, 12]} />
        <meshBasicMaterial color={color} />
      </mesh>
      <mesh position={[0, 0, length - headLength / 2]} scale={[headWidth, headLength, headWidth]} rotation-x={Math.PI / 2}>
        <coneGeometry args={[1, 1, 12]} />
        <meshBasicMaterial color={color} />
      </mesh>

      {text && <Billboard>
        <Text position={[0.5, 0, 0]} anchorX='left' {...text}>{text.content}</Text>
      </Billboard>}

    </group>
  )
}

Comments (0)

Loading comments...