아일렛 온라인에서 사용한 블럭 렌더링 소개
TRANSCRIPT
아일렛 온라인에 적용된 블록 렌더링 기술
발표자 소개
김정만 ㈜ 모래노리 소프트 대표이사 아일렛 온라인 프로그래밍 총괄 건국대학교 전자공학부 졸업
아일렛 온라인
2016 년 2 월 스팀 얼리억세스 출시2015 년 하반기 스팀 그린라이트 통과
발표 내용 소개구현 결과
렌더링된 결과물에 대한 소개
쉐이더
버텍스 압축 , 텍스처 레이어
폴리곤 구축
은면 제거 , 라이팅 계산
구현 결과
Shader
Shader
Vertex
X, Y, ZNormal
UV
Lighting
Normal, Static Lighting
Texture Layer
Diffuse Map , Cloud Map, Mask Map
Block
Blocks(Position+Normal+UV)
• 128mx128m 을 한번에 그리기– 128 x 128 x (6*4) = 39,3216– Position + Normal + UV
• 39,3216 x ( 12 + 12 + 8 ) = 12MBytes
• 256mx256m 을 한번에 그리기– 256 x 256 x 24 x 32bytes = 48MBytes– 256 x 256 x 16( 높이 ) = 48MB * 16 = 768MB !!!!!
• 실제 렌더링 될 때에는 은면을 제거하면 더 줄일 수 있다 ..
Blocks ( Case 1 )
Vertex : 2,277,668 Polygon : 113 만개
Vertex Memory2,277,668 * 32 = 69MB
Vertex Compression Memory2,277,668 * 8 = 17MB
Blocks ( Case 2 )
Vertex : 2,480,783Polygon : 113 만개
Vertex Memory2,480,783 * 32 = 75MB
Vertex Compression Memory2,480,783 * 8 = 18MB
Position DataFloat, Float, Float
4byte + 4 byte + 4 byte = 12 byte일반적으로 사용되는 Local 좌표계에서의 위치WorldMat * ViewMat * ProjectionMat ….
Byte, Byte, Byte ( with Chunk )만약 블록을 특정 영역만큼 나누어 그린다면 , 더 적은 Byte 로 렌더링이 가능 .
( 예 , 255x255x255 ) 1 + 1 + 1 = 3byte
Byte, Byte( 16^3 blocks )
한 개의 영역을 더 작게 16 개 단위로 분쇄하면 더욱 더 적은 비트로 표현이 가능하지만 16x16x16 에는 0~16 으로 17 을 표현을 필요로 하므로 4 비트로 쪼갤 수 없다 .
Position Data5bit, 5bit, 5bit
0~16 을 표현하기 위해서는 Component 당 5bit 가 필요 ( 0b10000 )X(1byte), Y(1byte), Z(1byte)
Normal ( 3bit )남는 3bit 로 표현 가능한 수는 0b000~0b111 로 0~7
육면체 모델의 특성상 Normal 은 6 방향만 필요 ( -X, -Y, -Z )~(X, Y, Z )
Tile Position ( 3bit )
Diffuse Map 을 16x16 등분으로 나누어 1 바이트에 담은 경우 , 각 사각형 면당 모서리 정보가 추가적으로 필요( 좌측상단 , 우측상단 , 좌측하단 , 우측하단 )
Position DataTile Map
16 x 16 칸으로 이루어진 타일 맵을 기본 Diffuse Map 으로 구성최대 255 가지의 블록을 표현이 가능
Tile X, Y
타일의 경우에는 0~15 까지 딱 16x16 으로 구성이 가능하기 때문에 1 바이트에 기록이 가능 , 이를 X, Y, Z, W 중 1 바이트로 기록 .
Vertex Format ( X, Y, Z, W = 4byte )
X = pos X + normal Y = pos Y + Tile Corner
Z = pos Z W = U + V
Extra Data
• 1Byte 정적 라이팅 계산 값 ( 블록 차폐 )• 1Byte 높이값 ( 반블럭 ) • 1Byte 윗면 여부 ( 구름 그림자용 )• 1Byte 더미• Position Data(4Byte) + Extra Data(4Byte)
For Mobile?
• GLES 2.0 이상에서 테스트• 삼성 갤럭시 1 과 LG G3 에서 테스트 완료
– 갤럭시 1 의 경우 SHADER VERSION 1.0 으로 인식
Texture Layer
Texture Layer
• Diffuse 2048x2048 32bit• Specular 2048x2048 32bit• Mask Map1024x1024 32bit
( RGB =Color, Alpha = Cloud Shadow )
• Shadow Map 1024x1024 32bit(float)
• For Android 50% resizing
Alpha & Water• 기본적으로 두 번씩 DP CALL 을 호출
( CW, CCW )
폴리곤 구축
ChunksChunk
기본적으로 16x16x16 크기의 정육면체 크기의 청크로 DP CALL 이 구분
Culling
Octree 를 이용하여 , 기본적인 Chunk 에 대한 Frustum Culling 을 실시 .
DP CALL
1 개의 청크는 불투명 블록 , 투명 블록 , 풀 (Grass), 물 (Water) 로 나뉘며 , 최대 총 6
번의 DP CALL 이 발생
은면제거• 1. 겹쳐져 있는 폴리곤을 우선 적으로 제거 .
– 기본적으로 배열 형식으로 되어 있기 때문에 쉽게 인접한 면의 여부를 파악할 수 있다 .– 현재 블록의 윗면과 윗쪽 블록의 아랫면을 비교하는 식으로 처리한다 . – 반블럭 (Half) 등을 위해서 양 옆은 높이 값도 같이 비교
• 2. 모든 면이 인접해 있다면 렌더링에서 완전히 배제
• 3. 반복하여 처리하면 내부 공간이 모두 채워져 있는 경우 , 렌더링에서 배제가 된다 .
라이팅 계산• 정적 라이팅 (Static Lighting)
– 오브젝트 ( 전등 ) 이나 차폐에 의한 어두워지는 현상– 라이트의 변화가 크게 없는 경우– CPU 단에서 미리 연산– Per Vertex Lighting
• 동적 라이팅 (Dynamic Lighting)– 라이트의 변화가 자주 일어나며 , 캐릭터의 횃불 같은 경우– 쉐이더에 의해 GPU 에서 연산– Per Pixel Lighting
• 지역 라이팅– Ambient + Diffuse + Specular– 시간 변화에 따른 변화– Per Vertex Lighting 연산
정적 라이팅• 기본적으로 Face 단위로 라이팅을 연산• 인접한 정점의 라이팅을 위해서 같은 면이라도 다른 밝기 값을 주어 더욱 깊이감을 표현
• 1 차적으로 은폐 여부를 파악– 태양광에서 부터 Ray 를 쏘았을때 Face 가 충돌하는가 ?– 해당 Face 의 Normal 방향으로 전진하였을때 태양광이 미치는 거리는 ?– 이때 블록은 정수 배열로 되어 있으므로 , 브레젠험의 라인 공식을 사용
• 2 차적으로 주위 Point Light 로 부터 라이팅을 연산
Block
동적 라이팅• Shader 에서 직접 연산
( 최대 4 개까지 1 회 DP CALL 당 처리 )
• 16x16x16 내에서 많은 Light 는 결국 전체적으로 밝아지는 효과가 있음 .
• Light 가 최대치를 넘은 경우 ,인접한 Light 끼리는 병합하여처리 .
Multi Threading
• 위에 까지 나온 모든 처리는 Multi Thread 로 연산• Lock/Unlock 을 최대한 줄이기 위하여 , 메모리를 최대한 독립적으로 사용 .
• 만약 지형의 변화가 없다면 , 미리 빌드된 정보를 읽어와서 바로 처리하는 것이 효과적 .
• 아일렛의 경우 서버로 부터 모든 정보를 갱신 받기 때문에 주기적으로 쓰레드를 사용하여 다시 빌드 .
Q / A
Thank You