MULTIMEDIA

Game Programming with DirectX : 3D Models - OBJ Models (part 3) - Preparing OBJ Files for Direct3D

5/19/2013 7:21:18 PM

3. Preparing OBJ Files for Direct3D

In the IntializeDemo() function, the shader and input layout is first created as usual. After that the OBJ file is loaded in an ObjModel object. A loop then follows that loops through each mesh of the model and creates a vertex buffer and texture out of it. This vertex buffer and texture is added to the DX10Mesh list and is what we render later in the rendering function. The InitializeDemo() function is shown in Listing 11, where the order of the function’s execution is as follows.

1.
Load the shader.

2.
Create the input layout.

3.
Load the OBJ file.

4.
Loop through each mesh.

5.
Load the mesh’s texture.

6.
Create a temp array of DX10Vertex and fill it with the vertex information (you could use the mesh itself, but additional information is in it that Direct3D 10 does not need).

7.
Create the mesh’s vertex buffer.

8.
Delete the temporary memory.

9.
Set the view and projection matrices.

Listing 11. The InitializeDemo() Function from the OBJ Models Demo
bool InitializeDemo()
{
   // Load the shader.

   DWORD shaderFlags = D3D10_SHADER_ENABLE_STRICTNESS;

#if defined( DEBUG )  || defined( _DEBUG )
   shaderFlags |= D3D10_SHADER_DEBUG;
#endif

   ID3D10Blob *errors = NULL;

   HRESULT hr = D3DX10CreateEffectFromFile("TextureMap.fx", NULL,
      NULL, "fx_4_0", shaderFlags, 0, g_d3dDevice, NULL, NULL,
      &g_shader, &errors, NULL);

   if(errors != NULL)
   {
      MessageBox(NULL, (LPCSTR)errors->GetBufferPointer(),
                 "Error in Shader!", MB_OK);

      errors->Release()
   }

   if(FAILED(hr))
      return false;

   g_textureMapTech = g_shader->GetTechniqueByName(
      "TextureMapping");

   g_worldEffectVar = g_shader->GetVariableByName(
      "World")->AsMatrix();

   g_viewEffectVar = g_shader->GetVariableByName(
      "View")->AsMatrix();

   g_projEffectVar = g_shader->GetVariableByName(
      "Projection")->AsMatrix();

   g_decalEffectVar = g_shader->GetVariableByName(
      "decal")->AsShaderResource();
   // Create the layout.

   D3D10_INPUT_ELEMENT_DESC layout[] =
   {
      { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0,
        D3D10_INPUT_PER_VERTEX_DATA, 0 },
      { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12,
        D3D10_INPUT_PER_VERTEX_DATA, 0 },
      { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24,
        D3D10_INPUT_PER_VERTEX_DATA, 0 },
   };

   unsigned int numElements = sizeof(layout) / sizeof(layout[0]);
   D3D10_PASS_DESC passDesc;

   g_textureMapTech->GetPassByIndex(0)->GetDesc(&passDesc);

   hr = g_d3dDevice->CreateInputLayout(layout, numElements,
      passDesc.pIAInputSignature, passDesc.IAInputSignatureSize,
      &g_layout);

   if(FAILED(hr))
      return false;


   // Load the model from the file.

   ObjModel model;

   if(model.LoadOBJ("box.ob] ") == false)
      return false;

   g_meshes.reserve(model.GetMeshCount());
   D3D10_BUFFER_DESC buffDesc;
   D3D10_SUBRESOURCE_DATA resData;

   // Loop through and create vertex buffers for each mesh.
   for(int m = 0; m < model.GetMeshCount(); m++)
   {
      DX10Mesh mesh;
      g_meshes.push_back(mesh);

      // Load the texture.
      string textureFile = model.GetMeshTextureFile(m);

      hr = D3DX10CreateShaderResourceViewFromFile(g_d3dDevice,
         textureFile.c_str(), NULL, NULL,
         &g_meshes[m].m_decal, NULL);

      if(FAILED(hr))
         return false;

      g_meshes[m].m_totalVerts = model.GetMeshTotalVerts(m);

      DX10Vertex *vertices =
         new DX10Vertex[g_meshes[m].m_totalVerts];

      float *modelVerts = model.GetMeshVertices(m);
      float *modelNorms = model.GetMeshNormals(m);
      float *modelTexC = model.GetMeshTexCoords(m);

      for(int i = 0; i < g_meshes[m].m_totalVerts;
      {
         vertices[i].pos.x = *(modelVerts + 0);
         vertices[i].pos.y = *(modelVerts + 1);
         vertices[i].pos.z = *(modelVerts + 2);
         modelVerts += 3;
         vertices[i].normal.x = *(modelNorms + 0);
         vertices[i].normal.y = *(modelNorms + 1);
         vertices[i].normal.z = *(modelNorms + 2);
         modelNorms += 3;

         vertices[i].tex0.x = *(modelTexC + 0);
         vertices[i].tex0.y = *(modelTexC + 1);
         modelTexC +=2;
      }

      // Create the vertex buffer.

      buffDesc.Usage = D3D10_USAGE_DEFAULT;

      buffDesc.ByteWidth = sizeof(DX10Vertex) *
         g_meshes[m].m_totalVerts;

      buffDesc.BindFlags = D3D10_BIND_VERTEX_BUFFER;
      buffDesc.CPUAccessFlags = 0;
      buffDesc.MiscFlags = 0;
      resData.pSysMem = vertices;

      hr = g_d3dDevice->CreateBuffer(&buffDesc, &resData,
         &g_meshes[m].m_vertices);

      if(FAILED(hr))
         return false;

      delete[] vertices;
   }

   // Set the shader matrix variables that won't change once here.
   D3DXMatrixIdentity(&g_worldMat);
   D3DXMatrixIdentity(&g_viewMat);
   g_viewEffectVar->SetMatrix((float*)&g_viewMat);
   g_pro]EffectVar->SetMatrix((float*)&g_projMat);

   return true;
}

					  

Rendering OBJ Models

The last piece of this demo deals with the rendering and shutdown functions. In this demo the model is rotating. This is done by creating the world matrix for the model that rotates a little bit along the X and Y axis each frame. This is done in the Update() function, which is called after the rendering to slightly update the world matrix. The Update() function is shown in Listing 12.

Listing 12. The Update() Function from the OBJ Models Demo
void Update()
{
   g_xRot += 0.0001f;
   g_yRot += 0.0002f;

   if(g_xRot < 0) g_xRot = 359;
   else if(g_xRot >= 360) g_xRot = 0;

   if(g_yRot < 0) g_yRot = 359;
   else if(g_yRot >= 360) g_yRot = 0;

   D3DXMATRIX trans, rotX, rotY;

   D3DXMatrixRotationX(&rotX, g_xRot);
   D3DXMatrixRotationY(&rotY, g_yRot);
   D3DXMatrixTranslation(&trans, 0, 0, 6);

   g_worldMat = (rotX * rotY) * trans;
}

The rendering function is pretty much the same as in previous demos, with the exception that there is now a loop that loops through and sets the vertex buffer and texture for each mesh in the mesh list. Each mesh is rendered out one at a time in this manner. The Shutdown() function is also the same as in previous demos, with the exception of a loop being used to release the vertex buffers and textures that were loaded in the InitializeDemo() function. The RenderScene() and Shutdown() functions from the OBJ Models demo are shown in Listing 13.

Listing 13. The RenderScene() and Shutdown() Functions
void RenderScene()
{
   float col[4] = { 0, 0, 0, 1 };

   g_d3dDevice->ClearRenderTargetView(g_renderTargetView, col);
   g_d3dDevice->ClearDepthStencilView(g_depthStencilView,
                                      D3D10_CLEAR_DEPTH, 1.0f, 0);

   g_d3dDevice->IASetInputLayout(g_layout);

   g_d3dDevice->IASetPrimitiveTopology(
      D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

   D3D10_TECHNIQUE_DESC techDesc;
   g_textureMapTech->GetDesc(&techDesc);

   unsigned int stride = sizeof(DX10Vertex);
   unsigned int offset = 0;

   for(int m = 0; m < (int)g_meshes.size(); m++)
   {
      g_worldEffectVar->SetMatrix((float*)&g_worldMat);
      g_decalEffectVar->SetResource(g_meshes[m].m_decal);

      g_d3dDevice->IASetVertexBuffers(0, 1,
         &g_meshes[m].m_vertices, &stride, &offset);
      for(unsigned int i = 0; i < techDesc.Passes; i++)
      {
         g_textureMapTech->GetPassByIndex(i)->Apply(0);
         g_d3dDevice->Draw(g_meshes[m].m_totalVerts, 0);
      }
    }

    g_swapChain->Present(0, 0);

    Update();
}

void Shutdown()
{
   if(g_d3dDevice) g_d3dDevice->ClearState();
   if(g_swapChain) g_swapChain->Release()
   if(g_renderTargetView) g_renderTargetView->Release()
   if(g_depthStencilTex) g_depthStencilTex->Release()
   if(g_depthStencilView) g_depthStencilView->Release()

   if(g_shader) g_shader->Release()
   if(g_layout) g_layout->Release()

   for(int m = 0; m < (int)g_meshes.size(); m++)
   {
      if(g_meshes[m].m_vertices)
         g_meshes[m].m_vertices->Release()

      if(g_meshes[m].m_decal)
      {
         ID3D10Resource *pRes;
         g_meshes[m].m_decal->GetResource(&pRes);

         pRes->Release()
         g_meshes[m].m_decal->Release()
      }
   }

   if(g_d3dDevice) g_d3dDevice->Release()
}

					  

To conclude this demo we must take a look at the shader’s file. Because we are rendering a model with volume, we must set the depth buffer state so that the geometry renders correctly. Without it we must render the triangles from back to front order to ensure that triangles behind other triangles are not rendered on top, but with the depth buffer the hardware ensures that primitives are drawn correctly.

Depth testing is a technique used to avoid having to render primitives in a specific order. In Direct3D and other APIs, a depth buffer is an actual buffer in the graphics card memory, similar to the color buffer that is the rendered image that is written to every time an object is rendered. The depth buffer stores depth values on the pixel level, which are the projected distances between the surface and the camera. Thus, when new primitives are rendered, Direct3D can look at the depth buffer (depth testing) and determine if the new primitive is in front of or behind one that was already rendered. If it is in front of the old primitive, then the new primitive is rendered; if it is not, the rendered scene is not affected.

The OBJ Models demo’s HLSL effect file is shown in Listing 14. The DepthStencilState is set in the technique by calling the HLSL function SetDepthStencilState(). A screenshot of the OBJ Models demo is shown in Figure 1.

Listing 14. The OBJ Models Demo’s HLSL Effect Shader
/*
  Texture Mapping HLSL Shader
  Ultimate Game Programming with DirectX 2nd Edition
  Created by Allen Sherrod
*/

Texture2D decal;
SamplerState DecalSampler
{
  Filter = MIN_MAG_MIP_LINEAR;
  AddressU = Wrap;
  ddressV = Wrap;
};

DepthStencilState DepthStencilInfo
{
   DepthEnable = true;
   DepthWriteMask = ALL;
   DepthFunc = Less;

   // Set up stencil states
   StencilEnable = true;
   StencilReadMask = 0xFF;
   StencilWriteMask = 0×00;

   FrontFaceStencilFunc = Not_Equal;
   FrontFaceStencilPass = Keep;
   FrontFaceStencilFail = Zero;

   BackFaceStencilFunc = Not_Equal;
   BackFaceStencilPass = Keep;
   BackFaceStencilFail = Zero;
};


cbuffer cbChangesEveryFrame
{
   matrix World;
   matrix View;
};
cbuffer cbChangeOnResize
{
   matrix Projection;
};

struct VS_INPUT
{
   float4 Pos : POSITION;
   float3 Norm : NORMAL;
   float2 Tex : TEXCOORD;
};

struct PS_INPUT
{
   float4 Pos : SV_POSITION;
   float2 Tex : TEXCOORDO;
};

PS_INPUT TextureMapVS(VS_INPUT input)
{
   PS_INPUT output = (PS_INPUT)0;

   float4 Pos = mul(input.Pos, World);
   Pos = mul(Pos, View);
   output.Pos = mul(Pos, Projection);

   output.Tex = input.Tex;

   return output;
}

float4 TextureMapPS(PS_INPUT input) : SV_Target
{
   return decal.Sample(DecalSampler, input.Tex);
}

techniquel0 TextureMapping
{
   pass P0
   {
      SetDepthStencilState(DepthStencilInfo, 0);

      SetVertexShader(CompileShader(vs_4_0, TextureMapVS()));
      SetGeometryShader(NULL);
      SetPixelShader(CompileShader(ps_4_0, TextureMapPS()));
   }
}

					  

Figure 1. The OBJ loader.
Other  
 
Video
Video tutorials
- How To Install Windows 8

- How To Install Windows Server 2012

- How To Install Windows Server 2012 On VirtualBox

- How To Disable Windows 8 Metro UI

- How To Change Account Picture In Windows 8

- How To Unlock Administrator Account in Windows 8

- How To Restart, Log Off And Shutdown Windows 8

- How To Login To Skype Using A Microsoft Account

- How To Enable Aero Glass Effect In Windows 8

- How To Install Windows Store Apps From Windows 8 Classic Desktop

- How To Disable Windows Update in Windows 8

- How To Disable Windows 8 Metro UI

- How To Add Widgets To Windows 8 Lock Screen

- How to create your first Swimlane Diagram or Cross-Functional Flowchart Diagram by using Microsoft Visio 2010
programming4us programming4us
Top 10
Free Mobile And Desktop Apps For Accessing Restricted Websites
MASERATI QUATTROPORTE; DIESEL : Lure of Italian limos
TOYOTA CAMRY 2; 2.5 : Camry now more comely
KIA SORENTO 2.2CRDi : Fuel-sipping slugger
How To Setup, Password Protect & Encrypt Wireless Internet Connection
Emulate And Run iPad Apps On Windows, Mac OS X & Linux With iPadian
Backup & Restore Game Progress From Any Game With SaveGameProgress
Generate A Facebook Timeline Cover Using A Free App
New App for Women ‘Remix’ Offers Fashion Advice & Style Tips
SG50 Ferrari F12berlinetta : Prancing Horse for Lion City's 50th
Popular Tags
Video Tutorail Microsoft Access Microsoft Excel Microsoft OneNote Microsoft PowerPoint Microsoft Project Microsoft Visio Microsoft Word Active Directory Exchange Server Sharepoint Sql Server Windows Server 2008 Windows Server 2012 Windows 7 Windows 8 Adobe Flash Professional Dreamweaver Adobe Illustrator Adobe Photoshop CorelDRAW X5 CorelDraw 10 windows Phone 7 windows Phone 8 Iphone