Lecture 7: Direct3D Basics (I) Prof. Hsien-Hsin Sean Lee School of Electrical and Computer Engineering Georgia Institute of Technology.

Download Report

Transcript Lecture 7: Direct3D Basics (I) Prof. Hsien-Hsin Sean Lee School of Electrical and Computer Engineering Georgia Institute of Technology.

Lecture 7: Direct3D Basics (I)
Prof. Hsien-Hsin Sean Lee
School of Electrical and Computer Engineering
Georgia Institute of Technology
DirectX and GPU (Nvidia-centric) History
DirectX 5
Riva 128
DirectX 6
Multitexturing
Riva TNT
(NV4)
DirectX 7
DirectX 8
T&L
SM 1.x
GeForce 256 GeForce3
Cg
(NV10)
(NV20)
DirectX 9
DirectX 9.0c
SM 3.0
SM 2.0
GeForceFX GeForce 6
(NV30)
(NV40)
DirectX 2
1996
3dfx’s
first
Voodoo
chip
1998
1999
NVidia’s
response
to Voodoo2
2000
3dfx demise
2001
2002
2003
DirectX 10
SM 4.0
GeForce 8
(G80)
2004
686 million
Transistors
1.5GHz
2006
Adapted from David Kirk’s slide
2
3D Apps
Direct3D
API
REF HAL
Direct3D Overview
GPU
• An Application Programming Interface for 3D
• “HAL device type” provides hardware independence and
makes apps compatible
– SOFTWARE_VERTEX_PROCESSING (T&L done in CPU)
– HARDWARE_VERTEX_PROCESSING (T&L done by GPU)
– MIXED_VERTEX_PROCESSING
• “REF device type” (Reference Rasterizer) supports the entire
D3D using emulation for debugging purposes
– E.g., use pixel shader on GPU that does not support pixel shader
– Need to install D3D SDK
3
Hardware Abstraction Layer
• Provide Hardware Independence to the upper layers
CreateDevice(
Adapter,
DeviceType,
HWND hWnd,
BehaviorFlags,
D3DPRESENT_PARAMETERS PresentParameters,
IDirect3DDevice9 **ReturnDeviceInterface
);
d3d->CreateDevice(..
– D3DDEVTYPE
• D3DDEVTYPE_HAL
– BehaviorFlags:
• D3DCREATE_SOFTWARE_VERTEXPROCESSING
• D3DCREATE_HARDWARE_VERTEXPROCESSING
• Provided by Graphics Hardware
– Vertex Processing
– Pixel Processing
– Programmable Shaders
4
The Big Picture
WinMain()
registerClass(&wc)
While (TRUE) {
hWnd = CreateWindow(…)
D3d = Direct3DCreate9(…)
D3d->CreateDevice(…,
&D3dpp, &gd3dDevice)
init_graphics();
if (PeekMessage(..))
{
/* Event Processing */
TranslateMessage();
DispatchMessage();
}
else {
/* D3D Game Loop */
render_a_frame();
}
}
clean_D3D();
init_lighting();
Initialization phase
5
Win32 Programming
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow);
• Initialize your program in WinMain()
• hInstance: a handle for this application
• hPrevInstance: for pre-32 bit apps that use the
same address space for the same app
• lpCmdLine: Command line arguments
• nCmdShow: control appearance of a window, we will
not use this
6
Create A Window
wc.lpfnWndProc
= MainWndProc;
wc.style = CS_HREDRAW | CS_VREDRAW;
... ...
registerClass(&wc);
Main message handler
of the program
hWnd = CreateWindow(NULL, L"WindowClass”,
L"First D3D Program”,
WS_OVERLAPPEDWINDOW,
0, 0, 300, 400,
NULL, NULL,
hInstance, NULL );
• Create the Window Class by registering wc class
• Create a Window using CreateWindow()
• Return a handle for this newly created window
7
Handling Windows Events and Messages
Event Queue
PeekMessage()
1. Key Pressed (Enter)
2. Mouse moved (Loc)
TranslateMessage()
MainWinProc()
Message
Recognized?
3. Window resized (size)
DispatchMessage()
4. …
Process
Message
Continue
Adapted from Chris Hanson’s page
8
Initialize Direct3D Object
IDirect3D9* D3d=0;
D3DPRESENT_PARAMETERS D3dpp;
IDirect3DDevice9* gd3dDevice=0;
CreateDevice(
Adapter,
DeviceType,
HWND hWnd,
BehaviorFlags,
D3DPRESENT_PARAMETERS PresentPara,
IDirect3DDevice9 **RtrnDevInterface
);
D3d = Direct3DCreate9(D3D_SDK_VERSION);
D3d->CreateDevice(D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&D3dpp,
&gd3dDevice,
);
• Acquire an IDirect3D9 interface
• Fill in D3D structure parameters (next slide)
• Create d3d device
9
Example of Filling D3DPRESENT_PARAMETERS
D3dpp.Windowed
D3dpp.SwapEffect
D3dpp.hDeviceWindow
D3dpp.BackBufferFormat
D3dpp.BackBufferWidth
D3dpp.BackBufferHeight
D3dpp.BackBufferCount
D3dpp.MultiSampleType
=
=
=
=
=
=
=
=
False; // Window mode
D3DSWAPEFFECT_DISCARD;
hWnd;
// Window handle
D3DFMT_X8R8G8B8;
SCREEN_WIDTH;
SCREEN_HEIGHT;
1;
// Typically 1
D3DMULTISAMPLE_NONE;
• Define basic property of d3d object instance
• There are more parameters you can specify
– Check msdn.microsoft.com for all parameters
10
Device Capabilities
IDirect3D9* D3d=0;
D3d = Direct3DCreate9(D3D_SDK_VERSION);
D3d->GetDeviceCaps(D3DADAPTER_DEFAULT,
deviceType,
&caps);
if (caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
devBehaviorFlags |= D3DCREATE_HARDWARE_VERTEXPROCESSING
else
devBehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
D3d->CreateDevice(D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
hWnd,
devBehaviorFlags,
&D3dpp,
&gd3dDevice,
);
• Check what are supported on your graphics hardware
11
Basic D3D Function Call Loop
While (TRUE)
{
gd3dDevice->Clear(0, NULL,
D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
D3DCOLOR_XRGB(0, 0, 0),
1.0f, // initialize z buffer (0, 1)
0
// for stencil buffer
);
gd3dDevice->BeginScene();
. . . .
gd3dDevice->EndScene();
gd3dDevice->Present(0, 0, 0, 0);
}
• Clear screen to nothing every frame
• BeginScene() and EndScene() enclose the rendering of one frame
• Present() presents the content of the next buffer
12
Clean D3D States
While (TRUE)
{
... ... ..
}
texture->Release();
vertex_buffer->Release();
... ... ..
gd3dDevice->Release();
D3d->Release();
• Release all COM objects prior to exiting the
program
13
The Big Picture
WinMain()
registerClass(&wc)
While (TRUE) {
hWnd = CreateWindow(…)
D3d = Direct3DCreate9(…)
D3d->CreateDevice(…,
&D3dpp, &gd3dDevice)
init_graphics();
if (PeekMessage(..))
{
/* Event Processing */
TranslateMessage();
DispatchMessage();
}
else {
/* D3D Game Loop */
render_a_frame();
}
}
clean_D3D();
init_lighting();
Initialization phase
14
First Direct3D Example
Hello Direct3D
(See Demo in Visual Studio)
Note that: DirectX 9.0 SDK Required
15
D3DX Vectors
• Various types
– D3DXVECTOR3 vec(x, y, z)
– D3DXVECTOR4 vec(x, y, z, w)
• D3DX provides several common vector functions
– float D3DXVec3Dot(D3DXVECTOR3*, D3DXVECTOR3*)
– D3DXVec3Cross(D3DXVECTOR3 *cross, D3DXVECTOR3
*v1, D3DXVECTOR3 *v2)
– D3DXVec3Normalize(D3DXVECTOR3 *out, D3DXVECTOR3*)
– float D3DXVec3Length(D3DXVECTOR3*)
16
D3DXVector Code Example
SimpleVectors
(See Demo in Visual Studio)
17
D3DX Matrix
• D3DXMATRIX (4x4)
• D3DX provides several common matrix manipulations
– D3DXVECTOR4 *D3DXVec4Transform (1x4 * 4x4)
– D3DXMATRIX *D3DXMatrixMultiply
– D3DXMatrixInverse
– D3DXMatrixTranspose
– D3DXMatrixIdentity
18
D3DXMATRIX Example
SimpleMatrix
(See Demo in Visual Studio)
19
Create Vertex Buffer
IDirect3DVertexBuffer9* v_buffer;
Struct Vertex
{
D3DXVECTOR3 pos;
}
gd3dDevice->CreateVertexBuffer(
3* sizeof( Vertex ),
0,
// usage
0,
// flexible vertex format
D3DPOOL_MANAGED, // indicate buffer in video mem
&v_buffer,
0);
// reserved, not used
• Create a container for allocating vertices
20
Access Vertex Buffer
IDirect3DVertexBuffer9::Lock(
UINT OffsetToLock,
UINT SizeToLock,
BYTE** ppbData, // return a ptr to the locked mem
DWORD Flags);
Vertex* vertices;
v_buffer->Lock(0, 0, (void**)&vertices, 0);
vertices[0] = VertexPos(-1.0f, 0.0f, 2.0f);
vertices[1] = VertexPos( 0.0f, 1.0f, 2.0f);
vertices[2] = VertexPos( 1.0f, 0.0f, 2.0f);
v_buffer->Unlock();
• Obtain a pointer to the vertex or index buffer
• Need to unlock() them when done
21
Preparing to Draw
Stream source id
IDirect3DDevice9::SetStreamSource(
UNIT StreamNumber,
IDirect3DVertexbuffer9* pStreamData,
UINT OffetInBytes,
UINT Stride);
Vertex buffer
Offset from the start
of the stream
Size of each element
in the vertex buffer
22
DrawPrimitive Method
Point, line, trianglelist
IDirect3DDevice9::DrawPrimitive(
D3DPRIMITIVETYPE PrimitiveType,
UINT StartVertex,
UINT PrimitiveCount);
Index to the element
in the vertex buffer
The number of
primitives to draw
Example
gd3dDevice->SetStramSource(0, v_buffer, 0, sizeof(VertexPC));
gd3dDevice->DrawPrimitive(
D3DPT_TRIANGLELIST, 0, 3);
23
DrawPrimitve Example
DrawFirstTriangle
(See Demo in Visual Studio)
24
Create Indexed Vertex Buffer
IDirect3DIndexBuffer9* Index_buffer;
gd3dDevice->CreateIndexBuffer(
36* sizeof( WORD ), // x86 word
D3DUSAGE_WRITEONLY, // usage
D3DFMT_INDEX16, // 16-bit indices
D3DPOOL_MANAGED, // indicate buffer in video mem
&Index_buffer,
0);
// reserved, not used
• To eliminate the repetitive definition of vertices
• Use a vertex buffer to store unique vertices
• Use an index buffer to store Index
25
DrawIndexedPrimitive Method (Recommended)
Point, line, trianglelist
IDirect3DDevice9::DrawIndexedPrimitive(
D3DPRIMITIVETYPE PrimitiveType,
UINT BaseVertexIndex,
UNIT MinIndex,
UNIT NumVertices,
UNIT Start Index,
UINT PrimitiveCount);
Number of
vertices
Used as an offset for
drawing same index
buffer for a different
vertex patch
Min vertex index used
relative to
BaseVertexIndex
First Index
Number of Primitives
Example
// Draw a tetrahedron
gd3dDevice->SetStreamSource(0, v_buffer, 0, sizeof(VertexPC));
gd3dDevice->SetIndices(i_buffer);
gd3dDevice->DrawIndexedPrimitive(
D3DPT_TRIANGLELIST, 0, 0, 8, 0, 12);
26
Indexed Vertex Structure
V[5]
V[1]
V[6]
V[2]
V[4]
V[0]
V[7]
V[3]
v_buffer->Lock(0,0,(void*)&v, 0);
v[0] = VertexPos(-1.0f, -1.0f, -1.0f);
v[1] = VertexPos(-1.0f, 1.0f, -1.0f);
v[2] = VertexPos( 1.0f, 1.0f, -1.0f);
v[3] = VertexPos( 1.0f, -1.0f, -1.0f);
v[4] = VertexPos(-1.0f, -1.0f, 1.0f);
v[5] = VertexPos(-1.0f, 1.0f, 1.0f);
v[6] = VertexPos( 1.0f, 1.0f, 1.0f);
v[7] = VertexPos( 1.0f, -1.0f, 1.0f);
v_buffer->Unlock();
Index_buffer->Lock(0, 0, (void**)&k, 0);
k[0] = 0; k[1] = 1; k[2] = 2; // Front face
k[3] = 0; k[4] = 2; k[5] = 3;
k[6] = 4; k[7] = 6; k[8] = 5; // Back face
k[9] = 4; k[10] = 7; k[11] = 6;
k[12] = 4; k[13] = 5; k[14] = 1; // Left face
k[15] = 4; k[16] = 1; k[17] = 0;
k[18] = 3; k[19] = 2; k[20] = 6; // Right face
k[21] = 3; k[22] = 6; k[23] = 7;
k[24] = 1; k[25] = 5; k[26] = 6; // Top face
k[27] = 1; k[28] = 6; k[29] = 2;
k[30] = 4; k[31] = 0; k[32] = 3; // Bottom face
k[33] = 4; k[34] = 3; k[35] = 7;
Index_buffer->Unlock();
27
DrawIndexedPrimitive Method
Index Buffer
Vertex Buffer
0
MinIndex
1
2
3
NumVertices
78
Start Index
26
25
25
27
26
25
27
27
28
28
gd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 29, 78, 2);
28
Tips
• Remember to add these libraries in linker
input dependencies
d3d9.lib d3dx9.lib dxguid.lib dinput.lib dinput8.lib dxerr9.lib
• Or have the following in the source code
#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9.lib")
#pragma comment(lib, "dxguid.lib")
………
29