[ReactThreeFiber] 광원
Light
예시
app.js
<Canvas
camera={{
fov: 75,
position: [7, 7, 0],
}}
>
<Light />
</Canvas>
Light.jsx 기본 세팅
const torusGeometry = new THREE.TorusGeometry(0.4, 0.1, 32, 32);
const torusMaterial = new THREE.MeshStandardMaterial({
color: "#9b59b6",
roughness: 0.5,
metalness: 0.9,
});
// usememo로 light 컴포넌트 안에 정의해도 된다.
function Light() {
useFrame((state) => {
const time = state.clock.elapsedTime;
const smallSpherePivot = state.scene.getObjectByName("smallSpherePivot");
smallSpherePivot.rotation.y = THREE.MathUtils.degToRad(time * 50);
});
/* useFrame안의 콜백함수는 매 프레이마다 호출되어 실행된다.
1. 가장 처음 프레임이 만들어진 이후 경과된 시간을 얻어온다 const time = state.clock.elapsedTime
time은 계속 증가할 것이다.
2. smallSpherePivot를 참조한다. const smallSpherePivot = state.scene.getObjectByName('smallSpherePivot');
3. smallSpherePivot를 y축으로 회전시킨다. 각도는 THREE.MathUtils.degToRad(time * 50);
*/
const light = useRef();
useHelper(light, THREE.DirectionalLightHelper);
/* 광원의 위치를 파악한다. 두개의 인자를 받는데 첫번째는 대상이 되는 광원 두번째는 helper에 대한 타입 */
return (
<>
<OrbitControls />
<ambientLight color="#ffffff" intensity={10} />
<mesh rotation-x={THREE.MathUtils.degToRad(-90)}>
<planeGeometry args={[10, 10]} />
<meshStandardMaterial
color="#2c3e50"
roughness={0.5}
metalness={0.5}
side={THREE.DoubleSide}
/>
</mesh>
<mesh rotation-x={THREE.MathUtils.degToRad(-90)}>
<sphereGeometry args={[1.5, 64, 64, 0, Math.PI]} />
<meshStandardMaterial color="#ffffff" roughness={0.1} metalness={0.2} />
</mesh>
{new Array(8).fill().map((item, idx) => {
return (
<group key={idx} rotation-y={THREE.MathUtils.degToRad(-45 * idx)}>
<mesh
geometry={torusGeometry}
material={torusMaterial}
position={[3, 0.5, 0]}
/>
</group>
);
})}
<group name="smallSpherePivot">
<mesh position={[3, 0.5, 0]}>
<sphereGeometry args={[0.3, 32, 32]} />
<meshStandardMaterial
color="#e74c3c"
roughness={0.2}
metalness={0.5}
/>
</mesh>
</group>
</>
);
}
export default Light;
ambientLight
광원의 색상과 세기값을 속성으로 받는다. color를 바꾸면 광원의 색상과 재질의 색상이 섞인다.
color, intensity는 다른 광원에 대해서도 마찬가지이다.
ambientLight는 주변광, 환경광이라고 불리며 장면에 존재하는 물체에 대해 단일 색상으로 렌더링되도록 한다.
보통 세기를 약하게해서 광원에 닿지 못하는 물체도 살짝 보이도록 사용된다.
<ambientLight color="#ffffff" intensity={10} />
hemisphereLight
주변광, 색상 2개 하나는 하늘, 하나는 지상에서 비추는 빛
args={[하늘으로부터의 빛, 땅으로부터의 빛, 세기]}
<hemisphereLight args={["#00f", "#f00", 3]} />
directionalLight
광원의 위치와 물체간의 거리 상관없이 특정방향으로 향하는 빛
빛의 방향은 광원의 포지션 위치에서 원점으로의 방향으로 결정됨
target-position으로 target의 위치도 정할 수 있다.
하지만 이렇게 타켓의 포지션 값을 변경하면 타겟을 장면에 추가해야함 이를 위해서는 장면에 대한 객체를 얻어와야함
<directionalLight
ref={light}
color="#ffffff"
intensity={5}
position={[0, 5, 0]}
target-position={[1, 0, 0]}
/>
하나의 mesh를 대상으로 타켓을 정하려면(target(구)를 따라가며 비추도록 하려면)
useFrame((state) => {
const time = state.clock.elapsedTime;
const smallSpherePivot = state.scene.getObjectByName("smallSpherePivot");
smallSpherePivot.rotation.y = THREE.MathUtils.degToRad(time * 50);
smallSpherePivot.children[0].getWorldPosition(light.current.target.position);
});
useHelper(light, THREE.DirectionalLightHelper);
/* 광원의 위치를 파악한다. 두개의 인자를 받는데 첫번째는 대상이 되는 광원 두번째는 helper에 대한 타입 */
const { scene } = useThree();
/** 장면에 대한 객체가 scene에 저장됨 */
useEffect(() => {
scene.add(light.current.target);
return () => {
scene.remove(light.current.target);
};
}, [light]);
/** 광원의 타켓을 장면에 추가한다. 또한 cleanUp 함수추가*/
정확히 scene.add를 통해서 뭘하는지는 제대로 이해가 안되는데 없으면 작동이 안되긴한다. light.current까지는 인식이되는데 light.current.target은 안됨..
light.current.target를 scene에 추가하는 것인지는 알겠는데 더 찾아봐야할 것 같다.
smallSpherePivot.children[0]은 smallSpherePivot안의 mesh. mesh의 getWorldPosition(좌표)를 광원의 target-position(light.current.target.position)에 저장
이렇게 타겟을 저장해서 쫓게하면 기존에 사용했던 target-position={[1, 0, 0]}
는 의미가 없어짐
pointLight
광원이 자신의 위치에서 모든 방향으로 빛을 발산한다.
헬퍼를 만들 수 있다.
useHelper(light, THREE.PointLightHelper, 0.5);
/** 세번째 인자는 헬퍼의 크기 */
<pointLight
ref={light}
color="#ffffff"
intensity={100}
position={[0, 5, 0]}
distance={1}
/>
광원이 구를 추적하게 만들기 위해
useFrame((state) => {
smallSpherePivot.children[0].getWorldPosition(light.current.position);
});
smallSpherePivot 자체가 pointLight가 된다.
distance - 광원의 위치에서 지정된 위치까지만 영향을 미치도록한다. 0은 무한
spotLight
광원의 위치에서 무대조명같이 깔대기 모양으로 빛이 퍼짐
//..
useHelper(light, THREE.SpotLightHelper);
//..
<spotLight
ref={light}
color="#ffffff"
intensity={100}
position={[0, 10, 0]}
target-position={[0, 0, 0]}
distance={20}
angle={THREE.MathUtils.degToRad(30)}
penumbra={0.5}
/>;
distance - 광원이 영향을 주는 거리. 0은 무한
angle - 깔대기의 각도
penumbra - 빛의 감쇄율(조명의 가장자리로 갈수록 빛이 세기가 줄어드는 정도)
광원의 타켓을 변경하기 위해서는
const { scene } = useThree();
/** 장면에 대한 객체가 scene에 저장됨 */
useEffect(() => {
scene.add(light.current.target);
return () => {
scene.remove(light.current.target);
};
}, [light]);
/** 광원의 타켓을 장면에 추가한다. 또한 cleanUp 함수추가*/
역시 구를 따라오게 하기 위해서는
useFrame에 smallSpherePivot.children[0].getWorldPosition(light.current.target.position); 를 추가한다.
rectAreaLight
형광등처럼 비추는 빛
효과적으로 사용하기 위해서
import { RectAreaLightUniformsLib } from "three/examples/jsm/lights/RectAreaLightUniformsLib";
import { RectAreaLightHelper } from "three/examples/jsm/helpers/RectAreaLightHelper";
하는데 아직 examples로만 남아있는 듯하다?
<rectAreaLight
ref={light}
color="#ffffff"
intensity={20}
width={1}
height={3}
position={[0, 5, 0]}
rotation-x={THREE.MathUtils.degToRad(-90)}
/>
하지만 제대로 작동하지 않는 모습을 보이는데 해결하려면 초기화 코드가 필요하다
RectAreaLightUniformsLib.init();
컴포넌트 밖에 입력
width, height - 형광등의 가로세로 크기.intensity와 함께 밝기에 영향을 미친다
rotation-x={THREE.MathUtils.degToRad(-90)}
target-position이 아닌 rotation으로 각도를 조절한다.
Environment
Drei에서 제공하는 컴포넌트
실제 환경을 360도로 촬영한 이미지이며, 이미지를 활용해서 광원을 효과적으로 표현할 수 있다.
같은 사이트에서 이미지를 다운받을 수 있다. HDRIs - 4k HDR로 다운로드
<Environment files={"../fouriesburg_mountain_lookout_2_4k.hdr"} background />
background 속성으로 files을 이용해서 3차원 장면의 배경으로 사용할 수도 있다.
blur={0.1} 속성으로 블러링도 가능하다.
댓글남기기