BabylonJS 기초 4일차 : 라이트 이해(조명 4종)
요약
3D 씬이 어둡게 보이는 가장 흔한 이유는 “카메라가 아니라 라이트 문제”입니다. Babylon.js에서는 기본적으로 Hemispheric / Directional / Point / Spot 네 가지 조명을 제공합니다.
오늘은 이 4종 라이트를 아주 쉽게 비교해 보고, 빛의 위치·강도·색과 기본 그림자 ON/OFF까지 실습해서 “왜 어둡게 보이는지”를 스스로 해결할 수 있는 상태가 되는 것이 목표입니다.
목차
- 1. 라이트가 하는 일 한 줄 정리
- 2. 조명 4종 개념 정리 (비유 위주)
- 3. 라이트 4종 비교 표
- 4. Shadow 맛보기: 그림자가 생기는 원리
- 5. 조명 변화 비교 씬 예제 코드
- 6. 실습 단계: 직접 따라 하기
- 7. 추가로 생각해볼 점
- 8. 블로그 최적화 정보
1. 라이트가 하는 일 한 줄 정리
라이트 = “씬 전체에 색과 밝기를 입히는 조명 스위치”라고 생각하시면 됩니다. 메쉬(박스, 구, 캐릭터 등)에 머티리얼과 텍스처를 아무리 예쁘게 입혀도, 라이트가 없으면 화면은 거의 까맣게 보입니다. Babylon.js에서는 라이트가 각 픽셀에 도달하는 빛의 세기와 색을 계산하고, 머티리얼이 그 빛을 어떻게 반사/하이라이트할지 결정합니다.
2. 조명 4종 개념 정리 (비유 위주)
2-1. HemisphericLight – “방 안 전체를 은근히 밝히는 형광등”
Hemispheric 라이트는 전체적인 주변 밝기(환경광)를 담당합니다. 빛이 특정 점에서 나오기보다는 “위쪽 하늘에서 은은하게 내려오는 빛”이라고 생각하면 이해가 쉽습니다.
- 어두운 씬을 빠르게 “대충 전체적으로” 밝게 만들고 싶을 때 가장 먼저 쓰는 라이트
direction은 빛이 들어오는 방향이 아니라 “어디서 반사되어 오는지”를 의미intensity를 0~1 사이에서 조절하면 전체 씬 밝기가 조절됩니다.groundColor를 이용해 바닥에서 튀어 오르는 색(예: 약간 청록색)을 표현할 수 있습니다.
2-2. DirectionalLight – “태양처럼 한 방향에서 쏟아지는 평행광”
Directional 라이트는 “태양빛” 비슷합니다. 빛이 아주 멀리서 오기 때문에 씬 전체에 거의 평행한 방향으로 빛이 들어옵니다.
- 무한히 멀리 있는 태양을 생각하면 됩니다. 빛의 위치보다 “방향(direction)”이 더 중요합니다.
- 실외 씬, 낮 장면, 큰 맵(도시, 들판, 건물들)에서 많이 사용됩니다.
- 그림자를 만들 때 자주 사용하는 타입입니다.
2-3. PointLight – “천장 전구, 전구 하나”
Point 라이트는 한 점에서 사방으로 퍼지는 전구라고 보시면 됩니다. 위치가 아주 중요하고, 가까운 곳은 밝고 먼 곳은 점점 어두워집니다.
- 실내 방 전구, 가로등, 램프 표현에 적합합니다.
- 위치(
position)를 바꾸면 빛이 움직이는 느낌이 바로 드러납니다. - 거리에 따라 감쇠(falloff)가 적용되어 현실적인 느낌을 줄 수 있습니다.
2-4. SpotLight – “손전등, 무대 스포트라이트”
Spot 라이트는 원뿔 모양으로 비추는 손전등이라고 생각하시면 됩니다. 방향과 각도(퍼지는 폭), 밝기 감쇠를 모두 제어할 수 있습니다.
- 플레이어가 손전등을 들고 돌아다니는 게임, 무대 공연 조명에 많이 사용
angle로 빔의 넓이,exponent로 중심부의 강도와 테두리 부드러움을 조절- 그림자와 함께 쓰면 “한 곳만 환하게 비치는” 극적인 장면 연출 가능
3. 라이트 4종 비교 표
| 타입 | 비유 | 주요 용도 | 핵심 속성 | 장점 | 주의점 |
|---|---|---|---|---|---|
| Hemispheric | 방 전체를 비추는 형광등 | 기본 환경광, 씬 전체가 너무 어두울 때 | intensity, diffuse, groundColor |
설정이 매우 간단, 씬을 빠르게 “살릴” 수 있음 | 그림자 표현엔 적합하지 않음, 평평한 느낌이 날 수 있음 |
| Directional | 태양빛 | 야외 씬, 넓은 맵, 메인 광원 | direction, intensity |
씬 전체에 일정한 방향의 빛, 그림자 표현에 좋음 | 거리 감쇠가 없어 실내 전구 표현에는 부자연스러울 수 있음 |
| Point | 전구 한 개, 가로등 | 실내 조명, 램프, 가로등, 작은 영역 | position, intensity |
위치 변경만으로도 빛 움직임이 직관적으로 보임 | 여러 개를 사용하면 성능에 영향, 그림자 사용 시 더욱 주의 |
| Spot | 손전등, 무대 스포트라이트 | 특정 대상 강조, 캐릭터 손전등, 무대 연출 | position, direction, angle, intensity |
아주 극적인 연출 가능, 시선 유도에 좋음 | 각도·강도 설정을 잘못하면 너무 인공적인 느낌이 날 수 있음 |
4. Shadow 맛보기: 그림자가 생기는 원리
Babylon.js에서 그림자는 ShadowGenerator라는 도우미 객체가 있어야 합니다.
흐름을 아주 단순화하면 다음과 같습니다.
- 그림자를 만들고 싶은 라이트(주로 Directional/Spot)에
new BABYLON.ShadowGenerator(...)를 붙입니다. - 빛을 가리는 메쉬(캐릭터, 박스 등)를
shadowGenerator.getShadowMap().renderList에 넣어 줍니다. - 그림자를 받는 바닥 메쉬에
receiveShadows = true를 설정합니다.
이렇게 하면 빛과 물체, 바닥 사이에 관계가 생기면서 자연스러운 그림자가 표현됩니다. 이번 포스팅에서는 아주 기본적인 ON/OFF 정도만 맛보고, 세부 품질(소프트 섀도, 해상도 등)은 나중 단계에서 다룬다고 생각하시면 됩니다.
5. 조명 변화 비교 씬 예제 코드
아래 예제는 동일한 씬에 라이트 4개를 만들어 두고, 버튼으로 어떤 라이트를 켤지 선택하는 데모입니다. 또한 Directional 라이트에 기본 그림자를 적용해, 그림자 ON/OFF도 확인할 수 있게 구성했습니다.
<!-- index.html (필요 부분만 예시) -->
<canvas id="renderCanvas" style="width:100%; height:420px;"></canvas>
<div style="margin-top:8px;">
<button id="btnHemi">Hemispheric</button>
<button id="btnDir">Directional</button>
<button id="btnPoint">Point</button>
<button id="btnSpot">Spot</button>
<button id="btnShadow">Shadow ON/OFF</button>
</div>
<script src="https://cdn.babylonjs.com/babylon.js"></script>
<script>
// JS 코드
const canvas = document.getElementById("renderCanvas");
const engine = new BABYLON.Engine(canvas, true);
const createScene = function () {
const scene = new BABYLON.Scene(engine);
// 카메라 (ArcRotate, 박스 중심을 바라봄)
const camera = new BABYLON.ArcRotateCamera(
"camera",
Math.PI / 4,
Math.PI / 3,
12,
new BABYLON.Vector3(0, 1, 0),
scene
);
camera.attachControl(canvas, true);
// 기본 메쉬
const ground = BABYLON.MeshBuilder.CreateGround("ground",
{ width: 20, height: 20 }, scene);
const box = BABYLON.MeshBuilder.CreateBox("box",
{ size: 2 }, scene);
box.position.y = 1;
// 1) Hemispheric Light
const hemiLight = new BABYLON.HemisphericLight(
"hemiLight",
new BABYLON.Vector3(0, 1, 0), // 위쪽에서 내려오는 빛
scene
);
hemiLight.intensity = 0.9;
// 2) Directional Light
const dirLight = new BABYLON.DirectionalLight(
"dirLight",
new BABYLON.Vector3(-1, -2, 1), // 왼쪽 위에서 오른쪽 아래로
scene
);
dirLight.position = new BABYLON.Vector3(10, 10, -10);
dirLight.intensity = 0.0; // 처음엔 꺼둠
// 3) Point Light
const pointLight = new BABYLON.PointLight(
"pointLight",
new BABYLON.Vector3(0, 5, -5),
scene
);
pointLight.intensity = 0.0; // 처음엔 꺼둠
// 4) Spot Light
const spotLight = new BABYLON.SpotLight(
"spotLight",
new BABYLON.Vector3(0, 6, -6), // 위치
new BABYLON.Vector3(0, -1, 1), // 방향
Math.PI / 4, // 각도
10, // exponent
scene
);
spotLight.intensity = 0.0; // 처음엔 꺼둠
// Directional Light에 그림자 생성기 추가
const shadowGenerator = new BABYLON.ShadowGenerator(1024, dirLight);
shadowGenerator.useBlurExponentialShadowMap = true;
shadowGenerator.blurKernel = 16;
// 그림자를 만들 메쉬 (캐스터)
shadowGenerator.getShadowMap().renderList.push(box);
// 그림자를 받을 메쉬
ground.receiveShadows = true;
let shadowEnabled = true;
// 라이트를 모두 꺼놓고 하나만 켜는 헬퍼
function setActiveLight(type) {
hemiLight.intensity = 0.0;
dirLight.intensity = 0.0;
pointLight.intensity = 0.0;
spotLight.intensity = 0.0;
switch (type) {
case "hemi":
hemiLight.intensity = 0.9;
break;
case "dir":
dirLight.intensity = 1.0;
break;
case "point":
pointLight.intensity = 1.0;
break;
case "spot":
spotLight.intensity = 1.0;
break;
}
}
// 버튼 이벤트 연결
document.getElementById("btnHemi").onclick = () => setActiveLight("hemi");
document.getElementById("btnDir").onclick = () => setActiveLight("dir");
document.getElementById("btnPoint").onclick = () => setActiveLight("point");
document.getElementById("btnSpot").onclick = () => setActiveLight("spot");
// Shadow ON/OFF
document.getElementById("btnShadow").onclick = () => {
shadowEnabled = !shadowEnabled;
shadowGenerator.getShadowMap().renderList =
shadowEnabled ? [box] : [];
};
// 시작은 Hemispheric Light
setActiveLight("hemi");
return scene;
};
const scene = createScene();
engine.runRenderLoop(() => {
scene.render();
});
window.addEventListener("resize", () => {
engine.resize();
});
</script>
이 예제로 다음을 직접 눈으로 확인하실 수 있습니다.
- Hemispheric 라이트만 켰을 때와 다른 라이트를 켰을 때의 전체 분위기 차이
- Directional / Point / Spot 라이트가 각각 어떤 방향과 범위로 빛을 뿌리는지
- Shadow ON/OFF 버튼으로 그림자가 생겼을 때와 없을 때의 입체감 차이
6. 실습 단계: 직접 따라 하기
-
기본 프로젝트 준비
index.html파일을 하나 만들고,<canvas id="renderCanvas">와 Babylon.js CDN 스크립트를 포함합니다. (위 코드처럼) -
씬과 카메라, 박스/바닥 만들기
이전 1~3일차에서 했던 방식대로 엔진(BABYLON.Engine), 씬(BABYLON.Scene), ArcRotate 카메라, 바닥, 박스를 생성합니다. -
라이트 4종을 차례로 추가
- 먼저 Hemispheric 라이트를 추가해 씬 전체를 적당히 밝게 만듭니다.
- 그 다음 Directional, Point, Spot 라이트를 추가하되, 처음에는
intensity = 0으로 꺼둡니다. - 버튼을 눌렀을 때만 해당 라이트의
intensity를 1로 켜고, 나머지는 0으로 꺼지게 처리합니다.
-
라이트 위치·방향·색 바꿔 보기
- Point 라이트의
position.y를 2 → 8로 바꾸며, 그림 위치가 어떻게 변하는지 관찰해 보세요. - Spot 라이트의
angle값을Math.PI / 6→Math.PI / 3으로 바꿔 빔이 좁았다가 넓어지는 느낌을 확인합니다. diffuse = new BABYLON.Color3(1, 0, 0)처럼 색을 바꾸어 붉은 조명, 푸른 조명을 만들어 봅니다.
- Point 라이트의
-
기본 그림자 켜고 끄기
- Directional 라이트에 ShadowGenerator를 붙이고, 박스를
renderList에 추가합니다. - 버튼 클릭 시
renderList를 비우거나 다시 채우는 방식으로 그림자 ON/OFF를 구현합니다. - 그림자가 켜졌을 때가 훨씬 입체적으로 느껴지는지 눈으로 확인해 보세요.
- Directional 라이트에 ShadowGenerator를 붙이고, 박스를
-
“왜 어둡지?”라는 질문에 답해 보기
이제 실제 프로젝트에서 화면이 어둡게 보이면, 다음 체크리스트를 떠올려 보시면 됩니다.- 라이트가 최소 하나라도 있는가? (특히 Hemispheric 하나만 있어도 기본은 보입니다.)
- 라이트의
intensity가 0에 가깝게 되어 있지는 않은가? - Point/Spot 라이트의 경우, 메쉬와 너무 멀리 떨어져 있지 않은가?
- 머티리얼의
emissive가 0이고diffuse색이 너무 어둡지는 않은가?
7. 추가로 생각해볼 점
- 실제 게임이나 서비스에서는 라이트 개수가 많을수록 성능에 영향을 줍니다. 기본 머티리얼은 한 번에 처리할 수 있는 라이트 수가 제한되어 있으므로(보통 4개), 핵심 라이트 위주로 사용하거나, 필요한 메쉬에만 특정 라이트를 연결하는 구조가 좋습니다.
- 씬 전체 분위기는 Hemispheric + Directional 조합으로 잡고, Point/Spot은 “강조용”으로만 사용하는 패턴이 상당히 많이 쓰입니다.
- 향후에는 Clustered Lighting 같이 더 고급 라이트 기술도 활용할 수 있는데, 이는 많은 수의 포인트/스팟 라이트를 효율적으로 처리하기 위한 기능입니다.

0 댓글