레이블이 OpenGL인 게시물을 표시합니다. 모든 게시물 표시
레이블이 OpenGL인 게시물을 표시합니다. 모든 게시물 표시

2018년 1월 15일 월요일

Buffers and Shader (2) - Shader

Buffers and Shader (2) - Shader


Shader 란 무엇인가? 라는 질문에 대한 답을 하기에는 매우 많은 지면이 필요할 것이다. 또한 초보적인 그래픽 프로그래머에게 만족스럽게 설명한다는 것은 어려운 일이 될 것이다.


우선 “The Book of Shaders” 라는 책을 권하고 싶다.


The book of shaders 에 나온 내용중 다음을 소개한다.


왜 쉐이더를 사람들이 어렵다고 할까?


2차 세계대전에서 쌀공급으로 유명한 미국의 벤삼촌이 이르길,


"큰 힘에는 큰 책임이 따른다"


고 했다.


병렬연산 또한 이 법칙을 따른다; GPU의 강력한 컴퓨테이션 능력은 이것을 쓰기 위해 따라야 할 제약과 제한이 있다.


파이프상에서 병렬처리를 하기 위해서는, 각 쓰레드마다, 서로에 대해 철저히 개별적이여야 한다.


쓰레드는 다른 쓰레드에 대해 "실명" 되어 있다고 미국에서는 표현하는데, 서로의 데이터에 대해 엑세스가 없다는 말이다.


그래서 각각의 프로세스들은 서로 데이터를 주고 받고 처리하는것이 불가능하다. 쓰레드끼리 소통하게 하는것은 데이터를 더럽힐수 있다.


또한, GPU는 모든 병렬 마이크로 프로세서들 (파이프들) 을 항시 바쁘게 하고 있다;
이 파이프들은 해당작업이 끝나는 대로 다른 작업을 받아 수행하도록 설계되어 있다.


또한, 각 쓰레드는 이미 수행한 작업에 대한 어떠한 정보도 가질수 없다.
보통 이런 작업들은 운영체제의 UI요소를 그리고 있는것이거나, 게임의 배경화면을 그리거나, 브라우져의 이메일 텍스트를 그리는 것들이다.


각 쓰레드는 서로에게 실명되있다고 표현할뿐아니라, 기억이없음 이라고도 표현하는데, 이것은 이미 수행한 작업에 대한 어떠한 정보도 가지고 있지 않다는 말이다.


바로 이런 점들이 일반적인 프로그래밍 요소와 크게 다른부분이라고 할수 있어서 프로그래밍을 막 접한 이들에게는 어려운 컨셉일수도 있는것이다.


왜 쉐이더는 빠를까?


이 질문에 대한 가장 간단한 답은 “Parallel processing” 병렬 처리 이다.


CPU가 하나의 큰 공장같은 파이프라고 가정하자.


파이프로 들어오는것들은 어떤 작업들이고, 그 작업들이 파이프를 지나면 나오면서 결과가 된다고 하자.


어떤 작업은 크고 복잡하기도 할것이고 어떤건 매우 단순하기도 할것이다.


그리고 컴퓨터는 설계상 절차적으로 작업을 실행하도록 되어 있다; 작업하나가 끝나야 그다음 작업이 시작된다.


근대의 컴퓨터들은 4개의 프로세서로 이루어진 그룹이 이런 파이프처럼 작동하는데, 역시 순차적으로 작업을 하나 끝내고 다음걸 시작하는 방식이다.


각 파이프는 thread라고도 알려져 있다.


CPU


비디오 게임이나 그래픽 응용 어플리케이션들은 일반적으로 보다 많은 프로세싱 파워를 요구한다.


이유는 그래픽 요소들 자체가 수많은 픽셀들의 연산으로 이루어졌기 때문이다.


스크린위에 모든 픽셀들이 각각 계산되고, 3D 게임의 경우, 각 3D 객체들과 모든 퍼스펙티브가 계산되어야 할 것이다.


다시 파이프와 작업들의 개념으로 돌아와서, 스크린위에 각 픽셀들은 각각 하나의 작은 작업들을 의미한다.
그리고 이 각각의 작은 작업들은 CPU에게 그다지 버겁지 않은 작업일 것이다.


하지만 문제는 이렇게 작은 작업들이 스크린위에 픽셀개수만큼 반복되어야 한다는 점이다.


800x600 의 해상도의 게임이라고 하면 480,000개의 픽셀들이 매 프레임 계산되어야 하는데 이말은 14,400,000 번의 계산이 초당 이루어 져야 한다는 말이다.


이것은 꽤나 비효율적일수 있다. 레티나 디스플레이의 경우, 2880x1800 해상도의  픽셀들이 초당 60번 계산되어야 하는데, 계산해보면 초당 311,040,000번이다.
그래픽 엔지니어들은 이 문제를 어떻게 풀까?




바로 이 문제를 풀기 위해 등장 하는 솔루션이 있다. 바로 parellel processing이다.


강력한 마이크로 프로세서를 몇개 또는 큰 파이프를 쓰는대신, 매우 작지만 많은 수의  마이크로 프로세서들을 한번에 동시에 돌리는 것이다.


그것이 바로 Graphic Processor Unit. GPU이다.


GPU


작은 마이크로프로세서들을 여러개의 파이프들로 이루어진 테이블로 생각해보자.
그리고 각 픽셀의 데이터를 핑퐁볼이라고 생각해보자.


14,400,000개의 핑퐁볼이 있다고 한다면, 800x600개의 작은 파이프들로 이루어진 테이블에 480,000개의 핑퐁볼을 30번 떨어뜨리면 아마 최대한 효과적으로 모든 핑퐁볼을 이 테이블 파이프를 통해 통과 시킬수 있을 것이다.


고해상도 화면의 렌더링도 이런식으로 진행되는 것이다 - 병렬하드웨어 지원이 높을수록 더 큰 픽셀데이터들을 다룰수 있게 되는것이다.
GPU의 또다른 슈퍼 파워중 하나는, 하드웨어 지원으로 가속된 수학 함수 연산이다. 즉, 소프트웨어상에서가 아닌, 마이크로칩상에서 바로 연산이 진행된다는 이야기다.


이말은 더 많은 삼각함수 연산, 매트릭스 연산이 가능하다는 말이다.


Shading Language


Shader를 구현하기 위해서는 Shading 언어를 알아야 한다. 즉 Shading 언어도 C 언어와 마찬가지로 프로그래밍 언어이다. C 언어와 매우 유사하다.


Shading 언어는 Graphic Engine에 따라 다르다.


OpenGL 은 GLSL 이라는 언어를 사용하고 Direct3D 는 HLSL 이라는 언어를 사용한다. 비슷하지만 서로 다른 라이브러리에서 사용되는 것이기 때문에 100% 호환은 아니다.


Shading 언어는 예약어나 규칙은 기타 다른 컴퓨터 컴파일 언어보다는 복잡하지 않다. 그 이유는 Shading 언어가 처리해야 하는것은 매우 한정적이기 때문이다.


GLSL : OpenGL Shading Language
C 언어를 기초로 한 상위레벨 쉐이딩 언어이다. GLslang로도 알려져 있다. HLSL 과 유사한 이 언어는 어셈블리 언어나 하드웨어에 의존한 언으를 사용하지 않고 개발자가 그래픽스 파이프라인을 직접 제어할 수 있도록 OpenGL ARB(Architecture Review Board) 가 책정하였다.


HLSL : High Level Shading Language
HLSL 은 마이크로소프트의 Direct3D API에 사용되는 쉐이딩 언어이다. 고급 쉐이딩 언어라고도 불리며 줄여서 HLSL이라고 불린다. 이 쉐이딩 언어는 OpenGL API에서 표준으로 사용되는 쉐이딩 언어인 GLSL과 유사한 언어이다. 또한 Nvidia 의 Cg 쉐이딩 언어와도 유사하다. Cg와 서로 협력하여 개발 하였기 때문이기도 하다.


OpenGL Shding Language 공식 사이트 주소는 아래와 같다.


HLSL 프로그래밍 가이드 사이트는 다음과 같다.


Shader 의 종류


Shader  는 Rendering Pipeline의 각 stage를 구성하는 요소로 작동하며 대표적으로 다음의 3가지를 들 수 있다.


  1. Vertex Shader 정점 쉐이더
  2. Pixel Shader 픽셀 쉐이더
  3. Geometry Shader 지오메트리 쉐이더


Vertex Shader (버텍스 쉐이더, 정점 쉐이더)
- 물체의 정점 정보에 수학적인 연산을 함으로써 물체에 특별한 효과를 주는데 사용되는 쉐이더.


- 정점은 3차원의 위치를 나타내는 x, y, z좌표나 색상, 텍스쳐, 조명 정보 등의 정보를 가짐.


- 버텍스 쉐이더는 정점의 정보값들을 변화시켜서 물체를 특별한 위치로 옮기거나 텍스쳐를 바꾸거나 색상을 바꾸는 등의 작업을 수행.


- 기존의 정점을 삭제하거나 새로운 정점을 추가하는 등의 작업은 불가능.


Pixel Shader (픽셀 쉐이더, PS)
- 렌더링 될 각각의 픽셀들의 색을 계산하는 방식의 쉐이더.


- 최종적으로 픽셀이 어떻게 보일지를 결정 함.


- 언제나 같은 색을 출력하는 간단한 일로부터 텍스쳐로부터 색을 읽어 오거나 빛을 적용하는 것, 범프 맵핑, 그림자, 반사광, 투명처리 등 복잡한 현상 등을 수행하는 것이 가능.
- 각각의 픽셀들이 렌더링될 때 수행되므로 다른 픽셀들과 아무런 연관이 없음.


- 오직 픽셀만을 연산하므로 주변의 픽셀 혹은 그리는 도형에 대한 정보를 알 수 없음.


- 매우 복잡한 효과를 생성하는 것은 불가능.


- 픽셀의 색 이외에 깊이(Z버퍼)나 다른색(다른 렌더 목표물)의 출력이 가능.


Geometry Shader (지오메트리 쉐이더)
- 버텍스 쉐이더가 수행된 후, 수행 됨.


- 버텍스 쉐이더를 거쳐온 도형 정보를 입력받아 출력 함.
 정점 3개가 지오메트리 쉐이더에 입력되면 쉐이더는 정점을 모두 없앨 수도 있고 더 많은 도형을 만들어 내보내는 것도 가능.


- 지오메트리 쉐이더를 지나간 도형 정보는 레스터라이즈를 거친 뒤 픽셀 쉐이더를 통과하게 됨.
- 버텍스 쉐이더에서 할 수 없는 점이나, 선, 삼각형 등의 도형 생성 가능.
- 지오메트리 쉐이더는 테셀레이션이나 그림자 효과, 큐브 맵을 한번의 처리로 렌더링 하는데 주로 사용 됨.


렌더링 파이프라인에서의 쉐이더


렌더링 파이프라인에는 Vertex Shader와 Fragment Shader는 반드시 구성되어 있어야 하며 Geometry Shader는 필요하지 않으면 없어도 된다.


아래 그림은 각각의 Shader가 렌더링 파이프라인에서 어느 부분에 위치 하는지를 보여준다.


우선 Vertex Data 는 Vertex Shader 에 전달되고 입력된 정점들을 정해진 규칙에 의하여 조립된다. 여기서 정해진 규칙이란, 정점들이 어떤 형태를 이루는 정점 데이터 들인지를 알려주는 규칙이다. 이러한 규칙은 정점들이 Line List인지 Line Strip 인지, 또는 Triangle List인지 Triangle Strip인지 에 대한 정보이다.


이렇게 조립된 정보는 이제 Geometry Shader로 전달된다. Geometry Shader는 반드시 있어야 하는 Shader는 아니다. Geometry Shader에서는 전달된 Geometry 정보를 쪼개거나 더하거나 하는 작업을 할 수 있다.


이렇게 만들어진 백터 그래픽 정보는 레스터라이징을 수행 하여 픽셀 정보로 바꾸게 된다.


만들어진 픽셀 정보는 Fragment Shader로 들어가게 되며 Fragment Shader에서는 각각의 픽셀에 대한 색상을 지정하게 된 후 Test and Blending 을 거쳐 최종의 이미지를 생산해 낸다.

2018년 1월 13일 토요일

OpenGL and Direct3D Header Files

OpenGL and Direct3D Header Files


우리는 컴퓨터 그래픽스 프로그래밍에 있어서 기본이 되는 Direct3D 및 OpenGL 기술에 대하여 알아 보고 있다.


또한 이러한 기술을 C/C++ 프로그래밍 기술에 의하여 살펴 보고자 한다.


C/C++ 프로그래밍은 어떠한 외부 라이브러리 또는 API 와 같은 인터페이스 기술을 가져와서 사용하고자 할 경우 header 파일을 이용하여 연결하고 코딩 하게 된다.


사실 엄밀히 말하면 header 파일은 하나의 혁식적인 측면에서 사용하는 것이지,그것 자체가 목적이 되지는 않는다.


많은 대부분의 C/C++ 라이브러리나 인터페이스 (API) 들은 header 파일을 제공하고 있다. 이는 해당 라이브러리에 포함된 함수 또는 Class들의 호출 규칙을 정해 놓은 파일이다.


그러므로 대부분의 C/C++ 개발자들은 해당 라이브러리나 인터페이스를 자신의 코드에서 호출하여 사용하고 싶을때 이들 header 파일의 존재를 확인하는것이 우선이 될 것이다.


Visual C++ 이나 C++ Builder 들은 해당 컴파일러를 시스템에 설치할 경우 라이브러리,  API 등과 같이 header 파일들도 자동으로 설치되어 사용할 수 있도록 준비하고 있다.


단 Direct3D 나 OpenGL 역시 각각 서로의 version 시스템이 있기 때문에 자신이 사용하고 싶은 version에 대한 header 파일을 사용하도록 하고 있다.


대부분의 컴파일러는 해당 컴파일러가 배포되는 싯점에서의 최신의 라이브러리를 제공하고자 노력하고 있다.


사실 OpenGL은 그 version 에 대하여 header 파일 이름이 따로 존재하지는 않는다. 그러나 Direct3D는 header file에 해당 버전의 숫자를 이름에 적용하고 있다. 이러한 부분이 Direct3D 와 그 개발 환경면에서 차이를 보인다고 볼 수 있지만, 중요한것은 아니다.


자신이 설치된 컴파일러에서 기본적으로 제공하는 라이브러리 또는 API를 사용할 수도 있으나 따로 해당 기술의 지원 페이지에서 원하는 버전의 라이브러리를 취득한 후 사용할 수 도 있으나 최신의 컴파일러를 설치하면 해당 컴파일러가 지원하는 최신의 API가 제공된다고 생각해도 틀리지 않으니 가능하면 이를 따르는것도 나쁘지 않다.

OpenGL Header Files






#include <gl/glew.h>
#include <gl/gl.h>
#include <gl/glu.h>


위의 3개의 header 파일이 기본으로 사용하는 파일들이다. 사실 glew.h 는 OpenGL 기본파일이 아니고 확장 파일이다.


GLEW 는 OpenGL SDK page에서 그 설명을 간단히 볼 수 있다.


GLEW is an open-source cross-platform extension loading library with thread-safe support for multiple rendering contexts and automatic code generation capability. GLEW provides easy-to-use and efficient methods for checking OpenGL extensions and core functionality.


간단히 해석을 해보면, GLEW 는 open source 이며 cross-platform 확장 라이브러리로 제공되며 이는 다중 렌더링을 위하여 스레드 세이프 코드로 제공한다. GLEW는 OpenGL 확장과 핵심 기능을 확인하는 데 사용하기 쉽고 효율적인 방법을 제공한다.

라고 되어 있다. 일반적으로 컴파일러가 기본적으로 제공하는 라이브러리에는 GLEW는 제공되고 있지 않은 경우가 많다. 내가 아는 한 대부분 기본으로 제공하지 않고 있다.

GLEW의 준비


그러므로 GLEW 는 스스로 다운로드 받아 자신의 개발 환경에 포함시켜 줘야 한다.


이글을 작성하는 필자는 Visual Studio 에서 제공하는 Visual C++ 과 RADSTUDIO 의 C++ Builder 를 모두 사용하고 있다. 두 경우 스스로 GLEW를 준비해야 하는 것은 마찬가지이다.


예를 든 두개의 컴파일러는 그들이 링크할 수 있는 object library의 format 구조가 다르다. 그러므로 OPENGL 홈페이지에서 받은 링크 가능한 파일을 받았다고 해도 직접 사용할 수 없는 경우가 많다.


특히 C++ Builder 에서 연결하고자 하는 라이브러리는 대부분의 라이브러리에서 제공하고 있지 않다. 윈도우의 경우 Visual C++ 용으로로 제공되며 GNU C 환경의 각종 컴파일 라이브러리로 제공하기도 하지만….. C++ Builder는 아니다.


그렇다고 못구하는 것은아니다. 구하지 못하면 만들면 된다.
사실 만든다는것은 아니고 “직접 만들어 낸다” 라고 생각하면 더 맞을 것이다.

GLEW 는 OpenSource 이다. 그러므로 누구나 쉽게 그 소스코드 (C 코드로 작성되었다)를 다운로드 받아 자신의 C 컴파일러로 컴파일 하면 된다.
가장 쉽고 확실한 방법이다.


GLEW C 소스 코드는 하나의 C 파일로 되어 있으니 복잡하지도 않으니 이 방법을 사용하기 바란다.  GLEW 소스코드를 받으면 3개의 C 파일이 있을텐데 두개는 그냥 테스트 코드이니 개의치 말기 바란다.


GLEW Website



Source

ZIP |  TGZ


Binaries





컴파일 하기 싫다면 미리 컴파일된 바이너리 파일을 받아도 상관없다. 나 역시도 바이너리 파일을 받아 링크하여 사용하고 있다. 그런것이 속편하다. ^^


GLEW 바이너리 파일을 받아보면 위와 같은 내용으로 이루어 진다. LICENSE.txt 는 읽어보기 바라며 만약 자신이 만든 어플리케이션이 GLEW를 사용하고 있다면 이 License.txt 의 내용을 명시해주는 용도로 사용하면 된다.


실제로 프로그래밍에 필요한 부분은 include 와 bin 의 각 시스템 버전에 맞는 DLL 파일이다.
glew32.dll 파일이 그렇다. 이는 Win32 와 x64 를 위하여 따로 구분된 파일을 제공한다.
단 아쉬운점은 64비트 버전도 이름은 glew32.dll 이라는 것이 아쉽다.


Visual C++ 을 사용한다면 lib 폴더의 lib 파일을 링크에 추가해 주면 된다.
그러나 C++ Builder 를 컴파일러로 사용한다면 lib 파일을 직접 사용할 수 없다.
그러므로 DLL 파일에서 object 파일을 생성하여 사용해야 한다.


그렇다고 크게 걱정할 필요는 없다. C++ Builder에 이러한 기능을 제공하고 있기 때문이다.
mkexp.exe
이는 C++ Builder 사용자에 해당하니 Visual C++ 사용자는 몰라도 되는 사항이다.
mkexp.exe 는 64bit 용이고 32비트용은 implib.exe 일 것이다.


둘다 사용법은 비슷하다. 두 프로그램의 사용법은 쉽게 알수 있을 것이다.


mkexp 의 사용법만 여기에 예를 들겠다.


mkexp glew.a glew32.dll


DOS 창을 열고 위와 같이 명령을 수행하면 (mkexp 가 있는 부분이 path 로 링크가 걸리는것은 당연하겠지만)   glew32.dll 에서 link 가능한 object 파일을 생성해 줄 것이다.
64비트의 경우 확장자가 .a 를 기본으로 사용한다는 것은 다 아는 내용이고..


여기서 만들어진 glew.a 파일을 link 에 포함시키면 된다. 프로젝트에 직접 포함해도 되고 자신의 source code에 #pragma link 로 포함시켜도 될 것이다.


복잡하게 설명 했지만 위의 글의 요약은 dll 과 header file들, dll호출을 위한 object 파일을 준비하는 내용이라 하겠다.

사실 Open Source 는 소스코드도 구하고 그 기술도 무료로 사용할 수 있는 장점은 있지만 그 확장이 매우 다양하기 때문에, 이를 사용하는 개발환경을 정확히 구축하는 것은 그렇게 만만히 볼 일은 아니다.


GLEW 외에 다양한 확장 라이브러리가 존재한다. 그러나 OpenGL 을 시작하는 입장에서 다른 다양한 확장은 없어도 무난하다. 그냥 OpenGL 자체와 GLEW 정도로 준비하면 된다.


나는 아주 가끔 mingw 를 컴파일러로 사용하기도 한다. 즉 gcc 를 사용할때도 있다는 것이다.
mingw 는 cross plotform 코드를 만들어 내는데 유용하기 때문이다. mingw 에서도 OpenGL을 사용하기 위해서는 비슷한 준비과정이 필요하지만 gcc 환경에서의 OpenSource 라이브러리의 설치는 더 편리한것 같다는 생각이 든다.


어쨌든 자신의 소스코드에
#include <gl/glew.h>
#include <gl/gl.h>
#include <gl/glu.h>


를 추가 한 후 컴파일이 성공하게 되면 OpenGL 프로그래밍을 시작할 환경은 준비된 것이라 생각하면 된다.


여기서 glew.h 는 gl.h , glu.h 보다 앞서 위치해야 한다는것은 명심하자.
사실 확장이 베이스보다 앞에 나온다는것이 의아하기는 하다..



Direct3D Header Files


#include <d3d11.h>
#include <d3dx10.h>
#include <d3dcompiler.h>


Direct3D 프로그래밍을 위하여 우리는 Direct3D 11 을 사용할 것이다. 과거 몇년동안 아니면 지금도 Direct3D9 을 사용하는 경우가 많지만 여기서는 Direct3D 11을 사용하도록 하겠다.


일단 Direct3D 는 기본 컴파일러에서 제공하는 Windows SDK를 설치하거나 Microsoft Soft 에서 제공하는 것을 설치해도 된다.
이경우 역시 C++ Builder 사용자라면 앞에서와 같이 DLL link를 수행할 수 있는 object 파일(library) 을 준비해야 하며 여기서 따로 설명하지는 않겠다.


일단 자신의 컴파일러에서 위의 header 파일을 소스코드에 넣고 컴파일 해보기 바란다.


d3d11l.lib 나 d3d11.a 파일 (target version에 맞추어) 링크에 추가해주면 될 것이다.

Direct3D에 있어서는 특별한 확장 라이브러리를 사용하지는 않을 것이지만 d3dx10.h 파일이 제공하는 메크로 확장 코드는 사용할수도 있으리라 생각한다.


d3dx11 이라고 해도 d3dx10 의 기능은 사용하지 않는 것이 아니며, 지금 싯점에서 d3dx11에서도 몇가지 매크로 함수들은 d3dx10 의 것을 그대로 사용하고 있기 때문이다.


또한 HLSL , 즉 Shader 프로그래밍을 하기 위하여 Shader 컴파일러가 필요하며 이는 d3dcompiler.h 에 정의 되어 있으므로 이것도 테스트 하기 바란다.

2018년 1월 12일 금요일

OpenGL - Initialize OpenGL

OpenGL - Initialize OpenGL

MSVC ignores floating point exceptions by default, BCB doesn't..

#ifndef _WIN64
_control87(MCW_EM, MCW_EM);
#endif

_clear87();
_control87(MCW_EM, MCW_EM);

before each frame is rendered, works fine for me..


Creating an OpenGL Context on Window

프로그램적으로 OpenGL Context가 생성되기 전에는 OpenGL이 존재하지 않는다. 그러므로 OpenGL의 표준 Spec에 의한 재약은 없다.

다시 말해서 각각의 시스템(OS system)에서 OpenGL Context 를 생성하는 방식에 대해서는 특정한 규정이 없다는 것이다.

그러므로 각각의 윈도우 시스템(MS Windows 또는 OSX , Linux 등등) 에서 제공하는 API를 이용하여 OpenGL Context를 만들어 주면 된다.

여기서는 Microsoft Windows System을 가정하여 설명하게 될 것이다. 즉 WGL 부분이 된다.

MS-Windows 에서 윈도우를 생성하면 HWND 가 만들어 진다. HWND는 반드시 생성 type으로 CS_OWNDC 옵션을 넣어서 만들어야 한다.

다음의 과정을 알아볼 것이다.

Pixel Format 설정 -> OpenGL Context 생성 -> Context 의 사용 -> OpenGL Context의 제거

Pixel Format

MS-Windows의 각 창에는 그와 연결된 Device Context(DC) 가 있다.  이러한 DC에는 Pixel Format이라는 형식을 지정할 수 있다.

이러한 Pixel Format 은 해당 윈도우에 만들어지는 OpenGL Context의 기본적인 Framebuffer의 속성으로 적용될 것이다.

Pixel Format 을 설정하는 것은 그렇게 직관적이지 않다.
픽셀 포맷을 만드는 방법은 원하는 기능을 설명하는 구조체의 각 필드들을 원하는 값으로 채우는 것이다.

다음 설정은 일반적으로 OpenGL 윈도우를 만들기 위한 Pixel Format을 보여주고 있다.

PIXELFORMATDESCRIPTOR pfd =
{
sizeof(PIXELFORMATDESCRIPTOR),
1,
PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,    // Flags
PFD_TYPE_RGBA,        // The kind of framebuffer. RGBA or palette.
32,                   // Colordepth of the framebuffer.
0, 0, 0, 0, 0, 0,
0,
0,
0,
0, 0, 0, 0,
24,                   // Number of bits for the depthbuffer
8,                    // Number of bits for the stencilbuffer
0,                    // Number of Aux buffers in the framebuffer.
PFD_MAIN_PLANE,
0,
0, 0, 0
};

보다시피 많은 필드들이 값 0 으로 세팅되어 있다는 것을 알 수 있으나 개의치 말기 바란다. 각 필드들에 대한 보다 더 자세한 내용을 알고 싶으면 Window SDK를 참조하기 바란다.


이렇게 준비한 Descriptor 를 우리는 ChoosePixelFormat 함수를 이용하여 하나의 숫자(정수)로 만들 수 있다.

int PixelFormat = ChoosePixelFormat(hdc, &pfd);

여기서 hdc는 적용하고자 하는 윈도우의 Device Context (DC) 값으로 Hand of Device Context 의 약자를 사용한 것이다.

Windows SDK에서 설명하는 HDC Data Type은 다음과 같다.

HDC
A handle to a device context (DC).

HDC 및 PIXELFORMATDESCRIPTOR 에 의한 PixelFormat값을 만들었다면 SetPixelFormat 함수를 이용하여 HDC 의 PixelFormat 을 설정할 수 있다.

아래의 내용은 이러한 과정을 보여주고 있다.

HWND hwnd = ***; // target window handle , 윈도우를 생성하면 얻을 수 있다.
HDC hdc = GetDC(hwnd)
BOOL ret = SetPixelFormat(hdc, PixelFormat, &pfd);

ret 값이 true이면 성공 , false 성공하지 못한것이다.

Create the Context
Pixel Format이 적용된 DC 에서 OpenGL Context를 만드는 것은 어렵지 않다.
바로 wglCreateContext 함수를 이용하면 된다.

HGLRC WINAPI wglCreateContext(
  HDC hdc
);
HGLRC hrc = wglCreateContext(hdc);

여기서 HGLRC 는 OpenGL Rendering Context Handle 이다.

만약 이 함수를 호출하기 이전에 이미 Context 가 생성되어 있다면, 기존 Context는 무효화 되며 새로운 Context를 만들게 될 것이며, 이렇게 생성된 이후의 OpenGL 명령들은 기존의 Context에 작동하지 않고 새롭게 만들어진 Context에서만 작동될 것이다.
여기서 무효화 된다는 것은 제거 된다는 것이 아니고, 더이상 해당 Context가 OpenGL Context로 작동하지 않는다는 뜻이다.

Delete the Context
다음 함수에 의하여 만들어진 OpenGL Context는 제거할 수 있다.
제거하기 이전에 우리는 해당 Context가 최근에 만들어진 최신의 Context 인지를 살펴봐야 한다. 사실 살펴보는 방법은 없다. 그러므로 우리는 제거하고자 하는 Context를 무효화 해야한다. 이는 wglMakeCurrent  함수에 HDC 인자로 NULL을 입력하면 된다.

wglMakeCurrent(NULL)


To be continue...

Vertex , 정점 정보의 확장

Vertex , 정점 정보의 확장 그동안의 설명에 있어서 우리는 VERTEX 정보에 대하여 3 차원의 위치 정보만 사용하였다. struct VERTEX {float x,y,z;}; 이제 이를 확장하여 색상을...