1장 – 그래픽스 시스템과 모델 2장 – 그래픽스 프로그래밍 3장 – 입력과 상호작용 4장 – 기하학적 객체와 변환 8장 이산적 기법들 1장 – 그래픽스 시스템과 모델 2장 – 그래픽스 프로그래밍 3장 – 입력과 상호작용 4장 – 기하학적 객체와 변환 5장 – 관측 6장 – 음영 7장 – 구현 클리핑 래스터화 은면제거
8장 이산적기법들 학습목표 기하학적 객체의 렌더링 외에 프레임 버퍼에 대한 작업을 이해 텍스처 매핑 등의 매핑 방법을 이해 합성방법의 이해
버퍼 공간해상도 (n x m)와 픽셀당 비트 수를 나타내는 깊이 k로 버퍼를 정의함 예 : 색버퍼(Color buffer), 깊이버퍼(Depth buffer)
OpenGL 프레임버퍼
OpenGL 버퍼들 컬러버퍼는 디스플레이 될 수 있다 깊이 버퍼 누적 버퍼 스텐실 버퍼 전면버퍼 후면버퍼 보조버퍼 오버레이 고해상도 버퍼 스텐실 버퍼 마스크를 가지고 있음
개념적으로는, 메모리 전체를 픽셀의 커다란 2차원 배열로 간주할 수 있다 픽셀의 사각 블록에 읽고 쓰기를 할 수 있다 버퍼에 쓰기 개념적으로는, 메모리 전체를 픽셀의 커다란 2차원 배열로 간주할 수 있다 픽셀의 사각 블록에 읽고 쓰기를 할 수 있다 비트블록전이[Bit block transfer (bitblt)] 연산들 프레임버퍼는 이 메모리의 일부이다 write_block(source, n, m, x, y, destination, u, v); (x,y) (u,v)
쓰기 모드 source 를 destination에 쓰기 전에 픽셀을 읽음
쓰기모드 source 와 destination 비트들은 비트별로 연산됨 16 개의 가능한 함수 XOR replace OR
쓰기모드
XOR 모드 3장에서 논리연산을 인에이블하고 XOR 쓰기모드를 선택함으로써 XOR 를 사용했었다 XOR는 화면 밖에 저장되는 메뉴와 같은 메모리 블록을 교환하는데 특히 유용하다 S 와 M이 각기 화면과 메뉴를 나타내면, 다음과 같은 일련의 연산이 S와 M을 교환한다 S S M M S M
OpenGL은 픽셀들을 위한 별도의 파이프라인을 가지고 있다 픽셀 파이프라인 OpenGL은 픽셀들을 위한 별도의 파이프라인을 가지고 있다 픽셀쓰기 프로세서 메모리에서 프레임버퍼로 픽셀을 이동 포맷변환 매핑, 룩업, 테스트 픽셀 읽기
OpenGL은 raster position 을 상태의 일부분으로 유지한다 래스터 위치 OpenGL은 raster position 을 상태의 일부분으로 유지한다 glRasterPos*()로 설정 glRasterPos3f(x, y, z); 래스터 위치는 기하학적 객체이다 기하 파이프라인을 통과 최종적으로 화면 좌표계에서 2D좌표로 됨 프레임 버퍼 내의 이 위치는 다음 번의 래스터 기본요소가 그려지는 위치이다
OpenGL은 컬러버퍼(전면, 후면, 보조)에 그리거나 읽기를 할 수 있다 버퍼의 선택 OpenGL은 컬러버퍼(전면, 후면, 보조)에 그리거나 읽기를 할 수 있다 디폴트는 후면버퍼이다 glDrawBuffer와 glReadBuffer로 변경 프레임 버퍼와 프로세서 메모리에서의 픽셀의 포맷이 다르며 이 두 종류의 메모리가 다른 위치에 있다 패킹과 언패킹이 필요하다 그리기와 읽기가 느릴 수 있다
OpenGL은 1-비트 픽셀들(bitmap)과 다중-비트 픽셀들(pixelmap)을 별도로 취급 비트맵들 OpenGL은 1-비트 픽셀들(bitmap)과 다중-비트 픽셀들(pixelmap)을 별도로 취급 bitmap은 프레임버퍼 내의 대응하는 픽셀이 현재 래스터 컬러로 그려질지를 결정하는 마스크이다 0 컬러 안 바뀜 1 쓰기모드에 따라 컬러 바뀜 bitmap은 래스터 텍스트에 유용하다 GLUT 폰트: GLUT_BIT_MAP_8_BY_13
glColor*()로 설정되는 그리기 색과 같다 glRasterPos*()에 대한 마지막 호출에 의해 고정된다 래스터 컬러 glColor*()로 설정되는 그리기 색과 같다 glRasterPos*()에 대한 마지막 호출에 의해 고정된다 객체는 청색으로 그려짐 비트맵 내에서는 적색의 그리기 색이 사용됨 glColor3f(1.0, 0.0, 0.0); glRasterPos3f(x, y, z); glColor3f(0.0, 0.0, 1.0); glBitmap(……. glBegin(GL_LINES); glVertex3f(…..)
비트맵 그리기 glBitmap(width, height, x0, y0, xi, yi, bitmap) 래스터위치로부터의 오프셋 비트맵이 그려진 후 래스터 위치의 증분 첫 번째 래스터 위치 두 번째 래스터 위치
예제: 체커보드 GLubyte wb[2] = {0x00, 0xff}; GLubyte check[512]; int i, j; for(i=0; i<64; i++) for (j=0; j<64, j++) check[i*8+j] = wb[(i/8+j/8)%2]; glBitmap(64,64,0.0,0.0,0.0,0.0,check);
OpenGL은 픽셀맵 또는 이미지라고 부르는 픽셀들의 사각 배열에 대해서 작업한다 픽셀은 바이트(8 bit) 덩어리로 이루어짐 휘도(회색조)이미지 1바이트/픽셀 RGB 3 바이트/픽셀 세가지 함수들: 픽셀 그리기: 프로세서 메모리에서 프레임 버퍼로 픽셀 읽기: 프레임 버퍼에서 프로세서 메모리로 픽셀 복사: 프레임 버퍼에서 프레임 버퍼로
OpenGL 픽셀 함수들 래스터 위치에서 시작 glReadPixels(x,y,width,height,format,type,myimage) 크기 픽셀 타입 프레임버퍼에서 시작위치 이미지타입 프로세서 메모리 로의 포인터 GLubyte myimage[512][512][3]; glReadPixels(0,0, 512, 512, GL_RGB, GL_UNSIGNED_BYTE, myimage); glDrawPixels(width,height,format,type,myimage) 래스터 위치에서 시작
그래픽스 카드가 초당 천 만개의 다각형을 렌더링 할 수 있지만 많은 현상들에 대해서 그것으로 충분하지 않다 텍스처 매핑 그래픽스 카드가 초당 천 만개의 다각형을 렌더링 할 수 있지만 많은 현상들에 대해서 그것으로 충분하지 않다 구름 풀 지형 피부
오렌지의 모델링 오렌지의 렌더링을 생각해 보자 오렌지 색의 구에서 시작해 보자 구를 보다 복잡한 형상으로 바꿈 지나치게 단순 표면특성을 잘 나타내지 못한다 (작은 홈들) 모든 홈을 모델링하려면 너무 많은 다각형이 필요
실제 오렌지 사진을 찍어 스캔한 후 단순한 기하 모델 위에 “붙여넣기”를 한다 오렌지의 모델링 실제 오렌지 사진을 찍어 스캔한 후 단순한 기하 모델 위에 “붙여넣기”를 한다 이것을 텍스처 매핑이라고 한다 그래도 표면이 부드럽기 때문에 충분하지 않다 국지적 형상을 바꿀 필요가 있다 범프매핑
세 가지 매핑 텍스처 매핑 환경(반사)매핑 범프매핑 다각형의 내부를 채우는데 이미지 사용 주변환경의 사진을 텍스처 맵으로 사용 고광택면의 시뮬레이션을 가능하게 함 범프매핑 렌더링 과정에서 법선 벡터를 바꾸어 줌
텍스처 매핑 기하 모델 텍스처 매핑된 구
환경 매핑
범프매핑
매핑의 구현위치 매핑기법은 파이프라인의 끝에 구현된다 클리퍼를 통과한 적은 수의 다각형에 대해서만 적용함으로 효율적이다
간단한가? 이미지를 표면에 매핑한다는 간단한 개념이지만 3,4 개의 좌표계가 관련되어 있다 2D 이미지 3D 표면
좌표계 매개변수 좌표계 텍스처 좌표계 세계 좌표계 화면 좌표계 곡면을 모델링하는데 사용될 수 있다 이미지 내에서 맵핑될 점들을 식별하는데 사용됨 세계 좌표계 개념적으로 매핑이 일어나는 곳 화면 좌표계 최종 이미지가 실제로 만들어지는 곳
텍스처 매핑 매개변수 좌표계 텍스처 좌표계 화면 좌표계 세계 좌표계
텍스처 좌표에서 표면의 한 점으로의 매핑을 생각해보자 세 개의 함수가 필요해 보임 매핑 함수들 기본적 문제는 어떻게 매핑을 발견하는 가이다 텍스처 좌표에서 표면의 한 점으로의 매핑을 생각해보자 세 개의 함수가 필요해 보임 x = x(s,t) y = y(s,t) z = z(s,t) 그러나 우리는 다른 방식을 원한다 s t (x,y,z)
역방향 매핑 우리가 원하는 것은 역방향 매핑이다 다음과 같은 형태의 매핑이 필요하다 이러한 함수는 일반적으로 찾기 어렵다 픽셀이 주어질 때, 객체 상의 어느 점이 거기 대응되는지를 알기 원한다 객체상의 한 점이 주어질 때, 텍스처 내의 어느 점이 거기 대응되는지를 알기 원한다 다음과 같은 형태의 매핑이 필요하다 s = s(x,y,z) t = t(x,y,z) 이러한 함수는 일반적으로 찾기 어렵다
2 단계 매핑 매핑문제의 한 해답은 먼저 텍스처를 단순한 중간 표면에 매핑하는 것이다 예: 실린더에 매핑
실린더 매핑 아래와 같은 매개변수적 실린더는 x = r cos 2p u y = r sin 2pu z = vh u,v 공간 내의 직사각형을 세계좌표계에서 반지름이 r 이고 높이가 h 인 실린더로 매핑한다 s = u t = v
구 매핑 다음과 같은 매개변수적 구를 x = r cos 2pu y = r sin 2pu cos 2pv z = r sin 2pu sin 2pv 실린더에서와 유사하게 사용하지만 어디에 왜곡을 둘 것인가를 결정해야 한다 구는 환경맵에서 사용된다
상자 매핑 간단한 직교투영과 함께 간단하게 사용된다 환경맵에서도 사용된다
2차 매핑 중간객체에서 실제 객체로의 매핑 실제 중간 중간 객체에서 실제 객체로의 법선 실제 객체에서 중간 객체로의 법선 중간 객체의 중심으로부터의 벡터 실제 중간
2 단계 매핑
앨리어싱 텍스처를 점 샘플링하는 것은 앨리어싱 에러를 일으킬 수 있다 u,v (또는 x,y,z)공간에서의 점 샘플 푸른 띠를 놓침 텍스처 공간에서의 점 샘플
면적 평균 보다 낫지만 더 느린 대안은 면적평균을 사용하는 것이다 픽셀 전이미지 픽셀의 전이미지는 곡면임
OpenGL에서의 기본전략 텍스처를 적용하는 3 단계 텍스처를 지정 이미지를 읽어 들이거나 생성 텍스처로 지정 텍스처를 인에이블 정점들에 텍스처 좌표를 지정 적절한 매핑함수의 사용은 응용의 몫이다 텍스처 매개변수의 지정 wrapping, filtering
텍스처 매핑 x y z 기하 화면 s t 이미지
텍스처 예제 아래의 텍스처는 256 x 256 이미지이고, 그것이 위와 같이 사각형에 매핑되어 투시관측되었다
이미지와 기하는 별도의 파이프라인을 따라서 래스터기에서 합쳐진다 텍스처 매핑과 OpenGL 파이프라인 이미지와 기하는 별도의 파이프라인을 따라서 래스터기에서 합쳐진다 “복잡한” 텍스처가 기하적 복잡성을 증가시키지 않는다 기하파이프라인 정점들 픽셀파이프라인 이미지 래스터기
텍셀 (texel , texture element)의 배열로 부터 CPU 메모리 안에 텍스처 이미지를 정의 텍스처 이미지의 지정 텍셀 (texel , texture element)의 배열로 부터 CPU 메모리 안에 텍스처 이미지를 정의 Glubyte my_texels[512][512]; 다른 픽셀 맵처럼 정의한다 스캔된 이미지 응용 코드로부터 생성 텍스처매핑을 인에이블 glEnable(GL_TEXTURE_2D) OpenGL 은 1-4 차원의 텍스처 맵을 지원
이미지를 텍스처로 지정 glTexImage2D( target, level, components, w, h, border, format, type, texels ); target: 텍스처 종류, e.g. GL_TEXTURE_2D level: 밉매핑을 위해 사용됨 (뒤에 논의됨) components: 텍셀당 요소들 w, h: texels 의 픽셀단위의 너비와 높이 border: smoothing을 위해 사용됨 (뒤에 논의됨) format, type: 텍셀을 기술 texels: 텍셀 배열에 대한 포인터 glTexImage2D(GL_TEXTURE_2D, 0, 3, 512, 512, 0, GL_RGB, GL_UNSIGNED_BYTE, my_texels); glEnable(GL_TEXTURE_2D);
이미지를 텍스처로 지정
OpenGL에서는 텍스처의 크기가 2의 정수 승이 되어야 한다 이미지를 텍스처로 지정 OpenGL에서는 텍스처의 크기가 2의 정수 승이 되어야 한다 이미지의 크기가 2의 정수승이 아니면 gluScaleImage( format, w_in, h_in, type_in, *data_in, w_out, h_out, type_out, *data_out ); data_in 은 소스 이미지 data_out 은 목적 이미지 이미지는 크기변환과정에서 보간되고 필터된다
glTexCoord*() 각 정점에서 지정됨 텍스처를 매핑함 매개변수적 텍스처 좌표에 기반함 glTexCoord*() 각 정점에서 지정됨 텍스처 공간 객체 공간 t 1, 1 (s, t) = (0.2, 0.8) 0, 1 A a c (0.4, 0.2) b B C s (0.8, 0.4) 0, 0 1, 0
전형적 코드 정점배열을 사용해서 효율을 높일 수 있음 glBegin(GL_POLYGON); glColor3f(r0, g0, b0); glNormal3f(u0, v0, w0); glTexCoord2f(s0, t0); glVertex3f(x0, y0, z0); glColor3f(r1, g1, b1); glNormal3f(u1, v1, w1); glTexCoord2f(s1, t1); glVertex3f(x1, y1, z1); . glEnd(); 정점배열을 사용해서 효율을 높일 수 있음
예제 전체 텍셀배열 사용 텍셀배열의 일부만 사용
보간 OpenGL은 지정된 텍스처 좌표에서 적절한 텍셀을 찾기 위해서 쌍일차 보간을 사용 왜곡이 일어날 수 있다 사다리꼴에 매핑 삼각형에매핑 다른 텍스처 좌표 선택
OpenGL은 텍스처 적용방식을 결정하는 다양한 매개변수들을 가지고 있다 텍스처 매개변수들 OpenGL은 텍스처 적용방식을 결정하는 다양한 매개변수들을 가지고 있다 wrapping 매개변수는 s와 t가 (0,1) 범위 밖에 있을 때 어떻게 동작할 지를 정해준다 필터모드는 점 샘플링 대신에 면적평균을 사용할 수 있도록 한다 밉매핑은 텍스처를 여러 해상도로 사용할 수 있게 한다 환경매개변수는 텍스처 매핑이 음영과 어떻게 상호작용 할 것인지를 정해준다
Clamping: if s,t > 1 use 1, if s,t <0 use 0 wrapping 모드 Clamping: if s,t > 1 use 1, if s,t <0 use 0 Wrapping: use s,t modulo 1 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP ) glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT ) texture s t GL_CLAMP wrapping GL_REPEAT
magnification과 minification 텍스처 값을 얻기 위해서 점 샘플링 (nearest texel) 또는 선형 필터링( 2 x 2 필터)을 사용할 수 있다 magnification minification
필터 모드 모드의 결정 glTexParameteri( target, type, mode ); glTexParameteri(GL_TEXTURE_2D, GL_TEXURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXURE_MIN_FILTER, GL_LINEAR); Note: 선형 필터링은 변에서의 필터링을 위해서 추가적인 텍셀의 경계를 필요로 한다 (border = 1)
밉매핑은 감소하는 해상도의 사전 필터된 텍스처 맵들의 사용을 가능하게 한다 밉맵된 텍스처 밉매핑은 감소하는 해상도의 사전 필터된 텍스처 맵들의 사용을 가능하게 한다 작은 텍스처된 객체들에 대해서 보간 에러를 줄여준다 gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, 64, 64, GL_RGB, GL_UNSIGNED_BYTE, my_texels); 원래 64x64 배열에 대해 위의 함수로 32x32, 16x16, 8x8, 4x4, 2x2, 1x1 배열을 설정
밉맵들은 다음 함수로 자동 설정됨 밉맵된 텍스처 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); 최적의 밉맵에서 포인트 샘플링 GL_NEAREST_MIPMAP_LINEAR : 최적의 밉맵에서 필터링 GL_LINEAR_MIPMAP_NEAREST : 밉맵간의 보간 후 포인트 샘플링 GL_LINEAR_MIPMAP_NEAREST : 밉맵간의 보간 후 필터링
예제 선형 필터링 점 샘플링 밉맵된 점 샘플링 밉맵된 선형 필터링
텍스처와 음영의 상호작용 디폴트 – 음영값과 텍스처 값을 곱함 glTexEnvi( GL_TEX_ENV, GL_TEX_MODE, GL_MODULATE); GL_DECAL : 텍스처만을 사용
불투명성과 반투명성 불투명 면으로는 빛이 통과하지 못한다 투명 면으로는 모든 빛이 통과한다 반투명 면은 일부의 빛을 통과시킨다 반투명성 = 1 – 불투명성 (a) 불투명 면 a =1
불투명성을 물리적으로 올바르게 다루는 것은 다음의 이유로 어렵다 물리적 모델 불투명성을 물리적으로 올바르게 다루는 것은 다음의 이유로 어렵다 광선과 재질의 복잡한 내부적 상호작용 파이프라인 렌더기의 사용
쓰기 모델 불투명성을 저장하기 위해서 RGBA 색의 A 성분을 사용 렌더링을 하는 동안 RGBA 값들을 사용하기 위해서 쓰기 모델을 확장할 수 있다 배합 소스 배합 계수 목적 성분 소스 성분 목적 배합 계수 색 버퍼
각 RGBA 성분에 대해서 소스와 목적 배합계수를 정의할 수 있다 배합 방정식 각 RGBA 성분에 대해서 소스와 목적 배합계수를 정의할 수 있다 s = [sr, sg, sb, sa] d = [dr, dg, db, da] 소스와 목적 색이 다음과 같다고 가정 b = [br, bg, bb, ba] c = [cr, cg, cb, ca] 다음과 같이 배합 c’ = [br sr+ cr dr, bg sg+ cg dg , bb sb+ cb db , ba sa+ ca da ]
glEnable(GL_BLEND) OpenGL 배합과 합성 배합을 인에이블링하고 소스와 목적계수를 설정 몇몇 계수들만 지원됨 glBlendFunc(source_factor, destination_factor) 몇몇 계수들만 지원됨 GL_ZERO, GL_ONE GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA Redbook 참조
Note: 이 식은 다각형이 불투명하거나 반투명하면 올바르다 예제 (R0,G0,B0,1)인 불투명 배경 색으로부터 시작한다고 가정 이 색은 초기 목적 색이 된다 (R1,G1,B1,a1) 색을 갖는 반투명 다각형으로 배합하기를 원한다 GL_SRC_ALPHA 와 GL_ONE_MINUS_SRC_ALPHA 를 소스와 목적 배합 계수로 선택한다 R’1 = a1 R1 +(1- a1) R0, …… Note: 이 식은 다각형이 불투명하거나 반투명하면 올바르다
모든 성분들(RGBA) - (0,1) 사이의 값을 갖도록 클램핑된다 클램핑과 정밀도 모든 성분들(RGBA) - (0,1) 사이의 값을 갖도록 클램핑된다 그러나 보통의 시스템에서, RGBA 값들은 8 비트를 갖는다 많은 성분들을 더하면 정밀도를 잃을 수 있다 예: n 개의 이미지들을 더함 클램핑을 피하기 위해서 모든 컬러 성분을 n으로 나눔 소스계수 = 1, 목적계수 = 1로 배합 그러나 n으로 나눔으로 비트를 잃어버림
순서 의존성 이 이미지는 올바른가? 아닐 수 있다 다각형들은 파이프라인을 통과한 순서대로 렌더링된다 배합기능은 순서에 의존적이다
고정된 컬러와 합성하되 합성계수를 깊이에 의존적이 되도록 할 수 있다. 연무 고정된 컬러와 합성하되 합성계수를 깊이에 의존적이 되도록 할 수 있다. 연무효과를 시뮬레이션한다 소스 컬러 Cs 와 연무 컬러 Cf 를 다음과 같이 배합 Cs’=f Cs + (1-f) Cf f 는 연무계수 지수적 가우시안 선형(depth cueing)
연무 함수들
OpenGL 연무 함수 GLfloat fcolor[4] = {……}: glEnable(GL_FOG); glFogf(GL_FOG_MODE, GL_EXP); glFogf(GL_FOG_DENSITY, 0.5); glFOgv(GL_FOG, fcolor);
직선 앨리어싱 이상적 래스터 직선은 폭이 한 픽셀이다 수직선과 수평선을 제외하면 모든 직선은 픽셀들을 부분적으로 덮는다 단순한 알고리즘들은 완전한 픽셀만 그림 계단효과, 즉 앨리어싱이 일어난다 다각형에서도 유사
앤티 앨리어싱 픽셀 컬러의 부분을 프레임버퍼에 더한다 중첩없음 중첩 비율은 조각에 의해 덮여지는 픽셀의 부분에 의존적이다 비율은 중첩이 있는지에 의존적이다 중첩없음 중첩
면적 평균 배합계수로 평균면적 a1+a2-a1a2 를 사용
점, 직선, 다각형에 대해서 별도로 인에이블 할 수 있다 OpenGL 앤티 앨리어싱 점, 직선, 다각형에 대해서 별도로 인에이블 할 수 있다 glEnable(GL_POINT_SMOOTH); glEnable(GL_LINE_SMOOTH); glEnable(GL_POLYGON_SMOOTH); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
합성과 배합은 프레임 버퍼의 해상도에 의해서 제약을 받는다 누적 버퍼 합성과 배합은 프레임 버퍼의 해상도에 의해서 제약을 받는다 보통 컬러 성분 당 8 비트 누적버퍼는 이 문제를 해결하기 위한 고해상도 버퍼이다 (성분 당16 비트 이상) 크기변환계수를 가지고 이 버퍼에 읽기 쓰기를 한다 프레임버퍼에 직접 합성하는 것보다 느림