; ═══════════════════════════════════════════════════════════════════ ; real.한선 — CrownyReal 병렬 렌더 엔진 (VM용) ; ; Metal/DirectX/Vulkan 대체. 벡터형 4상균형3진 기반 병렬 파이프라인. ; crownyc VM 위에서 Mac/Windows 모두 구동. ; ; 아키텍처: ; 앱 → real → [커맨드버퍼] → [타일빈닝] → [병렬래스터] → 프레임버퍼 ; ; 4상 가시성: 확정(+1)=풀렌더 미확인(0)=중간 오해(-1)=재평가 미인지(-2)=스킵 ; 3진 벡터: 각 성분이 트릿(T/O/A) 단위 → 큐브(27트릿) 정밀도 ; ; Metal 매핑: ; MTLDevice → real장치생성 ; MTLCommandQueue → real큐생성 ; MTLCommandBuffer → real버퍼생성 / real버퍼제출 ; MTLRenderPipeline → real파이프생성 ; Vertex Shader → real정점변환 ; Rasterizer → real타일래스터 ; Fragment Shader → real프래그먼트 ; MTLTexture → real텍스처생성 ; MTLDepthStencil → real깊이테스트 ; ; DirectX 12 매핑: ; ID3D12Device → real장치생성 ; ID3D12CommandQueue → real큐생성 ; ID3D12GraphicsCommandList → real버퍼생성 ; ID3D12PipelineState → real파이프생성 ; IDXGISwapChain → real스왑체인 ; ; 의존성: 없음 (내장함수만 사용) ; ═══════════════════════════════════════════════════════════════════ ; ══════════════════════════════════════ ; 상수 — 4상균형3진 ; ══════════════════════════════════════ 변수 _R확정 = 1 변수 _R미확인 = 0 변수 _R오해 = -1 변수 _R미인지 = -2 ; 트릿 상수 변수 _T양 = 1 변수 _T영 = 0 변수 _T음 = -1 ; 타일 설정 변수 _R타일크기 = 32 변수 _R최대타일 = 2400 변수 _R최대오브젝트 = 4096 변수 _R최대커맨드 = 8192 변수 _R최대정점 = 65536 ; ══════════════════════════════════════ ; 3진 벡터 수학 (큐브 정밀도) ; ══════════════════════════════════════ ; 3진 벡터 생성 (x, y, z — 정수 기반 고정소수점, 1000배) 함수 벡터3(x, y, z) { 변수 v = [] v = 추가(v, x) v = 추가(v, y) v = 추가(v, z) 반환 v } ; 벡터 덧셈 함수 벡터더하기(a, b) { 반환 벡터3(a[0] + b[0], a[1] + b[1], a[2] + b[2]) } ; 벡터 뺄셈 함수 벡터빼기(a, b) { 반환 벡터3(a[0] - b[0], a[1] - b[1], a[2] - b[2]) } ; 벡터 스칼라곱 (s는 1000배 고정소수점) 함수 벡터곱(v, s) { 반환 벡터3(v[0] * s / 1000, v[1] * s / 1000, v[2] * s / 1000) } ; 내적 (결과 1000배) 함수 벡터내적(a, b) { 반환 a[0] * b[0] / 1000 + a[1] * b[1] / 1000 + a[2] * b[2] / 1000 } ; 외적 함수 벡터외적(a, b) { 변수 x = a[1] * b[2] / 1000 - a[2] * b[1] / 1000 변수 y = a[2] * b[0] / 1000 - a[0] * b[2] / 1000 변수 z = a[0] * b[1] / 1000 - a[1] * b[0] / 1000 반환 벡터3(x, y, z) } ; 벡터 크기 제곱 (1000배) 함수 벡터크기2(v) { 반환 v[0] * v[0] / 1000 + v[1] * v[1] / 1000 + v[2] * v[2] / 1000 } ; 벡터 크기 (정수 근사) 함수 벡터크기(v) { 변수 sq = 벡터크기2(v) 만약 (sq <= 0) { 반환 0 } 반환 루트(sq * 1000) } ; 벡터 정규화 (1000배 단위벡터) 함수 벡터정규화(v) { 변수 m = 벡터크기(v) 만약 (m == 0) { 반환 벡터3(0, 0, 0) } 반환 벡터3(v[0] * 1000 / m, v[1] * 1000 / m, v[2] * 1000 / m) } ; 4x4 행렬 생성 (단위행렬) 함수 행렬단위() { 변수 m = [] 변수 i = 0 동안 (i < 16) { 만약 (i == 0) { m = 추가(m, 1000) } 혹시 (i == 5) { m = 추가(m, 1000) } 혹시 (i == 10) { m = 추가(m, 1000) } 혹시 (i == 15) { m = 추가(m, 1000) } 아니면 { m = 추가(m, 0) } i = i + 1 } 반환 m } ; 행렬×벡터 (4D, w=1000) 함수 행렬벡터곱(m, v) { 변수 x = m[0] * v[0] / 1000 + m[1] * v[1] / 1000 + m[2] * v[2] / 1000 + m[3] 변수 y = m[4] * v[0] / 1000 + m[5] * v[1] / 1000 + m[6] * v[2] / 1000 + m[7] 변수 z = m[8] * v[0] / 1000 + m[9] * v[1] / 1000 + m[10] * v[2] / 1000 + m[11] 변수 w = m[12] * v[0] / 1000 + m[13] * v[1] / 1000 + m[14] * v[2] / 1000 + m[15] 반환 [x, y, z, w] } ; 행렬×행렬 함수 행렬곱(a, b) { 변수 r = [] 변수 행 = 0 동안 (행 < 4) { 변수 열 = 0 동안 (열 < 4) { 변수 합 = 0 변수 k = 0 동안 (k < 4) { 합 = 합 + a[행 * 4 + k] * b[k * 4 + 열] / 1000 k = k + 1 } r = 추가(r, 합) 열 = 열 + 1 } 행 = 행 + 1 } 반환 r } ; 이동 행렬 함수 행렬이동(tx, ty, tz) { 변수 m = 행렬단위() m = 설정(m, 3, tx) m = 설정(m, 7, ty) m = 설정(m, 11, tz) 반환 m } ; 3진 부호 변환 (4상 → 트릿) 함수 사상트릿(사상값) { 만약 (사상값 == _R확정) { 반환 _T양 } 만약 (사상값 == _R미확인) { 반환 _T영 } 반환 _T음 } ; ══════════════════════════════════════ ; GPU 장치 (Metal MTLDevice / DX12 ID3D12Device 대체) ; ══════════════════════════════════════ 함수 real장치생성(이름, 코어수) { 변수 장치 = 맵생성() 장치 = 맵넣어(장치, "이름", 이름) 장치 = 맵넣어(장치, "코어수", 코어수) 장치 = 맵넣어(장치, "프레임", 0) 장치 = 맵넣어(장치, "총픽셀", 0) 장치 = 맵넣어(장치, "총삼각형", 0) 장치 = 맵넣어(장치, "큐목록", []) 장치 = 맵넣어(장치, "백엔드", "crownyreal") 반환 장치 } ; ══════════════════════════════════════ ; 커맨드 큐 (Metal MTLCommandQueue / DX12 ID3D12CommandQueue) ; ══════════════════════════════════════ 함수 real큐생성(장치) { 변수 큐 = 맵생성() 큐 = 맵넣어(큐, "버퍼목록", []) 큐 = 맵넣어(큐, "대기수", 0) 큐 = 맵넣어(큐, "완료수", 0) 변수 목록 = 맵꺼내(장치, "큐목록") 목록 = 추가(목록, 큐) 장치 = 맵넣어(장치, "큐목록", 목록) 반환 큐 } ; ══════════════════════════════════════ ; 커맨드 버퍼 (Metal MTLCommandBuffer / DX12 CommandList) ; ══════════════════════════════════════ 함수 real버퍼생성() { 변수 버퍼 = 맵생성() 버퍼 = 맵넣어(버퍼, "커맨드", []) 버퍼 = 맵넣어(버퍼, "상태", "기록중") 버퍼 = 맵넣어(버퍼, "정점", []) 버퍼 = 맵넣어(버퍼, "인덱스", []) 반환 버퍼 } ; 드로우 커맨드 추가 함수 real드로우(버퍼, 정점시작, 정점수, 파이프ID, 색상) { 변수 커맨드목록 = 맵꺼내(버퍼, "커맨드") 변수 cmd = [] cmd = 추가(cmd, 정점시작) cmd = 추가(cmd, 정점수) cmd = 추가(cmd, 파이프ID) cmd = 추가(cmd, 색상) cmd = 추가(cmd, 0) 커맨드목록 = 추가(커맨드목록, cmd) 버퍼 = 맵넣어(버퍼, "커맨드", 커맨드목록) 반환 버퍼 } ; 클리어 커맨드 함수 real클리어(버퍼, 색상) { 변수 커맨드목록 = 맵꺼내(버퍼, "커맨드") 변수 cmd = [] cmd = 추가(cmd, -1) cmd = 추가(cmd, 0) cmd = 추가(cmd, -1) cmd = 추가(cmd, 색상) cmd = 추가(cmd, 1) 커맨드목록 = 추가(커맨드목록, cmd) 버퍼 = 맵넣어(버퍼, "커맨드", 커맨드목록) 반환 버퍼 } ; 커맨드 버퍼 제출 함수 real버퍼제출(큐, 버퍼) { 버퍼 = 맵넣어(버퍼, "상태", "제출됨") 변수 목록 = 맵꺼내(큐, "버퍼목록") 목록 = 추가(목록, 버퍼) 큐 = 맵넣어(큐, "버퍼목록", 목록) 변수 대기 = 맵꺼내(큐, "대기수") 큐 = 맵넣어(큐, "대기수", 대기 + 1) 반환 큐 } ; ══════════════════════════════════════ ; 렌더 파이프라인 (Metal MTLRenderPipeline / DX12 PSO) ; ══════════════════════════════════════ 함수 real파이프생성(이름, 정점셰이더, 프래그셰이더) { 변수 파이프 = 맵생성() 파이프 = 맵넣어(파이프, "이름", 이름) 파이프 = 맵넣어(파이프, "VS", 정점셰이더) 파이프 = 맵넣어(파이프, "FS", 프래그셰이더) 파이프 = 맵넣어(파이프, "깊이쓰기", 1) 파이프 = 맵넣어(파이프, "깊이비교", "작으면") 파이프 = 맵넣어(파이프, "컬링", "뒷면") 파이프 = 맵넣어(파이프, "블렌드", "불투명") 반환 파이프 } ; 파이프 블렌드 모드 설정 함수 real파이프블렌드(파이프, 모드) { 파이프 = 맵넣어(파이프, "블렌드", 모드) 반환 파이프 } ; ══════════════════════════════════════ ; 4상 가시성 관리 (오클루전 컬링) ; ══════════════════════════════════════ ; 렌더 오브젝트 생성 함수 real오브젝트(id, 이름, 위치, 반지름) { 변수 obj = 맵생성() obj = 맵넣어(obj, "id", id) obj = 맵넣어(obj, "이름", 이름) obj = 맵넣어(obj, "위치", 위치) obj = 맵넣어(obj, "반지름", 반지름) obj = 맵넣어(obj, "가시성", _R미인지) obj = 맵넣어(obj, "LOD", 2) obj = 맵넣어(obj, "더티", 1) obj = 맵넣어(obj, "활성", 1) obj = 맵넣어(obj, "삼각형수", 0) obj = 맵넣어(obj, "변환", 행렬단위()) 반환 obj } ; 4상 가시성 전이 (프레임 결과에 따라) 함수 real가시성전이(현재, 보임) { ; 확정(+1) + 보임 → 확정 만약 (현재 == _R확정) { 만약 (보임 == 1) { 반환 _R확정 } 반환 _R오해 } ; 미확인(0) + 보임 → 확정, 안보임 → 미인지 만약 (현재 == _R미확인) { 만약 (보임 == 1) { 반환 _R확정 } 반환 _R미인지 } ; 오해(-1) → 한 프레임 더 확인 만약 (현재 == _R오해) { 만약 (보임 == 1) { 반환 _R미확인 } 반환 _R미인지 } ; 미인지(-2) + 보임 → 미확인, 안보임 → 유지 만약 (보임 == 1) { 반환 _R미확인 } 반환 _R미인지 } ; 렌더해야 하는가? (확정/미확인/오해만 렌더) 함수 real렌더해야(가시성) { 만약 (가시성 == _R확정) { 반환 1 } 만약 (가시성 == _R미확인) { 반환 1 } 만약 (가시성 == _R오해) { 반환 1 } 반환 0 } ; LOD 레벨 (가시성 기반) 함수 real_LOD(가시성) { 만약 (가시성 == _R확정) { 반환 0 } 만약 (가시성 == _R미확인) { 반환 1 } 만약 (가시성 == _R오해) { 반환 1 } 반환 2 } ; 프러스텀 컬링 (구체 vs 6평면 간소화 — 구 중심/반지름) 함수 real프러스텀컬링(위치, 반지름, 카메라위치, 시야각) { 변수 차이 = 벡터빼기(위치, 카메라위치) 변수 거리2 = 벡터크기2(차이) ; 시야각 밖이면 미인지 만약 (거리2 > 시야각 * 시야각) { 반환 _R미인지 } ; 가까우면 확정 만약 (거리2 < 반지름 * 반지름 * 4) { 반환 _R확정 } 반환 _R미확인 } ; ══════════════════════════════════════ ; 정점 변환 (Metal Vertex Shader 대체) ; ══════════════════════════════════════ ; 정점 구조: [x, y, z, nx, ny, nz, u, v, r, g, b] 함수 real정점(x, y, z, nx, ny, nz, u, v, r, g, b) { 변수 정점 = [] 정점 = 추가(정점, x) 정점 = 추가(정점, y) 정점 = 추가(정점, z) 정점 = 추가(정점, nx) 정점 = 추가(정점, ny) 정점 = 추가(정점, nz) 정점 = 추가(정점, u) 정점 = 추가(정점, v) 정점 = 추가(정점, r) 정점 = 추가(정점, g) 정점 = 추가(정점, b) 반환 정점 } ; MVP 정점 변환 (배치) → 스크린 좌표 [sx, sy, sz, sw, 색상] 함수 real정점변환(정점, mvp, 조명방향, 앰비언트, 화면너비, 화면높이) { 변수 반너비 = 화면너비 / 2 변수 반높이 = 화면높이 / 2 변수 위치 = 벡터3(정점[0], 정점[1], 정점[2]) 변수 변환 = 행렬벡터곱(mvp, 위치) 변수 w = 변환[3] ; w <= 0 이면 클리핑 만약 (w <= 1) { 반환 [-1, -1, 0, 0, 0] } ; NDC 변수 nx = 변환[0] * 1000 / w 변수 ny = 변환[1] * 1000 / w 변수 nz = 변환[2] * 1000 / w ; 스크린 좌표 변수 sx = (nx + 1000) * 반너비 / 1000 변수 sy = (1000 - ny) * 반높이 / 1000 ; 라이팅 (N dot L) 변수 법선 = 벡터3(정점[3], 정점[4], 정점[5]) 변수 반전조명 = 벡터3(0 - 조명방향[0], 0 - 조명방향[1], 0 - 조명방향[2]) 변수 ndotl = 벡터내적(법선, 반전조명) 만약 (ndotl < 0) { ndotl = 0 } 변수 밝기 = 앰비언트 + ndotl 만약 (밝기 > 1000) { 밝기 = 1000 } ; 색상 (R*밝기) 변수 cr = 정점[8] * 밝기 / 1000 변수 cg = 정점[9] * 밝기 / 1000 변수 cb = 정점[10] * 밝기 / 1000 변수 색상 = cr * 65536 + cg * 256 + cb 반환 [sx, sy, nz, w, 색상] } ; 배치 정점 변환 함수 real정점배치변환(정점배열, mvp, 조명, 앰비언트, 너비, 높이) { 변수 결과 = [] 변수 i = 0 동안 (i < 길이(정점배열)) { 변수 변환됨 = real정점변환(정점배열[i], mvp, 조명, 앰비언트, 너비, 높이) 결과 = 추가(결과, 변환됨) i = i + 1 } 반환 결과 } ; ══════════════════════════════════════ ; 타일 기반 래스터라이저 (Metal TBDR 대체) ; ══════════════════════════════════════ ; 타일맵 생성 함수 real타일맵생성(화면너비, 화면높이) { 변수 열수 = 화면너비 / _R타일크기 만약 (화면너비 % _R타일크기 > 0) { 열수 = 열수 + 1 } 변수 행수 = 화면높이 / _R타일크기 만약 (화면높이 % _R타일크기 > 0) { 행수 = 행수 + 1 } 변수 타일맵 = 맵생성() 타일맵 = 맵넣어(타일맵, "열수", 열수) 타일맵 = 맵넣어(타일맵, "행수", 행수) 타일맵 = 맵넣어(타일맵, "너비", 화면너비) 타일맵 = 맵넣어(타일맵, "높이", 화면높이) ; 타일별 삼각형 인덱스 목록 (초기 빈 배열) 변수 타일들 = [] 변수 총수 = 열수 * 행수 변수 i = 0 동안 (i < 총수) { 타일들 = 추가(타일들, []) i = i + 1 } 타일맵 = 맵넣어(타일맵, "타일들", 타일들) 반환 타일맵 } ; 삼각형을 타일에 빈닝 함수 real타일빈닝(타일맵, 변환정점들) { 변수 열수 = 맵꺼내(타일맵, "열수") 변수 행수 = 맵꺼내(타일맵, "행수") 변수 화면너비 = 맵꺼내(타일맵, "너비") 변수 화면높이 = 맵꺼내(타일맵, "높이") 변수 타일들 = 맵꺼내(타일맵, "타일들") 변수 삼각형수 = 길이(변환정점들) / 3 변수 ti = 0 동안 (ti < 삼각형수) { 변수 i0 = ti * 3 변수 v0 = 변환정점들[i0] 변수 v1 = 변환정점들[i0 + 1] 변수 v2 = 변환정점들[i0 + 2] ; w <= 0 이면 스킵 만약 (v0[3] > 0) { 만약 (v1[3] > 0) { 만약 (v2[3] > 0) { ; 바운딩 박스 변수 최소x = v0[0] 만약 (v1[0] < 최소x) { 최소x = v1[0] } 만약 (v2[0] < 최소x) { 최소x = v2[0] } 변수 최대x = v0[0] 만약 (v1[0] > 최대x) { 최대x = v1[0] } 만약 (v2[0] > 최대x) { 최대x = v2[0] } 변수 최소y = v0[1] 만약 (v1[1] < 최소y) { 최소y = v1[1] } 만약 (v2[1] < 최소y) { 최소y = v2[1] } 변수 최대y = v0[1] 만약 (v1[1] > 최대y) { 최대y = v1[1] } 만약 (v2[1] > 최대y) { 최대y = v2[1] } 만약 (최소x < 0) { 최소x = 0 } 만약 (최소y < 0) { 최소y = 0 } 만약 (최대x >= 화면너비) { 최대x = 화면너비 - 1 } 만약 (최대y >= 화면높이) { 최대y = 화면높이 - 1 } ; 겹치는 타일 범위 변수 시작tx = 최소x / _R타일크기 변수 끝tx = 최대x / _R타일크기 변수 시작ty = 최소y / _R타일크기 변수 끝ty = 최대y / _R타일크기 만약 (끝tx >= 열수) { 끝tx = 열수 - 1 } 만약 (끝ty >= 행수) { 끝ty = 행수 - 1 } 변수 ty = 시작ty 동안 (ty <= 끝ty) { 변수 tx = 시작tx 동안 (tx <= 끝tx) { 변수 idx = ty * 열수 + tx 만약 (idx < 길이(타일들)) { 변수 목록 = 타일들[idx] 목록 = 추가(목록, ti) 타일들 = 설정(타일들, idx, 목록) } tx = tx + 1 } ty = ty + 1 } } } } ti = ti + 1 } 타일맵 = 맵넣어(타일맵, "타일들", 타일들) 반환 타일맵 } ; ══════════════════════════════════════ ; 프레임버퍼 + Z-버퍼 ; ══════════════════════════════════════ 함수 real프레임버퍼생성(너비, 높이) { 변수 fb = 맵생성() fb = 맵넣어(fb, "너비", 너비) fb = 맵넣어(fb, "높이", 높이) 변수 크기 = 너비 * 높이 변수 픽셀 = [] 변수 깊이 = [] 변수 i = 0 동안 (i < 크기) { 픽셀 = 추가(픽셀, 0) 깊이 = 추가(깊이, 999999) i = i + 1 } fb = 맵넣어(fb, "픽셀", 픽셀) fb = 맵넣어(fb, "깊이", 깊이) 반환 fb } ; 프레임버퍼 클리어 함수 real프레임클리어(fb, 색상) { 변수 크기 = 맵꺼내(fb, "너비") * 맵꺼내(fb, "높이") 변수 픽셀 = 맵꺼내(fb, "픽셀") 변수 깊이 = 맵꺼내(fb, "깊이") 변수 i = 0 동안 (i < 크기) { 픽셀 = 설정(픽셀, i, 색상) 깊이 = 설정(깊이, i, 999999) i = i + 1 } fb = 맵넣어(fb, "픽셀", 픽셀) fb = 맵넣어(fb, "깊이", 깊이) 반환 fb } ; 단일 픽셀 쓰기 (깊이 테스트 포함) 함수 real픽셀쓰기(fb, x, y, z, 색상) { 변수 너비 = 맵꺼내(fb, "너비") 변수 높이 = 맵꺼내(fb, "높이") 만약 (x < 0) { 반환 fb } 만약 (y < 0) { 반환 fb } 만약 (x >= 너비) { 반환 fb } 만약 (y >= 높이) { 반환 fb } 변수 idx = y * 너비 + x 변수 깊이 = 맵꺼내(fb, "깊이") 만약 (z < 깊이[idx]) { 변수 픽셀 = 맵꺼내(fb, "픽셀") 픽셀 = 설정(픽셀, idx, 색상) 깊이 = 설정(깊이, idx, z) fb = 맵넣어(fb, "픽셀", 픽셀) fb = 맵넣어(fb, "깊이", 깊이) } 반환 fb } ; ══════════════════════════════════════ ; 타일 래스터라이저 (삼각형 래스터화) ; ══════════════════════════════════════ ; 단일 타일 래스터 (백페이스 컬링 + 무게중심 좌표) 함수 real타일래스터(fb, 타일x, 타일y, 타일너비, 타일높이, 변환정점들, 삼각형인덱스) { 변수 그린수 = 0 변수 ti = 0 동안 (ti < 길이(삼각형인덱스)) { 변수 삼각형idx = 삼각형인덱스[ti] 변수 i0 = 삼각형idx * 3 만약 (i0 + 2 < 길이(변환정점들)) { 변수 v0 = 변환정점들[i0] 변수 v1 = 변환정점들[i0 + 1] 변수 v2 = 변환정점들[i0 + 2] ; 백페이스 컬링 (면적 < 0 이면 뒷면) 변수 면적 = (v1[0] - v0[0]) * (v2[1] - v0[1]) - (v1[1] - v0[1]) * (v2[0] - v0[0]) 만약 (면적 > 0) { ; 타일 내 바운딩 박스 변수 최소x = v0[0] 만약 (v1[0] < 최소x) { 최소x = v1[0] } 만약 (v2[0] < 최소x) { 최소x = v2[0] } 만약 (최소x < 타일x) { 최소x = 타일x } 변수 최대x = v0[0] 만약 (v1[0] > 최대x) { 최대x = v1[0] } 만약 (v2[0] > 최대x) { 최대x = v2[0] } 변수 타일우 = 타일x + 타일너비 - 1 만약 (최대x > 타일우) { 최대x = 타일우 } 변수 최소y = v0[1] 만약 (v1[1] < 최소y) { 최소y = v1[1] } 만약 (v2[1] < 최소y) { 최소y = v2[1] } 만약 (최소y < 타일y) { 최소y = 타일y } 변수 최대y = v0[1] 만약 (v1[1] > 최대y) { 최대y = v1[1] } 만약 (v2[1] > 최대y) { 최대y = v2[1] } 변수 타일하 = 타일y + 타일높이 - 1 만약 (최대y > 타일하) { 최대y = 타일하 } ; 무게중심 래스터 변수 역면적 = 1000000 / 면적 변수 py = 최소y 동안 (py <= 최대y) { 변수 px = 최소x 동안 (px <= 최대x) { 변수 bw0 = ((v1[0] - px) * (v2[1] - py) - (v1[1] - py) * (v2[0] - px)) * 역면적 / 1000 변수 bw1 = ((v2[0] - px) * (v0[1] - py) - (v2[1] - py) * (v0[0] - px)) * 역면적 / 1000 변수 bw2 = 1000 - bw0 - bw1 만약 (bw0 >= 0) { 만약 (bw1 >= 0) { 만약 (bw2 >= 0) { ; 깊이 보간 변수 z = (bw0 * v0[2] + bw1 * v1[2] + bw2 * v2[2]) / 1000 fb = real픽셀쓰기(fb, px, py, z, v0[4]) 그린수 = 그린수 + 1 } } } px = px + 1 } py = py + 1 } } } ti = ti + 1 } 반환 fb } ; ══════════════════════════════════════ ; 계층적 Z-버퍼 (Early-Z 대체) ; ══════════════════════════════════════ 함수 real_HZ생성(너비, 높이) { 변수 열수 = 너비 / _R타일크기 만약 (너비 % _R타일크기 > 0) { 열수 = 열수 + 1 } 변수 행수 = 높이 / _R타일크기 만약 (높이 % _R타일크기 > 0) { 행수 = 행수 + 1 } 변수 hz = 맵생성() hz = 맵넣어(hz, "열수", 열수) hz = 맵넣어(hz, "행수", 행수) 변수 최소z = [] 변수 i = 0 동안 (i < 열수 * 행수) { 최소z = 추가(최소z, 999999) i = i + 1 } hz = 맵넣어(hz, "최소z", 최소z) 반환 hz } 함수 real_HZ갱신(hz, tx, ty, z) { 변수 열수 = 맵꺼내(hz, "열수") 변수 idx = ty * 열수 + tx 변수 최소z = 맵꺼내(hz, "최소z") 만약 (idx < 길이(최소z)) { 만약 (z < 최소z[idx]) { 최소z = 설정(최소z, idx, z) hz = 맵넣어(hz, "최소z", 최소z) } } 반환 hz } 함수 real_HZ보이는가(hz, tx, ty, 삼각형최대z) { 변수 열수 = 맵꺼내(hz, "열수") 변수 idx = ty * 열수 + tx 변수 최소z = 맵꺼내(hz, "최소z") 만약 (idx < 길이(최소z)) { 만약 (삼각형최대z <= 최소z[idx] + 1) { 반환 1 } 반환 0 } 반환 1 } ; ══════════════════════════════════════ ; 텍스처 시스템 (Metal MTLTexture 대체) ; ══════════════════════════════════════ 함수 real텍스처생성(너비, 높이, 채우기색상) { 변수 텍스처 = 맵생성() 텍스처 = 맵넣어(텍스처, "너비", 너비) 텍스처 = 맵넣어(텍스처, "높이", 높이) 변수 픽셀 = [] 변수 i = 0 동안 (i < 너비 * 높이) { 픽셀 = 추가(픽셀, 채우기색상) i = i + 1 } 텍스처 = 맵넣어(텍스처, "픽셀", 픽셀) 텍스처 = 맵넣어(텍스처, "필터", "최근접") 반환 텍스처 } ; 체커보드 텍스처 (디버그용) 함수 real텍스처체커(너비, 높이, 색1, 색2, 타일) { 변수 텍스처 = real텍스처생성(너비, 높이, 색1) 변수 픽셀 = 맵꺼내(텍스처, "픽셀") 변수 y = 0 동안 (y < 높이) { 변수 x = 0 동안 (x < 너비) { 변수 tx = (x / 타일) % 2 변수 ty = (y / 타일) % 2 만약 (tx != ty) { 변수 idx = y * 너비 + x 픽셀 = 설정(픽셀, idx, 색2) } x = x + 1 } y = y + 1 } 텍스처 = 맵넣어(텍스처, "픽셀", 픽셀) 반환 텍스처 } ; 텍스처 샘플링 (UV, 최근접) 함수 real텍스처샘플(텍스처, u, v) { 변수 너비 = 맵꺼내(텍스처, "너비") 변수 높이 = 맵꺼내(텍스처, "높이") 변수 x = u * 너비 / 1000 만약 (x < 0) { x = 0 } 만약 (x >= 너비) { x = 너비 - 1 } 변수 y = v * 높이 / 1000 만약 (y < 0) { y = 0 } 만약 (y >= 높이) { y = 높이 - 1 } 변수 픽셀 = 맵꺼내(텍스처, "픽셀") 반환 픽셀[y * 너비 + x] } ; ══════════════════════════════════════ ; 스왑체인 (DX12 IDXGISwapChain / Metal CAMetalDrawable) ; ══════════════════════════════════════ 함수 real스왑체인생성(너비, 높이, 버퍼수) { 변수 sc = 맵생성() sc = 맵넣어(sc, "너비", 너비) sc = 맵넣어(sc, "높이", 높이) sc = 맵넣어(sc, "버퍼수", 버퍼수) sc = 맵넣어(sc, "현재", 0) 변수 버퍼들 = [] 변수 i = 0 동안 (i < 버퍼수) { 버퍼들 = 추가(버퍼들, real프레임버퍼생성(너비, 높이)) i = i + 1 } sc = 맵넣어(sc, "버퍼들", 버퍼들) 반환 sc } 함수 real스왑(sc) { 변수 현재 = 맵꺼내(sc, "현재") 변수 버퍼수 = 맵꺼내(sc, "버퍼수") sc = 맵넣어(sc, "현재", (현재 + 1) % 버퍼수) 반환 sc } 함수 real현재버퍼(sc) { 변수 현재 = 맵꺼내(sc, "현재") 변수 버퍼들 = 맵꺼내(sc, "버퍼들") 반환 버퍼들[현재] } ; ══════════════════════════════════════ ; 병렬 프레임 렌더 (전체 파이프라인) ; ══════════════════════════════════════ ; 씬 렌더 — 오브젝트 배열 → 프레임버퍼 출력 함수 real프레임렌더(장치, fb, 오브젝트들, mvp, 조명, 앰비언트) { 변수 너비 = 맵꺼내(fb, "너비") 변수 높이 = 맵꺼내(fb, "높이") 변수 전체정점 = [] 변수 렌더수 = 0 변수 스킵수 = 0 변수 총삼각형 = 0 ; 1단계: 4상 컬링 — 렌더할 오브젝트 필터 변수 i = 0 동안 (i < 길이(오브젝트들)) { 변수 obj = 오브젝트들[i] 변수 가시성 = 맵꺼내(obj, "가시성") 변수 활성 = 맵꺼내(obj, "활성") 만약 (활성 == 1) { 만약 (real렌더해야(가시성) == 1) { ; 이 오브젝트의 삼각형 수집 (데모: 단일 삼각형) 변수 위치 = 맵꺼내(obj, "위치") 변수 반지름 = 맵꺼내(obj, "반지름") ; LOD에 따라 정점 수 조절 변수 lod = real_LOD(가시성) 변수 크기 = 반지름 만약 (lod == 1) { 크기 = 반지름 * 800 / 1000 } 만약 (lod == 2) { 크기 = 반지름 * 500 / 1000 } ; 단순 삼각형 생성 (프로토타입) 변수 v0 = real정점(위치[0], 위치[1] + 크기, 위치[2], 0, 1000, 0, 500, 0, 맵꺼내(obj, "id") * 30 % 256, 200, 100) 변수 v1 = real정점(위치[0] - 크기, 위치[1] - 크기, 위치[2], 0, 1000, 0, 0, 1000, 맵꺼내(obj, "id") * 30 % 256, 200, 100) 변수 v2 = real정점(위치[0] + 크기, 위치[1] - 크기, 위치[2], 0, 1000, 0, 1000, 1000, 맵꺼내(obj, "id") * 30 % 256, 200, 100) 전체정점 = 추가(전체정점, v0) 전체정점 = 추가(전체정점, v1) 전체정점 = 추가(전체정점, v2) 렌더수 = 렌더수 + 1 총삼각형 = 총삼각형 + 1 } 아니면 { 스킵수 = 스킵수 + 1 } } i = i + 1 } ; 2단계: 정점 변환 (배치) 변수 변환됨 = real정점배치변환(전체정점, mvp, 조명, 앰비언트, 너비, 높이) ; 3단계: 타일 빈닝 변수 타일맵 = real타일맵생성(너비, 높이) 타일맵 = real타일빈닝(타일맵, 변환됨) ; 4단계: 타일별 래스터 (병렬 시뮬레이션 — VM에서는 순차) 변수 열수 = 맵꺼내(타일맵, "열수") 변수 행수 = 맵꺼내(타일맵, "행수") 변수 타일들 = 맵꺼내(타일맵, "타일들") 변수 ty = 0 동안 (ty < 행수) { 변수 tx = 0 동안 (tx < 열수) { 변수 idx = ty * 열수 + tx 변수 삼각형목록 = 타일들[idx] 만약 (길이(삼각형목록) > 0) { 변수 타일왼 = tx * _R타일크기 변수 타일위 = ty * _R타일크기 변수 타일폭 = _R타일크기 변수 타일높 = _R타일크기 만약 (타일왼 + 타일폭 > 너비) { 타일폭 = 너비 - 타일왼 } 만약 (타일위 + 타일높 > 높이) { 타일높 = 높이 - 타일위 } fb = real타일래스터(fb, 타일왼, 타일위, 타일폭, 타일높, 변환됨, 삼각형목록) } tx = tx + 1 } ty = ty + 1 } ; 5단계: 통계 갱신 변수 프레임 = 맵꺼내(장치, "프레임") 장치 = 맵넣어(장치, "프레임", 프레임 + 1) 장치 = 맵넣어(장치, "총삼각형", 맵꺼내(장치, "총삼각형") + 총삼각형) 반환 fb } ; ══════════════════════════════════════ ; 통계 출력 ; ══════════════════════════════════════ 함수 real통계(장치) { 출력값("═══ CrownyReal 엔진 통계 ═══") 출력값("장치: " + 맵꺼내(장치, "이름")) 출력값("백엔드: " + 맵꺼내(장치, "백엔드")) 출력값("코어: " + 문자열변환(맵꺼내(장치, "코어수"))) 출력값("프레임: " + 문자열변환(맵꺼내(장치, "프레임"))) 출력값("총삼각형: " + 문자열변환(맵꺼내(장치, "총삼각형"))) 출력값("4상 가시성: 확정=" + 문자열변환(_R확정) + " 미확인=" + 문자열변환(_R미확인) + " 오해=" + 문자열변환(_R오해) + " 미인지=" + 문자열변환(_R미인지)) }