OpenGLES Programming Guide for iOS 번역 - 4장. OpenGL ES 드로잉
OpenGL ES/iOS 2011. 9. 21. 16:36본 번역은 얼마든지 정확하지 않을 수 있습니다. 참고용으로만 보시길... ^^;;;
이 장에서는 프레임 버퍼를 만들고 이미지를 프레임 버퍼에 렌더링하는 과정을 자세히 설명합니다. 프레임 버퍼 개체를 만들고 애니메이션을 실행하는 렌더링 루프의 구현 방법 및 Core Animation 사용에 관한 다양한 방법을 소개합니다. 마지막으로, Retina 디스플레이의 고해상도 이미지 렌더링 이미지 품질 향상을위한 멀티 샘플링 기능 사용, 외부 디스플레이에 이미지를 렌더링하는 OpenGL ES 사용 같은 고급 항목을 다룹니다.
렌더링 결과를 저장하는 프레임 버퍼 객체
OpenGL ES 스펙은 렌더링 이미지를 유지하는 프레임 버퍼를 만들고 응용프로그램이 사용할 수있는 메커니즘을 각 구현이 제공하는 것을 요구하고 있습니다. iOS 에서는 모든 프레임 버퍼가 프레임 버퍼 개체를 사용하여 구현됩니다. 프레임 버퍼 객체는 OpenGL ES 2.0 에 내장된 또는 iOS 의 모든 OpenGL ES 1.1 구현 GL_OES_framebuffer_object 확장 기능이 제공됩니다.
프레임 버퍼 개체를 사용하여 응용프로그램은 색상 깊이 및 스텐실 각 대상의 작성을 정밀하게 제어할 수 있습니다. 단일 컨텍스트 다중 프레임 버퍼 개체를 만들 수에서 프레임 버퍼간에 리소스를 공유할 수 있습니다.
프레임 버퍼를만드는 단계는 다음과 같습니다.
1. 프레임 버퍼 개체를 만듭니다.
2. 1개 이상의 대상 (렌더링 버퍼 또는 질감)을 만들고 저장소를 할당 프레임 버퍼 개체의 부착 지점에 스토리지를 각각 연결합니다.
3. 프레임 버퍼의 무결성을 테스트합니다.
응용프로그램은 실행하려는 작업에 따라 다른 개체를 설정하고 프레임 버퍼 객체에 연결합니다. 대부분의 경우 프레임 버퍼 설정의 차이는 프레임 버퍼 객체 색상 부착 포인트에 어떤 개체가 연결되는가하는 것입니다.
● 오프 스크린 이미지 처리 프레임 버퍼를 사용하는 경우 렌더링 버퍼를 연결합니다.
● 프레임 버퍼 이미지를 나중에 렌더링 단계의 입력으로 사용하려면 질감을 연결합니다.
● 프레임 버퍼를 사용자에게 표시하려는 경우, Core Animation 대응 특별한 렌더링 버퍼를 사용합니다.
오프 스크린 프레임 버퍼 객체 생성
오프 스크린 렌더링을 위한 프레임버퍼는 첨부 파일의 모든 OpenGL ES 렌더링 버퍼로 할당합니다.
다음 코드는 컬러와 깊이 첨부를 가진 프레임버퍼 객체를 할당합니다.
1. 프레임버퍼를 만들고 바인딩 합니다. (Create the framebuffer and bind it.)
GLuint framebuffer;
glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
2. 색상 렌더링버퍼를 만들고 스토리지를 할당하고, 프레임버퍼의 색상 부착지점에 스토리지를 연결합니다. (Create a color renderbuffer, allocate storage for it, and attach it to the framebuffer’s color attachment point.)
GLuint colorRenderbuffer;
glGenRenderbuffers(1, &colorRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRenderbuffer);
3. 깊이 또는 깊이/스텐실 렌더링 버퍼를 만들고 스토리지를 할당하고, 프레임버퍼의 깊이 첨부지점에 스토리지를 연결합니다. (Create a depth or depth/stencil renderbuffer, allocate storage for it, and attach it to the framebuffer’s depth attachment point.)
GLuint depthRenderbuffer;
glGenRenderbuffers(1, &depthRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, depthRenderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRenderbuffer);
4. 프레임버퍼의 무결성을 테스트합니다. 이 테스트는 프레임버퍼 설정이 변경된 경우에만 실행해야 합니다. (Test the framebuffer for completeness. This test only needs to be performed when the framebuffer’s configuration changes.)
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER) ;
if(status != GL_FRAMEBUFFER_COMPLETE) {
NSLog(@"failed to make complete framebuffer object %x", status);
}
프레임버퍼 객체를 사용하여 텍스처에 렌더링
이번 프레임버퍼를 만드는 코드는 오프스크린 예제와 같지만, 텍스처 할당 색상 부착지점에 연결된다는 점이 다릅니다.
1. 프레임버퍼 객체를 만듭니다. (앞선 설명과 같음)
2. 렌더링 대상 텍스처를 만들고, 텍스처를 프레임버퍼의 색상 부착지점에 연결합니다.
// 텍스처 만들기 GLuint texture; glGenTextures (1, & texture);
glBindTexture (GL_TEXTURE_2D, texture);
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
3. 깊이버퍼를 할당하고 연결합니다. (앞선 설명과 같음)
4. 프레임버퍼의 무결성을 테스트 합니다. (앞선 설명과 같음)
이 예제는 색상 텍스처에 렌더링을 전제로하고 있지만 다른 방법을 취할 수 있습니다.
예를 들어, OES_depth_texture 확장 기능을 사용하여 텍스처 심도 첨부 포인트에 연결하고 현장에서 얻은 깊이 정보를 텍스처에 저장할 수 있습니다. 이 심도 정보를 사용하여 최종적으로 렌더링되는 장면의 그림자를 계산할 수 있습니다.
Core Animation 레이어로 렌더링
OpenGL ES를 사용하여 그리는 응용프로그램의 대부분은 프레임 버퍼의 컨텐츠를 사용자에게 표시하려고 합니다.
iOS에서는 화면에 표시되는 모든 이미지를 Core Animation으로 처리합니다. 각 뷰의 후면에는보기에 대응하는 Core Animation 레이어가 있습니다. OpenGL ES는 특별한 Core Animation 계층인 CAEAGLLayer 통해 Core Animation 에 연결합니다. CAEAGLLayer 을 사용하여 OpenGL ES 렌더링 버퍼의 컨텐츠에 Core Animation 레이어 내용의 역할을 할 수 있습니다. 그러면 렌더링 버퍼 내용을 UIKit 와 Quartz 를 사용하여 렌더링된 콘텐츠를 포함하여 다른 컨텐츠와 함께 변환하거나 합성하거나 할 수 있습니다. Core Animation이 최종 이미지를 합성하면 최종 이미지는 장치의 기본 화면 또는 연결된 외부 디스플레이에 표시됩니다.
그림 4-1. Core Animation과 OpenGL ES와 렌더링 버퍼 공유
대부분의 경우 응용 프로그램이 CAEAGLLayer 개체를 직접 할당할 수 없습니다. 대신 응용 프로그램은 CAEAGLLayer 개체를 백업 레이어로 지정된 UIView의 서브 클래스를 정의합니다.
런타임에 응용 프로그램이 뷰를 인스턴스 렌더링 결과를 저장하는 프레임 버퍼 객체화하고 뷰를 뷰 계층에 배치합니다. 보기가 인스턴스화될 때 응용 프로그램은 OpenGL ES 컨텍스트를 초기화하고 Core Animation 에 연결 프레임 버퍼 개체를 만듭니다.
CAEAGLLayer는 EAGLDrawable 프로토콜을 구현하여 OpenGL ES에 지원 제공합니다. EAGLDrawable를 구현하는 객체는 EAGLContext 개체와 긴밀하게 협력합니다.
Drawable 개체는 2 개의 중요한 기능이 있습니다.
첫째는 렌더링 버퍼의 공유 스토리지를 할당할 수 있습니다.
둘째는 렌더링 버퍼의 컨텐츠를 표시하는 컨텍스트와 긴밀히 협력하는 것입니다.
렌더링 버퍼의 컨텐츠의 표시는 EAGL에 의해 대략적으로 정의되고 있습니다.
CAEAGLLayer 개체의 경우 렌더링 버퍼의 컨텐츠의 표시는, Core Animation의 그것까지 표시된 콘텐츠를 렌더링 버퍼의 내용을 옮겨놓는 것을 의미합니다. 이 모델의 장점은 Core Animation 레이어의 내용을 프레임마다 렌더링하는 필요없이 렌더링된 이미지가 실제로 변화하는 경우에만 렌더링하면 된다는 것입니다.
OpenGL ES 대응 뷰를 만드는 데 사용하는 절차는 다음과 같습니다. Xcode 에서 제공하는 OpenGL ES 템플릿을 사용하면 자신에서 다음 코드를 구현할 필요는 없습니다.
1. UIView 를 서브 클래스 화해, iOS 응용 프로그램 OpenGL ES 보기를 만듭니다.
2. layerClass 메서드를 재정의하고 기본 레이어로 CAEAGLLayer 개체보기를 만들도록 합니다. 이것을 실행하려면 layerClass 메서드를 사용하여 CAEAGLLayer 클래스를 반환합니다.
+ (Class) layerClass
{
return [CAEAGLLayer class];
}
3. 뷰 초기화 루틴에서보기 layer 속성을 읽습니다. 코드는 프레임 버퍼 개체를 만들 때 이 속성을 사용합니다.
myEAGLLayer = (CAEAGLLayer *) self.layer;
4. 계층의 속성을 설정합니다. 성능을 최적화하기 위해 CALayer 클래스가 제공하는 opaque 속성을 YES 로 설정함으로써 레이어를 불투명하게 지정합니다.
필요한 경우 값을 새로운 dictionary를 CAEAGLLayer 개체 drawableProperties 속성에 할당하여 렌더링 표면의 표면 속성을 설정합니다. EAGL에서는 렌더링 버퍼의 픽셀 포맷을 지정하고 Core Animation 표시 후 내용을 유지할지 여부를 지정할 수 있습니다. 설정 가능한 키 목록은
"EAGLDrawable Protocol Reference"를 참조하십시오.
5. 컨텍스트를 할당하여 컨텍스트를 현재 컨텍스트에 설정합니다.
6 프레임 버퍼 개체를 만듭니다 (위 참조).
7. 색상 렌더링 버퍼를 만듭니다.
컨텍스트 renderbufferStorage : fromDrawable : 메서드를 호출하여 스토리지를 할당하고 계층 개체를 매개 변수로 전달합니다. 폭, 높이, 픽셀 형식은 계층에서 검색하여 렌더링 버퍼 저장소를 할당하는 데 사용합니다.
GLuint colorRenderbuffer;
glGenRenderbuffers (1, & colorRenderbuffer);
glBindRenderbuffer (GL_RENDERBUFFER, colorRenderbuffer);
[myContext renderbufferStorage : GL_RENDERBUFFER fromDrawable : myEAGLLayer];
glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRenderbuffer);
참고 : Core Animation 레이어의 경계 사각형 또는 속성이 변경되면 응용 프로그램은 렌더링 버퍼 저장소를 다시 할당해야합니다. 렌더링 버퍼를 다시 할당하지 않으면 렌더링 버퍼의 크기가보기 크기와 일치하지 않습니다. 이 경우, Core Animation 은 이미지의 내용을보기 좋게 맞게 확대 축소할 수 있습니다. 이것을 방지하기 위해 Xcode 템플릿보기 레이아웃이 변경되면 항상 프레임 버퍼와 렌더링 버퍼를 다시 할당합니다.
8. 색상 렌더링 버퍼의 높이와 너비를 가져옵니다.
GLint width; GLint height;
glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, & width);
glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, & height);
앞의 각 예제에서는 버퍼에 스토리지를 할당하므로 렌더링 버퍼의 폭과 높이가 명시적으로 지정되어 있었습니다.
이 예제에서는 스토리지가 할당된 후 코드에서 색상 렌더링 버퍼에서 폭과 높이를 취득하고 있습니다. 응용프로그램이 이렇게하는 것은 색상 렌더링 버퍼의 실제 크기가 보기 경계 사각형과 배율에 따라 계산되기 때문입니다. 프레임 버퍼에 연결되는 다른 렌더링 버퍼 같은 크기여야 합니다. 깊이 버퍼를 할당하는 데 높이와 너비를 사용하는 것 외에 OpenGL ES 뷰포트 할당으로 추가 응용 프로그램의 텍스처와 모델에 필요한 자세한 수준의 결정을 돕기 위해 너비와 높이를 사용합니다.
9. 심도 버퍼를 할당하고 연결합니다.
10. 프레임 버퍼 개체를 테스트합니다.
쉽게 말하면, 프레임 버퍼를 만드는 방법은 거의 동일합니다. 색상 어태치먼트와 심도 첨부 파일을 할당 단계가 주로 다른점은 색깔 첨부 파일을 할당하는 방법입니다.
표 4-1. 프레임버퍼의 색상 어태치먼트를 할당하는 매커니즘
Offscreen renderbuffer | glRenderbufferStorage |
Drawable renderbuffer | renderbufferStorage: fromDrawable: |
Texture | glFramebufferTexture2D |
프레임버퍼 객체에 대한 그리기
프레임 버퍼 개체를 만든 후에는 다음 개체를 채울 필요가 있습니다. 이 섹션에서는 새 프레임을 렌더링하여 사용자에게 표시하는 데 필요한 단계를 설명합니다. 텍스처나 오프 스크린 프레임 버퍼에 렌더링은 똑같이 수행하지만 응용 프로그램이 마지막 프레임을 사용하는 방법만이 다릅니다.
일반적으로 응용 프로그램은 다음 두가지 중 하나의 상황에서 새로운 프레임을 렌더링합니다.
● 주문형 경우 : 응용 프로그램은 프레임의 렌더링에 사용되는 데이터가 변경된 인식하면 새로운 프레임을 렌더링합니다.
● 애니메이션 루프의 경우 : 응용 프로그램 프레임의 렌더링에 사용하는 데이터가 프레임마다 변화한다고 가정하는 경우입니다.
주문형 렌더링
주문형 렌더링 프레임의 렌더링에 사용하는 데이터가 자주 변경되지 않는 경우, 즉 사용자 액션에 응답하여 데이터가 변화하는 경우에만 적합합니다. iOS에 있어서 OpenGL ES는 이 모델에 잘 부합합니다. 프레임을 표시할 때, Core Animation 은 프레임을 캐시하고 새로운 프레임이 나타날 때까지 저장된 프레임을 사용합니다. 필요한 경우에만 새로운 프레임을 렌더링하여 장치의 배터리 절약되고 장치가 다른 작업을 수행하는 시간이 길어집니다.
참고 : OpenGL ES 를 지원하는 뷰는 뷰의 내용을 렌더링하는 데 drawRect : 메소드를 구현하지 않습니다. 대신 자신의 메소드를 구현하여 새로운 OpenGL ES 프레임을 그립 표시하고 데이터가 변경될 때 호출하도록 합니다. drawRect : 메소드를 구현하면 UIKit 의보기의 취급 방법에 다른 변화가 발생합니다.
애니메이션 루프를 사용하는 렌더링
애니메이션 루프를 사용하여 렌더링 데이터가 프레임마다 변화 가능성이 매우 높은 경우에 적합합니다. 예를 들어, 게임이나 시뮬레이션을 정지 화상을 표시하는 것은 거의 없습니다. 부드러운 애니메이션, 주문형 모델을 구현하는 것보다 중요합니다.
iOS는 애니메이션 루프를 설치하는 가장 좋은 방법은 CADisplayLink 개체를 사용하는 것입니다. 디스플레이 링크는 Core Animation 객체 그리기 및 화면 주사율을 동기화합니다. 그러면 stuttering과 티어링을 일으키지 않고 화면의 컨텐츠를 손쉽게 업데이트할 수 있습니다. 목록 4-1에서는보기가 표시되는 화면을 검색하고 해당 화면을 사용하여 새로운 디스플레이 연결 개체를 만들고 디스플레이 연결 개체를 실행 루프를 추가하는 방법을 보여줍 있습니다.
목록 4-1 디스플레이 링크의 생성 및 시작
displayLink = [myView.window.screen displayLinkWithTarget:self selector:@selector(drawFrame)];
[displayLink addToRunLoop: [NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
응용프로그램은 drawFrame 메소드의 구현 내부에서 디스플레이 링크 timestamp 속성을 읽어 렌더링 다음 프레임의 타임 스탬프를 취득해야합니다. 응용프로그램은이 값을 사용하여 다음 프레임의 객체의 위치를 계산할 수 있습니다.
일반적으로 디스플레이 연결 개체는 화면이 새로 때마다 작동합니다. 재생 값은 보통 60Hz 이지만 장치에 따라 다를 수 있습니다. 대부분의 응용 프로그램은 화면을 1초에 60번 업데이트할 필요가 없습니다.
디스플레이 링크 frameInterval 속성은 메서드가 호출되기 전에 경과하는 실제 프레임 수를 설정할 수 있습니다. 예를 들어, 프레임 간격을 3으로 설정되면 응용 프로그램은 3프레임마다 호출되며, 1초당 약 20프레임이 표시됩니다.
중요 : 최상의 결과를 얻으려면 응용프로그램이 지속적으로 달성 가능한 프레임 속도를 선택합니다. 부드럽고 일관된 프레임 속도는 일관성없는 프레임 속도보다 더 좋은 사용자 경험을 제공합니다.
프레임 렌더링
그림 4-2는 프레임을 렌더링하고 표시하는 데 iOS 에서 OpenGL ES 응용 프로그램이 취해야 할 단계를 설명합니다. 이 단계는 응용 프로그램의 성능을 향상시키는 힌트가 많이 포함되어 있습니다.
그림 4-2. iOS의 OpenGL 렌더링 단계
렌더링버퍼 지우기
각 프레임의 시작으로 다음 프레임의 렌더링에 필요하지 않은 이전 프레임의 내용을 포함하는 모든 렌더링 버퍼를 지웁니다. glClear 함수를 호출하여 삭제하는 모든 버퍼에 대한 비트 마스크를 전달합니다 ( 목록 4-2 참조).
목록 4-2. 렌더링버퍼 지우기
glBindFramebuffer (GL_FRAMEBUFFER, framebuffer);
glClear (GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
glClear의 사용은 수동으로 버퍼를 삭제하는 것보다 효율적이라고뿐만 아니라 glClear를 사용하여 기존 내용이 삭제 가능하다는 설명이 OpenGL ES 에 전달됩니다. 일부 그래픽 하드웨어에서는이 함수를 사용하면 지금까지의 내용을 메모리에 로드하는 부하의 큰 메모리 조작이 해결됩니다.
OpenGL ES 객체 생성
이 단계와 다음 단계는 응용프로그램의 핵심이며, 사용자에게 표시할 내용을 결정하는 단계입니다. 이 단계에서는 프레임의 렌더링에 필요한 모든 OpenGL ES 객체 (버텍스 버퍼 오브젝트, 텍스쳐 등)을 만듭니다.
그리기 명령
이 단계는 이전 단계에서 만들어진 개체를 검색하고 이러한 개체를 사용하는 드로잉 명령을 보냅니다. 렌더링 코드의이 부분이 효율적으로 실행되도록 설계하는 방법은 " OpenGL ES 응용 프로그램 디자인 지침 "에 설명되어 있습니다. 지금 바에 성능 최적화의 가장 중요한 점은 새로운 프레임 렌더링 시작시 OpenGL ES 개체를 수정하는 경우에만 응용 프로그램 실행 속도는 것으로합니다. 응용 프로그램은 개체의 수정 및 그리기 명령 전송을 교대로 실시 (점선으로 나타낸 부분) 할 수 있지만 응용 프로그램은 각 단계를 한번만 실행하려면 빠른 실행 됩니다.
멀티 샘플링 Resolve
응용 프로그램은 멀티 샘플링 기능을 사용하여 이미지 품질을 개선하는 경우 사용자에게 표시하기 전에 픽셀 Resolve 해야합니다. 멀티 샘플링 기능을 사용하는 응용 프로그램은 "멀티 샘플링 기능을 사용하여 이미지 품질 향상"에 설명되어 있습니다.
불필요한 렌더링 버퍼 삭제
삭제 작업은 EXT_discard_framebuffer 확장 정의되어 iOS 4.0 이상에서 사용할 수 있습니다.
삭제 작업은 iOS의 초기 버전에서 응용프로그램이 실행되고있는 경우는 제외해야하지만, 가능한 경우는 반드시 포함하도록 합니다.
삭제는 OpenGL ES에 대한 성능 팁으로, 힌트는 하나 이상의 렌더링 버퍼의 컨텐츠가 응용 프로그램에 사용되지 않으면 삭제 명령이 완료된 후 OpenGL ES에 전달됩니다.
렌더링 버퍼의 컨텐츠를 응용 프로그램이 필요로하지 않는다는 설명을 OpenGL ES에 전달하면 버퍼의 데이터를 삭제할 수 있고, 버퍼의 컨텐츠를 업데이 트 계속한다는 부담이 걸리는 작업을 방지할 수도 있습니다.
렌더링 루프의이 단계에서는 응용 프로그램 프레임에 대한 모든 드로잉 명령의 전송이 완료됩니다. 응용 프로그램이 화면에 표시하기위한 색상 렌더링 버퍼를 필요로하고있는 동안은 깊이 버퍼의 컨텐츠를 필요로하지 않을 수 있습니다.
목록 4-3은 깊이 버퍼의 내용을 삭제합니다.
목록 4-3. 심도 프레임 버퍼 삭제
const GLenum discards [] = {GL_DEPTH_ATTACHMENT};
glBindFramebuffer (GL_FRAMEBUFFER, framebuffer);
glDiscardFramebufferEXT (GL_FRAMEBUFFER, 1, discards);
Core Animation 에 결과보기
이 절차의 단계에서는 색상 렌더링 버퍼 렌더링 완료 프레임을 보유하고 있습니다. 그 때문에 필요한 것은 프레임을 사용자에게 표시하는 것입니다. 목록 4-4 렌더링 버퍼를 문맥에 바인드하고 렌더링 버퍼를 표시합니다. 이렇게 하면 렌더링 완료 프레임을 Core Animation에 전달할 수 있습니다.
목록 4-4. 렌더링 완료 프레임 표시
glBindRenderbuffer (GL_RENDERBUFFER, colorRenderbuffer);
[context presentRenderbuffer : GL_RENDERBUFFER];
기본적으로 렌더링 버퍼의 컨텐츠는 응용 프로그램이 렌더링 버퍼를 표시 후 삭제되는 것을 전제로 해야합니다. 이것은 응용프로그램 프레임을 표시 때마다 프레임의 내용을 완전히 다시 만들어 새 프레임을 렌더링해야 한다는 것을 의미합니다. 이러한 이유로 위의 코드는 항상 색상 버퍼를 지웁니다.
응용프로그램 프레임 사이의 색상 렌더링 버퍼의 컨텐츠를 유지해야하는 경우 kEAGLDrawablePropertyRetainedBacking 키를 CAEAGLLayer 개체 drawableProperties 속성에 저장되는 사전에 추가 이전 glClear 함수 호출에서 GL_COLOR_BUFFER_BIT 상수를 삭제합니다. 유지되는 백업은 버퍼의 컨텐츠를 유지하기 위해 추가 메모리 할당을 iOS 에 요청할 수 있으며 이로 인해 응용 프로그램 성능이 저하될 수 있습니다.
OpenGL ES 응용프로그램에서의 View Controller 지원
OpenGL ES 응용프로그램의 대부분은 몰입에서 전체 화면을 사용하여 콘텐츠를 표시합니다. 그러나 같은 몰입형 응용프로그램에서 iOS 다른 기능과 상호 작용이 필요한 경우가 적지 아닙니다. 예를 들어, iAd 광고를 표시하는 응용 프로그램이나 Game Center 기본 View Controller 를 사용하는 응용 프로그램은 View Controller를 제공해야합니다. 이 View Controller는 시스템 View Controller가 제공하는 콘텐츠를 모달 모드로 표시하는 데 사용합니다. 따라서 Xcode 템플릿은 해당 View Controller를 제공하고 보기를 관리합니다. 응용프로그램도 마찬가지로 해야합니다.
View Controller의 사용으로 중요한 것은 뷰 회전을 취급할 수 있습니다. iOS 4.2 이상을 실행하는 PowerVR SGX을 갖춘 장치는 Core Animation의 회전 및 OpenGL ES 콘텐츠 확대 축소 성능이 크게 향상됩니다. 응용 프로그램은 "View Controller Programming Guide for iOS"에서 설명한대로 View Controller를 사용하여 허용되는 방향을 설정하고 사용자가 장치를 회전 시켰을 때의 방향과 방향 사이 전환을 할 필요가 있습니다. View Controller를 사용하면 View Controller 모달 모드로 표시하는 다른 View Controller는 표시 측의 View Controller와 같은 방향으로 표시됩니다.
응용프로그램이 PowerVR MBX 을 갖춘 장치를 지원하는 경우 이러한 장치는 Core Animation의 사용을 피해야 할 경우가 발생할 수 있습니다. 대신 OpenGL ES 내부에서 직접 회전을 실행합니다. 회전 할 때 모델 뷰 및 투영 행렬을 변경하고 glViewport 함수 및 glScissor 함수의 폭과 높이의 인수를 바꿉니다.
Core Animation 의 합성 기능의 성능 향상
렌더링 버퍼의 컨텐츠는, 애니메이션화된 뷰 계층에 포함된 다른 Core Animation 레이어와 합성됩니다. 합성되는 계층은 OpenGL ES , Quartz 또는 다른 그래픽 라이브러리에 그려진 여부와 관계없이 유용합니다. 왜냐하면 OpenGL ES가 Core Animation 가장 우선순위에 있는 그래픽 라이브러리라는 것을 의미하기 때문입니다.
그러나 OpenGL ES 컨텐츠를 다른 컨텐츠와 혼합할 때 시간이 걸립니다. 적절하게 사용하지 않으면 응용 프로그램의 실행 속도가 저하하고 상호 작용할 프레임 속도에 도달하는 데 시간이 걸릴 수 있습니다. 콘텐츠를 혼합 적합시키는 데 따른 성능 페널티는 iOS 장치에 탑재되는 기본 그래픽 하드웨어에 따라 달라집니다. PowerVR MBX 그래픽 프로세서를 사용하는 장치는 복잡한 장면의 합성 시에 의해 중대한 처벌을 지게됩니다. 최상의 결과를 얻기 위해서는 출하되는 모든 iOS 장치에서 반드시 응용 프로그램을 테스트하십시오.
최상의 성능을 보장하려면 응용프로그램에서 OpenGL ES 만을 사용하여 콘텐츠를 렌더링해야 합니다. 이렇게 CAEAGLLayer 객체를 보관 유지하는 뷰를 크기를 화면에 일치시켜 화면 opaque 속성을 YES 로 설정하고 다른 Core Animation 계층이나 뷰가 보이지 않도록합니다. OpenGL ES 계층이 다른 계층 중에서도 맨 위에 합성되는 경우 CAEAGLLayer 개체를 융화함으로써 성능상의 부담은 줄일 수 있지만 제거할 수는 없습니다.
CAEAGLLayer 객체가 그 아래에 있는 레이어 계층 구조의 최상위 계층에서 합성되는 경우 렌더링 버퍼의 색상 데이터는 Core Animation이 제대로 합성하도록 사전에 계산이 끝난 알파 형식으로되어 있어야 합니다 그렇지 않으면 OpenGL ES 컨텐츠를 다른 컨텐츠에서 합성하는 것은 성능상의 심각한 처벌을 수반합니다.
멀티 샘플링 기능을 사용하여 이미지 품질 향상
iOS4 이후 OpenGL ES는 APPLE_framebuffer_multisample 확장 기능을 지원합니다. 멀티 샘플링 기능은 앤티 앨리어싱의 한가지 형식으로 응용프로그램이 들쭉날쭉한 가장자리를 부드럽게하거나 화질을 향상 시키거나 할 수 있습니다. 멀티 샘플링 기능은 더 많은 리소스(메모리 조각 처리)를 사용하지만 대부분의 3D 응용 프로그램에서 이미지 품질이 향상됩니다.
그림 4-3은 멀티 샘플링 기능의 개념을 보여줍니다.
멀티 샘플링 기능은 응용 프로그램은 한개의 프레임 버퍼 객체를 생성하는 대신에 프레임 버퍼 객체를 2개 만듭니다.
첫번째 프레임 버퍼 객체는 Resolve 버퍼 색상 렌더링 버퍼를 저장하지만, 그 점을 제외하고 위와 동일하게 할당됩니다. Resolve 버퍼는 최종 이미지가 렌더링되는 위치입니다.
두번째 프레임 버퍼 객체인 멀티 샘플 버퍼는 깊이 어태치먼트와 색상 어태치먼트를 모두 저장합니다. 멀티 샘플 렌더링 버퍼는 리절브 프레임 버퍼와 같은 크기를 사용하여 할당됩니다, 각각의 멀티 샘플 렌더링 버퍼는 각 픽셀에 대해 저장되는 샘플 수를 지정하는 추가 매개 변수가 포함됩니다.
응용 프로그램은 멀티 샘플 버퍼에 렌더링 모든 실행 후 버퍼 샘플을 Resolve 버퍼에 Resolve 수에 따라 앤티화된 최종 이미지를 생성합니다.
그림 4-3 멀티 샘플링 기능 구조
목록 4-5는 멀티 샘플링 버퍼를 만드는 코드를 보여줍니다.
이 코드는 이전에 만든 버퍼의 너비와 높이를 사용하여 glRenderbufferStorageMultisampleAPPLE 함수를 호출하여 렌더링 버퍼에 멀티 샘플화된 스토리지를 만듭니다.
목록 4-5. 멀티 샘플링 버퍼 만들기
glGenFramebuffers(1, &sampleFramebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, sampleFramebuffer);
glGenRenderbuffers(1, &sampleColorRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, sampleColorRenderbuffer);
glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER, 4, GL_RGBA8_OES, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, sampleColorRenderbuffer);
glGenRenderbuffers(1, &sampleDepthRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, sampleDepthRenderbuffer);
glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER, 4, GL_DEPTH_COMPONENT16, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, sampleDepthRenderbuffer);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
NSLog(@"Failed to make complete framebuffer object %x",
glCheckFramebufferStatus(GL_FRAMEBUFFER));
멀티 샘플링 기능을 지원하는 렌더링 코드의 수정 절차를 보여줍니다.
1. 버퍼 지우기 절차는 멀티 샘플링 프레임 버퍼의 내용을 지웁니다.
glBindFramebuffer(GL_FRAMEBUFFER, sampleFramebuffer);
glViewport(0, 0, framebufferWidth, framebufferHeight);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
2. 드로잉 명령을 보낸 후 멀티 샘플링 버퍼의 컨텐츠를 Resolve버퍼로 Resolve 합니다. 각 픽셀에 저장된 샘플은 Resolve버퍼에서 한개의 샘플에 결합됩니다.
glBindFramebuffer(GL_DRAW_FRAMEBUFFER_APPLE, resolveFrameBuffer);
glBindFramebuffer(GL_READ_FRAMEBUFFER_APPLE, sampleFramebuffer);
glResolveMultisampleFramebufferAPPLE();
3. 파기 절차에서는 멀티 샘플링 프레임 버퍼에 연결되어있는 두 렌더링 버퍼를 삭제할 수 있습니다. 이것은 보려고하는 내용이 Resolve버퍼에 저장되어 있기 때문입니다.
const GLenum discards [] = {GL_COLOR_ATTACHMENT0, GL_DEPTH_ATTACHMENT};
glDiscardFramebufferEXT (GL_READ_FRAMEBUFFER_APPLE, 2, discards);
4. 표시 단계에서는 리절브 프레임 버퍼에 연결되는 색상 렌더링 버퍼를 표시합니다.
glBindRenderbuffer (GL_RENDERBUFFER, colorRenderbuffer);
[context presentRenderbuffer : GL_RENDERBUFFER];
멀티 샘플링 기능은 부담이 없는 것은 아닙니다. 추가 샘플을 저장하려면 추가 메모리가 필요하며 Resolve 프레임 버퍼에 샘플 Resolve 시간이 걸립니다. 멀티 샘플링 기능을 응용프로그램에 추가하려면 가능한 성능 수준을 유지하도록 응용 로그램의 성능을 반드시 테스트하십시오.
OpenGL ES 를 사용하여 고해상도 디스플레이 지원
응용프로그램이 렌더링 OpenGL ES를 사용하는 경우 기존의 그리기 코드는 변경없이 그대로 작동합니다. 그러나 고해상도 화면에 그리면 그것에 따라 콘텐츠가 확대 축소되어 Retina가 아닌 디스플레이에 표시되는 것처럼 보입니다. 그 이유는 CAEAGLLayer 클래스의 기본 동작 배율을 1.0 로 설정하고 있기 때문입니다. 고해상도 그림을하려면 OpenGL ES 콘텐츠 표시에 사용하는보기의 배율을 변경해야 합니다. UIKit 에서 고해상도 디스플레이를 지원하는 방법에 대한 자세한 내용은 "ES 를 사용하여 고해상도 디스플레이 지원"을 참조하십시오.
View의 contentScaleFactor 속성을 변경하면 이에 해당하는 기본 CAEAGLLayer 개체의 배율이 변경됩니다. renderbufferStorage : fromDrawable : 메서드는 렌더링 버퍼 저장소를 만드는 데 사용되는 메서드, 레이어의 경계와 그 배율을 곱셈하는 것으로 렌더링 버퍼의 크기를 계산합니다. "Core Animation 레이어로 렌더링"에 표시된 코드는 Core Animation의 렌더링 버퍼 저장소를 할당하여 렌더링 버퍼의 너비와 높이를 가져옵니다. 그러면 렌더링 버퍼 저장소는 내용의 배율 변경을 자동으로 얻을 수 있습니다. 배율을 2배로하면 렌더링 버퍼에 렌더링하는 픽셀이 4배 저장됩니다. 렌더링 후 콘텐츠를 제공하여 추가 분 픽셀을 채우기 여부는 선택적입니다.
중요 : CAEAGLLayer 개체에 의해 지원되는 View는 사용자 지정 drawRect 메서드를 구현해서는 안됩니다.
drawRect : 메소드의 구현을 통해 View의 기본 배율은 화면 비율과 일치하도록 암시적으로 변경됩니다. 응용 프로그램의 그리기 코드가 이 동작을 설정하고 있지 않으면 응용 프로그램 콘텐츠가 제대로 렌더링되지 않습니다.
고해상도 그림을 사용하려면 그에 따라 애플 리케이션의 모델 assets 및 텍스처 assets을 조정합니다. iPad 또는 고해상도 장치에서 실행되는 경우 더 자세한 모델과 텍스처를 선택하여 보다 고화질의 이미지를 렌더링 할 수 있습니다. 반대로 표준 해상도의 iPhone 에서 작은 모델과 텍스처를 계속 사용할 수 있습니다.
고해상도의 컨텐츠를 지원하는지 여부를 결정할 때 중요한 요소로 성능이 있습니다. 레이어 배율을 1.0 에서 2.0 로 변경했을 때 픽셀이 4배가 되면 처리하는 부분이 4배가 됩니다. 응용 프로그램이 조각 단위의 계산을 많이 수행하는 경우 픽셀 수의 증가로 인해 응용 프로그램의 프레임 속도가 저하될 수 있습니다. 높은 배율에서는 응용 프로그램 실행이 매우 느려지게 경우 다음 옵션을 고려하십시오.
● 이 문서의 성능 튜닝 지침을 사용하여 조각 쉐이더 성능을 최적화합니다.
● 더 간단한 알고리즘을 조각 셰이더 구현한다. 이렇게하면 개별 픽셀의 품질을 낮추고 전체 이미지를 높은 해상도로 렌더링합니다.
● 1.0 및 화면 배율 사이의 배율을 설정한다. 1.5 배율은 1.0 배율보다 품질이 높아지지만, 2.0 확대되고 이미지보다 채우는 데 필요한 픽셀 수는 적습니다.
● 대신 멀티 샘플링 기능을 사용한다. 추가 혜택으로 멀티 샘플링 기능은 고해상도 디스플레이를 지원하지 않는 장치에서 높은 품질이 초래되는 것을 들 수 있습니다.
● 양호한 결과를 얻을 가능한 낮은 정밀도 형식을 사용하여 색상 렌더링 버퍼와 깊이 렌더링 버퍼를 만듭니다. 그러면 렌더링 버퍼 처리에 필요한 메모리 대역폭이 줄어 듭니다.
최선의 해결책은 OpenGL ES 응용 프로그램의 요구에 따라 다릅니다. 개발 단계에서이 부분을 테스트하고 성능 및 이미지 품질의 균형이 가장 좋은 방법을 선택합니다.
외부 디스플레이의 OpenGL ES 컨텍스트 작성
일부 iOS 장치는 외부 디스플레이에 연결할 수 있습니다. 외부 디스플레이 해상도 및 콘텐츠의 배율은 메인 화면과 다를 수 있습니다. 프레임을 렌더링하는 코드 적용 맞추기 조정해야 합니다. 컨텍스트를 만들려면 메인 화면으로 만드는 것과 거의 동일합니다.
다음 단계를 따르십시오.
1. "Displaying Content on an External Display" in View Programming Guide for iOS 과 같이 외부 디스플레이에 새로운 윈도우를 만듭니다.
2. 윈도우에 OpenGL ES 뷰를 추가합니다.
3. 윈도우의 screen 속성을 검색하고 displayLinkWithTarget : selector : 을 호출하여 디스플레이 연결 개체를 만듭니다. 이렇게하면 디스플레이에 최적화된 디스플레이 링크가 생성됩니다.