첫 질문은 단순한 질문에서 시작하였습니다. 가장 권장할만 하고, 가장 추천해야 할 쉐이더는 무엇인가?
어떤 쉐이더를 사용해야 PC에서도, 아이폰에서도 만족할 만한 속도와 품질과 편리함을 가지고 있는 쉐이더인가?
물론 라이팅은 하나도 안 하고 텍스쳐만 딸랑 출력하는 Unlit 쉐이더가 가장 빠르겠지만, 라이트가 적용되는 최고 속도의 쉐이더는 알려진 바와 같이 정말 Diffuse Fast 인가? 라고 하는 것입니다. 즉 이 쉐이더가 결정되면, 모든 쉐이더를 어떤 방식으로 쉐이더를 작성해야 하는지에 대한 기초적인 기반이 정립되게 되는 것입니다. 덕분에 영향받는게 꽤 있지요.
물론 PC에서 이론적으로는 Diffuse Fast가 가장 빠른 것이 사실입니다. 라이팅 연산을 할 때 버텍스로 연산하는 것이, 픽셀별로 라이팅 하는 것보다 느릴리 없겠죠.
그리고 다른 얘긴데 사실,
Diffuse Fast 쉐이더를 열어보면
// Does not do anything in 3.x
Shader “Legacy Shaders/Diffuse Fast” {
Properties {
_Color (“Main Color”, Color) = (1,1,1,1)
_MainTex (“Base (RGB)”, 2D) = “white” {}
}
Fallback “VertexLit”
}

… 야
우스운게, 자체적 쉐이더가 있는게 아니라 vertexlit 쉐이더로 값만 대충 넘기는 방식을 사용하고 있습니다.
이거 완전 사기잖아. 뭐 그건 그렇다 치고..
그래서 무식하게 테스트부터 시작해 보았습니다. 텍스쳐 입힌 Sphere 64개 !!!
간단하게 생각해도 DP call만 64개를 사용하는 (아이폰에서 권장하는 DPcall은 30개 정도) 오브젝트입니다.
굉장히 무거운 상태죠.
이 데이터를 그대로 아이폰 3GS 로 빌드해서 프레임을 테스트 해 보았습니다.
Diffuse fast (Vertexlit) : 17 프레임

Diffuse : 29.75 프레임

….읭?
자, 잠깐. 지금 DP call 한계를 2배나 벗어났다고! 30프레임 가까이 나오면 어떡하자는거야!!!
하도 이상해서 simple verex light shader를 직접 제작해서 넣어 봤습니다.
버텍스 라이팅에서 이보다 빠른 쉐이더는 만들 수 없습니다.
http://www.unifycommunity.com/wiki/index.php?title=Simply_Lit
Shader “Simply Lit” {
Properties {
_Color (“Color”, Color) = (1,1,1)
_MainTex (“Texture”, 2D) = ""
}
SubShader {
Lighting On
Material {
Ambient [_Color]
Diffuse [_Color]
}
Pass {
SetTexture [_MainTex] {Combine texture * primary Double}
}
}
}

그래도 15프레임….
의읭????????????????
뭔가 헷갈립니다. 분명히 버텍스 라이팅이 라이팅 연산에서 빠르다는 것이 일반적 상식인데, 그 상식이 통용되지 않습니다.
어째서 픽셀 라이팅이 버텍스 라이팅보다 두 배나 빠른거야???????
간단하게 끝났어야 할 실험이 미궁으로 빠져듭니다. 이대로라면 캐릭터 쉐이더도 다르게 짜는 것이 좋고.. (사실 픽셀 라이팅 방식은 서피스 쉐이더 방식이라, 여러 가지 효과를 줄 때 편합니다… )
그래서 각종 가정을 해 보았습니다.
- 엔진이 미쳤다.
- 사실 아이폰은 픽셀쉐이더가 빠르다.
- 알파 테스팅이 더 느리다고 하는 아이폰이니 그럴 수도 있다.
그렇게 원인을 찾아 떠돌다가 찾은 문서.
http://developer.apple.com/library/ios/#documentation/3DDrawing/Conceptual/OpenGLES_ProgrammingGuide/OpenGLESPlatforms/OpenGLESPlatforms.html
Another advantage of deferred rendering is that it allows the GPU to perform hidden surface removal before fragments are processed. Pixels that are not visible are discarded without sampling textures or performing fragment processing,
디퍼드 렌더러의 장기는 픽셀 처리 하기 전에 안보이는 면 날려버리는 건데유, 안보이는 픽셀은 과감히 내쳐서 텍스쳐 셈플링도 안하고 픽셀 쉐이더 처리도 안해유.
… 오호라.
아이폰에 들어가 있는 PowerVR SGX Platform 은 Tile-Based Deferred Rendering 라고 하는 ‘지연 렌더링 방식’을 사용하고 있는데요.
디퍼드 렌더러(지연 렌더러)란 라이트 연산을 위해 모든 오브젝트를 버퍼에 렌더링 해 놓고 몰아서 한 번에 라이팅 처리해 버리는 방식이라, 특성상 버텍스 라이팅을 강제로 사용하면 포워드 렌더링 처럼 돌아가니까… 덕분에 숨겨진 버텍스를 처리 못하는게 아닌가… 라는 가정이 생기게 되었습니다.
즉 그렇게 되면 저 예제들처럼 ‘가려진 면이 많은 경우’ 에서는 버텍스 라이팅이 픽셀라이팅보다 더 안좋은 퍼포먼스를 낼 수 밖에 없다는 것이지요.
물론 전 그래픽 디자이너 출신인데다가 아이폰에서 돌아가는 Tile-Based Deferred Rendering 에 대해서 더 깊이 파지 않은 상태에서 한 생각이기 때문에 어디까지나 ‘가정’ 이지만 말이죠. (예를 들어, ‘그럼 왜 여러 개 라이팅을 다이나믹으로 쓰는건 안되는거야? ’ 라고 질문하면 할말이 없지요 켈켈켈 )
어쨌건 그 원인을 찾는건 모바일 팀에서 찾을 일이고(윤과장님에게 패스), 저야 여기까지 조사해서 현실적 결론을 내리면 거기까지가 임무인지라 - 시간도 없는데 한도 끝도 없이 팔 수도 없고. 이미 반나절이 넘게 지났다고요. - 어쨌건 위의 가정대로라면 ‘가려진 면이 없으면 Diffuse Fast (Vertexlit) 이 조금이라도 더 빠르지 않느냐 라는 생각이 또 떠올라서 간략하게 테스트 해 보았습니다.
이미 이것때문에 시간을 많이 써버린 상태라 더 복잡하게는 못하고, 간락하게 조건을 살짝 바꿔서 테스트 해 본 결과,
공을 커다랗게 하나만 만들어 테스트 (버텍스 쉐이더 부담은 줄이고 픽셀쉐이더에게만 부담주기죠)
Diffuse Fast : 30.03 프레임

Diffuse : 29.46 프레임
뭐 일단 오차범위. 별 차이는 없군요. 가려진 면이 여전히 많아서 그런 걸까요?
한번 더 테스트
Diffuse Fast : 24.43

Diffuse : 26.95 프레임(오차범위)

여기서도 큰 차이를 발견할 수는 없었습니다. 약 10% 내외는 오차범위로 왔다갔다 하기 때문에 2-3 프레임씩의 차이는 확실한 차이라고 보기 힘듭니다. 여기서도 Diffuse 쉐이더는 전혀 느리지 않았습니다.
======================================================================================================
물론 여기에도 이슈는 있습니다. 윤과장님 테스트에 의하면 지형에 한해서는 Diffuse Fast가 약간 더 빠르게 나왔다는 테스트 보고도 있고, 3.2 에서는 Diffuse Fast가 사라지고 대신 Mobile 카테고리가 생기면서 거기 Vertexlit 쉐이더가 생겼습니다. (그래봤자 위에서 쓴 simple light랑 똑같을거라고 생각합니다만) 때문에 뭔가 조금 더 처리가 생기지 않았을까 하는 희박한 희망사항을 생각해 봅니다.
어쨌거나 결론적으로 정리하자면 다음과 같겠네요,
픽셀 라이팅 연산을 하는 Diffuse 쉐이더는 그렇게 무섭게 느린 쉐이더가 아닙니다.
캐릭터 처럼 겹치는 vertex가 많은 상태에서는 오히려 Diffuse Fast(Vertexlit) 보다 빠를 수도 있으며, 일반적인 경우에서도 대단한 차이가 나지 않습니다.
그러므로 모바일에서도 캐릭터에는 Diffuse 쉐이더를 써도 괜찮을 것 같습니다. (배경은 여전히 Diffuse Fast를 쓰세요. 사실 더 권장하는건 Unlit 쉐이더입니다만)