Making my first 3D scene with a shadow

Started by
17 comments, last by Programmer101 16 years, 11 months ago
Hey all, I want to make a 3D scene in DirectX. I want to make a scene with a rotating object ( .x mesh file ) and a wall. The object is rotating in front of the wall. I want to point a light on the object and display the shadow of the object on the wall. I also want to add HDR lighting if possible. So where should I start? Any help would be greatly appreciated. Greetings, Vinnie.
Advertisement
These are some pretty advanced topics. Are you sure you are ready for them yet?
I am not sure what language you are using, but I am going to assume c++. One of the best tutorial sites I found when I was first starting is http://www.codesampler.com

Give that a shot, and when you get stuck with more specific questions, it will be easier to help you out.
Hello there!

I think you can find all the answers (except for the HDR question) in the book "Introduction to 3D game programming with DirectX9.0c a shader approach" (http://www.amazon.com/Introduction-Game-Programming-Direct-9-0c/dp/1598220160/ref=pd_bbs_sr_1/105-5554788-4478845?ie=UTF8&s=books&qid=1180706658&sr=8-1) written by Frank. D. Luna. The book will cover everything you have to know from the beginning.
_____________________Lecturer at Blekinge Institute of Technology
Thanks for the replies guys!

Well the thing is, I'm making my portfolio. And I want to show off some good programs.

The programming language I'm using is, indeed, C++.

But, lets first make a 3D scene with a rotating object and a wall.

This is my code right now:

// 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 1680#define SCREEN_HEIGHT 1050#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 declarationsLPDIRECT3D9 d3d;    // the pointer to our Direct3D interfaceLPDIRECT3DDEVICE9 d3ddev;    // the pointer to the device classLPDIRECT3DVERTEXBUFFER9 t_buffer = NULL;    // the pointer to the vertex bufferLPDIRECT3DSURFACE9 z_buffer = NULL;    // the pointer to the z-buffer// mesh declarationsLPD3DXMESH meshSpaceship;    // define the mesh pointerD3DMATERIAL9* material;    // define the material objectDWORD numMaterials;    // stores the number of materials in the mesh// function prototypesvoid initD3D(HWND hWnd);    // sets up and initializes Direct3Dvoid render_frame(void);    // renders a single framevoid cleanD3D(void);    // closes Direct3D and releases memoryvoid init_graphics(void);    // 3D declarationsvoid init_light(void);    // sets up the light and the material// 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 = (WNDPROC)WindowProc;    wc.hInstance = hInstance;    wc.hCursor = LoadCursor(NULL, IDC_ARROW);    wc.lpszClassName = L"WindowClass1";    RegisterClassEx(&wc);    hWnd = CreateWindowEx(NULL,                          L"WindowClass1",                          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 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 = FALSE;    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;    d3dpp.hDeviceWindow = hWnd;    d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;    d3dpp.BackBufferWidth = SCREEN_WIDTH;    d3dpp.BackBufferHeight = SCREEN_HEIGHT;    d3dpp.EnableAutoDepthStencil = TRUE;    // automatically run the z-buffer for us    d3dpp.AutoDepthStencilFormat = D3DFMT_D16;    // 16-bit pixel format for the z-buffer    // 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 triangle    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    return;}// 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();    // SET UP THE TRANSFORMS    D3DXMATRIX matView;    // the view transform matrix    D3DXMatrixLookAtLH(&matView,    &D3DXVECTOR3 (0.0f, 4.0f, 8.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     D3DXMATRIX matProjection;    // the projection transform matrix    D3DXMatrixPerspectiveFovLH(&matProjection,                               D3DXToRadian(70),    // the horizontal field of view                               SCREEN_WIDTH / SCREEN_HEIGHT,    // the aspect ratio                               1.0f,    // the near view-plane                               100.0f);    // the far view-plane    d3ddev->SetTransform(D3DTS_PROJECTION, &matProjection);    // set the projection    static float index = 0.0f;		if ( KEY_DOWN(VK_LEFT) )		index += 0.03f;    // an ever-increasing float value	if ( KEY_DOWN(VK_RIGHT) )		index -= 0.03f;    D3DXMATRIX matRotateY;    // a matrix to store the rotation for each triangle    D3DXMatrixRotationY(&matRotateY, index);    // the rotation matrix    d3ddev->SetTransform(D3DTS_WORLD, &(matRotateY));    // set the world transform    // draw the spaceship    for(DWORD i = 0; i < numMaterials; i++)    // loop through each subset    {        d3ddev->SetMaterial(&material);    // set the material for the subset        meshSpaceship->DrawSubset(i);    // draw the subset    }    d3ddev->EndScene();     d3ddev->Present(NULL, NULL, NULL, NULL);    return;}// this is the function that cleans up Direct3D and COMvoid cleanD3D(void){    meshSpaceship->Release();    // close and release the spaceship mesh    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 RAMvoid init_graphics(void){    LPD3DXBUFFER bufShipMaterial;    D3DXLoadMeshFromX(L"spaceship 2.x",    // load this file                      D3DXMESH_SYSTEMMEM,    // load the mesh into system memory                      d3ddev,    // the Direct3D Device                      NULL,    // we aren't using adjacency                      &bufShipMaterial,    // put the materials here                      NULL,    // we aren't using effect instances                      &numMaterials,    // the number of materials in this model                      &meshSpaceship);    // put the mesh here    // retrieve the pointer to the buffer containing the material information    D3DXMATERIAL* tempMaterials = (D3DXMATERIAL*)bufShipMaterial->GetBufferPointer();    // create a new material buffer for each material in the mesh    material = new D3DMATERIAL9[numMaterials];    for(DWORD i = 0; i < numMaterials; i++)    // for each material...    {        material = tempMaterials.MatD3D;    // get the material info        material.Ambient = material.Diffuse;    // make ambient the same as diffuse    }    return;}// this is the function that sets up the lights and materialsvoid 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 = 500.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 = 0.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;}


There is a single object rotating in the centre of the screen with a point light pointing at it. Now I just need a .x file for a wall, but can't seem to find one anywhere..

What do you guys think about the code?

You can download the .x file here: http://directxtutorial.com/Graphics/Meshes/spaceship%202.x

EDIT - I found a .x file exporter for Maya. I have the .x file for the wall. :)

[Edited by - Vinniee on June 1, 2007 1:55:49 PM]
You could use the free modeling program Blender to make the .x file for a wall, I'm sure it wouldn't be too complicated.
Quote:Original post by ChristmasCelery
You could use the free modeling program Blender to make the .x file for a wall, I'm sure it wouldn't be too complicated.


Hehe check my previous post mate, I found a .x file plugin for Maya :)

So how do I get the wall behind the spaceship? :)
You'd have to draw the ship, then move to a different location and draw the wall.
This discusses the world transformation stage with Direct3D, and there is always [google]

Bear in mind that you don't get shadows "free" with light in Direct3D or OpenGL, you have to implement them yourself, and that is quite an advanced topic. Search "shadow volumes" when you are ready.
Quote:Original post by ChristmasCelery
You'd have to draw the ship, then move to a different location and draw the wall.
This discusses the world transformation stage with Direct3D, and there is always [google]

Bear in mind that you don't get shadows "free" with light in Direct3D or OpenGL, you have to implement them yourself, and that is quite an advanced topic. Search "shadow volumes" when you are ready.


Hehe ok, thanks.

Have you checked out my code? What do you think about it?

And what exactly is a matrix?

Sorry guys, but I'm quite new to this. :)
Quote:Original post by Vinniee
[...]And what exactly is a matrix?

Sorry guys, but I'm quite new to this. :)


Okay, a matrix is basically a 4x4 float array which can be constructed by one of numerous D3DX functions. There are three general types of transforms in direct3d which are all defined by matrices.

The first type is the perspective matrix which defines the depth clipping (how far away stuff can be rendered), field of view(how much you can see horizontally), and aspect ratio(screen width/height) for a scene. This transform is commonly defined with this function
D3DXMatrixPerspectiveFovLH(output matrix, field of view, aspect ratio,min clip(around 1.0),max clip(i use 1000.0));

The second type is the view transform (camera position). This is basically a inverse world transform for the camera position. There are a few ways to make this but my favorites are:
The old school way :)

D3DXMatrixRotationX(&matRotX, -XAngle);D3DXMatrixRotationY(&matRotY, -YAngle);D3DXMatrixRotationZ(&matRotZ, -ZAngle);D3DXMatrixTranslation(&matTrans, -XPos, -YPos, -ZPos);D3DXMatrixIdentity(&matView);D3DXMatrixMultiply(&matView, &matView, &matTrans);D3DXMatrixMultiply(&matView, &matView, &matRotZ);D3DXMatrixMultiply(&matView, &matView, &matRotY);D3DXMatrixMultiply(&matView, &matView, &matRotX);


and
D3DXMatrixLookAtLH()


The final type of transform is the world matrix(object position). This is what you will use to place your wall. You can create it just like you can create the view matrix:

D3DXMatrixRotationX(&matRotX, XAngle);D3DXMatrixRotationY(&matRotY, YAngle);D3DXMatrixRotationZ(&matRotZ, ZAngle);D3DXMatrixTranslation(&matTrans, XPos, YPos, ZPos);D3DXMatrixIdentity(&matWorld);D3DXMatrixMultiply(&matWorld, &matWorld, &matTrans);D3DXMatrixMultiply(&matWorld, &matWorld, &matRotZ);D3DXMatrixMultiply(&matWorld, &matWorld, &matRotY);D3DXMatrixMultiply(&matWorld, &matWorld, &matRotX);


Transformations can be set through this directx function

IDirect3DDevice9::SetTransform(D3DTRANSFORMSTATETYPE State, const D3DMATRIX *pMatrix)


the state is either D3DTS_PERSPECTIVE, D3DTS_VIEW, or D3DTS_WORLD

hth,
Stewart
Thanks for explaining that dude. So how should I implent this in my code?

Also, I'm trying to rotate my object along the X and Y axis. But I only can rotate it along the X axis.

This is the part of the code I'm talking about:

static float index_y = 0.0f;static float index_x = 0.0f;	if ( KEY_DOWN(VK_LEFT) )	index_y += 0.03f;    // an ever-increasing float valueif ( KEY_DOWN(VK_RIGHT) )	index_y -= 0.03f;if ( KEY_DOWN(VK_UP) )	index_x += 0.03f;    // an ever-increasing float valueif ( KEY_DOWN(VK_DOWN) )	index_x -= 0.03f;D3DXMATRIX matRotateY;    // a matrix to store the rotation for each triangleD3DXMATRIX matRotateX;D3DXMatrixRotationY(&matRotateY, index_y);    // the rotation matrixD3DXMatrixRotationX(&matRotateX, index_x);d3ddev->SetTransform(D3DTS_WORLD, &(matRotateX));d3ddev->SetTransform(D3DTS_WORLD, &(matRotateY));    // set the world transform


Does anyone know what I'm doing wrong?
I can't seem to use the function SetTransform() multiple times.

This topic is closed to new replies.

Advertisement