상세 컨텐츠

본문 제목

video backgorund with @react-three/fibre

three.js

by 폴리프레임 2024. 11. 22. 22:37

본문

반응형

배경을 비디오 처리하고, overlay와 3D Geometry 을 위에 구현해 본 코드입니다.

// App.jsx

import bgVideo from "./assets/seokang-background.mp4";
import RenderModel from "./components/RenderModel";

import Blocks from "./components/models/Blocks";


function App() {
  return (
    <main className="relative min-h-screen flex items-center justify-center">
      <video
        className="absolute top-0 left-0 w-full h-full object-cover"
        src={bgVideo}
        autoPlay
        loop
        muted
      />
      {/* <div className="absolute inset-0 bg-black bg-opacity-70"></div> */}
      <div className="absolute top-0 left-0 w-full h-full bg-black bg-opacity-60 z-10"></div>
      <div className="w-full h-screen absolute z-20 flex justify-center items-center">
        <RenderModel>
          <Blocks />
        </RenderModel>
      </div>
    </main>
  );
}

export default App;
// Blocks.jsk

/* eslint-disable */
import React, { useRef, useMemo } from "react";
import { useNavigate } from "react-router-dom";
import { Canvas, useFrame } from "@react-three/fiber";
import * as THREE from "three";

function createMesh(geometry, material, position, name) {
  const mesh = new THREE.Mesh(geometry, material.clone());
  mesh.position.set(...position);
  mesh.name = name;
  mesh.castShadow = true;
  mesh.receiveShadow = true;
  return mesh;
}

function Box({ geometry, material, position, name }) {
  const navigate = useNavigate();
  
  const mesh = useMemo(
    () => createMesh(geometry, material, position, name),
    [geometry, material, position, name]
  );
  
  // Random color generation
  const color = useMemo(
    () => new THREE.Color(Math.random(), Math.random(), Math.random()),
    []
  );
  mesh.material.color = color;

  const handlePointerOver = (event) => {
    document.body.style.cursor = 'pointer';
  };

  const handlePointerOut = (event) => {
    document.body.style.cursor = 'default';
  };

  const handleClick = (event) => {
    navigate(`/${name}`);
  };

  return (
    <mesh
      position={position}
      castShadow
      receiveShadow
      onPointerOver={handlePointerOver}
      onPointerOut={handlePointerOut}
      onClick={handleClick}
    >
      <boxGeometry args={[1, 1, 1]} />
      <meshStandardMaterial attach="material" color={color} />
    </mesh>
  );
}

const Blocks = React.memo(function Blocks(props) {
  const modelRef = useRef();

  // Define geometry and material within Blocks
  const boxGeometry = useMemo(() => new THREE.BoxGeometry(1, 1, 1), []);
  const material = useMemo(() => new THREE.MeshStandardMaterial(), []);

  useFrame((state) => {
    modelRef.current.position.y =
      -1.5 + Math.sin(state.clock.elapsedTime) * 0.15;
  });

  return (
    <group
      {...props}
      dispose={null}
      ref={modelRef}
      position={[0, 1, 0]} // y축 값을 변경하여 위치 조정
      scale={[1, 1, 1]} // scale 값을 변경하여 크기 조정
    >
      <Box
        geometry={boxGeometry}
        material={material}
        position={[1.5, 0, 0]} // 오른쪽
        name="Box A"
      />
      <Box
        geometry={boxGeometry}
        material={material}
        position={[-1.5, 0, 0]} // 왼쪽
        name="Box B"
      />
      <Box
        geometry={boxGeometry}
        material={material}
        position={[0, 1.5, 0]} // 위
        name="Box C"
      />
      <Box
        geometry={boxGeometry}
        material={material}
        position={[0, -1.5, 0]} // 아래
        name="Box D"
      />
    </group>
  );
});

export default Blocks;

'three.js' 카테고리의 다른 글

이미지 매핑하기  (1) 2024.11.24
touch event - @react-three/fiber  (2) 2024.11.23
resize - Three.js  (0) 2024.11.22
lookAt(), getWorldDirection()  (1) 2024.11.21
Capsule class  (2) 2024.11.21

관련글 더보기