react three.js 빛

해적왕·2022년 8월 26일
1
post-custom-banner

마우스 따라오는 빛

import { Canvas, useFrame, useThree } from '@react-three/fiber';
import { SpotLight, useDepthBuffer, OrbitControls } from '@react-three/drei'
import { Suspense, useRef } from 'react';
import { Vector3 } from 'three'

const MovieSpot = ({ vec = new Vector3(), ...props }) => {
  const light = useRef();
  const viewport = useThree((state) => state.viewport);
  useFrame((state) => {
    light.current.target.position.lerp(vec.set((state.mouse.x * viewport.width) / 2, (state.mouse.y * viewport.height) / 2, 0), 0.1)
    light.current.target.updateMatrixWorld()
  });
  return <SpotLight castShadow ref={light} penumbra={1} distance={6} angle={0.35} attenuation={5} anglePower={4} intensity={2} {...props} />
}

useThree
이 후크를 사용하면 기본 렌더러, 장면, 카메라와 같이 내부에 보관된 모든 기본 객체에 액세스할 수 있다. 또한 화면 및 뷰포트 좌표에서 캔버스의 현재 크기를 제공한다. 예를 들어 브라우저 크기를 조정한 후 새 측정값을 얻을 경우 변경할 수 있는 모든 기본값에도 동일하게 적용됨.

lerp
첫 번째 인수로 보간할 다른 벡터와 알파라고 불리는 두 번째 인자를 사용한다. 알파는 위치가 새로운 벡터를 향해 보관되어야 하는 속도라고 생각할 수 있다.

updateMatrixWorld()
로컬 변환을 업데이트한다.

SpotLight
이 빛은 원뿔을 따라 한 방향으로 한 지점에서 방출되는데, 원뿔은 원뿔의 크기가 커질수록 빛으로부터 멀어질수록 더 커진다.
penumbra
반음파로 인해 감쇠되는 스포트라이트 원뿔의 백분율. 0과 1 사이의 값을 사용한다. 기본값은 0.
distance
조명의 최대 범위. 기본값은 0(제한 없음).
angle
상한이 Math.PI/2.인 방향에서 빛의 최대 분산 각도.

const Ball = () => {
  const depthBuffer = useDepthBuffer({ frames: 1 });

  return (
    <>
      <MovieSpot depthBuffer={depthBuffer} color="yellow" position={[1, 3, 0]} />
      <MovieSpot depthBuffer={depthBuffer} color="#eee" position={[-1, 3, 0]} />
      <mesh castShadow receiveShadow>
        <sphereGeometry args={[1, 46, 46]} />
        <meshStandardMaterial color={"orange"} metalness={0.1} roughness={0.3} />
      </mesh>
      <mesh receiveShadow position={[0, -1, 0]} rotation-x={-Math.PI / 2}>
        <planeGeometry args={[50, 50]} />
        <meshPhongMaterial color={"#202020"}/>
      </mesh>
    </>
  )
}
const Example = () => {
  return (
    <Canvas
      style={{ height: 600, width: 600 }}>
      <color attach="background" args={['#202020']} />
      <ambientLight intensity={0.1} />
      <Suspense fallback={null}>
        <Ball />
      </Suspense>
      <OrbitControls />
    </Canvas>
  )
}

export default Rounded;

마우스 따라오는 빛2

파일 적용법. 이전글 참고
https://velog.io/@iepppop/react-three.js-%EC%A0%81%EC%9A%A9%EB%B2%95
사용한 파일 주소
https://sketchfab.com/3d-models/reinhardt-helmet-overwatch-fc6201d0eeed4fb5ab4b19c9935e537c

import { Canvas, useFrame, useThree } from '@react-three/fiber';
import { SpotLight, useDepthBuffer, Html, useGLTF } from '@react-three/drei'
import { OrbitControls } from "@react-three/drei";
import { Suspense, useRef } from 'react';
import { Vector3 } from 'three';
import * as THREE from 'three';


function Model({ ...props }) {
  const group = useRef()
  const { nodes, materials } = useGLTF('/scene.gltf')
  //이 부분이 마우스를 움직일 때 같이 움직이게 해줌.
  useFrame(({ pointer }) => (group.current.rotation.y = THREE.MathUtils.lerp(group.current.rotation.y, pointer.x * (Math.PI / 5), 0.01)))
  return (
  // 스케일 값을 따로 조정해줬다.
    <group ref={group} {...props} dispose={null} scale={0.7} position={[0,-0.7,0]}>
      <group rotation={[-Math.PI / 2, 0, 0]} scale={1.47}>
        <group rotation={[Math.PI / 2, 0, 0]}>
          <mesh geometry={nodes.pCube1_joues_0.geometry} material={materials.joues} />
          <group position={[0.25, 0.21, -1.15]} rotation={[-0.04, 0, -Math.PI / 2]} scale={[0.31, 1, 0.31]}>
            <mesh geometry={nodes.pCylinder1_Crane_0.geometry} material={materials.Crane} />
          </group>
          <mesh geometry={nodes.pCube2_Piques_0.geometry} material={materials.Piques} />
          <mesh geometry={nodes.pCube3_blinn2_0.geometry} material={materials.blinn2} />
        </group>
      </group>
    </group>
  )
}


const Lights = () => {
  const groupL = useRef()
  const groupR = useRef()
  const front = useRef()
  useFrame(({ pointer }) => {
    groupL.current.rotation.y = THREE.MathUtils.lerp(groupL.current.rotation.y, -pointer.x * (Math.PI / 2), 0.1)
    groupR.current.rotation.y = THREE.MathUtils.lerp(groupR.current.rotation.y, pointer.x * (Math.PI / 2), 0.1)
    front.current.position.x = THREE.MathUtils.lerp(front.current.position.x, pointer.x * 12, 0.05)
    front.current.position.y = THREE.MathUtils.lerp(front.current.position.y, 2 + pointer.y * 4, 0.05)
  })
  return (
    <>
      <group ref={groupL}>
        <pointLight position={[0, 7, -15]} distance={15} intensity={10} />
      </group>
      <group ref={groupR}>
        <pointLight position={[0, 7, -15]} distance={15} intensity={10} />
      </group>
      <spotLight castShadow ref={front} penumbra={0.75} angle={Math.PI / 4} position={[10, 50, 8]} distance={10} intensity={10} shadow-mapSize={[2048, 2048]} />
    </>
  )
}

const Zoom = () => {
  useFrame((state) => {
    state.camera.position.lerp({ x: 0, y: 0, z: 12 }, 0.005)
    state.camera.lookAt(0, 0, 0)
  })
}


const Example = () => {
  return (
    <Canvas shadows camera={{ position: [0, 1.5, 14], fov: 30 }}>
      <color attach="background" args={['#202020']} />
      <fog attach="fog" args={['black', 0, 20]} />
      <pointLight position={[0, 10, -10]} intensity={1} />
      <Suspense fallback={  <Html center className="loader">
            LOADING
          </Html>}>
        <Model />
        <Zoom />
        <Lights />
      </Suspense>
      <OrbitControls />
    </Canvas>
  )
}

export default Example;
profile
프론트엔드
post-custom-banner

0개의 댓글