Skip to content

Commit

Permalink
move all models to models file
Browse files Browse the repository at this point in the history
  • Loading branch information
kirkas committed Oct 28, 2024
1 parent 651b39d commit a5ba1a8
Show file tree
Hide file tree
Showing 2 changed files with 228 additions and 221 deletions.
221 changes: 11 additions & 210 deletions apps/web/src/components/ThreeHero/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,20 @@
'use client';

// Libraries
import { useMediaQuery } from 'usehooks-ts';
import classNames from 'classnames';
import { useRef, useMemo, useState, useEffect, Suspense, useCallback } from 'react';
import { useRef, useState, useEffect, Suspense, useCallback } from 'react';
import dynamic from 'next/dynamic';

// Components
import Image, { StaticImageData } from 'next/image';
import Link from 'apps/web/src/components/Link';

// Assets
import {
BlackMaterial,
BaseLogoModel,
BaseLogo,
Boxes,
Lightning,
blue,
Balls,
Controller,
Eth,
Globe,
Expand All @@ -23,30 +25,23 @@ import {
Play,
Blobby,
Cursor,
Pointer,
} from './models';
import Link from 'apps/web/src/components/Link';

// Assets
import baseLogo from './assets/base-logo.svg';
import environmentLight from './assets/environmentLight.jpg';

// 3D libraries - types
import type { Euler, Vector3 } from '@react-three/fiber';
import type { Vector3Tuple, CylinderArgs, BallArgs, RapierRigidBody } from '@react-three/rapier';
import type { Vector3 } from '@react-three/fiber';
import type { Vector3Tuple } from '@react-three/rapier';
import type {
ColorRepresentation,
Mesh,
BufferGeometry,
NormalBufferAttributes,
Material,
Group,
DirectionalLight,
} from 'three';

// 3D Libraries - static - These cannot be dynamically imported
import { useThree, useFrame } from '@react-three/fiber';
import { MathUtils, Vector3 as ThreeVector3, BackSide } from 'three';

// 3D libraries - dynamic imports

// Dynamic - react-three/fiber
Expand All @@ -59,10 +54,6 @@ const Html = dynamic(async () => import('@react-three/drei').then((mod) => mod.H
ssr: false,
});

const Center = dynamic(async () => import('@react-three/drei').then((mod) => mod.Center), {
ssr: false,
});

const Lightformer = dynamic(
async () => import('@react-three/drei').then((mod) => mod.Lightformer),
{
Expand All @@ -82,20 +73,6 @@ const Physics = dynamic(async () => import('@react-three/rapier').then((mod) =>
ssr: false,
});

const BallCollider = dynamic(
async () => import('@react-three/rapier').then((mod) => mod.BallCollider),
{ ssr: false },
);

const CylinderCollider = dynamic(
async () => import('@react-three/rapier').then((mod) => mod.CylinderCollider),
{ ssr: false },
);

const RigidBody = dynamic(async () => import('@react-three/rapier').then((mod) => mod.RigidBody), {
ssr: false,
});

// Dynamic - react-three/postprocessing
const EffectComposer = dynamic(
async () => import('@react-three/postprocessing').then((mod) => mod.EffectComposer),
Expand Down Expand Up @@ -208,7 +185,7 @@ export function Scene(): JSX.Element {

<mesh>
<sphereGeometry args={sceneSphereArguments} />
<meshPhysicalMaterial color="#666" side={BackSide} depthTest={false} />
<meshPhysicalMaterial color="#666" side={1} depthTest={false} />
</mesh>
<Effects />
<EnvironmentSetup />
Expand Down Expand Up @@ -332,179 +309,3 @@ export function Everything() {
</group>
);
}

const boxGeometry: [width: number, height: number, depth: number] = [0.5, 0.5, 0.5];
const boxesCount = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
function Boxes() {
const boxes = useMemo(
() =>
boxesCount.map((id) => {
return (
<PhysicsMesh scale={0.5} gravityEffect={0.03} key={id}>
<mesh castShadow receiveShadow>
<boxGeometry args={boxGeometry} />
<BlackMaterial />
</mesh>
</PhysicsMesh>
);
}),
[],
);

return <group>{boxes}</group>;
}

const sphereGeometry: [width: number, height: number, depth: number] = [0.25, 64, 64];
const sphereCount = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
function Balls() {
const boxes = useMemo(
() =>
sphereCount.map((id) => {
return (
<PhysicsMesh scale={0.25} gravityEffect={0.004} key={id}>
<mesh castShadow receiveShadow>
<sphereGeometry args={sphereGeometry} />
<meshPhysicalMaterial color={blue} />
</mesh>
</PhysicsMesh>
);
}),
[],
);

return <group>{boxes}</group>;
}

const baseLogoRotation: Euler = [Math.PI / 2, 0, 0];
const baseLogoPosition: [x: number, y: number, z: number] = [0, 0, -10];

function BaseLogo() {
const logoRef = useRef<Group>(null);
const doneRef = useRef<boolean>(false);
const isMobile = useMediaQuery('(max-width: 769px)');

useFrame(({ pointer }) => {
if (!logoRef.current) return;

if (doneRef.current) {
logoRef.current.rotation.y = MathUtils.lerp(logoRef.current.rotation.y, pointer.x, 0.05);
logoRef.current.rotation.x = MathUtils.lerp(logoRef.current.rotation.x, -pointer.y, 0.05);
} else {
logoRef.current.rotation.y = MathUtils.lerp(logoRef.current.rotation.y, 0, 0.05);
}
logoRef.current.position.z = MathUtils.lerp(logoRef.current.position.z, 0, 0.05);

// lerp never gets to 0
if (logoRef.current.position.z > -0.01) {
doneRef.current = true;
}
});

const cylinderArguments: CylinderArgs = useMemo(() => [10, isMobile ? 1.1 : 2], [isMobile]);

return (
<RigidBody type="kinematicPosition" colliders={false}>
<CylinderCollider rotation={baseLogoRotation} args={cylinderArguments} />
<group ref={logoRef} position={baseLogoPosition}>
<Center scale={isMobile ? 0.075 : 0.13}>
<BaseLogoModel />
</Center>
</group>
</RigidBody>
);
}

const ballArguments: BallArgs = [1];
export function PhysicsMesh({
vec = new ThreeVector3(),
r = MathUtils.randFloatSpread,
scale = 1,
gravityEffect = 0.2,
children,
}: {
vec?: ThreeVector3;
r?: (a: number) => number;
scale?: number;
gravityEffect?: number;
children: React.ReactNode;
}) {
const rigidBodyApiRef = useRef<RapierRigidBody>(null);
const { viewport } = useThree();

const randomNumberBetween = (min: number, max: number) => {
const posOrNeg = Math.random() > 0.5 ? 1 : -1;
const num = Math.min(Math.random() * (max - min) + min, 14);
return posOrNeg * num;
};

const pos = useMemo(
() =>
new ThreeVector3(
randomNumberBetween(viewport.width * 0.5, viewport.width * 2),
randomNumberBetween(viewport.height * 0.5, viewport.height * 2),
randomNumberBetween(viewport.width * 0.5, viewport.width * 2),
),
[viewport.height, viewport.width],
);
const rot = useMemo(() => new ThreeVector3(r(Math.PI), r(Math.PI), r(Math.PI)), [r]);

useFrame(() => {
if (!rigidBodyApiRef.current) return;
const vector = rigidBodyApiRef.current.translation();
const vector3 = new ThreeVector3(vector.x, vector.y, vector.z);
rigidBodyApiRef.current.applyImpulse(
vec.copy(vector3).negate().multiplyScalar(gravityEffect),
true,
);
});

return (
<RigidBody
linearDamping={4}
angularDamping={1}
friction={0.1}
position={pos.toArray()}
rotation={rot.toArray()}
ref={rigidBodyApiRef}
colliders={false}
scale={scale}
>
<BallCollider args={ballArguments} />
{children}
</RigidBody>
);
}

const pointerPosition: Vector3 = [0, 0, 0];
const pointerLightPosition: Vector3 = [0, 0, 10];
function Pointer() {
const vec = new ThreeVector3();
const rigidBodyApiRef = useRef<RapierRigidBody>(null);
const light = useRef<DirectionalLight>(null);
const isMobile = useMediaQuery('(max-width: 769px)');

useFrame(({ pointer, viewport }) => {
rigidBodyApiRef.current?.setNextKinematicTranslation(
vec.set((pointer.x * viewport.width) / 2, (pointer.y * viewport.height) / 2, 0),
);
light.current?.position.set(0, 0, 10);
light.current?.lookAt((pointer.x * viewport.width) / 2, (pointer.y * viewport.height) / 2, 0);
});

const ballColliderArgs: BallArgs = useMemo(() => [isMobile ? 1 : 2], [isMobile]);

return (
<>
<RigidBody
position={pointerPosition}
type="kinematicPosition"
colliders={false}
ref={rigidBodyApiRef}
>
<BallCollider args={ballColliderArgs} />
</RigidBody>

<directionalLight ref={light} position={pointerLightPosition} intensity={10} color={blue} />
</>
);
}
Loading

0 comments on commit a5ba1a8

Please sign in to comment.