블로그 이미지
대갈장군

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. 15. 04:30 프로그래밍/DirectX

앞서 살펴본 directional 빛은 물론 좋기는 하나 어디나 존재하는 빛이다. 문제는 사용자는 어디나 존재하는 빛 대신 특정한 곳에만 존재하는 빛을 원할때가 있다. 바로 그때 필요한 빛이 point light와 spot light인데 이것에 대해서 더 알아보자.

그리고 사실 빛에는 문제가 있다는데... 무슨 문제가 있을까?

1. The Scaling Problem
한가지 대표적인 문제가 물체의 크기에 따라서 빛의 강도가 바뀌는 문제라는데 정말 그런가? 작으면 작을수록 빛은 밝아지고 크면 클수록 어두워 진단다.

이것이 발생하는 이유는 바로 normal vertor 때문이라는데 물체가 커지거나 작아지면 이 normal vector도 같이 커지고 작아져서 그렇다라고 하는데... 같이 커지고 작아져서 라기 보다는 촘촘해지고 엉성해지고 그래서 그런거 아닌가? 암튼 이유는 정확히 모르나 normal vector가 문제인건 확실하다.

흠, 실제로 테스트 해보니 그렇네... 아, 그런데 여기서 역시나 해결 방법이 있으니 바로 normalize다. 헐헐 여기서 또 만나는 구나.

d3ddev->SetRenderState(D3DRS_NORMALIZENORMALS, TRUE);

이것을 설정 함으로써 D3D가 알아서 normal vector들을 관리하게 해준다. 고로 요것들의 길이들을 적절히 알아서 조절해 줌으로써 빛의 밝기 차이가 나타나지 않게 한단다.

헐, 이게 다래.... 그니까 빛을 설치할때는 항상 저 명령 넣는것을 잊지 말라는 말이군.

2. Point Lights
Image 10.1 - Point Light

Image 10.1 - Point Light

흠. 드디어 내가 생각한 부분의 설명이 나오는군. 앞에서 살펴본 directional 빛의 경우는 무한 발산이지만 지금 보게되는 point light는 무한 발산이 아니다. 즉, 거리가 멀면 멀수록 빛이 약해진다는 의미. attenuation이 발생한다는 말이다.

또한 중요한 차이점으로는 정확한 빛의 위치가 있다는 점으로 거기서 부터 빛이 나오게 된다.

2-1. Range
아래처럼 빛의 비춰질 최대 범위를 지정할 수가 있다.
light.Range = 100.0f;

이것을 설정함으로써 포인트 소스에서 100 유니트 이상 떨어진 위치에서는 빛에 대한 계산이 전혀 이루어지지 않으므로 속도의 향상을 기대할 수 있다.

2-2. Attenuation
여기서는 약간의 산수가 들어가기 시작하는데 거리에 따라 감쇠하는 빛의 세기는 이차원 방정식으로 표현 가능하다. (물론 고차원도 가능하겠지만 2차원이 적당한가 보다)

함수 공식은 Atten = 1 / (att0 + att1 * d + att2 * d2) 인데 좌변은 빛의 강도가 되겠고 1.0 에서 0.0까지 분포한다.

d는 물론 distance 이며 att0, att1, att2가 있는데 이들은 중요인자들이죠. 빛의 감쇠 정도를 결정하는 인자들일것이다.

첫번째 인자인 att0는 감쇠하지 않는 빛의 세기이다. 고로 이것은 최대 거리에 있는 물체도 기본적으로 받게 되는 빛의 양이된다.

Image 10.2 - att0 graphed at 0.5

Image 10.2 - att0 graphed at 0.5


두번째 인자인 att1은 역함수 형태인데 거리에 따라서 점점 감소하는 모습을 보인다. 가장 현실성 있는 빛의 감쇠를 나타내고 있다고 할수 있겠다.
 
Image 10.3 - att1 graphed at 1.0

Image 10.3 - att1 graphed at 1.0

이제 마지막인 att2인데 이놈은 두번째 인자와는 달리 빠른 속도로 감쇄하는데 이는 불꽃을 표현하는데 아주 좋다. 아주 가까운 곳만 심하게 밝게 나타낼수 있는 효과를 가지고 있다.

Image 10.4 - att2 graphed at 1.0

Image 10.4 - att2 graphed at 1.0

Using the Equation
자, 자세히는 모르겠지만 (아직) 이런 세개의 상수를 잘 설정 함으로써 (사용자가 직접) 다양한 형태의 빛을 표현 할 수 있을 것이다. 하지만 명심 해야 할 것이 있으니 만약 range를 설정해놓았다면 그 지점을 넘어서는 순간 빛은 바로 없어지게 된다. (감쇄 현상 계산 한계 지점) 고로 이 위치를 속도 향상을 위해서 사용한다손 치더라도 적절한 거리 계산이 반드시 필요하다는 점 명심하라.

또 다른 한가지는 directional light에는 감쇄가 없다. 고로 이런 세팅을 해봐야 아무런 영향을 주지도 않는다.

Coding a Point Light
// this is the function that sets up the lights
void init_light(void)
{
    D3DLIGHT9 light;    // create the light struct

    ZeroMemory(&light, sizeof(light));    // clear out the light struct for use
    light.Type = D3DLIGHT_POINT;    // make the light type point light'
    light.Diffuse.r = 0.5f;    // .5 red
    light.Diffuse.g = 0.5f;    // .5 green
    light.Diffuse.b = 0.5f;    // .5 blue
    light.Diffuse.a = 1.0f;    // full alpha (we'll get to that soon)
    light.Range = 100.0f;    // a range of 100
    light.Attenuation0 = 0.0f;    // no constant inverse attenuation
    light.Attenuation1 = 0.125f;    // only .125 inverse attenuation
    light.Attenuation2 = 0.0f;    // no square inverse attenuation

    D3DVECTOR vecPosition = {0.0f, 5.0f, 0.0f};    // the position of the light
    light.Position = vecPosition;    // set the position

    d3ddev->SetLight(0, &light);    // send the light struct properties to light #0
    d3ddev->LightEnable(0, TRUE);    // turn on light #0

    return;
}

새로 등장한 놈이 있으니 Type 인자에 들어온 새 플래그 D3DLIGHT_POINT이다. 뭐... 이건 대충봐도 포인트 라이트 소스를 말한다는 것은 알겠다.

이제 포인트 소스를 이용하므로 range설정이 가능한데 여기서는 100.0f로 설정했다.

그리고 앞서 살펴본 빛의 감쇄 인자 3개를 설정하는데 특이한 것은 att0가 0.0f라는 점. :) 전혀 감쇄하지 않는 빛은 없다는 말이다. 고로 오로지 거리에 따라 자연스레 감소하는 att1 인자만 값이 존재한다.

마지막으로 빛의 위치를 정의하는 값이 드디어 등장 했으니... 예측한 대로다.

위의 세팅을 이용해서 결과를 그려보면,

Image 10.5 - The Point Light

Image 10.5 - The Point Light
위와 같은 결과가 나온다.

3. Spot Light

Image 10.6 - Spot Light

Image 10.6 - Spot Light
새로운 빛의 형태가 등장했구나~ 스포트 라이트... 헐헐헐... 이 빛은 시작 위치가 있고 그 지점부터 특정한 방향으로 빛을 비춘다. ambient와 diffuse는 본질적으로 다른 속성이다.

위의 그림에서 보듯이 3개의 물체가 있지만 spot light는 지정한 방향 앞에 존재하는 물체만을 비추게 된다는점.

3-1. Phi and Theta
물론 spot 라이트는 점으로 나가는 레이져가 아니다. 다음 그림처럼 중심에서 부터 조금씩 퍼져나가는 빛의 형태를 띄어야 할것이다.

Image 10.7 - Phi and Theta

Image 10.7 - Phi and Theta

보면 2중 구조로 되어 있는데... 이것은 어두운 방에서 후래쉬를 켜보라.. 그러면 딱 저렇게 된다... 왜그렇지? 헐헐헐...

어쨌든, 결론은 spot light의 경우에는 두개의 각 theta와 phi에 의해서 그 형태가 결정된다는 말.

3-2. Falloff
어두운 방에서 다시 플래스를 켜보라. 다음과 같은 그림의 형태로 빛이 감쇄할 것이다.

Image 10.8 - Spot Light Falloff

Image 10.8 - Spot Light Falloff

안쪽으로 점차 점차 빛이 모여드는 느낌인데 이런 감쇄현상을 falloff라고 한단다. 헌데 이러한 감쇄현상의 값을 조절할수가 있으니 이로써 특별한 느낌을 줄수가 있다고 한다.

Image 10.9 - Various Falloff Values

Image 10.9 - Various Falloff Values

허나 일반적으로 falloff 값으로 1.0을 쓰는데 이유는 계산 시간이 좀 더 걸리기 때문이고 사실상 spot light 자체를 잘 안쓰는데 왜냐면 별도의 계산이 추가로 필요하기 때문이다.

3-3. Coding a Spot Light
자, 본격적으로 어떻게 spot light를 만드는지 보면,
// this is the function that sets up the lights
void init_light(void)
{
    D3DLIGHT9 light;    // create the light struct

    ZeroMemory(&light, sizeof(light));    // clear out the light struct for use
    light.Type = D3DLIGHT_SPOT;    // make the light type spot light'
    light.Diffuse.r = 0.5f;    // .5 red
    light.Diffuse.g = 0.5f;    // .5 green
    light.Diffuse.b = 0.5f;    // .5 blue
    light.Diffuse.a = 1.0f;    // full alpha (we'll get to that soon)
    light.Range = 100.0f;    // a range of 100
    light.Attenuation0 = 0.0f;    // no constant inverse attenuation
    light.Attenuation1 = 0.125f;    // only .125 inverse attenuation
    light.Attenuation2 = 0.0f;    // no square inverse attenuation
    light.Phi = D3DXToRadian(40.0f);    // set the outer cone to 30 degrees
    light.Theta = D3DXToRadian(20.0f);    // set the inner cone to 10 degrees
    light.Falloff = 1.0f;    // use the typical falloff


    D3DVECTOR vecPosition = {-8.0f, 0.0f, 30.0f};    // the position of the light
    light.Position = vecPosition;    // set the position

    D3DVECTOR vecDirection = {0.0f, 0.0f, -1.0f};    // the direction of the light
    light.Direction = vecDirection;    // set the direction

    d3ddev->SetLight(0, &light);    // send the light struct properties to light #0
    d3ddev->LightEnable(0, TRUE);    // turn on light #0

    return;
}

보면 추가된 것으로 phi와 theta 값 그리고 falloff 값, 빛의 위치는 그전에 사용하던대로이고, 대신 비추는 방향이 바뀌었다.

위대로 하고 실행해보면
 
Image 10.10 - The Spot Light

Image 10.10 - The Spot Light
저런 결과가 나오는데 오른쪽 박스는 일부 스폿 라이트를 받으나 왼쪽 상자는 못받고 있단다... (좀더 빛의 가까이서 강하게 줬으면 좋았을텐데...)

4. The Finished Program
// include the basic windows header files and the Direct3D header file
#include <windows.h>
#include <windowsx.h>
#include <d3d9.h>
#include <d3dx9.h>

// define the screen resolution and keyboard macros
#define SCREEN_WIDTH 640
#define SCREEN_HEIGHT 480
#define KEY_DOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
#define KEY_UP(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1)

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

// global declarations
LPDIRECT3D9 d3d;    // the pointer to our Direct3D interface
LPDIRECT3DDEVICE9 d3ddev;    // the pointer to the device class
LPDIRECT3DVERTEXBUFFER9 t_buffer = NULL;    // the pointer to the vertex buffer

// texture declarations
LPDIRECT3DTEXTURE9 texture_1;    // our first texture

// 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
void init_graphics(void);    // 3D declarations
void init_light(void);    // sets up the light and the material

struct CUSTOMVERTEX {FLOAT X, Y, Z; D3DVECTOR NORMAL; FLOAT U, V;};
#define CUSTOMFVF (D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1)

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


// the entry point for any Windows program
int WINAPI WinMain(HINSTANCE hInstance,
                   HINSTANCE hPrevInstance,
                   LPSTR lpCmdLine,
                   int nCmdShow)
{
    HWND hWnd;
    WNDCLASSEX wc;

    ZeroMemory(&wc, sizeof(WNDCLASSEX));

    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = (WNDPROC)WindowProc;
    wc.hInstance = hInstance;
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
      wc.lpszClassName = L"WindowClass";

    RegisterClassEx(&wc);

    hWnd = CreateWindowEx(NULL, L"WindowClass", L"Our Direct3D Program",
                          WS_EX_TOPMOST | WS_POPUP, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT,
                          NULL, NULL, hInstance, NULL);

    ShowWindow(hWnd, nCmdShow);

    // set up and initialize Direct3D
    initD3D(hWnd);

    // enter the main loop:

    MSG msg;

    while(TRUE)
    {
        DWORD starting_point = GetTickCount();

        if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            if (msg.message == WM_QUIT)
                break;

            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }

        render_frame();

        // check the 'escape' key
        if(KEY_DOWN(VK_ESCAPE))
            PostMessage(hWnd, WM_DESTROY, 0, 0);

        while ((GetTickCount() - starting_point) < 25);
    }

    // clean up DirectX and COM
    cleanD3D();

    return msg.wParam;
}


// this is the main message handler for the program
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch(message)
    {
        case WM_DESTROY:
            {
                PostQuitMessage(0);
                return 0;
            } break;
    }

    return DefWindowProc (hWnd, message, wParam, lParam);
}


// this function initializes and prepares Direct3D for use
void initD3D(HWND hWnd)
{
    d3d = Direct3DCreate9(D3D_SDK_VERSION);

    D3DPRESENT_PARAMETERS d3dpp;

    ZeroMemory(&d3dpp, sizeof(d3dpp));
    d3dpp.Windowed = FALSE;
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    d3dpp.hDeviceWindow = hWnd;
    d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
    d3dpp.BackBufferWidth = SCREEN_WIDTH;
    d3dpp.BackBufferHeight = SCREEN_HEIGHT;
    d3dpp.EnableAutoDepthStencil = TRUE;
    d3dpp.AutoDepthStencilFormat = D3DFMT_D16;

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

    init_graphics();    // call the function to initialize the cube
    init_light();    // call the function to initialize the light and material

    d3ddev->SetRenderState(D3DRS_LIGHTING, TRUE);    // turn on the 3D lighting
    d3ddev->SetRenderState(D3DRS_ZENABLE, TRUE);    // turn on the z-buffer
    d3ddev->SetRenderState(D3DRS_AMBIENT, D3DCOLOR_XRGB(50, 50, 50));    // ambient light
    d3ddev->SetRenderState(D3DRS_NORMALIZENORMALS, TRUE);    // handle normals in scaling

    return;
}


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

    d3ddev->BeginScene();

    // select which vertex format we are using
    d3ddev->SetFVF(CUSTOMFVF);

    // set the view transform
    D3DXMATRIX matView;    // the view transform matrix
    D3DXMatrixLookAtLH(&matView,
    &D3DXVECTOR3 (0.0f, 40.0f, 30.0f),    // the camera position
    &D3DXVECTOR3 (0.0f, 0.0f, 0.0f),    // the look-at position
    &D3DXVECTOR3 (0.0f, 1.0f, 0.0f));    // the up direction
    d3ddev->SetTransform(D3DTS_VIEW, &matView);    // set the view transform to matView

    // set the projection transform
    D3DXMATRIX matProjection;    // the projection transform matrix
    D3DXMatrixPerspectiveFovLH(&matProjection,
                               D3DXToRadian(45),    // the horizontal field of view
                               (FLOAT)SCREEN_WIDTH / (FLOAT)SCREEN_HEIGHT, // aspect ratio
                               1.0f,    // the near view-plane
                               100.0f);    // the far view-plane
    d3ddev->SetTransform(D3DTS_PROJECTION, &matProjection);    // set the projection

    // set the world transform
    static float index = 0.0f; index+=0.03f;    // an ever-increasing float value
    D3DXMATRIX matTranslate;    // the world transform matrix
    D3DXMatrixTranslation(&matTranslate,
                          (float)sin(index) * 12.0f,
                          0.0f,
                          (float)cos(index) * 25.0f);
    d3ddev->SetTransform(D3DTS_WORLD, &(matTranslate));    // set the world transform

    // select the vertex buffer to display
    d3ddev->SetStreamSource(0, t_buffer, 0, sizeof(CUSTOMVERTEX));

    // set the texture
    d3ddev->SetTexture(0, texture_1);

    // draw the textured cube
    d3ddev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
    d3ddev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 4, 2);
    d3ddev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 8, 2);
    d3ddev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 12, 2);
    d3ddev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 16, 2);
    d3ddev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 20, 2);

    // set the other world transform
    D3DXMatrixTranslation(&matTranslate,
                          (float)sin(index) * -12.0f,
                          0.0f,
                          (float)cos(index) * -25.0f);
      d3ddev->SetTransform(D3DTS_WORLD, &(matTranslate));    // set the world transform

    // draw the other textured cube
    d3ddev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
    d3ddev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 4, 2);
    d3ddev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 8, 2);
    d3ddev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 12, 2);
    d3ddev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 16, 2);
    d3ddev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 20, 2);  

    d3ddev->EndScene();

    d3ddev->Present(NULL, NULL, NULL, NULL);

    return;
}


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

    return;
}


// this is the function that puts the 3D models into video RAM
void init_graphics(void)
{
    // load the texture we will use
    D3DXCreateTextureFromFile(d3ddev,
                              L"wood1.png",
                              &texture_1);

    // create the vertices using the CUSTOMVERTEX struct
    CUSTOMVERTEX t_vert[] =
    {
        // side 1
        { -3.0f, 3.0f, -3.0f, 0, 0, -1, 0, 1, },
        { 3.0f, 3.0f, -3.0f, 0, 0, -1, 1, 1, },
        { -3.0f, -3.0f, -3.0f, 0, 0, -1, 0, 0, },
        { 3.0f, -3.0f, -3.0f, 0, 0, -1, 1, 0, },

        // side 2
        { -3.0f, 3.0f, 3.0f, 0, 0, 1, 0, 1, },
        { -3.0f, -3.0f, 3.0f, 0, 0, 1, 0, 0, },
        { 3.0f, 3.0f, 3.0f, 0, 0, 1, 1, 1, },
        { 3.0f, -3.0f, 3.0f, 0, 0, 1, 1, 0, },

        // side 3
        { -3.0f, 3.0f, 3.0f, 0, 1, 0, 0, 1, },
        { 3.0f, 3.0f, 3.0f, 0, 1, 0, 1, 1, },
        { -3.0f, 3.0f, -3.0f, 0, 1, 0, 0, 0, },
        { 3.0f, 3.0f, -3.0f, 0, 1, 0, 1, 0, },

        // side 4
        { -3.0f, -3.0f, 3.0f, 0, -1, 0, 0, 1, },
        { -3.0f, -3.0f, -3.0f, 0, -1, 0, 0, 0, },
        { 3.0f, -3.0f, 3.0f, 0, -1, 0, 1, 1, },
        { 3.0f, -3.0f, -3.0f, 0, -1, 0, 1, 0, },

        // side 5
        { 3.0f, 3.0f, -3.0f, 1, 0, 0, 1, 0, },
        { 3.0f, 3.0f, 3.0f, 1, 0, 0, 1, 1, },
        { 3.0f, -3.0f, -3.0f, 1, 0, 0, 0, 0, },
        { 3.0f, -3.0f, 3.0f, 1, 0, 0, 0, 1, },

        // side 6
        { -3.0f, 3.0f, -3.0f, -1, 0, 0, 1, 0, },
        { -3.0f, -3.0f, -3.0f, -1, 0, 0, 0, 0, },
        { -3.0f, 3.0f, 3.0f, -1, 0, 0, 1, 1, },
        { -3.0f, -3.0f, 3.0f, -1, 0, 0, 0, 1, },
    };    // that reminds me of programming in binary!

    // create a vertex buffer interface called t_buffer
    d3ddev->CreateVertexBuffer(24*sizeof(CUSTOMVERTEX),
                               0,
                               CUSTOMFVF,
                               D3DPOOL_MANAGED,
                               &t_buffer,
                               NULL);

    VOID* pVoid;    // a void pointer

    // lock t_buffer and load the vertices into it
    t_buffer->Lock(0, 0, (void**)&pVoid, 0);
    memcpy(pVoid, t_vert, sizeof(t_vert));
    t_buffer->Unlock();

    return;
}


// this is the function that sets up the lights and materials
void init_light(void)
{
    D3DLIGHT9 light;    // create the light struct
    D3DMATERIAL9 material;    // create the material struct

    ZeroMemory(&light, sizeof(light));    // clear out the struct for use
    light.Type = D3DLIGHT_POINT;    // make the light type 'point light'
    light.Diffuse.r = 0.5f;    // .5 red
    light.Diffuse.g = 0.5f;    // .5 green
    light.Diffuse.b = 0.5f;    // .5 blue
    light.Diffuse.a = 1.0f;    // full alpha (we'll get to that soon)
    light.Range = 100.0f;    // a range of 100
    light.Attenuation0 = 0.0f;    // no constant inverse attenuation
    light.Attenuation1 = 0.125f;    // only .125 inverse attenuation
    light.Attenuation2 = 0.0f;    // no square inverse attenuation

    D3DVECTOR vecPosition = {0.0f, 5.0f, 0.0f};    // the position of the light
    light.Position = vecPosition;    // set the
position

    d3ddev->SetLight(0, &light);    // send the light struct properties to light #0
    d3ddev->LightEnable(0, TRUE);    // turn on light #0

    ZeroMemory(&material, sizeof(D3DMATERIAL9));    // clear out the struct for use
    material.Diffuse.r = material.Ambient.r = 1.0f;    // set the material to full red
    material.Diffuse.g = material.Ambient.g = 1.0f;    // set the material to full green
    material.Diffuse.b = material.Ambient.b = 1.0f;    // set the material to full blue
    material.Diffuse.a = material.Ambient.a = 1.0f;    // set the material to full alpha

    d3ddev->SetMaterial(&material);    // set the globably-used material to &material

    return;
}


Image 10.11 - The Point Light in Action

Image 10.11 - The Point Light in Action



posted by 대갈장군