import React , { useRef , useMemo } from 'react' ; import * as THREE from 'three' ; import { useLoader , useThree , useFrame } from '@react-three/fiber' ; import { STLLoader } from 'three/examples/jsm/loaders/STLLoader' ; import { useEdgeSplit } from 'src/helpers/hooks/useEdgeSplit' ; import texture from 'src/components/IdeViewer/dullFrontLitMetal.png' ; import { MeshDistortMaterial , Sphere , useTexture } from '@react-three/drei' ; const thresholdAngle = 10 ; export default function AssetWithGooey ( { assetUrl , scale , } ) { const geo = useLoader ( STLLoader , assetUrl ) ; const edgeRef = useRef ( null ) ; const coffeeRef = useRef ( null ) ; const mesh = useEdgeSplit ( ( thresholdAngle * Math . PI ) / 180 , true , geo ) ; const colorMap = useTexture ( texture ) ; const edges = React . useMemo ( ( ) => new THREE . EdgesGeometry ( geo , 12 ) , [ geo ] ) ; const position = [ 0 , 0 , 5 ] ; const scaleArr = Array . from ( { length : 3 } ) . map ( ( ) => scale ) ; const { mouse } = useThree ( ) ; const [ rEuler , rQuaternion ] = useMemo ( ( ) => [ new THREE . Euler ( ) , new THREE . Quaternion ( ) ] , [ ] ) ; useFrame ( ( state , delta ) => { if ( edgeRef . current ) { edgeRef . current . rotation . y += 0.01 ; } if ( coffeeRef . current ) { rEuler . set ( ( - mouse . y * Math . PI ) / 4 , ( mouse . x * Math . PI ) / 2 , 0 ) ; coffeeRef . current . quaternion . slerp ( rQuaternion . setFromEuler ( rEuler ) , 0.1 ) ; } } ) ; return ( < group dispose = { null } ref = { edgeRef } position = { position } > < group ref = { coffeeRef } > < mesh ref = { mesh } scale = { scaleArr } geometry = { geo } > < meshPhysicalMaterial color = "#FF6EBD" map = { colorMap } clearcoat = { 0.5 } clearcoatRoughness = { 0.01 } roughness = { 0 } metalness = { 0.7 } smoothShading / > < /mesh> < lineSegments scale = { scale } geometry = { edges } renderOrder = { 100 } > < lineBasicMaterial color = "#aaaaff" / > < /lineSegments> < /group> < ambientLight intensity = { 2 } / > < Gooey /> < ambientLight intensity = { 1.8 } / > < /group>); } function randomSign ( num ) { return Math . random ( ) > 0.5 ? num : - num ; } function Gooey ( ) { const blobsData = useMemo ( ( ) => { const firstSet = Array . from ( { length : 5 } ) . map ( ( _ , index ) => { const dist = Math . random ( ) * 3 + 2.5 ; const x = randomSign ( Math . random ( ) * dist ) ; const y = randomSign ( Math . sqrt ( dist * dist - x * x ) ) ; const z = randomSign ( Math . random ( ) * 2 ) ; const position = [ x , z , y ] ; const size = Math . random ( ) * 0.8 + 0.1 ; const distort = size > 0.1 ? Math . random ( ) * 0.6 * size + 0.2 : 0 ; const speed = size > 0.1 ? ( Math . random ( ) * 0.8 ) / size / size + 0.1 : 0 ; return { position , size , distort , speed } ; } ) ; const secondSet = Array . from ( { length : 5 } ) . map ( ( _ , index ) => { const dist = Math . random ( ) * 3 + 1.5 ; const x = randomSign ( Math . random ( ) * dist ) ; const y = randomSign ( Math . sqrt ( dist * dist - x * x ) ) ; const z = randomSign ( Math . random ( ) * 2 ) ; const position = [ x , z , y ] ; const size = Math . random ( ) * 0.2 + 0.05 ; const distort = size > 0.1 ? Math . random ( ) * 0.8 * size + 0.2 : 0 ; const speed = size > 0.1 ? ( Math . random ( ) * 0.5 ) / size / size + 0.1 : 0 ; return { position , size , distort , speed } ; } ) ; return [ ... firstSet , ... secondSet ] ; } , [ ] ) ; return ( < > { blobsData . map ( ( { position , size , distort , speed } , index ) => ( < Sphere key = { index } visible position = { position } args = { [ size , 16 , 200 ] } > < MeshDistortMaterial color = "#173E6F" attach = "material" distort = { distort } speed = { speed } roughness = { 0.2 } opacity = { 0.6 } transparent / > < /Sphere>))} < />); }