The global section of the
Transformations demo starts by adding matrices for the projection, view,
and world. It also adds effect variables that allow these matrices to
be bound to the shader. The global section from the Transformations demo
is shown in Listing 1. Effect matrix variables are represented by the type ID3D10EffectMatrixVariable.
Listing 1. The Global Section from the Transformations Demo
#include<windows.h> #include<d3d10.h> #include<d3dx10.h>
#pragma comment(lib, "d3d10.lib") #pragma comment(lib, "d3dx10.lib")
#define WINDOW_NAME "Transformations" #define WINDOW_WIDTH 800 #define WINDOW_HEIGHT 600
// Direct3D 10 objects. ID3D10Device *g_d3dDevice = NULL; IDXGISwapChain *g_swapChain = NULL; ID3D10RenderTargetView *g_renderTargetView = NULL;
// Effect objects and variables. ID3D10Effect *g_shader = NULL; ID3D10EffectTechnique *g_technique = NULL; ID3D10EffectMatrixVariable *g_worldEffectVar = NULL; ID3D10EffectMatrixVariable *g_viewEffectVar = NULL; ID3D10EffectMatrixVariable *g_projEffectVar = NULL;
// Display object to store scene geometry. ID3D10InputLayout *g_layout = NULL; ID3D10Buffer *g_vertexBuffer = NULL;
// Structure used to represent a single vertex. struct DX10_Vertex { D3DXVECTOR3 pos; };
// Projection, world, and view transformations. D3DXMATRIX g_worldMat, g_viewMat, g_projMat;
|
The
projection matrix depends on the window’s dimensions. Because of this,
the projection matrix is set in the demo’s resizing function, ResizeD3D10Window(). This function in the Transformations demo adds a line of code at the end that creates a left-handed projection matrix using D3DXMatrixPerspectiveFOVLH(), which is shown in Listing 2.
Listing 2. The Resizing Function from the Transformations Demo
void ResizeD3D10Window(int width, int height) { if(g_d3dDevice == NULL) return;
D3D10_VIEWPORT vp;
vp.Width = width; vp.Height = height; vp.MinDepth = 0.0f; vp.MaxDepth = 1.0f; vp.TopLeftX = 0; vp.TopLeftY = 0;
g_d3dDevice->RSSetViewports(1, &vp);
D3DXMatrixPerspectiveFovLH(&g_projMat, (float)D3DX_PI * 0.25f, width/(FLOAT)height, 0.1f, 1000.0f); }
|
The
demo’s initialization function adds code to bind the effect variables
and to set the two remaining matrices. The projection matrix is set and
updated by the ResizeD3D10Window()
function, so it is not included in the initialize function. The world
matrix is not set to anything, so it is cleared by calling D3DXMatrixIdentity(). The D3DXMatrixIdentity() function is essentially used to clear matrices.
The view matrix is set 15 units back, which places the view farther
back in the scene than what it was in the Primitives demo. The square
looks smaller in the scene because perspective projection is being used.
There is no difference between the square geometry in the
Transformations demo and that in the Primitives demo. The difference is
in the camera’s position. The demo’s initialize function is shown in Listing 3. Effect variables are obtained by calling the GetVariableByName() function, which takes as a parameter the name used in the shader file for the variable.
Listing 3. The Demo’s Initialize Function
bool InitializeDemo() {
…
g_technique = g_shader->GetTechniqueByName("PassThrough"); g_worldEffectVar = g_shader->GetVariableByName( "World")->AsMatrix(); g_viewEffectVar = g_shader->GetVariableByName( "View")->AsMatrix(); g_projEffectVar = g_shader->GetVariableByName( "Proj")->AsMatrix();
… // Clear the matrices. D3DXMatrixIdentity(&g_worldMat); D3DXMatrixIdentity(&g_viewMat);
D3DXVECTOR3 eye(0, 0, -15); D3DXVECTOR3 lookAt(0, 0, 0); D3DXVECTOR3 up(0, 1, 0);
D3DXMatrixLookAtLH(&g_viewMat, &eye, &lookAt, &up);
return true; }
|
In
the rendering function, three added lines of code are used to set the
matrices to the shader. Technically, it is only necessary to set effect
variables when they change or when you switch shaders. The matrices are
set by using the effect variable’s function SetMatrix(),
which takes as a parameter the matrix represented by a float array.
This can be done by casting the matrix to a float pointer. The rendering
function from the Transformations demo is shown in Listing 4.
Listing 4. The Rendering Function from the Transformations Demo
void RenderScene() { float col[4] = { 0, 0, 0, 1 };
// Clear the rendering destination to a specified color.
g_d3dDevice->ClearRenderTargetView(g_renderTargetView, col);
unsigned int stride = sizeof(DX10_Vertex); unsigned int offset = 0;
// Setup the geometry buffer that will be rendered.
g_d3dDevice->IASetInputLayout(g_layout); g_d3dDevice->IASetVertexBuffers(0, 1, &g_vertexBuffer, &stride, &offset); g_d3dDevice->IASetPrimitiveTopology( D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
// Prepare the effect we will use to draw the geometry.
g_viewEffectVar->SetMatrix((float*)&g_viewMat); g_projEffectVar->SetMatrix((float*)&g_projMat); g_worldEffectVar->SetMatrix((float*)&g_worldMat);
D3D10_TECHNIQUE_DESC techDesc; g_technique->GetDesc(&techDesc);
// Loop through each pass of the technique and draw.
for(unsigned int i = 0; i < techDesc.Passes; i++) { g_technique->GetPassByIndex(i)->Apply(0); g_d3dDevice->Draw(6, 0); }
// Display the results to the target window (swap chain).
g_swapChain->Present(0, 0); }
|
The last code that needs to be seen is the Transformations demo’s shader. This shader starts by defining three variables (World, View, and Proj),
each of which are obtained by the application by name. These variables
are used by the vertex shader to multiply the matrices against the
incoming vertex position. The vertex is transformed by the world matrix
first, then the view, and then the projection. If the world, view, and
projection matrices where concatenated into one, then one multiplication
would be used. In this demo we’ll see the longer form by multiplying
against each in order. The rest of the shader is the same from the
Primitives demo. The shader from the Transformation demo is shown in Listing 5. Figure 1 shows a screenshot of the demo.
Listing 5. The Transformations Demo’s Shader
/* Chapter 5 - Transformations Ultimate Game Programming with DirectX 2nd Edition Created by Allen Sherrod */
matrix World; matrix View; matrix Proj;
struct VS_INPUT { float4 Pos : POSITION; };
struct PS_INPUT { float4 Pos : SV_POSITION; };
PS_INPUT VS(VS_INPUT input) { PS_INPUT output = (PS_INPUT)0;
output.Pos = mul(input.Pos, World); output.Pos = mul(output.Pos, View); output.Pos = mul(output.Pos, Proj); return output; }
float4 PS(PS_INPUT input) : SV_Target { return float4(1, 0, 1, 1); }
technique10 PassThrough { pass P0 { SetVertexShader(CompileShader(vs_4_0, VS()));
SetGeometryShader(NULL);
SetPixelShader(CompileShader(ps_4_0, PS())); } }
|
|