DirectX: Manipulating 'direction' on diffuse lighting

This topic is 3326 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

Recommended Posts

I've been working my way through the tutorials at www.directxtutorial.com and I've reached the lighting one. And when I go to do the challenge sections, I can't manipulate the lighting's direction (challenge number 4). I'm convinced that it's the exact same problem that I had with manipulating vertices, specifically I ended up re-creating the vertex array and loading the new one into directX. There has to be a way to manipulate the data that's been loaded into directX, I just have no clue what it is. Other than that, I've done everything except #5, which i'm not prepared to touch (way to much work, and I'm not sure how to calculate normal direction when the planes aren't at 'right angles' to the axis with a reasonable amount of effort). I've already ordered a couple of books in preparation for my senior project, but they won't arrive for a while, and I want to have this website 'finished' through lighting by Thursday so that I can satisfy the teacher on the amount of progress I've made on the class-project for one of my current courses. (He wants textures, but I think that he'll accept lighting in their place since he thought they came after, difficulty wise.) Anyway, right at the moment my code boils down to creating a new light, with a changed direction, and trying to load that into directX 'over' the existing light, but it doesn't work. I could create 360 separate lights and rotate it that way, but it seems like a rather overblown approach to the problem, suggesting that there's an easier way to manage it. Any ideas?

Share on other sites
If you have a directional light, the light's direction is controlled by light.direction.

If so, you can set the light's direction dynamically using something like:
float angleAboutYAxis = 0; // initialize a value to increment laterD3DXVECTOR3 lightDirection = D3DXVECTOR3(1,-1,1); // initial direction for the lightwhile( true ) {   D3DXMATRIX rotMat;   D3DXMatrixRotationY(&rotMat,angleAboutYAxis); // change the angle around the y axis   D3DXVECTOR3 newDirection = lightDirection; // get the initial direction   D3DXVec3Normalize(&newDirection, &newDirection); // normalize vec   D3DXVec3TransformNormal(&newDirection,&newDirection,&rotMat);   light.direction = newDirection;   angleAboutYAxis += 0.05f; // change the angle for the next render   // that increment can be adjusted for the frame rate   //.. render using the light}

Share on other sites
Wait... (and sorry I forgot to add source code rather than just linking to the website I'm using) are you saying that the set light function creates a pointer to a light object, rather than copying it?

The init_light function I'm using appears to have defined 'light' as a local variable, which means that after the function ends it expires (I know that's not the right technical terminology, sorry). So I assumed the SetLight function copied it into an internal buffer of some kind in DirectX...

[source language=C++]void init_light(void){    D3DLIGHT9 light;    D3DMATERIAL9 material;    ZeroMemory(&light, sizeof(light));    light.Type = D3DLIGHT_POINT;    // make the light type 'point light'    light.Diffuse = D3DXCOLOR(0.5f, 0.5f, 0.5f, 1.0f);    light.Position = D3DXVECTOR3(0.0f, 5.0f, 0.0f);    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    d3ddev->SetLight(0, &light);    d3ddev->LightEnable(0, TRUE);    ZeroMemory(&material, sizeof(D3DMATERIAL9));    material.Diffuse = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f);    material.Ambient = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f);    d3ddev->SetMaterial(&material);}

What I was trying to do was something similar to how the rotation was set up:

[source language=c++]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);

Only instead of using translation, I'd change the light based on the float.

End result? I think the website I'm using isn't doing an adequate job of teaching me what it's supposed to, and since I've got a DirectX10 book (amongst others) in the mail anyway, I'll just hope the teacher accepts my current project. (Hopefully that book arrives soon enough that I can get through to the textures part soon enough for this project...)

Edit: Gah, screwed up my source tag and put it down here... wrong! Also, since it looks like the source code tag handles large code so well here's the full program (his version, since my efforts completely failed), in case it helps.

[source language=C++]// 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#define SCREEN_WIDTH 800#define SCREEN_HEIGHT 600// include the Direct3D Library files#pragma comment (lib, "d3d9.lib")#pragma comment (lib, "d3dx9.lib")// global declarationsLPDIRECT3D9 d3d;LPDIRECT3DDEVICE9 d3ddev;LPDIRECT3DVERTEXBUFFER9 v_buffer = NULL;LPDIRECT3DINDEXBUFFER9 i_buffer = NULL;// function prototypesvoid initD3D(HWND hWnd);void render_frame(void);void cleanD3D(void);void init_graphics(void);void init_light(void);struct CUSTOMVERTEX {FLOAT X, Y, Z; D3DVECTOR NORMAL;};#define CUSTOMFVF (D3DFVF_XYZ | D3DFVF_NORMAL)// the WindowProc function prototypeLRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);// the entry point for any Windows programint 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 = 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_OVERLAPPEDWINDOW, 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)    {        while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))        {            TranslateMessage(&msg);            DispatchMessage(&msg);        }        if(msg.message == WM_QUIT)            break;        render_frame();    }    cleanD3D();    return msg.wParam;}// this is the main message handler for the programLRESULT 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 usevoid initD3D(HWND hWnd){    d3d = Direct3DCreate9(D3D_SDK_VERSION);    D3DPRESENT_PARAMETERS d3dpp;    ZeroMemory(&d3dpp, sizeof(d3dpp));    d3dpp.Windowed = TRUE;    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}// this is the function used to render a single framevoid 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 and index buffers to use    d3ddev->SetStreamSource(0, v_buffer, 0, sizeof(CUSTOMVERTEX));    d3ddev->SetIndices(i_buffer);    // draw the cube    d3ddev->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 24, 0, 12);    d3ddev->EndScene();     d3ddev->Present(NULL, NULL, NULL, NULL);}// this is the function that cleans up Direct3D and COMvoid cleanD3D(void){    v_buffer->Release();    // close and release the vertex buffer    i_buffer->Release();    // close and release the vertex buffer    d3ddev->Release();    // close and release the 3D device    d3d->Release();    // close and release Direct3D}// this is the function that puts the 3D models into video RAMvoid init_graphics(void){    // create the vertices using the CUSTOMVERTEX struct    CUSTOMVERTEX vertices[] =    {        { -3.0f, -3.0f, 3.0f,  0.0f, 0.0f, 1.0f, },    // side 1        { 3.0f, -3.0f, 3.0f,  0.0f, 0.0f, 1.0f, },        { -3.0f, 3.0f, 3.0f,  0.0f, 0.0f, 1.0f, },        { 3.0f, 3.0f, 3.0f,  0.0f, 0.0f, 1.0f, },        { -3.0f, -3.0f, -3.0f,  0.0f, 0.0f, -1.0f, },    // side 2        { -3.0f, 3.0f, -3.0f,  0.0f, 0.0f, -1.0f, },        { 3.0f, -3.0f, -3.0f,  0.0f, 0.0f, -1.0f, },        { 3.0f, 3.0f, -3.0f,  0.0f, 0.0f, -1.0f, },        { -3.0f, 3.0f, -3.0f,  0.0f, 1.0f, 0.0f, },    // side 3        { -3.0f, 3.0f, 3.0f,  0.0f, 1.0f, 0.0f, },        { 3.0f, 3.0f, -3.0f,  0.0f, 1.0f, 0.0f, },        { 3.0f, 3.0f, 3.0f,  0.0f, 1.0f, 0.0f, },        { -3.0f, -3.0f, -3.0f,  0.0f, -1.0f, 0.0f, },    // side 4        { 3.0f, -3.0f, -3.0f,  0.0f, -1.0f, 0.0f, },        { -3.0f, -3.0f, 3.0f,  0.0f, -1.0f, 0.0f, },        { 3.0f, -3.0f, 3.0f,  0.0f, -1.0f, 0.0f, },        { 3.0f, -3.0f, -3.0f,  1.0f, 0.0f, 0.0f, },    // side 5        { 3.0f, 3.0f, -3.0f,  1.0f, 0.0f, 0.0f, },        { 3.0f, -3.0f, 3.0f,  1.0f, 0.0f, 0.0f, },        { 3.0f, 3.0f, 3.0f,  1.0f, 0.0f, 0.0f, },        { -3.0f, -3.0f, -3.0f,  -1.0f, 0.0f, 0.0f, },    // side 6        { -3.0f, -3.0f, 3.0f,  -1.0f, 0.0f, 0.0f, },        { -3.0f, 3.0f, -3.0f,  -1.0f, 0.0f, 0.0f, },        { -3.0f, 3.0f, 3.0f,  -1.0f, 0.0f, 0.0f, },    };    // create a vertex buffer interface called v_buffer    d3ddev->CreateVertexBuffer(24*sizeof(CUSTOMVERTEX),                               0,                               CUSTOMFVF,                               D3DPOOL_MANAGED,                               &v_buffer,                               NULL);    VOID* pVoid;    // a void pointer    // lock v_buffer and load the vertices into it    v_buffer->Lock(0, 0, (void**)&pVoid, 0);    memcpy(pVoid, vertices, sizeof(vertices));    v_buffer->Unlock();    // create the indices using an int array    short indices[] =    {        0, 1, 2,    // side 1        2, 1, 3,        4, 5, 6,    // side 2        6, 5, 7,        8, 9, 10,    // side 3        10, 9, 11,        12, 13, 14,    // side 4        14, 13, 15,        16, 17, 18,    // side 5        18, 17, 19,        20, 21, 22,    // side 6        22, 21, 23,    };    // create an index buffer interface called i_buffer    d3ddev->CreateIndexBuffer(36*sizeof(short),                              0,                              D3DFMT_INDEX16,                              D3DPOOL_MANAGED,                              &i_buffer,                              NULL);    // lock i_buffer and load the indices into it    i_buffer->Lock(0, 0, (void**)&pVoid, 0);    memcpy(pVoid, indices, sizeof(indices));    i_buffer->Unlock();}// this is the function that sets up the lights and materialsvoid init_light(void){    D3DLIGHT9 light;    D3DMATERIAL9 material;    ZeroMemory(&light, sizeof(light));    light.Type = D3DLIGHT_POINT;    // make the light type 'point light'    light.Diffuse = D3DXCOLOR(0.5f, 0.5f, 0.5f, 1.0f);    light.Position = D3DXVECTOR3(0.0f, 5.0f, 0.0f);    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    d3ddev->SetLight(0, &light);    d3ddev->LightEnable(0, TRUE);    ZeroMemory(&material, sizeof(D3DMATERIAL9));    material.Diffuse = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f);    material.Ambient = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f);    d3ddev->SetMaterial(&material);}

Share on other sites
Quote:
 I can't manipulate the lighting's direction

You need to setup a directional light, rather than a point light.

You can modify the init_light function to do that. The "D3DLIGHTTYPE Type;" variable in the D3DLIGHT9 structure would then be set to D3DLIGHT_DIRECTIONAL, rather than D3DLIGHT_POINT. Check the docs to ensure you set the other parameters consistent with that change. The D3DLIGHT9 structure has a variable "D3DVECTOR Direction;" which can be changed as I previously described.

You can either put:
static float lightAngle = 0;lightAngle += 0.05f; // change the direction slightly on each call

inside the init_light function, or change the function to accept a light angle argument to be used to set the light direction:
void init_light(float lightAngle) // set the lightAngle as desired{  //.. set the light direction using lightAngle}

Share on other sites
... That's what goes with jumping around in the tutorial (I read and worked on the next one after I had some trouble with an earlier challenge in this one), I was modifying the wrong version of the code somehow.

Now I feel really stupid.

1. 1
2. 2
3. 3
Rutin
15
4. 4
khawk
14
5. 5
frob
12

• 9
• 11
• 11
• 23
• 12
• Forum Statistics

• Total Topics
633662
• Total Posts
3013231
×