Jump to content
  • Advertisement
Sign in to follow this  
Rilbur

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.

If you intended to correct an error in the post then please contact us.

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 this post


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

Is your question about how to change that direction?

If so, you can set the light's direction dynamically using something like:

float angleAboutYAxis = 0; // initialize a value to increment later
D3DXVECTOR3 lightDirection = D3DXVECTOR3(1,-1,1); // initial direction for the light
while( 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 this post


Link to post
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 declarations
LPDIRECT3D9 d3d;
LPDIRECT3DDEVICE9 d3ddev;
LPDIRECT3DVERTEXBUFFER9 v_buffer = NULL;
LPDIRECT3DINDEXBUFFER9 i_buffer = NULL;

// function prototypes
void 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 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 = 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 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 = 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 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 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 COM
void 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 RAM
void 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 materials
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);
}

Share this post


Link to post
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 this post


Link to post
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.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!