Upload
edgar-mcdonald
View
268
Download
1
Embed Size (px)
Citation preview
그래픽 출력
1
Introduction
Quartz 2D Core Graphics frameworks 에 포함됨
OpenGL ES Cross-platform library 인 OpenGL 의
embedded system 버전
2
Quartz approach to drawing
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 2.0);// 선의 굵기가 2 가 되게 함
CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);// stroke color ( 선 또는 도형의 윤곽선에 사용 ) 설정 . 참고 , fill color 는 채우는 색
CGConextMoveToPoint(context, 100.0f, 100.0f);// 그리는 위치를 (100, 100) 으로 옮김
CGConextAddLineToPoint(context, 200.0f, 200.0f);// (100, 100) 에서 (200, 200) 으로 그림
CGContextStrokePath(context);// 위의 설정으로 그림을 화면에 출력 .// 이 함수 실행전에는 화면에 나타나지 않음
3
좌표계
(100,100)
(200, 200)
(100,100)
(200, 200)
(0, 0)
(0, 0)Quartz 2D OpenGL ES
4
Color RGBA 사용
Red, Green, Blue + Alpha 각 색은 0 ~ 1.0 사이의 값을 가짐 Alpha 는 투명도를 나타냄
OpenGL ES 에서는 이 모델만 사용 Quartz 2D 는 다른 color model 도 사용할 수 있음
색을 프로그램에서 기술할 때 UIColor 객체의 CGColor reference 를 써야 함 예
[UIColor redColor].CGColor [UIColor colorWithRed:1.0f green:0.0f blue:0.0f
alpha:1.0f];
5
Alpha 값의 역할 = 투명도 조절
RGB = ( 0.1, 0.8, 0.4)
RGB = ( 0.7, 0.1, 0.4, 0.5)
RGBA = ( 0.7*0.6+0.1*0.4, 0.1*0.6+0.8*0.4, 0.4*0.6+0.5*0.4),즉 , (0.46, 0.38, 0.44)
RGBA 데이터
그리기
RGBA 데이터
그리기
Alpha 값이 0.6 인 경우
이미 있던 영상 값의 40% +새로운 영상 값 60%
Alpha 값이 0 에 가까울 수록투명하게 영상을 그리게 됨
6
이미지 그리기
UIImage *drawImage;
drawImage = [UIImage imageNamed:@”iphone.png”];// resource 목록에 넣은 iphone.png 파일을 로딩
CGFloat horizontalOffset = drawImage.size.width /2;CGFloat verticalOffset = drawImage.size.height/2;CGPoint drawpoint = CGPointMake(100.0f - horitontalOffset, 100.0f-verticalOffset);
// (100, 100) 에 이미지의 중심이 위치하도록 그리는 위치 설정
[drawImage drawAtPoint: drawPoint];// 화면에 출력
7
참고자료
Quartz 2D programming guide http://developer.apple.com/mac/library/
documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/Introduction/Introduction.html
8
OpenGL 이란 ?
OpenGL 그래픽 하드웨어 제어를 위한 소프트웨어
인터페이스 3D 그래픽을 위한 라이브러리 규약 “OpenGL implementation”, 즉 , 디바이스
드라이버를 제작하고자 하면 OpenGL 라이선스를 SGI 사에서 받아야 함 그러나 드라이버 사용자는 비용지불 안함
DirectX 는 경쟁자
9
OpenGL ES 란 ? OpenGL 의 Embedded System (ES) 버전
OpenGL 함수의 상당부분이 생략됨 OpenGL ES 2.0 스팩은 iPhone OS 3.0 이상에서만 지원됨
호환성을 위해서는 OpenGL ES 1.1 을 사용해야 함
OpenGL ES 스펙 자료 http://www.khronos.org/opengles/spec/
http://www.khronos.org/registry/gles/specs/1.1/es_full_spec.1.1.12.pdf
본 수업에서는 3D 는 다루지 않고 2D 만을 다룰 것임 iPhone SDK 샘플 코드에 좋은 자료 (2D, 3D) 가 많이 있으니
이것을 분석하고 변형시켜 보는 것이 효과적임
10
OpenGL ES 로 그림 출력 절차
그림그리기( 포토샵 )
반드시 크기가 2 의 배수가 되도록 저장(*.png)
Xcode 의 “ resources” 에 추가하기OpenGL ES 템플릿 생성혹은 GLSprite 예제를 수정
다음 슬라이드에 나오는 방식을 기반으로 코드 작성
11
이미지 출력 사전 준비하기 (1)
// 화면 넓이 및 높이가 각각 backingWidth, backingHeight 일 때 // 화면 전체를 출력에 사용하는 경우 다음과 같이 설정 glVewport(0, 0, backingWidth, backingHeight); glLoadIdentity(); glOrthof(0.0f, (GLfloat)backingwidth, 0.0, (GLfloat)backingHeight, 1.0, -1.0); glLoadIdentity(); glClearColor(0.0f, 0.0f, 1.0f, 1.0f); // clear 색을 blue 로 설정 glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY);
// 2D 이미지를 텍스쳐로 쓸 수 있게 만듦 glEnable(GL_TEXTURE_2D); // 기존 이미지와 새로운 이미지가 혼합될 수 있게 함 glEnable(GL_BLEND); // 새로운 이미지로 기존 이미지를 덮어 쓰게 함 glBlendFunc(GL_ONE, GL_SRC_COLOR); // 만일 새로운 이미지를 기존 이미지 위에 alpha 값에 따라 투명하게 하고 // 싶으면 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
텍스쳐로 사용할 이미지 데이터를 준비시키키
12
이미지 출력 사전 준비하기 (2)
// Creates a Core Graphics image from an image file spriteImage = [UIImage imageNamed:@"Sprite.png"].CGImage; // 이미지의 넓이와 높이를 구함 . 이 값은 2 의 배수여야 함 (2, 4, 8, 16, …)width = CGImageGetWidth(spriteImage); height = CGImageGetHeight(spriteImage); if(spriteImage) {
// 이미지 데이터를 저장할 공간 할당 . RGBA 모델이므로 1 픽셀당 4 바이트 .spriteData = (GLubyte *) malloc(width * height * 4); // core graphics framework 에서 제공되는 비트맵 context 를 생성spriteContext = CGBitmapContextCreate(spriteData, width, height, 8,
width * 4, CGImageGetColorSpace(spriteImage), kCGImageAlphaPremultipliedLast);
// 비트맵 context 에 이미지를 출력 . 결과적으로 spriteData 에 그린 결과가 저장CGContextDrawImage(spriteContext, CGRectMake(0.0, 0.0, (CGFloat)width,
(CGFloat)height), spriteImage); // 메모리 leak 방지를 위해 비트맵 context 를 해제CGContextRelease(spriteContext);
}
텍스쳐로 사용할 이미지 데이터를 준비시키키
이미지 마다 위의 행위를 해 주어야 함13
이미지 출력 사전 준비하기 (3)
// 텍스쳐 이름 , 즉 , 번호 얻기 glGenTextures(1, &spriteTexture); // 얻은 텍스쳐 번호를 바인딩 하기glBindTexture(GL_TEXTURE_2D, spriteTexture); // Specify a 2D texture image, provideing the a pointer to the image data in
memory glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height,
0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData); free(spriteData);
이미지를 텍스쳐로 만들기
이미지 마다 위의 행위를 해 주어야 함14
이미지 출력 사전 준비하기 (4)
// Set the texture parameters to use a minifying filter and a linear filer // (weighted average) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // Enable use of the texture glEnable(GL_TEXTURE_2D); // Set a blending function to use glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); // Enable blending
glEnable(GL_BLEND);
파라미터 설정
15
이미지 출력 (1)
Surface
Texture
Vertices 로 표현예 : Glfloat spriteVertices[] = { 10.0, 20.0,
30.0, 20.0,10.0, 10.0, 30.0, 10.0
}; 10, 10 30, 10
30, 2010, 20
1 2
3 4
(0.0, 1.0)
(0.0, 0.0) (1.0, 0.0)
(1.0, 1.0)Texture coordinates 로 표현예 : Glfloat texCoords[] = { 0.0, 1.0,
1.0, 1.0,0.0, 0.0, 1.0, 0.0
};
16
이미지 출력 (2)
Surface10, 10 30, 10
30, 2010, 20
// 출력될 이미지의 화면 영역 설정 glVertexPointer(2, GL_FLOAT, 0, spriteVertices); // 출력 ( 즉 , 매핑 ) 할 때 사용할 이미지 영역 설정 glTexCoordPointer(2, GL_FLOAT, 0, texCoords); // 텍스쳐 이미지 설정 . 이 텍스쳐의 texCoords 영역이 텍스쳐 매핑에 사용됨 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
imgWidth, imgHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData);
// 화면에 그리기 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4 );
17
텍스쳐 사용에 대한 좋은 자료
http://iphonedevelopment.blogspot.com/2009/05/opengl-es-from-ground-up-part-6_25.html
18
EAGLView.h (1/2)#import <UIKit/UIKit.h> #import <OpenGLES/EAGL.h> #import <OpenGLES/ES1/gl.h> #import <OpenGLES/ES1/glext.h> @interface EAGLView : UIView {
@private /* The pixel dimensions of the backbuffer */ GLint backingWidth, backingHeight; EAGLContext *context;
/* OpenGL names for the renderbuffer and framebuffers used to render to this view */ GLuint viewRenderbuffer, viewFramebuffer;
/* OpenGL name for the depth buffer that is attached to viewFramebuffer, if it exists (0 if it does not exist) */
GLuint depthRenderbuffer;
/* OpenGL name for the sprite texture */ GLuint spriteTexture; // 이미지 출력을 위해 사용되는 텍스쳐
이 코드를 기반으로 추가 /변경할 것
19
EAGLView.h (2/2)
NSTimer *animationTimer; NSTimeInterval animationInterval;
} -(void)startAnimation; // 애니메이션을 시작 시키는 함수-(void)stopAnimation; // 에니메이션을 중지 시키는 함수-(void)drawView; // 애니메이션 주기마다 호출되는 그리기 함수
// 응용은 주로 이 함수를 변경
@property NSTimeInterval animationInterval; // 에니메이션 주기
@end
20
EAGLView.m (1)#import <QuartzCore/QuartzCore.h> #import <OpenGLES/EAGLDrawable.h> #import "EAGLView.h"
// category 정의임 . 향후 설명@interface EAGLView (EAGLViewPrivate) -(BOOL)createFramebuffer; -(void)destroyFramebuffer; @end
// category 정의임 . 향후 설명@interface EAGLView (EAGLViewSprite) -(void)setupView; @end
@implementation EAGLView
@synthesize animationInterval; // You must implement this + (Class) layerClass { return [CAEAGLLayer class]; }
21
EAGLView.m (2)//The GL view is stored in the nib file. // When it's unarchived it's sent -initWithCoder: -(id)initWithCoder:(NSCoder*)coder { if((self = [super initWithCoder:coder])) {
// Get the layer CAEAGLLayer *eaglLayer = (CAEAGLLayer*) self.layer; eaglLayer.opaque = YES; eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:FALSE], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil];
context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1]; if(!context || ![EAGLContext setCurrentContext:context] || ![self createFramebuffer]) {
[self release]; return nil;
} animationInterval = 1.0 / 60.0; // 초당 60 프레임 [self setupView]; [self drawView];
} return self; }
22
EAGLView.m (3)-(void)layoutSubviews { [EAGLContext setCurrentContext:context]; [self destroyFramebuffer]; [self createFramebuffer]; [self drawView]; } -(BOOL)createFramebuffer { glGenFramebuffersOES(1, &viewFramebuffer); glGenRenderbuffersOES(1, &viewRenderbuffer); glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer); glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer); [context renderbufferStorage:GL_RENDERBUFFER_OES
fromDrawable:(id<EAGLDrawable>)self.layer]; glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES,
GL_RENDERBUFFER_OES, viewRenderbuffer); glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth); glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES,&backingHeight); if(glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) { NSLog(@"failed to make complete framebuffer object %x",
glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES)); return NO;
} return YES; }
스크린 크기 저장
23
EAGLView.m (4) -(void)destroyFramebuffer {
glDeleteFramebuffersOES(1, &viewFramebuffer); viewFramebuffer = 0; glDeleteRenderbuffersOES(1, &viewRenderbuffer); viewRenderbuffer = 0; if(depthRenderbuffer) {
glDeleteRenderbuffersOES(1, &depthRenderbuffer); depthRenderbuffer = 0;
} }
-(void)startAnimation { animationTimer = [NSTimer scheduledTimerWithTimeInterval:animationInterval
target:self selector:@selector(drawView) userInfo:nil repeats:YES]; }
-(void)stopAnimation { [animationTimer invalidate]; animationTimer = nil;
} -(void)setAnimationInterval:(NSTimeInterval)interval {
animationInterval = interval; if(animationTimer) {
[self stopAnimation]; [self startAnimation];
} } 24
EAGLView.m (5)
// Sets up an array of values to use as the sprite vertices. const GLfloat spriteVertices[] = {
-0.5f, -0.5f, 0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 0.5f,
};
// Sets up an array of values for the texture coordinates. const GLshort spriteTexcoords[] = {
0, 0, 1, 0, 0, 1, 1, 1,
};
25
EAGLView.m (6)-(void)setupView {
CGImageRef spriteImage; CGContextRef spriteContext; GLubyte *spriteData; size_t width, height;
// Sets up matrices and transforms for OpenGL ES glViewport(0, 0, backingWidth, backingHeight); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrthof(-1.0f, 1.0f, -1.5f, 1.5f, -1.0f, 1.0f); glMatrixMode(GL_MODELVIEW); // Clears the view with black glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Sets up pointers and enables states needed for using vertex arrays and textures glVertexPointer(2, GL_FLOAT, 0, spriteVertices); glEnableClientState(GL_VERTEX_ARRAY); glTexCoordPointer(2, GL_SHORT, 0, spriteTexcoords); glEnableClientState(GL_TEXTURE_COORD_ARRAY);
2D 그리픽을 설정sprite.png 파일을 텍스쳐로 로딩
26
EAGLView.m (7)
// Creates a Core Graphics image from an image file spriteImage = [UIImage imageNamed:@"Sprite.png"].CGImage; // Get the width and height of the image width = CGImageGetWidth(spriteImage); height = CGImageGetHeight(spriteImage); // Texture dimensions must be a power of 2. // If you write an application that allows users to supply an image, // you'll want to add code that checks the dimensions and //takes appropriate action if they are not a power of 2. if(spriteImage) {
// Allocated memory needed for the bitmap context spriteData = (GLubyte *) malloc(width * height * 4); // Uses the bitmatp creation function provided by the Core Graphics framework. spriteContext = CGBitmapContextCreate(spriteData, width, height, 8,
width * 4, CGImageGetColorSpace(spriteImage), kCGImageAlphaPremultipliedLast);
// After you create the context, you can draw the sprite image to the context. CGContextDrawImage(spriteContext, CGRectMake(0.0, 0.0, (CGFloat)width,
(CGFloat)height), spriteImage); 27
EAGLView.m (8)// You don't need the context at this point, so you need to release it // to avoid memory leaks. CGContextRelease(spriteContext);
// Use OpenGL ES to generate a name for the texture. glGenTextures(1, &spriteTexture); // Bind the texture name. glBindTexture(GL_TEXTURE_2D, spriteTexture); // Specify a 2D texture image, provideing the a pointer to the image data in
memory glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height,
0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData); // Release the image data free(spriteData); // Set the texture parameters to use a minifying filter and a linear filer // (weighted average) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // Enable use of the texture glEnable(GL_TEXTURE_2D); // Set a blending function to use glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); // Enable blending glEnable(GL_BLEND);
} }
28
EAGLView.m (9)// Updates the OpenGL view when the timer fires -(void)drawView { // 애니메이션을 위해 변경하는 주요 부분
// Make sure that you are drawing to the current context [EAGLContext setCurrentContext:context]; glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer); glRotatef(3.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer); [context presentRenderbuffer:GL_RENDERBUFFER_OES];
} // Stop animating and release resources when they are no longer needed. -(void)dealloc {
[self stopAnimation]; if([EAGLContext currentContext] == context) {
[EAGLContext setCurrentContext:nil]; } [context release]; context = nil; [super dealloc];
} @end
29
실습 OpenGL ES 템플릿으로 OpenGLTest
예제 생성하고 내용 살펴 보기
GLSprite 예제를 살펴 보기 OpenGL ES 템플릿과 차이점 확인하기
실습 : 2 개의 이미지를 애니메이션 1 개는 화면의 위에서 아래로 1 개는 화면의 왼쪽에서 오른쪽으로
30
숙제
Aiolos 예제를 iPhone 용으로 변환 전체는 시간과 노력이 많이 걸릴 수 있으므로
다음만 수행 스테이지 1 의 배경과 구름만 출력
가이드 라인 (GLSprite 수정 ) setupView 에 1 개의 이미지가 아닌 여러 개가
되도록 만듦 drawView 수정
31
drawView 수정-(void)drawView { // 애니메이션을 위해 변경하는 주요 부분
// Make sure that you are drawing to the current context [EAGLContext setCurrentContext:context]; glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer); glRotatef(3.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer); [context presentRenderbuffer:GL_RENDERBUFFER_OES];
}
-(void)drawView { glClear(GL_COLOR_BUFFER_BIT);RenderBufferScene();
// Make sure that you are drawing to the current context [EAGLContext setCurrentContext:context]; glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer); [context presentRenderbuffer:GL_RENDERBUFFER_OES];
} 32
RenderBufferScene void RenderBufferScene(void) { static int first = 0;
if( first == 0 ) {
// 처음 실행될 때 필요한 것 // 즉 , Aiolos 의 경우 START_EVENT 일 때 실행하는 코드 삽입
first = 0; } else {
// Aiolos 의 TIMEOUT_EVENT 때 실행하는 코드 EVENT_TIMEOUT();
}}
33