Introduction to Direct 3D
Total Page:16
File Type:pdf, Size:1020Kb
Introduction to Direct 3D by John Tsiombikas [email protected] What is Direct3D? 3D graphics API (Application Programming Interface) Similar to OpenGL Takes advantage of available graphics hardware Usable through C++ Based on COM objects and OOP paradigm Direct3D vs OpenGL Controlled completely by MS Controlled by ARB Object oriented design Procedural interface, functions that affect Usable through C++ only the state of the OpenGL state machine Even the most recent features are fully Usable through C or C++ integrated into the core of the API Most very recent features are provided Frequent revisions / volatile interface through an extension mechanism Only available on MS Windows Slow major revisions / stable interface Cross-platform (UNIX, Windows, MacOS etc.) Direct3D Initialization Steps Win32 API: create window, handle events, etc. Initialize Direct3D Device (see example below) IDirect3D8 *d3d = Direct3DCreate8(D3D_SDK_VERSION); D3DDISPLAYMODE d3ddm; d3d->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm); D3DPRESENT_PARAMETERS d3dpp; memset(&d3dpp, 0, sizeof(D3DPRESENT_PARAMETERS)); d3dpp.Windowed = true; d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; d3dpp.BackBufferFormat = d3ddm.Format; IDirect3DDevice *d3ddevice; d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, window, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &d3ddevice); Direct3D rendering pipeline local (model) space d3ddevice->SetTransform(D3DTS_WORLD, matrix); world space d3ddevice->SetTransform(D3DTS_VIEW, matrix); camera (view) space d3ddevice->SetTransform(D3DTS_PROJECTION, matrix); homogeneous clip space Perspective divide by w of homogeneous vectors (provided by the projection transformation) normalized screen space d3ddevice->SetViewport(viewport); device screen space d3ddevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, count); Primitive types D3DPT_POINTLIST D3DPT_LINELIST D3DPT_LINESTRIP D3DPT_TRIANGLELIST D3DPT_TRIANGLESTRIP D3DPT_TRIANGLEFAN Flexible Vertex Format specification Posible FVF flags Position (3 floats) Reciprocal homogeneous w coord for pretransformed vertices (float) Vertex blending weights for skin morphing (1-3 floats) Normal vector (3 floats) Point size, for point rendering (float) Packed diffuse color (32bit integer) Packed specular color (32bit integer) Texture coordinate set 1 (1 – 4 floats) Texture coordinate set 2 (1 – 4 floats) . Texture coordinate set 8 (1 – 4 floats) Flexible Vertex Format specification // sample vertex structure and corresponding FVF struct Vertex { float x, y, z; // position vector float nx, ny, nz; // normal vector float tu, tv; // texture coordinates }; const unsigned long fvf = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1; // creation of a vertex buffer to hold such vertices IDirect3DVertexBuffer8 *vbuf; d3ddevice->CreateVertexBuffer(vertex_count * sizeof(Vertex), 0, fvf, D3DPOOL_DEFAULT, &vbuf); Rendering the Vertex Buffer // set the current vertex source d3ddevice->SetStreamSource(0, vbuf, sizeof(Vertex)); // specify that we want to use the standard fixed pipeline d3ddevice->SetVertexShader(fvf); // render from the active source d3ddevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, triangle_count); Available rendering functions DrawPrimitive(primitive_type, start_vertex, primitive_count); DrawIndexedPrimitive(primitive_type, min_index, vertex_count, start_index, primitive_count); DrawPrimitiveUP(primitive_type, primitive_count, vertex_ptr, vertex_size); DrawIndexedPrimitiveUP(primitive_type, min_index, vertex_count, primitive_count, index_ptr, index_format, vertex_ptr, vertex_count); Lighting: setting lights Phong illumination model calculated per vertex (Gouraud), modulated by the active material colors. // initialize a light structure D3DLIGHT8 light; light.Type = D3DLIGHT_POINT; D3DVECTOR pos = {0.0, 1.0, -1.0}; light.Position = pos; D3DCOLORVALUE col = {1.0, 1.0, 1.0, 1.0}; light.Diffuse = light.Specular = col; // set it as light 0 d3ddevice->SetLight(0, &light); Lighting: setting materials Material contains: color, specular power (shinniness), etc. // initialize a material structure D3DMATERIAL8 material; D3DCOLORVALUE red = {1.0, 0.0, 0.0, 1.0}; material.Ambient = material.Diffuse = red; D3DCOLORVALUE white = {1.0, 1.0, 1.0, 1.0}; material.Specular = white; D3DCOLORVALUE black = {0.0, 0.0, 0.0, 1.0}; material.Emissive = black; material.Power = 60.0; // set it as light 0 d3ddevice->SetMaterial(&material); Overview of a Direct3D program Win32 specifics, handle window creation etc. Create the Direct3D Device object Create a Vertex Buffer with a user defined FVF for each object Fill the buffers with vertices of the corresponding format Enter main loop - Set active lights - For each object + Set material + Set world transformation matrix + Set vertex stream to the vertex buffer of this object + call DrawPrimitive() to draw the object - call Present() to show the result on screen Destroy the Direct3D objects and exit D3DX (utility library) Direct3D lacks “helper” functionality, provided in D3DX Matrix stack Matrices (translate / rotate / scale / inverse) Vectors (vector math / cubic spline vector interpolation) Colors (math / saturation djust / contrast adjust) Quaternions (quat. math / slerp / axis-angle) Hierarchical animation helpers Texture / mesh loading Examples Setting up a project for Direct3D Using d3dut to abstract the disgusting part (win32) Creating a simple window Showing a rotating triangle Setting up a D3D project with Visual Studio Download & install the DirectX SDK (approx 120mb) Create a new Win32 Application project (empty console app preferably) go to project->Add existing item and add the d3d8.lib & d3dx8.lib Add the directory with DX headers to the search path (tools->options projects->VC++ Directories) #include “d3d8.h” & #include “d3dx8.h” Using d3dut (like glut) d3dut is designed in order to abstract the details of window creation, event handling, etc... it also handles the creation of the d3d device. Create a new Win32 Application project (empty console app) go to project->Add existing item and add the d3dut.lib Add the directory with d3dut headers to the search path (tools->options projects->VC++ Directories) #include “d3dut.hpp” Creating a simple window and clearing it #include “d3dut.hpp” void UpdateDisplay(); Idirect3DDevice8 *dev; // ptr to a d3d device, returned by d3dut::Init() int main() { dev = d3dut::Init(640, 480); // create win, initialize d3d etc d3dut::SetIdleHandler(UpdateDisplay); // set idle function d3dut::AssumeControl(); // begin event handling } // this function uses Direct3D calls to clear the screen and show it void UpdateDisplay() { dev->Clear(0, 0, D3DCLEAR_TARGET, 0, 1.0, 0); dev->Present(0, 0, 0, 0); } Showing a rotating triangle (slide 1 / 3) #include “d3dut.hpp” struct Vertex { float x, y, z; // position unsigned long color; // color }; // the flexible vertex format specifier, which we provide to d3d later const unsigned long fvf = D3DFVF_XYZ | D3DFVF_DIFFUSE; // create an array of 3 vertices and initialize it Vertex tri_verts[3] = { { 0, 1, 0, 0xffff0000}, { 1, -1, 0, 0xff00ff00}, {-1, -1, 0, 0xff0000ff} }; // a pointer to the d3d device, aquired through n3dut::Init() IDirect3DDevice8 *dev; Showing a rotating triangle (slide 2 / 3) void UpdateDisplay(); // forward declaration of our idle function int main() { dev = d3dut::Init(640, 480); d3dut::SetIdleHandler(UpdateDisplay); // setup the transformation matrices and pass them to d3d D3DXMATRIX proj; D3DXMatrixPerspectiveFovLH(&proj, D3DX_PI/4, 1.3333, 1.0, 1000.0); dev->SetTransform(D3DTS_PROJECTION, &proj); D3DXMATRIX view; D3DXMatrixTranslation(&view, 0, 0, 5); dev->SetTransform(D3DTS_VIEW, &view); // tell d3d what is the format of our vertices by giving it our fvf dev->SetVertexShader(fvf); d3dut::AssumeControl(); } Showing a rotating triangle (slide 3 / 3) void UpdateDisplay() { dev->Clear(0, 0, D3DCLEAR_TARGET, 0, 1.0, 0); // in each redisplay we will create a rotation matrix with a rotation angle // based on elapsed time (GetTickCount()). That way the triangle will // look like it's rotating around its Z axis. D3DXMATRIX world; D3DXMatrixRotationZ(&world, (float)GetTickCount() / 1000.0); dev->SetTransform(D3DTS_WORLD, &world); // draw our 3 vertices in form of a triangle list dev->DrawPrimitiveUP(D3DPT_TRIANGLELIST, 1, tri_verts, sizeof(Vertex)); dev->Present(0, 0, 0, 0); // and show the result }.