Obtaining Direct3D
- Direct3D is part of the DirectX and DirectMedia technologies, all of which are COM based services
- You can download these tools from the Microsoft site
- The DirectX runtime consists of DLLs in the System or System32 directory
- The DLLs are relatively small, and come with Win98, WinNT 4 and Win2000. It is also easy to download using Windows Update.
- The very valuable DirectX SDK is large, but can be downloaded if you have a T1 line. Or you can usually order the CD on the web from www.microsoft.com/directx for under $10.
- The DirectX SDK also comes with the MSDN
- The headers you need for C++ development ship with CBuilder
- You can update these headers with more recent files from the SDK. There is a Borland lib directory on the SDK CD.
- Direct3D retained mode is usually considered part of DirectMedia, so you want the DirectMedia SDK, but the DirectX SDK usually also has the headers. At least in the last round of CDs, DirectMedia had the docs for Direct3D retained mode.
- The current version of DirectX is 6.1. 7.0 is scheduled to ship this fall.
- Windows NT 4 currently supports only DirectX 3. Windows 2000, currently scheduled to ship in Nov, will support at least DirectX 6.0, probably 7.0
Key Terms used in 3D Programming
- Describing 3D Spaces: Origin, Axes, Vectors, Planes, etc.
- Describing 3D Shapes: A Mesh made up of vectors that describe faces and normals
- Moving Shapes in Space: Translating, rotating and scaling
- Textures
- Lights
- Z Buffering: Don't draw faces not visible to the user
- Rendering: Wireframe mode, Flat, Gouroud and Phong shading
- Animation
- The goal is to find an object framework that will wrap these technologies.
Describing 3D Spaces
- In the Direct3D by default the Origin is at the bottom left corner of your screen.
- 3D space has three axes: X, Y, and Z.
- The positive x-axis points to the right and the positive y-axis points up. Z gets larger as you move away from the viewer, into the screen.
- A Point is an infinitely small area in space described by three values, one for each axis
- A Vectors is a line between two points.
- Planes are flat surfaces that extent infinitely in two directions.
- In Direct3D, a face is a triangular area on a plane.
- A vertex is a point used to describe the corners of a face.
Describing 3D Shapes
- You can describe 3D shapes with a mesh, usually built in a third party tool and stored in an X file.
- The format for X files is found on the Direct Media SDK CD
- A mesh is made up of a series of faces.
- Normals are vectors often used to describe the colors of the faces in a mesh.
- You control a mesh with the IDirect3DRMMesh or IDirect3DRMMeshBuilder interface.
- The IDirect3DRMMeshBuilder interface is the easier to use, but it is slower.
MyShape 4 4
1.0 1.5 2.4
2.0 3.5 3.4
1.0 2.5 4.4
1.0 4.5 2.4
1 3 2
2 3 4
3 2 1
1 2 3
Moving Shapes in Space
- The act of moving a 3D space in Direct3D is called a translation.
- If you change the size of a 3D object, then you are scaling it.
- To Turn an object in Direct3D you rotate it.
- There are several ways to do this sort of thing, but you often use the ID3DMeshBuilder or ID3DMeshBuilderFrame.
Textures and materials
- These are bitmaps painted on a mesh.
- Textures are what Wolfenstein, Doom and Quake are all about. In fact they are central to most modern games.
- You can scale, wrap and animate textures.
- Use the IDirect3DRMTexture and the IDirect3DRmTextureWrap interface
- A material controls whether an object is shiney, dull, or appears to emit light.
- Use the IDirect3DRMMaterial interface to control this feature.
Lights
- Lights can be colored, or they can be just plain white ramp lights.
- Ambient lights illuminate an entire scene. This tends to create a very flat look.
- A point light emanates in all directions from one location
- Directional lights come from one direction, but have no particular origin
- Spot lights produce light in the shape of cone
- Lighting is much more important than it might appear at first. A scene with good lighting is many times better than an ordinary scene lit with ambient light.
- IDirect3DRMLight IDirect3DRMFrame are the key objects when working with lights.
Z Buffering
- This is a technique to make sure time is not wasted drawing surfaces that are never shown to the user.
- Rendering is performed in front to back order, so hidden surfaces are never drawn.
- A program running in 800X600 16 bit mode requires a megabyte of memory.
- You need to conserve memory whenever possible.
- A Clipper makes sure you don't attempt to draw anything outside the edges of the current window.
- The scope of the window itself is defined by the viewport, which I will define later.
Rendering
WireFrame mode draws only the edges of a face.
- Unlit scenes render quickly but objects appear flat and lifeless.
- Flat mode renders a mesh with each face completely flat. It uses face normals.
- Gouraud shading uses vertex normals and then light intensities are averaged over the face.
- Phong shading uses vertex normals, and calculates light intensities over the face.
Animation
- Motion attributes will allow you to translate, rotate, or scale an object.
- In key-framing you declare the starting and ending points of a path.
- The computer then moves the object from point A to B over a vector or spline path.
- You can do this with DirectD3RMAnimation and Directe3DRAnimation set.
Initialization Overview
- I'm now going to step you through the process of getting a Direct3D program up and running
- Most of this code you can write once and then reuse
- It is important that you understand the code, however, as it will need to be tweaked to meet you needs
Direct3D Overview
- All the objects are COM objects. Helper functions make it easy to use: Direct3DCreate, etc
- Create a D3DObject
- Create a Clipper object
- Create a Device object
- Create the ZBuffer
- Create a Viewport
- Create a Camera object
- Create Lights
-
- Load the meshes and textures
- Most of this code you can write once and then reuse
- It is important that you understand the code, however, as it will need to be tweaked to meet you needs
Creating Direct3D
- You may need to turn off floating point exceptions.
- Call Direct3DRMCreate to create an instance of the Direct3D Object
- Direct3D is of type IDirect3DRM. Like all of Direct3D, it is a COM object
- The RM is IDirect3DRM stands for Retained Mode
- IDirect3DRM is declared in d3drmobj.h
CODE:
HResult hr;
IDirect3DRM *FDirect3D;
hr = Direct3DRMCreate(&FDirect3D);
if (hr != DD_OK)
raise Exception("Could not initialize Direct3D. Is DirectX Installed?");
ALTERNATE
#include <comobj.hpp>
...
OleCheck(Direct3DRMCreate(&FDirect3D));
DECLARATION:
STDAPI Direct3DRMCreate(LPDIRECT3DRM FAR *lplpDirect3DRM);
Creating Clipper Objects
- Call DirectDrawCreateClipper to create a clipper object
- You must have a clipper object, as you will use it to create a Device
- Clippers insure that you don't waste time drawing vertices that are off screen
CODE:
hr = DirectDrawCreateClipper(0, &FD3DClipper, NULL);
if(hr != D3DRM_OK)
throw Exception("DirectDrawCreateClipper failed");
OleCheck(FD3DClipper->SetHWnd(0, FHandle));
DECLARATION:
HRESULT WINAPI DirectDrawCreateClipper(
DWORD dwFlags, // Not used must be zero
LPDIRECTDRAWCLIPPER FAR *lplpDDClipper, // The object you want
IUnknown FAR *pUnkOuter // COM aggregation, must be NULL
);
Creating a Device
- Retained Mode supports devices that render directly to the
screen, to windows, or into application memory.
- The device itself is virtual, and can contain attributes you define
- You can define what you want the device to do, for instance, you set the bit depth
and quality you want it to use
- DirectX will tell you if you are trying to create a device not supported by the current system
- By passing in nil in the second parameter we are saying that we
want Windows to choose the device.
- Use Direct3D.FindDevice if you want to specify the device
- Call CreateDeviceFromClipper to return an IDirect3DRMDevice in the
last parameter
CODE:
hr = FDirect3D->CreateDeviceFromClipper(FD3DClipper, NULL, ClientWidth,
ClientHeight, &FD3Device);
if(hr != D3DRM_OK)
throw Exception("CreateDeviceFromClipper failed");
Setting up the Device and Direct3D object
- Set the Quality, Shades, TextureColors, TextureShapes and whether
or not you want to dither.
- This is not a complete list of things you can do with the
IDirect3DRMDevice interface. See the online docs for more info.
CODE:
OleCheck(FD3Device->SetQuality(D3DRMRENDER_GOURAUD));
DC = GetDC(FHandle);
Bpp = GetDeviceCaps(DC, BITSPIXEL);
ReleaseDC(FHandle, DC);
switch (Bpp)
{
case 8:
FD3Device->SetDither(false);
break;
case 16:
FD3Device->SetShades(32);
FDirect3D->SetDefaultTextureColors(64);
FDirect3D->SetDefaultTextureShades(32);
FD3Device->SetDither(false);
break;
case 24, 32:
FD3Device->SetShades(256);
FDirect3D->SetDefaultTextureColors(64);
FDirect3D->SetDefaultTextureShades(256);
FD3Device->SetDither(false);
break;
default:
throw Exception("Bit depth not expected: " + IntToStr(Bpp));
}
Understanding Frames
- We are now going to create a scene, and then load some objects,
such as a mesh, a camera, and some lights, into it.
- The scene will be of type IDirect3DRMFrame, as will the camera.
- A third frame will hold the mesh itself.
- The term frame is meant to be used in the same context as the word "frame" in the English phrase "frame of reference."
- Frames are located in space, and they can have a rotation, a
velocity, and they can be moved, or "transformed".
- The root frame, which in this case is the scene, has no parent.
All other frames in this program have a parent.
- If you move a parent frame, then the child frames move with it
- The child uses the parent as it's "frame of reference"
- For example, a camera sits in a frame. If you want to move or
turn the camera, act directly on its frame.
Creating Scenes
- The first frame you create in your program is the scene.
- The scene has no parent. We specify this fact by passing in nil in the first parameter to CreateFrame:
- No Parent: FDirect3D->CreateFrame(nil, FD3DScene);
- To give a frame a parent, pass in the parent frame in the first parameter to CreateFrame
- With Parent: FDirect3D->CreateFrame(FD3DScene, SomeFrame);
- Set the background color for your scene: SetSceneBackgroundRGB
- If a parent frame moves, then its children move with it
- You can use AddChild to add and remove frames
CODE:
//Create frame for D3DScene as root
hr = FDirect3D->CreateFrame(NULL, &FD3DScene);
if(hr != D3DRM_OK)
throw Exception("CreateFrame failed");
FD3DScene->SetSceneBackgroundRGB(1.0, 1.0, 1.0);
if (MeshName != "")
if (!LoadMesh(MeshName))
return FALSE;
Setting up meshes
- Use an IDirect3DRMMeshBuilder object to create a mesh.
- Use the MeshBuilder to load, scale and set the perspective for
the mesh
- Then create an IDirect3DRMFrame as a child of the scene to house
the Mesh
- Use the AddVisual method to add the MeshBuilder to your frame.
- In this case, we want the mesh to rotate, so use the SetRotation
method of the frame.
CODE:
DeleteMesh();
OleCheck(FDirect3D->CreateMeshBuilder(&FD3DMeshBuilder));
OleCheck(FD3DMeshBuilder->Load(FileName.c_str(), NULL, D3DRMLOAD_FROMFILE, NULL, NULL));
FMeshValid = TRUE;
OleCheck(FD3DMeshBuilder->SetPerspective(true));
ScaleMesh(FD3DMeshBuilder, 25);
FDirect3D->CreateFrame(FD3DScene, &FD3DMeshBuilderFrame);
FD3DMeshBuilderFrame->SetRotation(FD3DScene, 1, 0, 0, 0.1);
FD3DMeshBuilderFrame->AddVisual(FD3DMeshBuilder);
Setting up Textures
- Use the IDirect3DRM object to load a texture into an IDirect3DRMTexture object.
- Set the texture in the MeshBuilder (not the MeshFrame!)
- We won't use this IDirect3DRMTexture object again, so free it.
CODE:
OleCheck(FDirect3D->LoadTexture(FileName.c_str(), &D3DTexture));
FD3DMeshBuilder->SetTexture(D3DTexture);
FD3DMeshBuilder->SetPerspective(true);
//D3DTexture.Release();
D3DTexture->Release();
return TRUE;
Setting up the Lights
- An ambient light comes from all directions at once
- There are also spot lights, point source lights, parallel point lighting and directional lights
CODE:
// This code is part of the initialization process
OleCheck(FDirect3D->CreateFrame(FD3DScene, &FD3DLightFrame));
OleCheck(FD3DLightFrame->AddTranslation(D3DRMCOMBINE_REPLACE, 0.0, 0, -50));
...
// This code sets the first light or allows changing the lighting
{
if ((FD3DLight) && (FD3DLightFrame))
{
FD3DLightFrame->DeleteLight(FD3DLight);
FD3DLight->Release();
}
OleCheck(FDirect3D->CreateLightRGB(D3DRMLIGHT_SPOT, 1, 1, 1, &FD3DLight));
OleCheck(FD3DLightFrame->AddLight(FD3DLight));
}
Creating the Camera and ViewPort
- The camera is the eye of the scene
- When you play Doom or Quake, you are essentially playing the part of the camera
- The ViewPort is a rectangular 2D area of a device into which objects will be rendered
- Notice that the ViewPort gets a camera passed into it during creation
- All viewports have cameras
CODE:
//Create a camera
OleCheck(FDirect3D->CreateFrame(FD3DScene, &FD3DCamera));
OleCheck(FD3DCamera->SetPosition(FD3DScene, 0, 0, -50));
//Create Viewport
OleCheck(FDirect3D->CreateViewport(FD3Device, FD3DCamera,
0, 0, FD3Device->GetWidth(), FD3Device->GetHeight(), &FD3DViewPort));
Traveling Through a 3D Scene
- Games like Doom and Quake work by moving the camera through a scene
- The code shown here moves the camera through a scene
- First you get the orientation of the camera, then you set its velocity along that vector
- If the user wants to look to his left or right, use the SetRotation routine
CODE:
void TSteerShip::Steer(int Key)
{
D3DVECTOR Direction, Up;
FCamera->GetOrientation(FScene, &Direction, &Up);
switch (Key)
{
case VK_UP:
FCamera->SetVelocity(FScene, Direction.x, Direction.y, Direction.z, False);
break;
case VK_DOWN:
FCamera->SetVelocity(FScene, -Direction.x, -Direction.y, -Direction.z, False);
break;
case VK_RIGHT:
FCamera->SetRotation(FScene, 0.0, 1.0, 0.0, 0.1);
break;
case VK_LEFT:
FCamera->SetRotation(FScene, 0.0, 1.0, 0.0, -0.1);
break;
}
}
Summary
- This talk provided an overview of the 3D programming, and how to Initialize Direct3D
- To write me or to get materials form the talk: http://community.borland.com/soaps/techvoyage
- Write ccalvert@borland.com
- Recommended Reading:
- I learned mostly from the docs and examples that game with the sdk
- I have not found a great book on this subject, but the best book I've seen is:
- The Awesome Power of Direct3D by Peter Kovach, Manning Publications in Greenwich, CT. (orders@manning.com)
- This is not perfect, but it is much better than anything else I've seen
- www.delphi-jedi.org