이 모닥불엔 불 그림이 한 장도 없습니다. 장작의 연료가 실제로 줄면서 열이 되고, 열은 유체 방정식을 타고 오르고, 타고 남은 것은 연기가 되어 따로 흐르고, 뜨거운 자리에서 잔불이 튀어 바람에 실려 갑니다. 불 위의 밤하늘이 일렁이는 것도 장식이 아니라 뜨거운 공기 기둥이 빛을 굴절시키는 것을 흉내낸 층입니다. 장작이 다 타면 불은 정말로 꺼집니다 — 다시 넣어 보세요.
아래 띠에는 불 사진이 한 장도 안 쓰였습니다 —
온도 T 하나를 세 줄짜리 식에 넣어 나온 색입니다.
왼쪽 끝이 갓 식은 숯, 오른쪽 끝이 불꽃 심지입니다.
장작 윗면의 연료 있는 칸만 열원이 된다. 연료는 실제로 줄고, 준 만큼 겉이 숯으로 검게 변한다. 노이즈로 흔들려서 불꽃 뿌리가 매 순간 다르게 넘실댄다.
flick = noise(x*0.09, t*0.16)
T += burn*flick ; F −= 소모율
S += 연기율 * (1−flick*0.4) // 탈수록 연기
속도·온도에 더해 연기 밀도장이 따로 흐른다. 온도는 복사로 빨리 식지만 연기는 천천히 흩어진다 — 불꽃은 짧고 연기 기둥은 길게 남는 이유다.
advect(T) ; advect(S) ; advect(u,v) T −= 냉각*T² ; S *= 0.9975
아주 뜨거운 칸에서 확률적으로 잔불 입자가 태어난다. 그 자리의 유체 속도를 물려받고, 바람에 실리고, 식으면서 어두워지다 사라진다 — 궤적이 곧 바람의 기록이다.
if (T > 0.82 && random() < p) {
ember = {v: 유체속도+위로, 수명: 1~3s}
}
흑체 복사 램프 — 검정→검붉음→주황→노랑→백열. 별도의 불 텍스처가 없다. 연기는 아래에서 불빛을 받아 배가 주황으로 물든다.
r=T*2.7 ; g=T^1.75*1.95 ; b=T^3.4*1.5 연기색 = 회색 + 불빛(T아래) * 주황
불그림을 흐린 채 한 번 더 겹쳐 빛무리(bloom)를 만들고, 불 위 배경은 온도 기울기로 좌우를 흔들어 아지랑이를 넣는다. 카메라가 불을 찍을 때 생기는 그 두 가지다.
blur(14px) + lighter 0.5 // bloom 슬라이스마다 dx = k * ∂T/∂x // 아지랑이
장작이 다 타면 열원이 사라지고, 남은 열이 식으며 불이 정말로 사그라든다. 숯의 붉은 잔광이 마지막까지 남는다 — 검증기가 이 일생(점화→전성기→소진→꺼짐)을 단언한다.
if (F 총량 == 0) 열원 없음
→ T 총량 単조 감소 → 꺼짐
위 화면은 유체 방정식을 매 프레임 풀어 그린 불입니다. 그림 파일을 불러다 쓴 게 아니고요. 진짜 장작불은 이렇게 생겼습니다.
장작을 세워 놓고 태우는 모습입니다. 불꽃이 위로만 솟고, 뿌리 쪽은 좁고 위로 갈수록 흔들리며 벌어집니다.
위 계산이 그리는 게 정확히 이 모양입니다 — 뜨거운 공기가 가벼워서 부력으로 떠오르고, 그 흐름을 나비에·스토크스로 풉니다. 불꽃이 좌우로 안 퍼지고 위로만 가는 건 그래서고, 바람 손잡이를 주면 그 기둥이 통째로 눕습니다.
장작 사이 벌겋게 남은 자리가 잔불입니다. 위 화면의 잔불도 같은 것이고, 불꽃과 달리 천천히 식으며 오래 갑니다. 최고 온도는 화면에서 색으로 역산한 값이라 별표를 달아 뒀습니다 — 온도계를 꽂아 잰 게 아닙니다.
기준일을 100으로 놓고 그린 선입니다. 통화가 서로 달라 지수로 겹쳤습니다.