-
Notifications
You must be signed in to change notification settings - Fork 0
Module Lighting
yoshin edited this page Feb 12, 2026
·
3 revisions
Phong 조명 모델과 그림자 시스템을 담당하는 모듈입니다.
| 파일 | 역할 |
|---|---|
lighting.c |
apply_lighting — 다중 광원 Phong 모델 적용 + 체커보드/범프맵 hook |
lighting_utils.c |
clamp_color, fast_pow32 — 조명 유틸리티 |
shadow_calc.c |
calculate_shadow_factor — 소프트 섀도우 팩터 계산 |
shadow_test.c |
is_in_shadow — 단일 shadow ray 차폐 테스트 |
shadow_config.c |
init_shadow_config — 그림자 설정 초기화 + offset LUT |
apply_lighting(scene, hit) 실행 흐름:
1. 체커보드 hook: has_checker → checkerboard_color()로 hit->color 교체
2. 범프맵 hook: bump_map → bump_perturb_normal()로 hit->normal 교란
3. view_dir = normalize(camera.position - hit.point)
4. adjust_samples(): 광원 수에 따라 소프트 섀도 샘플 동적 조절
5. for each light in lights[0..light_count-1]:
a. light_dir = normalize(light.position - hit.point)
b. diffuse = max(0, dot(normal, light_dir))
c. shadow_factor = calculate_shadow_factor(...)
d. specular = pow(max(0, dot(reflect_dir, view_dir)), 32) × 0.5
e. acc += (diffuse + specular) × (1 - shadow_factor) × brightness × light_color
6. 원본 샘플 수 복원
7. final_color = clamp(object.color × (ambient + acc), 0, 255)
pow(x, 32.0) 대신 fast_pow32(x) 사용:
x² → x⁴ → x⁸ → x¹⁶ → x³² (곱셈 5회, pow 호출 제거)
- Hit point에서 광원 방향으로 여러 shadow ray 발사
- 각 ray에 offset을 적용하여 광원 주변을 샘플링
- 차폐된 ray 비율 = shadow factor (0.0: 완전 조명, 1.0: 완전 그림자)
calculate_shadow_factor(scene, query, light_pos, config)
├── calculate_shadow_bias(normal, light_dir, base_bias)
└── for i in [0, samples):
├── offset_lut != NULL → offset = offset_lut[i] × radius
│ └── offset_lut == NULL → generate_shadow_sample_offset() 폴백
├── sample_pos = light_pos + offset
└── is_in_shadow(scene, biased_point, sample_pos, bias)
├── BVH any-hit (objects >= threshold)
│ └── bvh_intersect_any()
└── brute-force (objects < threshold)
└── 모든 오브젝트 순회
init_shadow_offset_lut()에서 grid-based stratified 오프셋을 1회 사전 계산:
grid_size = (int)sqrt(samples);
for (i = 0; i < samples; i++)
{
angle = 2π × (i % grid_size) / grid_size;
r = (i / grid_size + 0.5) / grid_size;
lut[i] = (t_vec3){r × cos(angle), r × sin(angle), 0};
}- Grid 기반 층화 샘플링으로 균일한 분포 보장
- 매 shadow sample에서 삼각함수 호출 제거
-
scene_destroy()시 LUT 메모리 해제 -
set_shadow_samples()호출 시 LUT 재생성
double calculate_shadow_bias(t_vec3 normal, t_vec3 light_dir, double base_bias)표면 각도에 따라 bias를 조절하여 shadow acne(자기 교차 아티팩트)를 방지합니다:
- 법선과 광원 방향의 각도가 클수록(grazing angle) bias 증가
- 계산식:
bias = base_bias × (1.0 + angle_factor × 2.0) angle_factor = 1.0 - |dot(normal, light_dir)|- 호출 시
base_bias = 0.001고정
is_in_shadow()에서 BVH 활성화 여부와 오브젝트 수에 따라 분기:
is_in_shadow(scene, point, light_pos, bias)
├── BVH 활성화 && objects > SHADOW_BVH_THRESHOLD (5)
│ ├── bvh_intersect_any() → hit → return 1 (early exit)
│ └── check_plane_shadow() → plane 별도 순회
└── 그 외
└── check_object_shadow() → brute-force 전체 순회
| 조건 | 경로 |
|---|---|
| BVH 활성화 + objects > 5 |
bvh_intersect_any() + check_plane_shadow()
|
| 그 외 |
check_object_shadow() brute-force 순회 |
- Any-hit는 첫 번째 차폐 발견 시 즉시 종료하므로 일반 BVH 순회보다 빠름
- BVH 경로에서는 plane이 BVH에 포함되지 않으므로
check_plane_shadow()로 별도 테스트