블로그 이미지
대갈장군

calendar

1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30

Notice

2008. 2. 6. 05:12 프로그래밍/DirectX
이 내용은 www.directxtutorial.com 사이트의 내용을 번역한 하여 참조하였습니다.

보통 3차원 물체는 삼각형들로 구성이 되고 이 삼각형은 Vertex로 구성이 된다.

Vertex는 사실 "3차원 공간의 어떤 한 점에 대한 위치 정보 + 속성 정보" 라고 정의 가능하다.

OpneGL에서도 시계 방향이었는지 기억은 안나지만 DX에서는 삼각형 정의를 위해서 3개의 점이 시계 방향으로 정의 되어야 한다고 되어 있다.

Image 3.5 - A Triangle Built From Vertices

Image 3.5 - A Triangle Built From Vertices

뭐 아시다시피 그래서 Primitives가 정의가능한데 바로 도형인 셈이다. 하지만 딱 도형이라고 말하기는 그렇고 (왜냐면 선, 점들도 들어가니까) 그냥 일련의 Vertex의 모임인데 Primitives라고 기억하는 것이 더 좋을 듯 하다. 총 6가지의 Primitives가 있는데 다음과 같다.

1.  Point Lists
화면상에서 점들을 나타내는 방법인데, 와우에서 보면 채광이 미니맵에 뜨는 것정도에 사용할수 있지 않나 싶다.
Image 3.6 - A Point List

Image 3.6 - A Point List (6 Primitives)


2.  Line Lists
잘 알다시피 선이다.
Image 3.7 - A Line List

Image 3.7 - A Line List (3 Primitives)

3.  Line Strips
이 형태의 모습은 Max 9에서 아웃라인만 보는 기능을 쓸때 사용하는 것과 같은 효과를 주는구나. 디버깅 할때 효과적이라고 한다.
Image 3.8 - A Line Strip

Image 3.8 - A Line Strip  (5 Primitives)

4.  Triangle Lists

Image 3.9 - A Triangle List

Image 3.9 - A Line List (2 Primitives)


5.  Triangle Strips
게임에서 면을 생성하고 물체를 그리기 위해 사용하는 가장 효과적인 방법이 바로 이것.
Image 3.10 - A Triangle Strip

Image 3.10 - A Triangle Strip (4 Primitives)

6.  Triangle Fans

Image 3.11 - A Triangle Fan

Image 3.11 - A Triangle Fan (4 Primitives)

A primitive Quirk
이 부분에서 설명하는 것은 OpenGL에서도 봤다시피 폴리곤의 앞면과 뒷면을 동시에 보여 줄것인가 아니면 한쪽면만 보여 줄것인가에 대한 것으로써 일반적으로는 한쪽 면만 보여 주지만 만약 내부에서도 사용자가 물체를 보게 될 일이 있다면 양면 모두 렌더링 하는 것이 좋다.

Image 3.12 - Primitive Only Visible When Drawn Clockwise

Image 3.12 - Primitive Only Visible When Drawn Clockwise

Image 3.13 - Primitive Visible When Drawn Either Way

Image 3.13 - Primitive Visible When Drawn Either Way

COLOR
드디어 색상 부분인데.. 헐헐...

Subtractive Color vs. Additive Color
헐 이거 중요한 개념 인데? 어렸을 적에 배운 빨강, 파랑, 노랑이 삼원색이어서 모든 색을 구성한다는 것이 틀렸단다.

색에는 Subtractive 와 Additive가 있는데 이 둘의 가장 큰 차이는 이 색들이 어떤 대상을 가리키냐 인데 바로 '빛을 가리키냐' 와 '물체를 가리키냐'로 나뉜단다.

Subtractive 색상은 바로 물체의 색상이며 주 색상이 magenta, cyan, yellow이고 Additive 색상은 바로 빛의 색상이며 주 색이 red, green, blue이다.

위 두가지 모두 어릴적 배운 3원색과는 다르군.. 그렇군.

빛의 색상은 아래와 같이 중첩되면 빛의 색이 더해서 밝은 힌색을 띄게 되어 additive color라 표현한다.

Image 3.14 - Additive Colors Add Up to White

Image 3.14 - Additive Colors Add Up to White

그런데 자세히 보면 중첩 되는 3개의 색상이 사실 magenta, cyan, yellow다!! (충격적이지 않은가?)
왜 그런지 좀 있다 살펴보고, Subtracitive 색상을 살펴 보면.. 헐 이해가 안된다. 흠. 좀 어렵군.

Image 3.15 - Subtractive Colors Subtract Out to Black

Image 3.15 - Subtractive Colors Subtract Out to Black

꼭 알아야 한다고 생각되지는 않는데 ... 게임 프로그래밍에서는 항상 Additive 색상을 사용하기는 한다. 왜냐면 모니터가 빛의 색상 조합으로 구성되기 때문인데, Subtractive도 이해해 놓는 것이 편하기는 하다.

Alpha Coloring
RGB + 알파 인데 알다시피 투명도 속성이다.

Setting the Color Using 32 Bits
D3D에서는 일반적으로 32 비트를 이용해서 색상을 지정하는데 아래와 같은 형식을 따른다.

Image 3.16 - Bit Layout of Color

Image 3.16 - Bit Layout of Color

다음 코드들이 몇가지 색상을 지정하는 방법인데

DWORD Color_A = 0xff00ff00;
DWORD Color_B = 0x88ff00cc;

저렇게 숫자로 넣으면 기억하기 힘드니 편리하게 0~255 값을 사용할 수 있는 함수가 있으니 바로 다음과 같은 함수들이다.

DWORD Color_A = D3DCOLOR_XRGB(0, 255, 0);
DWORD Color_B = D3DCOLOR_ARGB(136, 255, 0, 204);

위의 두 함수중에 XRGB는 알파 채널이 없는 색상 즉 255 값을 자동으로 알파 채널이 주는 함수다.

Light and Color
빛의 완전한 모방이란 불가능에 가깝고 그래서 3가지 종류의 빛으로 나누어서 D3D에서는 구현하는데 바로 Diffuse light, Ambient light, Specular light 이죠.

Diffuse Light
직접적인 빛이 아닌 반사에 의한 빛이 물체에 비치는 것.

Image 3.17 - Diffuse Lighting

Image 3.17 - Diffuse Lighting

Later, you will learn about sources of light.  This sphere is lit by one source, coming off from the left somewhere.  The further the sphere curves away from the light, the less that portion is lit by the source.

Ambient Light
이 빛은 어디에나 있는 것으로 간주되는 '은은한 빛'으로써 diffuse와는 달리 source가 없으며 모든 방향을 비추는 빛이다. 아래 그림은 위의 diffuse 라이트 + ambient 라이트 이다.

Image 3.18 - Diffuse and Ambient Lighting

Image 3.18 - Diffuse and Ambient Lighting

Specular Light
이것은 바로 Highlight 빛인데 반사가 존재하는 물체의 빛이다.

Image 3.19 - Diffuse, Ambient and Specular Lighting

Image 3.19 - Diffuse, Ambient and Specular Lighting



 
posted by 대갈장군
2008. 2. 2. 01:02 프로그래밍/DirectX
이 내용은 www.directxtutorial.com 사이트의 내용을 번역한 하여 참조하였습니다.

풀 스크린으로 만드는 것은 몇가지 사항을 추가해야 하고 코드도 바꿔야 한다. 여기서 살펴볼 두가지 사항은 어떻게 나의 스크린 해상도를 globalize 하는가 어떤 메커니즘으로 최대화면을 만드는지 이다.

1. Setting Up the Screen Size
프로그램 실행중에 빈번하게 나의 화면 크기를 조사하고 바꾸어야 할 때가 많은데 이럴때 어떻게 하는지 살펴보자.

우선 두개의 기본값을 설정하자.
// define the screen resolution
#define SCREEN_WIDTH  640
#define SCREEN_HEIGHT 480

그리고 나서 아마도 WinMain안에 있는 아래 함수를 다음과 같이 바꾸자 (blod)
    hWnd = CreateWindowEx(NULL,
                          L"WindowClass",
                          L"Our Direct3D Program",
                          WS_OVERLAPPEDWINDOW,
                          300, 300,
                          SCREEN_WIDTH, SCREEN_HEIGHT,    // set window to new resolution
                          NULL,
                          NULL,
                          hInstance,
                          NULL);

이렇게 하면 정의된 사이즈로 윈도우가 만들어 질 것이다. (아직 FULL screen 아닐거임)

2. Changing to Fullscreen Mode
    hWnd = CreateWindowEx(NULL,
                          L"WindowClass",
                          L"Our Direct3D Program",
                          WS_EX_TOPMOST | WS_POPUP,    // fullscreen values
                          0, 0,    // the starting x and y positions should be 0
                          SCREEN_WIDTH, SCREEN_HEIGHT,
                          NULL,
                          NULL,
                          hInstance,
                          NULL);

우선 Full screen 모드로 들어가기 위해서 해줘야 할 것이 4가지 있는데,
1. 윈도우 시스템에게 어떤 윈도우 외곽선도 보이지 말게 하라는 명령을 줘야 하고
2. 스크린 위에 있는 모든 다른 것을 overlap 하라는 (덮어 씌워 버리라는) 명령을 줘야 하고
3. DirectX에게 모니터 해상도를 내가 원하는 대로 바꾼다고 알려줘야 하고
4. 윈도우 배경 색은 남겨두라는 명령이랜다. (이건 뭐 별로 중요하지 않대요)

1번과 2번은 위의 CreateWindowEx 함수의 굵은 글씨제 부분에서 해결한다.

그리고 WINDOWCLASSEX 구조체에서 바꿔야 할 부분은,
// wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
게임 시작할때 윈도우를 안보이게 한다음 한꺼번에 나타내는 기술인가봐...

그라고 나서 인제 해야 할 부분이 DirectX에게 알려주는 것인데, 이것은 d3dpp 구조체를 바꿈으로써 가능하다. 굵은 부분이 추가 혹은 바뀐 부분이다.
D3DPRESENT_PARAMETERS d3dpp;    // create a struct to hold various device information

    ZeroMemory(&d3dpp, sizeof(d3dpp));    // clear out the struct for use
    d3dpp.Windowed = FALSE;    // program fullscreen, not windowed
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;    // discard old frames
    d3dpp.hDeviceWindow = hWnd;    // set the window to be used by Direct3D
    d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;    // set the back buffer format to 32-bit
    d3dpp.BackBufferWidth = SCREEN_WIDTH;    // set the width of the buffer
    d3dpp.BackBufferHeight = SCREEN_HEIGHT;    // set the height of the buffer

일단 windowed 인자가 false로 바뀌었다. 저것으로써 fullscreen mode를 선언함.

BackBufferFormat이 나와 있는데 여기서 사용할수 있는 몇가지 타입이 있는데 요즘은 거의 32 비트를 사용하나 보다.

Value Description
D3DFMT_A8R8G8B8 This is a 32-Bit pixel format, with 256 levels (8 bits) of red, green, blue and alpha (semi-transparency).
D3DFMT_X8R8G8B8 This is similar to A8R8G8B8, with the one difference being that it does not support alpha, even though there are 8 bits to represent this.
D3DFMT_A2R10G10B10 This is a 32-Bit pixel format, with only two bits of alpha, but 10 bits (1024 levels) of each red, green and blue.
D3DFMT_A16B16G16R16 64-BIT COLOR!  If you have the capability to run 64-bit color, I'd recommend playing around with this to see how it works.  Of course, Windows Vista will fully support 64-bit color, and so this is just a prelude for now.

This value has 16 bits for each component (65536 levels compared to the current measly 256!)

BackBufferWidth와 BackBufferHeight는 단순히 봐도 뭔지 알겠다....

3. The Escape Route
이제는 탈출을 하는 코드를 만들때인데 원래라면 DirectInput을 사용하는가 본데 여기서는 약간의 편법을 이용해서 하는 것같다.

#define KEY_DOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
#define KEY_UP(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1)

우선 이 두 줄을 코드 제일 위에 붙여 주고 (현재 키가 눌러졌는지 안눌러 졌는지 조사하는 매크로) 그 다음에

// check the 'escape' key
if(KEY_DOWN(VK_ESCAPE))
    PostMessage(hWnd, WM_DESTROY, 0, 0);
를 이용해서 ESC 키가 눌러졌는지를 확인하는 코드를 적절한 곳에 삽입해 주면 윈도를 뿌수고 나올수 있따.

참고로 키 테이블을 올려 놨다.
Description Hexadecimal Value Identifier
Left Mouse Button 01 VK_LBUTTON
Right Mouse Button 02 VK_RBUTTON
Backspace Key 08 VK_BACK
Tab Key 09 VK_TAB
Enter Key 0D VK_RETURN
Shift Key 10 VK_SHIFT
Control Key 11 VK_CONTROL
Alt Key 12 VK_MENU
Pause Key 13 VK_PAUSE
Escape Key 1B VK_ESCAPE
Spacebar 20 VK_SPACE
Page Up Key 21 VK_PRIOR
Page Down Key 22 VK_NEXT
End Key 23 VK_END
Home Key 24 VK_HOME
Left Arrow Key 25 VK_LEFT
Up Arrow Key 26 VK_UP
Right Arrow Key 27 VK_RIGHT
Down Arrow Key 28 VK_DOWN
Insert Key 2D VK_INSERT
Delete Key 2E VK_DELETE
0 - 9 Keys 30-39 No Identifier
A - Z Keys 41-5A No Identifier
F1 - F12 Keys 70-7B VK_F1 ... VK_F12



posted by 대갈장군
2008. 2. 1. 07:44 프로그래밍/DirectX
이 내용은 www.directxtutorial.com 사이트의 내용을 번역한 하여 참조하였습니다.

간단한 Direct3D Program을 만들어보자. 물론 '간단'이라는 말이 우습기는 하다만.... '간단'해 지려면 우선 API를 알아야 하고 C, C++를 알아야 하며 COM에 대해서도 감을 잡고 있어야 한다.

이게 '간단'인가? =.=; 헐

글쓴이가 말한대로 간단한 D3D (Direct3D) 프로그램은 다음과 같은 4단계 구조를 가진다.

1. 전역 변수 선언과 함수들의 프로토 타입 선언
2. D3D를 초기화 하는 함수 생성 및 D3D device 생성
3. 한개의 화면을 그려주는 함수 생성
4. D3D 닫기

1. 전역 변수 선언과 함수들의 프로토 타입 선언
// include the basic windows header files and the Direct3D header file
#include <windows.h>
#include <windowsx.h>
#include <d3d9.h>

// include the Direct3D Library file
#pragma comment (lib, "d3d9.lib")

// global declarations
LPDIRECT3D9 d3d;    // the pointer to our Direct3D interface
LPDIRECT3DDEVICE9 d3ddev;    // the pointer to the device class

// function prototypes
void initD3D(HWND hWnd);    // sets up and initializes Direct3D
void render_frame(void);    // renders a single frame
void cleanD3D(void);    // closes Direct3D and releases memory

// the WindowProc function prototype
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

헐헐, 갑작스레 등장하는 API 코드들에 난감스럽다.>.<

글쓴이는 친철하게 하나 하나 설명해 주고 있는데, 우선 #include <d3d9.h>는 Direct3D 9의 헤더 파일을 포함시키는 것이다.

#pragma comment(lib, "d3d9.lib") 요놈은 Direct3D 9의 라이브러리 파일을 포함시키라는 명령인데 첫번째 인자가 어떤 형태의 파일을 추가 할 것인지 그리고 두번째 놈이 파일 이름이다.

LPDIRECT3D9 d3d; 앞에 붙은 타입 명, 고녀석 이름도 참 거창하고 길다. 저런 생전 처음 보는 타입을 두려워 할 필요 없다. 저것은 보통 클래스나 구조체를 가리키는 포인터 타입일뿐 이해 불가능한 것이 아니다. 이 변수는 나중에 저 클래스 타입을 가지는 클래스의 객체를 선언한 후 그 놈을 가리키게 될것이다.

LPDIRECT3DDEVICE9 d3ddev; 이놈은 더 길다. 젠장. 이놈은 사실 Direct3D Device interface 라는 놈인데 이것도 사실 알고보면 분명히 클래스일 것이고 좀더 자세히 말해서 COM 컴포넌트 일것이다. 혹은, 추상 클래스 정도라고 추측할수 있다. 어쨌건 간에 이놈은 그래픽 장치나 비디오 카드등 그래픽과 관련된 하드웨어에 대한 일괄된 정보를 관리한다고 보면 된다.

그 아래에 3개의 함수 원형이 선언 되어 있는데 이것은 옆의 주석 설명대로 초기화 함수, 화면 그려주기 함수, 메모리 해제 함수다. 이로써 1단계가 끝났다.

2. D3D를 초기화 하는 함수 생성 및 D3D device 생성
// this function initializes and prepares Direct3D for use
void initD3D(HWND hWnd)
{
    d3d = Direct3DCreate9(D3D_SDK_VERSION);    // create the Direct3D interface

    D3DPRESENT_PARAMETERS d3dpp;    // create a struct to hold various device information

    ZeroMemory(&d3dpp, sizeof(d3dpp));    // clear out the struct for use
    d3dpp.Windowed = TRUE;    // program windowed, not fullscreen
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;    // discard old frames
    d3dpp.hDeviceWindow = hWnd;    // set the window to be used by Direct3D

    // create a device class using this information and information from the d3dpp stuct
    d3d->CreateDevice(D3DADAPTER_DEFAULT,
                      D3DDEVTYPE_HAL,
                      hWnd,
                      D3DCREATE_SOFTWARE_VERTEXPROCESSING,
                      &d3dpp,
                      &d3ddev);

    return;
}
드디어 뭔가가 나오기 시작했다... 두둥.

D3D 코딩의 첫파트는 사실 interface를 만들고 graphic device를 초기화 하는 것이다. 여기서 interface의 의미가 와닿지 않는다면 김상형씨께서 쓰신 혼자연구하는 C/C++ 책 29장 상속편을 읽어보면 참 좋을것이다.

사실 이부분에서는 크게 설명할 원리는 없고 다만 뭐가 뭐다라는 식의 설명만 가능한데, 이것은 예전에 OpenGL을 배울때와 유사하다.

첫 프로그램을 짤때는 이렇게 '그렇다더라...'는 식의 코드를 많이 접하는데 이는 어쩔수가 없다. 특히 Direct3D 처럼 거대한 라이브러리 함수를 가지고 노는 프로그램의 경우는 더더욱 심하다.

원문을 쓰신 분이 나름 추가의 글을 적어 놨기에 나도 옮겨 적어야 할것 같다.... -_-

d3d = Direct3DCreate9(D3D_SDK_VERSION);

이것이 사실상 최초로 접하는 D3D function이다. 이 함수의 목적은 D3D interface를 만드는 것이다. 저 함수가 리턴하는 것은 바로 만들어진 interface의 주소다. (고로 포인터죠) 사실 객체 지향 언어인 C++를 사용하면서 전역으로 함수를 선언하는 것은 조금 모순된다.

C++가 원래 지향하는것이 부품 조립형 프로그래밍인데 전역 변수는 이에 예외를 둠으로써 그런 규칙을 어느정도는 깨고 있기 때문이다. 하지만 D3D에서 선언한 전역 변수가 중요한 이유는 이렇게 호출한 함수가 리턴하는 주소값을 프로그램 여기저기서 수시로 사용하기 때문인데 만약 그 주소값을 저장하는 포인터 변수가 지역 변수여서 함수를 넘나들지 못하면 이 프로그램은 제구실을 할수가 없다.

이건 순전히 내 여담이고.... -_-; 뒤에 인자로 들어가는 값은 항상 저걸로 고정되어 있는데 이값은 버전에 따라서 변하는 모양이다. 어쨌든 저걸 넣어 줌으로써 어떤 버전의 DirectX로 프로그래머가 프로그램을 짰는지 알려주는 모양이다. 고로 이식성이 좋다나 뭐래나...

D3DPRESENT_PARAMETERS d3dpp;    
ZeroMemory(&d3dpp, sizeof(d3dpp));    // clear out the struct for use
d3dpp.Windowed = TRUE;    // program windowed, not fullscreen
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;    // discard old frames
d3dpp.hDeviceWindow = hWnd;    // set the window to be used by Direct3D


요거 다섯줄은 사실 뭉태기로 보면 더 쉽다. 사실 API에도 CreateWindow 함수인가를 쓸때 보면 뒤에 따라붙는 함수 인자가 대략 20가지는 되어 보인다.

졸라게 긴 이런 입력 인자들을 위해서 하나의 구조체를 만들었으니 바로 D3DPRESENT_PARAMETERS와 같은 놈이다. 이런 구조체를 선언하고 그 값중 필요한 것만 골라서 지정한 다음 바로 다음 명령인,

 d3d->CreateDevice(....);

를 호출할때 인자로써 이놈을 넣어주면 함수 인자갯수가 확 준다. 좋지 아니한가?

d3dpp.SwapEffect = ... 명령을 보면 세가지 가능한 값이 오는데 우선 우리가 지정한 DISCARD가 제일 빠르다.  이것외에 FLIP과 COPY가 있는데 이 두가지는 첫번째 방법에 비해 느리며 전문가가 특별한 용도로 사용을 주로 한단다. 테이블은 다음과 같다.

Value Description
D3DSWAPEFFECT_DISCARD This type of swap chain is used to get the best speed possible.  However, if you later want to look at the previous back buffer (which can be useful for various effects), you cannot guarantee the image will still be intact.
D3DSWAPEFFECT_FLIP This type is similar to discarding, but is reasonably slower, because it has to take the time to ensure your previous back buffer(s) are protected and unchanged.
D3DSWAPEFFECT_COPY This last type is the one I least recommend.  Instead of switching pointers like the other two, this method copies the image, pixel by pixel, from the back buffer to the front buffer.  This is not prefered, although required for some advanced techniques.

드디어 나오는데 CreateDevice() 함수다.
HRESULT CreateDevice(
    UINT Adapter,
    D3DDEVTYPE DeviceType,
    HWND hFocusWindow,
    DWORD BehaviorFlags,
    D3DPRESENT_PARAMETERS *pPresentationParameters,
    IDirect3DDevice9 **ppReturnedDeviceInterface
);
이 함수가 하는 일은, graphics device interface를 생성한다. 즉, 이것은 내가 필요로하는 모든 그래픽 관련 일들을 관리해줄 클래스를 하나 만드는 것이다.

여기서 각각의 인자에 대해서 알아보면,
UINT Adapter : 비 부호 정수형 값을 저장하는데 어떤 그래픽 어댑터나 비디오 카드를 사용할지 알려주는 번호를 저장하나보다.

D3DDEVTYPE DeviceType : 일단은 하나만 쓴다. D3DDEVTYPE_HAL.
D3DDEVTYPE_HAL 는 Direct3D에게 Hardware Abstraction Layer 쓰라고 알려준덴다.  The Hardware Abstraction Layer 또는 HAL은 D3D에게 Hardware를 쓰라고 알려주는 것이란다. 뭐 요즘 하드웨어가 다들 고속 프로세싱을 해주니 당연히 HAL을 써야 하겠죠?

HWND hFocusWindow : This is the handle to our window.  We can just put 'hWnd' in here as we passed the value from WinMain().

DWORD BehaviorFlags : D3DCREATE_SOFTWARE_VERTEXPROCESSING, D3DCREATE_MIXED_VERTEXPROCESSING, D3DCREATE_HARDWARE_VERTEXPROCESSING. 
주로 요 세가지를 다루는데 (물론 많은 값이 들어갈수 있다만) 이름을 보면 대강 설명이된다. 소프트웨어적으로 처리, 하드웨어적으로 처리, 그리고 둘다 합쳐서 처리.

D3DPRESENT_PARAMETERS *pPresentationParameters : This is a pointer to the d3dpp struct that we filled out earlier.  We just fill this with '&d3dpp'.

IDirect3DDevice9 **ppReturnedDeviceInterface : graphics device interface를 가리키는 포인터, 미리 선언한대로 d3ddev죠. 주소 전달을 위해서 &d3ddev 전달.

3. 한개의 화면을 그려주는 함수 생성

// this is the function used to render a single frame
void render_frame(void)
{
    // clear the window to a deep blue
    d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 40, 100), 1.0f, 0);

    d3ddev->BeginScene();    // begins the 3D scene

    // do 3D rendering on the back buffer here

    d3ddev->EndScene();    // ends the 3D scene

    d3ddev->Present(NULL, NULL, NULL, NULL);    // displays the created frame

    return;
}

이제 위 함수는 한개의 장면을 렌더링 하는 함수인데 매우 간단하다. OpenGL에서 보던것과는 좀 다른데, 일단 그리는 것이 아무것도 없어서 그럴수도 있지만 Clear 하는 방법과 Rendering 하는 것이 좀 더 간단해 보인다.

d3ddev->Clear() 함수는 지정된 색으로 윈도우 배경을 지우는 함수다.

d3ddev->BeginScene() 함수는 D3D에게 그림 그릴 준비 하라는 함수다. 이 함수가 불러져야 하는 두가지 이유는 내가 D3D에게 메모리를 관리하고 있음을 알려줘야 하기 때문이고 둘째로 locking 이라는 과정을 통해서 빠르게 비디오 메모리에 접근하는 방식을 설정해주기 때문이다.

d3ddev->EndScene() 이름만 봐도 알겠다. unlocking을 한다.

d3ddev->Present() 이건 뭐 display하라는 명령인가 보다. 자세한 설명은 없군.


4. D3D 닫기

// this is the function that cleans up Direct3D and COM
void cleanD3D(void)
{
    d3ddev->Release();    // close and release the 3D device
    d3d->Release();    // close and release Direct3D

    return;
}

이것은 꼭 빼먹지 말아야 하는데 만약 이걸 안하면 프로그램 종료후에도 댕글링 메모리가 남게 되어 리부팅 할때까지 남아있는 문제 발생한다.
 

posted by 대갈장군
2008. 1. 26. 01:39 프로그래밍/DirectShow
알고보니 DirectShow Application을 작성할때 (직접 코딩할때) 제일 중요한 것은 COM 의 개념을 이해하고 어떻게 그것을 이용/생성/해제 하는가와 필터 그래프 관리자와 그래프 에디터가 결국은 같은 것임을 깨닳는 것이다.

코딩시 그래프 에디터가 만들어주는 널 렌더링 기법을 위해서는 우선 필터 그래프 관리자를 생성해야 하는데, 이 놈은 바로 COM 컴포넌트이다.

이 컴포넌트에 원료를 줘서 생산을 해야 하는데 바로 그 명령이,

CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, llD_lGraphBuilder, (void **)&m_pGB));

이다. 필터 그래프는 첫번째 인자인 COM 컴포넌트에 들어가있음을 알려주고 세번째 인자가 요청하는 것이 필터그래프매니져 인터페이스인데, 조금 헷갈릴 수도 있다.

물론 그냥 그렇다라고 알고 가도 되지만, 좀더 해석해보자면, COM 컴포넌트는 추상 클래스이다. 이 추상클래스는 객체화 되지 않은 그냥 빈 틀인데 여기다가 내가 원하는 특정한 기능을 만들고 싶다면 그것이 무엇인지 COM 컴포넌트에게 알려줘야 하고 그게 바로 세번째 인자인것 같다.

결국은 그렇다면 첫번째 인자는 가장 위쪽에 위치한 할배 추상 클래스이고 세번째 인자는 자식이나 손주뻘쯤 되는 상속 클래스의 이름이라고 보면 되겠는가? :)

원래라면 사용자가 모두 객체화 하고 함수를 써줘야 하는데 DirectShow Application은 그럴필요가 전혀 없어 보인다. 과연 이것이 장점일까?

한가지 더 중요한 것은 Release() 함수인데 이것은 앞서 만든 객체를 해제 할때 사용하는 함수다. COM 객체는 똑똑해서 자신을 참조하는 객체의 갯수를 항상 세고 있다가 0이되면 알아서 자폭한다.

고로 마구마구 Release를 쓰면 아직 사용중인 COM 객체가 날아가는 수가 있다. 고로 항상 짝을 이루어 조심히 써라는 말.

그리고 널 렌더링시 알아서 필터를 구성해주는 기법은 어플리케이션에서 다음 한줄이면 끝이다.

m_pGB->RenderFile(wFileName,NULL);

엄청 간단하다... -_-
posted by 대갈장군
2008. 1. 24. 05:39 프로그래밍/DirectShow

이걸 모르면 문맥을 자꾸 놓치게 되니까 하나하나씩 정리해 놓자.

1. RIFF (Resource Interchange File Format) : 헤더에 압축 방식을 기술 해놓는 걸 말하나 보다. 아, 그래서 이것을 적용한 파일의 경우 다양한 필터의 적용이 가능해진다. 그렇구나..

2. PCM (Pulse Code Modulation) : 정통과에서 배운 아날로그 신호의 디지털화다. 계단으로 좌좍 나누어 디지털 정보로 표현하기.

3. ADPCM (Adaptive Differential PCM) : 이건 위키에도 안나와있군. 단지 목소리를 디지털 신호로 바꾸는 거랜다.

4. ACM (Audio Compression Manager) : 기존의 윈도우 기술에서 사용되는 오디오 압축/해제를 의미한다. 그래서 압축된 형태의 오디오 파일은 ACM 래퍼 필터를 통해 Decompress 된다는 거군.

5. VCM (Vedio Compression Manager) : ACM과 함께 윈도우에서 사용되는 비디오 압축/해제 기술.

posted by 대갈장군
2008. 1. 15. 05:02 프로그래밍/C++

음.. 아주 중요한 단어가 드디어 등장했다. 순수 가상 함수... Pure Virtual Function이군.

자바를 해본 사람이라면 아마도 너무나도 당연한 개념일 것이고 나처럼 C++를 구렁이 담 넘어 가듯이 알고 있는 사람이라면 왜 이말이 중요한지 아직 모를수도 있다.

C++의 큰 장점은 "다형성" 이라고 할 수 있다.

부모 클래스로 부터 차례 차례 상속을 받아 필요로 하는 함수와 멤버를 상속 받고 최종 자식 클래스는 자신이 필요한 것들을 정의하면 된다.

이때 앞에서 본 가상 함수가 필요한데, 왜 필요한가 하면은....

C프로그램을 짤때는 흔히 포인터를 선언하고 포인터를 이용해 멤버 함수를 호출하곤 한다. 이때 부모클래스의 포인터를 선언하고 자식 클래스를 대입한후 자식 클래스의 멤버 함수(부모 클래스도 같은 이름의 멤버 함수를 가지고 있다면)를 호출하고자 한다면 반드시 "동적 결합"을 해야 하고 그 동적 결합을 위해서는 반드시 부모 클래스의 멤버 함수 앞에 "Virtual"이라는 키워드를 넣어야 한다.

그렇지 않고 "정적 결합"을 하게 되면 (Virtual 키워드를 안적으면) 포인터가 선언될 당시의 타입 (부모 클래스 타입이죠)의 멤버 함수만 계속 호출하게 된다.

그래서 가상 함수라는 것이 필요로 하는데 여기서 새로 등장한 순수 가상 함수란,

아무것도 정의 되지 않은 가상 함수를 말한다... 그리고 이것을 가지는 클래스를 바로 추상 클래스 (abstract class)라한다.

그렇다면 왜 비어있는 가상 함수를 선언하는가? 바로 이 질문이 나와야 한다.

질문의 답이 바로 저 위에 써놓은 C++ 장점 때문이다. 다형성을 실현하기 위해서는 동적 결합을 해야 하는데 그렇게 하기 위해서는 서로 다른 형태를 가지는 자식 클래스들이 공통의 부모 클래스를 가질 필요가 있다.

그렇게 되어야 부모 클래스 타입의 포인터를 배열로 할당해서 자식 클래스를 각각의 배열 요소로 가지도록 한다음 임의의 자식 클래스 객체의 멤버 함수를 호출 했을때 그 클래스에 맞는 멤버 함수가 자동으로 호출되게 할 수 있다는 것이다.

개념이 쉽지는 않다. 하지만 알고나면 "아... 이게 꼭 필요하긴 하겠구나" 하는 생각이 든다.

자바를 예전에 잠깐 써봤을때 추상 클래스에 대해서 수도 없이 들었지만 사실 왜 필요한가에 대한 대답은 몰랐었다. 하지만 지금 보니 왜 추상 클래스가 필요한지 알겠다.

posted by 대갈장군
2008. 1. 15. 04:21 프로그래밍/DirectX

DirectShow (줄여서 DS)는 원래 DirectX (줄여서 DX)의 일부였단다... (정확히는 모름)

DX안에는 DS뿐만 아니라 DirectPlay, Direct... 등등 뭐가 많이 있단다.

그런데 이 중에서도 왜 나는 DS는 참 흥미로운 놈인것 같다.

아직 DS에 대한 책이나 참고자료를 보지 않아서 저녀석의 세부사항은 전혀 모르지만 한가지 분명한것은 DS는 입력 영상과 출력 영상을 조절해주는 놈이라는 것이다.

사실 컴퓨터로 들어오는 입력 영상은 수없이 많다. 대표적인 예로 카메라. CCTV 같은 실시간 촬영 카메라의 경우 초당 수십 프레임의 영상이 컴퓨터로 들어오게 되는데 이때 들어오는 영상은 물론 어떤 색상의 어떤 사이즈를 가지는 그림들일것이다.

이렇게 들어오는 임의의 입력 영상을 화면에 출력하기 위해서는 현재 모니터에서 사용하고 있는 색상으로 바꿔줘야 할 의무가 있다. 바로 이럴때 사용하는 것이 DS인데 Windows가 DS를 이용해서 정말로 색상 처리를 해주는지는 잘 모르겠지만 아마도 그럴것 같다.

DS가 사실 Window API 라이브러리 이니까 OS에도 그대로 사용되지 않을까 싶다.

아무튼, 이 DS라는 놈은 영상의 입력과 출력을 고속으로 처리해주는, 그리고 그 둘사이에서 색상 타입 변경, 렌더링, 필터링등을 처리해 주는 특화된 API라이브러리 라고 나는 생각한다.

물론 이것은 전적으로 나의 개념이지 책에서 설명하는 이야기가 아니다...=.=

posted by 대갈장군
2008. 1. 11. 07:32 프로그래밍
C++를 예전부터 알아왔지만 그저 외워야 할, 알아야 할 언어라고 생각했을뿐 그 진정한 필요성과 효용에 대해서는 통감한 적이 없었다.

하지만 현재 여러사람이 하는 프로젝트를 하다보니 이게 왜 필요한가 그리고 왜 C++같은 객체 지향적 언어가 필요한가를 심히 알것 같다.

우선 객체 지향 언어의 대표적인 특징이 캡슐화가 꼭 그룹 프로젝트에서는 필요하다고 본다.

물론 코드가 적고 간단한 경우는 오히려 이놈의 객체 지향 언어가 짜증난다. 생성자, 파괴자, 멤버 함수, 공개, 보호, 등등... 이거 뭐 제대로 작동하게 만들기 부터 쉽지가 않다.

하지만 제대로 만들어진 클래스 한개의 파워는 상상을 초월하는 것 같다.

진정한 부품 조립형 프로그래밍의 파워가 바로 클래스에서 출발하는 것이다.

우리 연구실에서 주로 사용하는 TCP/IP 통신을 누군가가 멎진 클래스로 만들어서 배포했다... 사용을 어떻게하는지 읽어보는데 시간이 좀 소모되겠지만 그 사용 효과는 끝내준다.

마치 우리가 C를 처음 배울때 printf 하나만으로도 놀랬던 그 시절로 돌아가는 기분을 느끼게 해준다.

수업들으면서 C로 프로그래밍 할때는 한번 짜놓고 나면 6개월 정도 지나서 다시 볼려고 하면 골이 띵 해온다... 하지만 객체 지향으로 짜 놓고 약간의 주석과 사용방법 등만 기술해 놓으면 언제든지 부품처럼 가져다 와서 쓸수 있으니 이 얼마나 좋은가?

비록 이번 학기에 들었던 교수님의 말에 의하면 객체 지향 언어는 곧 망할거라는데... 글쎄? 프로그래밍에 아직 무지한 나로써는 아닌거 같은데요? =.=
posted by 대갈장군
2008. 1. 10. 07:45

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

2008. 1. 10. 06:19 프로그래밍

사실 영상 처리 분야를 공부하면서 그닥 관심두지 않았던 부분중에 하나가 DirectX인데 이놈이 갑자기 내 골을 아프게 한다.


교수님의 부탁으로 DirectShow strmbase.lib라는 라이브러리를 필요로하게 되었는데 이놈이 뭐하는 놈인지 아직 모른다.


근데... 젠장할 설치가 졸~라 어려웠다. 우선 2005년인가 몇년부터 원래 DirectX SDK에 포함되어 있던 이 놈이 뚝 떨어져 나가 버렸단다. 이것은 microsoft사가 이 놈을 버린 자식으로 취급해서라는데 정확한 원인은 모르겠다.


우찌되었든 MS사도 책임이 있다... =.= 설치를 쉽게 하게 해줘야 할꺼 아냐!~~ 세상 프로그래머 모두가 다 잘하는건 아니잖아~~ 초보자도 생각해줘야지!!


우쨌든. 그래서 나는 DirectShow가 현재는 Platform SDK에 편입되어 있다는 소식을 접하고 최신 PSDK를 받았다. 2003 server R2 어쩌고 저쩌고... 하여튼 MS 홈페이지에서 설치를 했다.


그래서~ 설치된 폴더를 뒤적거려본 결과 이놈의 strmbase.lib는 없었다. 두둥.... 알고보니 이놈을 사용하려면 만드시 컴파일을 해야 한다고 하는데 젠장... 다른 문제는 이 놈을 build할 프로젝트 파일이 없다!!!


예전에 OpenCV를 사용할때는 프로젝트 파일이 있어서 알아서 lib 파일을 만들어 줬는데 이런 XX는 그런게 없었다. 다만 흐릿하게 makefile이 내 눈에 보였다. 기본적으로 makefile은 UNIX에서 컴파일을 위해 사용하는 매크로 코드인데? 라는 생각이 들어서 윈도우에서도 make라는 명령이 있는지 검색을 해보았다.


아... 그랬더니 윈도우에도 그런 것과 유사한 nmake라는 명령이 있지않은가?? 상당히 놀라웠다.... 그렇다면 왜 MS는 자신들이 자랑하는 VS 2005의 프로젝트 파일로 만들기 보다 굳이 힘든 nmake라는 도스 명령어를 사용하는가?


참, 그리고 저놈을 실행할때는 웃기게도 윈도우에 설치된 PSDK의 메뉴에 들어가서 retail version으로 dos command line을 실행해야만 된다는 점이다. 안그러면 안된다.... 쓰블....


암튼, 이래 저래 고생해서 그 힘들다는 strmbase.lib를 만들어 냈다. 이제부터 이놈이 뭐하는 놈인지 알아봐야 겠네.... 에휴..

posted by 대갈장군
2007. 11. 9. 00:37 프로그래밍
RPCGEN 이라는 흥미로운 유닉스 명령어가 있다.

RPC라 함은 Remote procedure call 일꺼다.. -_-;
몇일 전에 외웠는데 까먹었군.. 이놈은 하나의 프로토콜인데 원격 사용자가 서버에 접속하여 명령을 실행하는 것을 말한다..

사실 RPC도 TCP나 UDP를 통해서 원격 사용자 (클라이언트)의 입력값들을 서버측으로 넘겨준다. 결국 TCP/IP 기반의 프로토콜인셈...

하지만 RPCGEN이라는 명령어 때문에 좀 특별해 지는데, 원래 RPC를 사용하려면 클라이언트 측과 서버 측의 stub 를 꼬옥 만들어줘야 한다. (처음에는 걍 하면 안되나 했던 기억이 난다...) 여기서 stub라 함은 하나의 프로그램으로써 사용자에게 각종 잡다한일 예를 들자면 통신 규격으로의 인코딩/디코딩, 각종 입력값의 변환등을 알아서 다 해주는 것이다.

물론 저넘을 사용자가 직접짠다면 골때린다. 우선 RPC를 위한 특별 언어가 따로 존재하여 그 언어를 사용해야만 한다. 아마도 .xdr일 것이다. 고로 언어를 새로 배워야 한다.. 젠장. 물론 C와 매우 매우 유사하기는 해도 짜증이 벌써 밀려온다.

바로 이런 것을 편리하게도 RPCGEN이라는 명령어가 대신해준다. 그저 사용자는 간단한 규칙에 따라서 .x 파일을 작성해 주고 repgen *.x를 해주면 알아서 5개인가 6개의 파일이 만들어진다.

그중에 가장 중요한 파일이 헤더 파일로써 사용자는 그 헤더 파일을 항상 포함시켜서 나머지 사용자 정의 함수를 정의해야 한다.

그러니까 사실 .x 파일은 헤더 파일의 헤더 파일 소스인거다.. -__-;;

암튼, 이렇게 하니까 멀리 떨어진 다른 컴퓨터에서 서버 코드를 실행시켜 놓고 내 컴퓨터에서 클라이언트 프로그램을 수행하면 서버측으로 입력값이 TCP 혹은 UDP를 통해서 날아가는데 이것은 전부 stub라는 놈이 알아서 다 해준다. 사용자는 인터페이스와 규칙만 설정하면 된다.

서버는 들어온 값을 분석하여 서버 컴퓨터의 자원을 이용하여 결과를 다시 리턴하는데 이때도 마찬가지로 리턴되는 모든 것들은 stub를 이용해서 알아서 잘 날아간다...

어찌보면 심히 편하기도 하다. 왜냐면 서로 다른 컴퓨터간의 통신시 가장 문제가 되는 규격을 일치시키는 복잡한 과정이 rpcgen이라는 명령을 통해서 쉽게 이루어 지기 때문인데 단점으로는 세세한 조절을 할 수 없다고 하더라. 당연히 그렇겠지만 그렇다고 새로 언어를 습득하는 것보다는 낫지 않을까?

posted by 대갈장군
2007. 10. 10. 04:08 프로그래밍

숙제가 있었다. TCP 커넥션을 만들어서 구성원들끼리 대화를 주고 받는 프로그램인데 특이한 점이라면 서버/클라이언트가 하나의 프로그램에 동시에 존재한다는 점과 한개의 파일로 어디서나 작동하게끔 만들어야 한다는 점이었다.

그닥 어렵지는 않다. 뭐 서버 클라이언트 관계는 못만들 이유가 없고 소켓만 잘 순서대로 연결해주면 아무 탈 없이 돌아갈 줄 알았다. 그런데 문제는 의외에 장소에서 터졌다.

프로그래머라면 당연히 관련된 정보는 하나의 구조체로 묶어서 관리하는 것이 좋다는 것을 안다. 그리고 나도 그대로 했다. 특정한 형태를 유지 시키기 위해서 구조체를 만들어서 각종 정보를 담아 두었다.

이 프로그램은 ssh를 이용해서 다른 컴퓨터에 접속한 다음 거기서 명령을 실행하는 것이 주 목적이다. 근데 이상하게도 바꾸지도 않았는데 구조체의 값들이 지 맘대로 변하는 것이 아닌가?

아무래도 이상해서 이리저리 테스트를 해보아도 도데체 이유를 몰랐다. 그런데... 알고보니...

구조체에 char *IP_addr이라는 멤버가 바로 문제 였다. 이 포인터의 값이 비록 내가 ssh를 이용해 원격 접속을 다른 컴퓨터에 하더라도 같은 값을 가지며 현재 사용중이 컴퓨터의 local memory를 가리킬 것이라고 생각 못했다.

분명히 다른 컴퓨터의 다른 주소에 위치 할 줄 알았는데 그게 아니었다. 그래서 아무리 값을 바꾸려고 해도 그 값들은 오직 같은 값만을 유지했던 것이다. 이런건 책에 나와 있는지 모르겠다. 아무튼 구조체 내에 절대로 포인터를 쓰지 말라는 말은 들어본 적이 없는 것 같다.

아무튼 저놈 때문에 금요일 오후를 홀딱 날렸다. 젠당.. 다음부턴 주의 해야지. 아, 해결법은, 구조체 내에 멤버를 선언할 때 char IP_addr[MAXLEN] 처럼 고정된 주소 공간을 가지는 형태로 바꾸고 strcpy를 이용해서 데이터를 입력해 넣었더니 '무슨 일 있었나요?' 라고 하며 바로 작동이 잘되었음... 젠당...


'프로그래밍' 카테고리의 다른 글

프로그램, 프로세스, 스레드  (2) 2008.10.22
객체 지향 언어(C++) V.S. 비 객체 지향 언어(C)  (2) 2008.10.18
왜 객체 지향인가?  (0) 2008.01.11
젠장할 Direct Show  (0) 2008.01.10
RPCGEN  (0) 2007.11.09
posted by 대갈장군
prev 1 2 3 4 next