This tutorial is part of a Collection: 03. DirectX 11 - Braynzar Soft Tutorials
rate up
0
rate down
12976
views
bookmark
09. Transformations

This is another pretty short lesson on tranformations. We will transform the world space for each object (the two cubes) using transformation matrices.

1489 downloads
##Introduction## Here we will learn how to transform geometry in a 3D scene. Transformations make use of matrices, which the xna math library conveniently provides functions to help us out with. ##Transformations## Transformations in Direct3D use a 4x4 Matrix. Thats because they use 4 dimensions, 3 spacial, x, y, z, and 1 change, which is represented by the letter w. w is usually equal to a one(1) or a zero(0). I don't want to get into too much math, so if you don't know much about matrices, you should learn a little more if this gets confusing. When you want to transform an object, you take its 3D vector, v=[x, y, z], add in the w so it can be multiplied by a 4x4 Matrix, so it looks like v=[x, y, z, 1]. you set w to one because that means it will be transformed. Then you multiply v by the 4x4 Matrix which we will call M. the outcome of vM will be v'. v * M=v'. Matrices in the xna math library are of the XMMATRIX type. [M11,M12,M13,M14] v'[x', y', z', 1]=v[x, y, z, 1] x M[M21,M22,M23,M24] [M31,M32,M33,M34] [M41,M42,M43,M44] x'=(x*M11) + (y*M21) + (z*M31) + (1*M41) y'=(x*M12) + (y*M22) + (z*M32) + (1*M42) z'=(x*M13) + (y*M23) + (z*M33) + (1*M43) ##Scaling## Scaling Matrices will scale the size of an object in 3D space. The xna math library has functions that will compute transformations for us. the Scaling Matrix can be computed with the following function: XMMATRIX XMMatrixScaling ( FLOAT ScaleX, // x=axis scale FLOAT ScaleY, // y-axis scale FLOAT ScaleZ // z-axis scale ) The result of this function is a returned matrix, which will be used to find the World space matrix. The 4x4 scaling matrix looks like this: [S1, 0, 0, 0] S = [ 0,S2, 0, 0] [ 0, 0,S3, 0] [ 0, 0, 0, 1] ##Rotating## Rotation Matrices are used to rotate an object in 3D space. There are 3 different matrices for rotating around each of the x, y, and z-axis's. Here are the three functions to create each of the rotation matrices, and what the 4x4 translation matrix looks like. Where r is the angle in radians. Rotation around the x-axis: [ 1, 0, 0, 0] Rx = [ 0, cos(r),sin(r), 0] [ 0,-sin(r),cos(r), 0] [ 0, 0, 0, 1] XMMATRIX XMMatrixRotationX( FLOAT Angle //Rotation angle in radians ) Rotation around the y-axis: [cos(r), 0,-sin(r), 0] Ry = [ 0, 1, 0, 0] [sin(r), 0, cos(r), 0] [ 0, 0, 0, 1] XMMATRIX XMMatrixRotationY( FLOAT Angle //Rotation angle in radians ) Rotation around the z-axis: [ cos(r),sin(r), 0, 0] Rz = [-sin(r),cos(r), 0, 0] [ 0, 0, 1, 0] [ 0, 0, 0, 1] XMMATRIX XMMatrixRotationZ( FLOAT Angle //Rotation angle in radians ) Maybe your object will not always rotate only around the x, y, or z axis's. In this case, we could either combine the functions above, or, use another function the xna math library provides, which rotates around a vector: XMMATRIX XMMatrixRotationAxis( XMVECTOR Axis, //Vector describing the axis of rotation FLOAT Angle //Rotation angle in radians ) ##Translating## There is one more type of transformation which we can use in our 3d scenes, translation. Translation Formations are used to move an object in 3D space. If you wanted to take and object positioned at [1,2,0] and move it over on the x-axis 3 units, the outcome would look like [4,2,0]. Below is how the Translation matrix looks and what the function to create it is. mx is the units translated on the x-axis, my is the units translated on the y=axis, and mz is the units translated on the z-axis. [ 1, 0, 0, 0] T = [ 0, 1, 0, 0] [ 0, 0, 1, 0] [mx,my,mz, 1] XMMATRIX XMMatrixTranslation( FLOAT OffsetX, // Units translated on the x-axis FLOAT OffsetY, // Units translated on the y-axis FLOAT OffsetZ // Units translated on the z-axis ) ##Combining Transformations## We can combine multiple transformation matrices into one matrix. We do this by multiplying each one together. We have to do it in order to get the desired outcome. We have a scaling matrix called 'S', a rotation matrix called 'R', and a translation matrix called 'T'. our outcome is 'O'. O = S * R * T. Thats the order we must do it in. If we were to put the translation matrix first, 0 = T * S * R, our object would be rotating around where it was originally, not where it is now. It would create more of an orbit effect instead of a spinning effect. In our last lesson, we learned that the World space is a matrix, describing the objects position, rotation, and size in the world, compared to the other objects in the scene. To create a world space matrix for an object, we will use transformations, which we have just learned how to do. Each object in the scene will have their own world space matrix. In this lesson, we will have two cubes, one rotating around the other. We will create two world space matrices for the cubes, one for each, called cube1World, and cube2World. ##Global Declarations## Here are a couple new declarations. The first two are the new world matrices. We have one per cube. The second three are used for the transformations, one for rotation, scaling, and translating. The last one is a float used to keep track of our rotation. XMMATRIX cube1World; XMMATRIX cube2World; XMMATRIX Rotation; XMMATRIX Scale; XMMATRIX Translation; float rot = 0.01f; ##The Cube## Now we go down to our initialize scene function, where we need to update our vertex buffer and index buffer to hold a cube instead of just a square, so thats what we do here. Look at the line: indexBufferDesc.ByteWidth = sizeof(DWORD) * 12 * 3; We changed "2" to "12", because in the previous lessons, we had a square, which consisted of 2 faces (or triangles), and now we have a cube, which consists of 12 faces or triangles. Similarily the line: vertexBufferDesc.ByteWidth = sizeof( Vertex ) * 8; Where we changed "4" to "8". Because the previous lessons only had four vertices making up the square, but now we have eight vertices which make up the cube. Vertex v[] = { Vertex( -1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f ), Vertex( -1.0f, +1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f ), Vertex( +1.0f, +1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f ), Vertex( +1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 1.0f ), Vertex( -1.0f, -1.0f, +1.0f, 0.0f, 1.0f, 1.0f, 1.0f ), Vertex( -1.0f, +1.0f, +1.0f, 1.0f, 1.0f, 1.0f, 1.0f ), Vertex( +1.0f, +1.0f, +1.0f, 1.0f, 0.0f, 1.0f, 1.0f ), Vertex( +1.0f, -1.0f, +1.0f, 1.0f, 0.0f, 0.0f, 1.0f ), }; DWORD indices[] = { // front face 0, 1, 2, 0, 2, 3, // back face 4, 6, 5, 4, 7, 6, // left face 4, 5, 1, 4, 1, 0, // right face 3, 2, 6, 3, 6, 7, // top face 1, 5, 6, 1, 6, 2, // bottom face 4, 0, 3, 4, 3, 7 }; D3D11_BUFFER_DESC indexBufferDesc; ZeroMemory( &indexBufferDesc, sizeof(indexBufferDesc) ); indexBufferDesc.Usage = D3D11_USAGE_DEFAULT; indexBufferDesc.ByteWidth = sizeof(DWORD) * 12 * 3; indexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER; indexBufferDesc.CPUAccessFlags = 0; indexBufferDesc.MiscFlags = 0; D3D11_SUBRESOURCE_DATA iinitData; iinitData.pSysMem = indices; d3d11Device->CreateBuffer(&indexBufferDesc, &iinitData, &squareIndexBuffer); d3d11DevCon->IASetIndexBuffer( squareIndexBuffer, DXGI_FORMAT_R32_UINT, 0); D3D11_BUFFER_DESC vertexBufferDesc; ZeroMemory( &vertexBufferDesc, sizeof(vertexBufferDesc) ); vertexBufferDesc.Usage = D3D11_USAGE_DEFAULT; vertexBufferDesc.ByteWidth = sizeof( Vertex ) * 8; vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; vertexBufferDesc.CPUAccessFlags = 0; vertexBufferDesc.MiscFlags = 0; ##Camera Position## We just updated this line to move the camera back and up a little, to get a little better view of the two cubes. camPosition = XMVectorSet( 0.0f, 3.0f, -8.0f, 0.0f ); ##The Update Scene Function## This is our UpdateScene() function, which will do all the updating of our scene when things change, while the function after this one just renders the scene. It's a good idea to keep them separate. The first couple lines are just updating the rotation variable that tells how many degrees our cube is to be rotated. To keep from getting too big of a number, we check to make sure its greater than 2pi, or 6.28. If its greater, then we set it back to 0. Next, we reset the cube1World matrix using the XMMatrixIdentity() function. After that, We create our transformation matrices. The first line when creating our transformations, is the vector which we will use to rotate the objects around. We set it to rotate around the y-axis, by setting 1.0f in the second parameter. Next, we use this new vector describing the axis of rotation, the rot variable describing how many degrees to rotate, and the function XMMatrixRotationAxis() to create the rotation matrix based off the axis and angle of rotation we give it. We store that matrix in the Rotation matrix we difined globaly. Next we create the Translation matrix using the XMMatrixTranslation() function. We set it to translate the cube 4.0f units on the z-axis, which will make the cube move 4 units away from the camera. We set this in the Translation matrix. Now we need to set the cube1World matrix, which is the matrix defining the first cubes world space. Take carefull notice of the order in which we multiply the transformation matrices. We Translate the object, THEN rotate the object. Doing translation before rotation gives an orbit effect. So what happens now, is that this cube will first be translated 4 units into the screen, then rotated, So this cube will be rotating around the first cube (since we will not translate the first cube), while keeping a distance of 4 units from it. Next we transform the second cube. First we reset the cube2World matrix, then define the transformations, which are rotating the cube along the axis defined by the vector rotaxis, -rot degrees, which means it will be rotating in the opposite direction as the first cube, then making the cube 1.3 times larger than it originally is, by scaling it 1.3f units on every axis using the XMMatrixScaling() function. After that we set the cube2World matrix. void UpdateScene() { //Keep the cubes rotating rot += .0005f; if(rot > 6.28f) rot = 0.0f; //Reset cube1World cube1World = XMMatrixIdentity(); //Define cube1's world space matrix XMVECTOR rotaxis = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f); Rotation = XMMatrixRotationAxis( rotaxis, rot); Translation = XMMatrixTranslation( 0.0f, 0.0f, 4.0f ); //Set cube1's world space using the transformations cube1World = Translation * Rotation; //Reset cube2World cube2World = XMMatrixIdentity(); //Define cube2's world space matrix Rotation = XMMatrixRotationAxis( rotaxis, -rot); Scale = XMMatrixScaling( 1.3f, 1.3f, 1.3f ); //Set cube2's world space matrix cube2World = Rotation * Scale; } ##The Render Scene Function## Now that we have updated our scene, we can draw the geometry. The new code in the DrawScene() function are not actually new since we covered this stuff in previous lessons. We modified it though, and as you can see, we changed where it used to say "World" to "cube1World" and "cube2World". So whats happening here is we first send the WVP matrix to the constant buffer in the shader file using the first cubes world matrix. Then we draw the first cube. You can see we also changed the number from 6, to 36. This number, if you can recall, is the number of indices we want to draw from the index buffer. We now have a cube, and it takes 36 indices to define, so we put 36 here. Next we do the exact same thing for the second cube, but instead we use the second cubes world matrix, cube2World, set that to the shaders constant buffer, then draw the second cube. void DrawScene() { //Clear our backbuffer float bgColor[4] = {(0.0f, 0.0f, 0.0f, 0.0f)}; d3d11DevCon->ClearRenderTargetView(renderTargetView, bgColor); //Refresh the Depth/Stencil view d3d11DevCon->ClearDepthStencilView(depthStencilView, D3D11_CLEAR_DEPTH|D3D11_CLEAR_STENCIL, 1.0f, 0); ///////////////**************new**************//////////////////// //Set the WVP matrix and send it to the constant buffer in effect file WVP = cube1World * camView * camProjection; cbPerObj.WVP = XMMatrixTranspose(WVP); d3d11DevCon->UpdateSubresource( cbPerObjectBuffer, 0, NULL, &cbPerObj, 0, 0 ); d3d11DevCon->VSSetConstantBuffers( 0, 1, &cbPerObjectBuffer ); //Draw the first cube d3d11DevCon->DrawIndexed( 36, 0, 0 ); WVP = cube2World * camView * camProjection; cbPerObj.WVP = XMMatrixTranspose(WVP); d3d11DevCon->UpdateSubresource( cbPerObjectBuffer, 0, NULL, &cbPerObj, 0, 0 ); d3d11DevCon->VSSetConstantBuffers( 0, 1, &cbPerObjectBuffer ); //Draw the second cube d3d11DevCon->DrawIndexed( 36, 0, 0 ); ///////////////**************new**************//////////////////// //Present the backbuffer to the screen SwapChain->Present(0, 0); } Not a very long lesson, but i hope you still got something out of it! ##Exercise:## 1. Orbit the first cube around a different axis. 1. Play with the different transformations, and try to order them differently when multiplying them together, to see different effects. Here's the final code: main.cpp: //Include and link appropriate libraries and headers// #pragma comment(lib, "d3d11.lib") #pragma comment(lib, "d3dx11.lib") #pragma comment(lib, "d3dx10.lib") #include <windows.h> #include <d3d11.h> #include <d3dx11.h> #include <d3dx10.h> #include <xnamath.h> //Global Declarations - Interfaces// IDXGISwapChain* SwapChain; ID3D11Device* d3d11Device; ID3D11DeviceContext* d3d11DevCon; ID3D11RenderTargetView* renderTargetView; ID3D11Buffer* squareIndexBuffer; ID3D11DepthStencilView* depthStencilView; ID3D11Texture2D* depthStencilBuffer; ID3D11Buffer* squareVertBuffer; ID3D11VertexShader* VS; ID3D11PixelShader* PS; ID3D10Blob* VS_Buffer; ID3D10Blob* PS_Buffer; ID3D11InputLayout* vertLayout; ID3D11Buffer* cbPerObjectBuffer; //Global Declarations - Others// LPCTSTR WndClassName = L"firstwindow"; HWND hwnd = NULL; HRESULT hr; const int Width = 300; const int Height = 300; XMMATRIX WVP; ///////////////**************new**************//////////////////// XMMATRIX cube1World; XMMATRIX cube2World; ///////////////**************new**************//////////////////// XMMATRIX camView; XMMATRIX camProjection; XMVECTOR camPosition; XMVECTOR camTarget; XMVECTOR camUp; ///////////////**************new**************//////////////////// XMMATRIX Rotation; XMMATRIX Scale; XMMATRIX Translation; float rot = 0.01f; ///////////////**************new**************//////////////////// //Function Prototypes// bool InitializeDirect3d11App(HINSTANCE hInstance); void CleanUp(); bool InitScene(); void UpdateScene(); void DrawScene(); bool InitializeWindow(HINSTANCE hInstance, int ShowWnd, int width, int height, bool windowed); int messageloop(); LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); //Create effects constant buffer's structure// struct cbPerObject { XMMATRIX WVP; }; cbPerObject cbPerObj; //Vertex Structure and Vertex Layout (Input Layout)// struct Vertex //Overloaded Vertex Structure { Vertex(){} Vertex(float x, float y, float z, float cr, float cg, float cb, float ca) : pos(x,y,z), color(cr, cg, cb, ca){} XMFLOAT3 pos; XMFLOAT4 color; }; D3D11_INPUT_ELEMENT_DESC layout[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, }; UINT numElements = ARRAYSIZE(layout); int WINAPI WinMain(HINSTANCE hInstance, //Main windows function HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) { if(!InitializeWindow(hInstance, nShowCmd, Width, Height, true)) { MessageBox(0, L"Window Initialization - Failed", L"Error", MB_OK); return 0; } if(!InitializeDirect3d11App(hInstance)) //Initialize Direct3D { MessageBox(0, L"Direct3D Initialization - Failed", L"Error", MB_OK); return 0; } if(!InitScene()) //Initialize our scene { MessageBox(0, L"Scene Initialization - Failed", L"Error", MB_OK); return 0; } messageloop(); CleanUp(); return 0; } bool InitializeWindow(HINSTANCE hInstance, int ShowWnd, int width, int height, bool windowed) { typedef struct _WNDCLASS { UINT cbSize; UINT style; WNDPROC lpfnWndProc; int cbClsExtra; int cbWndExtra; HANDLE hInstance; HICON hIcon; HCURSOR hCursor; HBRUSH hbrBackground; LPCTSTR lpszMenuName; LPCTSTR lpszClassName; } WNDCLASS; WNDCLASSEX wc; wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WndProc; wc.cbClsExtra = NULL; wc.cbWndExtra = NULL; wc.hInstance = hInstance; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 2); wc.lpszMenuName = NULL; wc.lpszClassName = WndClassName; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); if (!RegisterClassEx(&wc)) { MessageBox(NULL, L"Error registering class", L"Error", MB_OK | MB_ICONERROR); return 1; } hwnd = CreateWindowEx( NULL, WndClassName, L"Lesson 4 - Begin Drawing", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, width, height, NULL, NULL, hInstance, NULL ); if (!hwnd) { MessageBox(NULL, L"Error creating window", L"Error", MB_OK | MB_ICONERROR); return 1; } ShowWindow(hwnd, ShowWnd); UpdateWindow(hwnd); return true; } bool InitializeDirect3d11App(HINSTANCE hInstance) { //Describe our SwapChain Buffer DXGI_MODE_DESC bufferDesc; ZeroMemory(&bufferDesc, sizeof(DXGI_MODE_DESC)); bufferDesc.Width = Width; bufferDesc.Height = Height; bufferDesc.RefreshRate.Numerator = 60; bufferDesc.RefreshRate.Denominator = 1; bufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; bufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; bufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; //Describe our SwapChain DXGI_SWAP_CHAIN_DESC swapChainDesc; ZeroMemory(&swapChainDesc, sizeof(DXGI_SWAP_CHAIN_DESC)); swapChainDesc.BufferDesc = bufferDesc; swapChainDesc.SampleDesc.Count = 1; swapChainDesc.SampleDesc.Quality = 0; swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swapChainDesc.BufferCount = 1; swapChainDesc.OutputWindow = hwnd; swapChainDesc.Windowed = TRUE; swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; //Create our SwapChain hr = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, NULL, NULL, NULL, D3D11_SDK_VERSION, &swapChainDesc, &SwapChain, &d3d11Device, NULL, &d3d11DevCon); //Create our BackBuffer ID3D11Texture2D* BackBuffer; hr = SwapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), (void**)&BackBuffer ); //Create our Render Target hr = d3d11Device->CreateRenderTargetView( BackBuffer, NULL, &renderTargetView ); BackBuffer->Release(); //Describe our Depth/Stencil Buffer D3D11_TEXTURE2D_DESC depthStencilDesc; depthStencilDesc.Width = Width; depthStencilDesc.Height = Height; depthStencilDesc.MipLevels = 1; depthStencilDesc.ArraySize = 1; depthStencilDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; depthStencilDesc.SampleDesc.Count = 1; depthStencilDesc.SampleDesc.Quality = 0; depthStencilDesc.Usage = D3D11_USAGE_DEFAULT; depthStencilDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL; depthStencilDesc.CPUAccessFlags = 0; depthStencilDesc.MiscFlags = 0; //Create the Depth/Stencil View d3d11Device->CreateTexture2D(&depthStencilDesc, NULL, &depthStencilBuffer); d3d11Device->CreateDepthStencilView(depthStencilBuffer, NULL, &depthStencilView); //Set our Render Target d3d11DevCon->OMSetRenderTargets( 1, &renderTargetView, depthStencilView ); return true; } void CleanUp() { //Release the COM Objects we created SwapChain->Release(); d3d11Device->Release(); d3d11DevCon->Release(); renderTargetView->Release(); squareVertBuffer->Release(); squareIndexBuffer->Release(); VS->Release(); PS->Release(); VS_Buffer->Release(); PS_Buffer->Release(); vertLayout->Release(); depthStencilView->Release(); depthStencilBuffer->Release(); cbPerObjectBuffer->Release(); } bool InitScene() { //Compile Shaders from shader file hr = D3DX11CompileFromFile(L"Effects.fx", 0, 0, "VS", "vs_4_0", 0, 0, 0, &VS_Buffer, 0, 0); hr = D3DX11CompileFromFile(L"Effects.fx", 0, 0, "PS", "ps_4_0", 0, 0, 0, &PS_Buffer, 0, 0); //Create the Shader Objects hr = d3d11Device->CreateVertexShader(VS_Buffer->GetBufferPointer(), VS_Buffer->GetBufferSize(), NULL, &VS); hr = d3d11Device->CreatePixelShader(PS_Buffer->GetBufferPointer(), PS_Buffer->GetBufferSize(), NULL, &PS); //Set Vertex and Pixel Shaders d3d11DevCon->VSSetShader(VS, 0, 0); d3d11DevCon->PSSetShader(PS, 0, 0); ///////////////**************new**************//////////////////// //Create the vertex buffer Vertex v[] = { Vertex( -1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f ), Vertex( -1.0f, +1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f ), Vertex( +1.0f, +1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f ), Vertex( +1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 1.0f ), Vertex( -1.0f, -1.0f, +1.0f, 0.0f, 1.0f, 1.0f, 1.0f ), Vertex( -1.0f, +1.0f, +1.0f, 1.0f, 1.0f, 1.0f, 1.0f ), Vertex( +1.0f, +1.0f, +1.0f, 1.0f, 0.0f, 1.0f, 1.0f ), Vertex( +1.0f, -1.0f, +1.0f, 1.0f, 0.0f, 0.0f, 1.0f ), }; DWORD indices[] = { // front face 0, 1, 2, 0, 2, 3, // back face 4, 6, 5, 4, 7, 6, // left face 4, 5, 1, 4, 1, 0, // right face 3, 2, 6, 3, 6, 7, // top face 1, 5, 6, 1, 6, 2, // bottom face 4, 0, 3, 4, 3, 7 }; D3D11_BUFFER_DESC indexBufferDesc; ZeroMemory( &indexBufferDesc, sizeof(indexBufferDesc) ); indexBufferDesc.Usage = D3D11_USAGE_DEFAULT; indexBufferDesc.ByteWidth = sizeof(DWORD) * 12 * 3; indexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER; indexBufferDesc.CPUAccessFlags = 0; indexBufferDesc.MiscFlags = 0; D3D11_SUBRESOURCE_DATA iinitData; iinitData.pSysMem = indices; d3d11Device->CreateBuffer(&indexBufferDesc, &iinitData, &squareIndexBuffer); d3d11DevCon->IASetIndexBuffer( squareIndexBuffer, DXGI_FORMAT_R32_UINT, 0); D3D11_BUFFER_DESC vertexBufferDesc; ZeroMemory( &vertexBufferDesc, sizeof(vertexBufferDesc) ); vertexBufferDesc.Usage = D3D11_USAGE_DEFAULT; vertexBufferDesc.ByteWidth = sizeof( Vertex ) * 8; vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; vertexBufferDesc.CPUAccessFlags = 0; vertexBufferDesc.MiscFlags = 0; ///////////////**************new**************//////////////////// D3D11_SUBRESOURCE_DATA vertexBufferData; ZeroMemory( &vertexBufferData, sizeof(vertexBufferData) ); vertexBufferData.pSysMem = v; hr = d3d11Device->CreateBuffer( &vertexBufferDesc, &vertexBufferData, &squareVertBuffer); //Set the vertex buffer UINT stride = sizeof( Vertex ); UINT offset = 0; d3d11DevCon->IASetVertexBuffers( 0, 1, &squareVertBuffer, &stride, &offset ); //Create the Input Layout hr = d3d11Device->CreateInputLayout( layout, numElements, VS_Buffer->GetBufferPointer(), VS_Buffer->GetBufferSize(), &vertLayout ); //Set the Input Layout d3d11DevCon->IASetInputLayout( vertLayout ); //Set Primitive Topology d3d11DevCon->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST ); //Create the Viewport D3D11_VIEWPORT viewport; ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT)); viewport.TopLeftX = 0; viewport.TopLeftY = 0; viewport.Width = Width; viewport.Height = Height; viewport.MinDepth = 0.0f; viewport.MaxDepth = 1.0f; //Set the Viewport d3d11DevCon->RSSetViewports(1, &viewport); //Create the buffer to send to the cbuffer in effect file D3D11_BUFFER_DESC cbbd; ZeroMemory(&cbbd, sizeof(D3D11_BUFFER_DESC)); cbbd.Usage = D3D11_USAGE_DEFAULT; cbbd.ByteWidth = sizeof(cbPerObject); cbbd.BindFlags = D3D11_BIND_CONSTANT_BUFFER; cbbd.CPUAccessFlags = 0; cbbd.MiscFlags = 0; hr = d3d11Device->CreateBuffer(&cbbd, NULL, &cbPerObjectBuffer); //Camera information ///////////////**************new**************//////////////////// camPosition = XMVectorSet( 0.0f, 3.0f, -8.0f, 0.0f ); ///////////////**************new**************//////////////////// camTarget = XMVectorSet( 0.0f, 0.0f, 0.0f, 0.0f ); camUp = XMVectorSet( 0.0f, 1.0f, 0.0f, 0.0f ); //Set the View matrix camView = XMMatrixLookAtLH( camPosition, camTarget, camUp ); //Set the Projection matrix camProjection = XMMatrixPerspectiveFovLH( 0.4f*3.14f, (float)Width/Height, 1.0f, 1000.0f); return true; } ///////////////**************new**************//////////////////// void UpdateScene() { //Keep the cubes rotating rot += .0005f; if(rot > 6.26f) rot = 0.0f; //Reset cube1World cube1World = XMMatrixIdentity(); //Define cube1's world space matrix XMVECTOR rotaxis = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f); Rotation = XMMatrixRotationAxis( rotaxis, rot); Translation = XMMatrixTranslation( 0.0f, 0.0f, 4.0f ); //Set cube1's world space using the transformations cube1World = Translation * Rotation; //Reset cube2World cube2World = XMMatrixIdentity(); //Define cube2's world space matrix Rotation = XMMatrixRotationAxis( rotaxis, -rot); Scale = XMMatrixScaling( 1.3f, 1.3f, 1.3f ); //Set cube2's world space matrix cube2World = Rotation * Scale; } ///////////////**************new**************//////////////////// void DrawScene() { //Clear our backbuffer float bgColor[4] = {(0.0f, 0.0f, 0.0f, 0.0f)}; d3d11DevCon->ClearRenderTargetView(renderTargetView, bgColor); //Refresh the Depth/Stencil view d3d11DevCon->ClearDepthStencilView(depthStencilView, D3D11_CLEAR_DEPTH|D3D11_CLEAR_STENCIL, 1.0f, 0); ///////////////**************new**************//////////////////// //Set the WVP matrix and send it to the constant buffer in effect file WVP = cube1World * camView * camProjection; cbPerObj.WVP = XMMatrixTranspose(WVP); d3d11DevCon->UpdateSubresource( cbPerObjectBuffer, 0, NULL, &cbPerObj, 0, 0 ); d3d11DevCon->VSSetConstantBuffers( 0, 1, &cbPerObjectBuffer ); //Draw the first cube d3d11DevCon->DrawIndexed( 36, 0, 0 ); WVP = cube2World * camView * camProjection; cbPerObj.WVP = XMMatrixTranspose(WVP); d3d11DevCon->UpdateSubresource( cbPerObjectBuffer, 0, NULL, &cbPerObj, 0, 0 ); d3d11DevCon->VSSetConstantBuffers( 0, 1, &cbPerObjectBuffer ); //Draw the second cube d3d11DevCon->DrawIndexed( 36, 0, 0 ); ///////////////**************new**************//////////////////// //Present the backbuffer to the screen SwapChain->Present(0, 0); } int messageloop(){ MSG msg; ZeroMemory(&msg, sizeof(MSG)); while(true) { BOOL PeekMessageL( LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg ); if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT) break; TranslateMessage(&msg); DispatchMessage(&msg); } else{ // run game code UpdateScene(); DrawScene(); } } return msg.wParam; } LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch( msg ) { case WM_KEYDOWN: if( wParam == VK_ESCAPE ){ DestroyWindow(hwnd); } return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, msg, wParam, lParam); } Effects.fx: cbuffer cbPerObject { float4x4 WVP; }; struct VS_OUTPUT { float4 Pos : SV_POSITION; float4 Color : COLOR; }; VS_OUTPUT VS(float4 inPos : POSITION, float4 inColor : COLOR) { VS_OUTPUT output; output.Pos = mul(inPos, WVP); output.Color = inColor; return output; } float4 PS(VS_OUTPUT input) : SV_TARGET { return input.Color; }