Light & Shadow
React Three Fiber(R3F)에서 빛과 그림자는 3D 장면을 보다 현실감 있게 만드는 요소
빛이 없다면 아무것도 보이지 않으며, 그림자가 없다면 입체감이 부족하게 보일 수 있음
현실 세계를 가상으로 모방하는 3D 그래픽에서는 빛과 그림자의 효과를 적절하게 조절하는 것이 필수적
빛(Light)
- ambientLight : 장면 전체를 균일하게 밝게 비춤
- pointLight : 특정 위치에서 전 방향으로 빛을 방출
- spotLight : 특정 위치에서 원뿔 형태로 빛을 쏨
- directionalLight : 태양광처럼 특정 방향에서 평행하게 빛을 쏨
ambientLight (전체적인 밝기 조절)
<ambientLight intensity={0.7} />
directionalLight (태양광과 같은 평행한 빛)
<directionalLight
castShadow
intensity={2}
target-position={[0, -1, 0]}
shadow-mapSize={[5000, 5000]}
position={[-4, -2.1, 4]}
/>
빛의 위치 조절
position={[-4, -2.1, 4]}
- 빛의 위치를 설정하면, 조명의 방향과 강도를 조절 가능
useHelper를 활용한 빛의 방향 확인
Helper
장면(Scene) 내 특정 요소의 시각적 디버깅을 돕는 도구
DirectionalLightHelper 사용
import { useHelper } from "@react-three/drei";
import { DirectionalLightHelper } from "three";
import { useRef } from "react";
const Elements = () => {
const lightRef = useRef(null);
useHelper(lightRef, DirectionalLightHelper, 1, "blue");
return (
<>
<ambientLight intensity={0.7} />
<directionalLight ref={lightRef} {...} />
</>
);
};
- 빛이 어디에서 오는지 쉽게 확인 가능
그림자(Shadow)
3D 장면의 입체감을 강조하며, 물체가 공간에 위치하고 있음을 시각적으로 표현
그림자 활성화 단계
1. 빛에 그림자 활성화
<directionalLight castShadow ... />
2. 물체에 그림자 받기 활성화
<mesh receiveShadow ... />
3. Canvas에서 그림자 활성화
<Canvas shadows ... />
그림자 품질 조절
기본적으로 그림자는 계단현상이 있을 수 있음
→ 해상도를 조절하여 계단현상 개선
shadow-mapSize={[5000, 5000]}
빛의 방향 조절
target-position={[0, -1, 0]}
- directionalLight의 방향을 조절할 수 있음
App.jsx
import './App.css'
import { useRef } from "react";
import { Canvas } from "@react-three/fiber";
import { OrbitControls, useHelper } from '@react-three/drei';
import { useLoader, useThree } from "@react-three/fiber";
import * as THREE from "three";
const CardData = [
{
imageUrl: "/card_1.jpg",
position: [-1.1, -1.15, 0.4],
rotationY: 10,
rotationZ: 30,
},
{
imageUrl: "/card_2.jpg",
position: [-0.7, -1.05, 0.2],
rotationY: 10,
rotationZ: 10,
},
{
imageUrl: "/card_3.jpg",
position: [0, -1.05, 0],
rotationY: 0,
rotationZ: 0,
},
{
imageUrl: "/card_4.jpg",
position: [0.7, -1.15, -0.2],
rotationY: -10,
rotationZ: -10,
},
{
imageUrl: "/card_5.jpg",
position: [1.3, -1.30, -0.4],
rotationY: -10,
rotationZ: -30,
},
]
const CardComponent = ({ position, rotationY, rotationZ, imageUrl }) => {
const { scene } = useThree();
const texture = useLoader(THREE.TextureLoader, imageUrl)
texture.colorSpace = THREE.SRGBColorSpace;
scene.rotation.set(0, 20, 0);
const materials = [
new THREE.MeshStandardMaterial(), // 오른쪽
new THREE.MeshStandardMaterial(), // 왼쪽
new THREE.MeshStandardMaterial(), // 윗면
new THREE.MeshStandardMaterial(), // 바닥면
new THREE.MeshStandardMaterial({ map: texture }), // 앞면 (이미지 적용)
new THREE.MeshStandardMaterial({ map: texture }), // 뒷면 (이미지 적용)
];
return (
<mesh
castShadow
receiveShadow
position={position}
rotation-y={THREE.MathUtils.degToRad(rotationY)}
rotation-z={THREE.MathUtils.degToRad(rotationZ)}
material={materials}
>
<axesHelper />
<boxGeometry args={[1, 1.6, 0.02]} />
</mesh>
)
}
const Elements = () => {
const lightRef = useRef(null);
useHelper(lightRef, THREE.DirectionalLightHelper, 1, "blue");
return (
<>
<OrbitControls />
<ambientLight intensity={1} /> {/* ambientLight : 환경광 (모든 방향에서 균일하게 씌워지는 빛)-모든 오브젝트가 동일한 강도로 조명을 받는 빛 */}
<directionalLight
castShadow ref={lightRef}
intensity={3}
target-positon={[0, -1, 0]}
shadow-mapSize={[5000, 5000]}
position={[-4, 2, 5]} />
{
CardData.map((props) => {
return <CardComponent key={props.imageUrl} {...props} />
})
}
</>
)
}
function App() {
return (
<Canvas shadows>
<Elements />
</Canvas>
);
}
export default App;
'React > ReactThreeFiber' 카테고리의 다른 글
Obj 3D & Transform (0) | 2025.03.06 |
---|---|
Material & Texture (1) | 2025.03.05 |
Geometry (0) | 2025.03.04 |
GUI Controller (2) | 2025.03.03 |
3D 개발을 도와주는 도구들 - OrbitControls, AxesHelper, GridHelper (0) | 2025.03.02 |