This tutorial is part of a Collection: 02. DirectX 10 - Braynzar Soft Tutorials
rate up
0
rate down
1351
views
bookmark
09. World, View, and Local Space

We get to learn about the World, View and Local spaces in Direct3D, and how to initialize them, set them, and convert them!

There are no files for this tutorial
When we create a 3d scene, we have a bunch of different objects that make up the scene. Usually we will create these objects called 3d models in a modeling program such as 3ds max or maya. When we create these models, we do not create them relative to the other objects in our scene. Take for example a tree. We would not build the tree in the scene relative to all the other trees, ground and everything else, we would create it relative to its own space, which we call "Local Space". All the objects in our scene put together is called the "World Space", and everything the camera can see is called the "View Space". Creating models in "Local Space" is good because, think of a cube, it is easy to define a cubes vertices in its local space, flat on the ground, but maybe in our scene we need the cube to be tilted a little. If the cube is tilted, it is very difficult to define the vertice positions. Another reason we create objects in local space, is we might need multiples of the same object, such as a tree in a forrest, it would be a waste of time and memory to define every single tree in the forrest, when we can just have one tree and copy it a bunch of times. All spaces are defined by a 4x4 matrix. We first need to transform the local space of the object into the world space with all the other objects in our scene. I won't go into all the math details, as you can find it on the internet if your really interested. After we transform local into world, we need to transform the world into the view, which is what our camera sees. We put all those spaces together in the "World, Space, View" matrix. We have added something to our effect file, which is called a constant buffer. We can store variables in there, we will get to that next. Lets look at the effect file. We have something new here. Its called a constant buffer. This is where we will store our WVP space matrix. We are able to update the matrix, and variables in our effect file, so we will do that in a bit. We will have more constant buffers, but usually constant buffers are separated based on how frequently they are updated. This buffer is changed per Object, so we name it based on that. cbuffer cbPerObject { float4x4 WVP; }; Go down to the vertex shader function now. We are modifying the vertex's local position by multiplying it with the WVP matrix. This will change the vertex's position relitive to the world, view, and projection spaces. output.Pos = mul(inPos, WVP); Now lets go into our main code. We have a couple new declarations here. The first one is declaring the pointer we will use to access our WVP matrix in our effect file. We are accessing a matrix variable, so we use ID3D10EffectMatrixVariable. But there are others for other types, like ID3D10EffectVectorVariable and ID3D10EffectScalarVariable. The next four lines are declaring the matrices we will use: WVP, World, View, and Projection. ID3D10EffectMatrixVariable* fxWVPVar; D3DXMATRIX WVP; D3DXMATRIX World; D3DXMATRIX View; D3DXMATRIX Projection; Next you'll notice we moved a couple these three vectors from being declared in the initScene to being declared globaly at the top of our file. This is so we can use them in our drawscene function too. D3DXVECTOR3 Position; D3DXVECTOR3 Target; D3DXVECTOR3 Up; Here we first set the World matrix to an identity matrix, which is the starting point for matrices that will modify verticies for rotating, scaling and translating. The next line, we are creating a vector which will be used as the cameras position. The line after that is the target, which is where the camera is looking at. And the line after that is the "up" in world space. We set that to (0.0f, 1.0f, 0.0f), meaning that the positive "y" axis is up. Then finally we do all the calculations i decided not to explain, which essentially creates our view matrix, using the vectors we just described. The parameters of the D3DXMatrixLookAtLH function should be pretty clear. D3DXMatrixIdentity( &World ); D3DXVECTOR3 Position( 0.0f, 0.0f, -1.0f ); D3DXVECTOR3 Target( 0.0f, 0.0f, 0.0f ); D3DXVECTOR3 Up( 0.0f, 1.0f, 0.0f ); D3DXMatrixLookAtLH( &View, &Position, &Target, &Up ); Lets go down to the initScene function, where we have this new line. What this line does, is set the fxWVPVar matrix which we declared at the top of our code, to the "WVP" matrix in our effect file. We do this so we can update the WVP matrix in our effect file. fxWVPvar = FX->GetVariableByName("WVP")->AsMatrix(); Now in our drawScene function, we create the Perspective projection matrix using the D3DXMatrixPerspectiveFovLH function. The first parameter here is a pointer to our returned projection matrix. The second is the vertical field of view angle in radians, hence the 3.14(PI). The fourth is the Aspect Ratio, which is the width of our window, divided by the height. Fourth is the distance to the near plane, objects between with a distance to the camera smaller than 1 will not be drawn to the screen. And the last parameter is the distance to the far plane. Objects further than 1000 from the camera will not be drawn, so only the objects within the field of view, and between the near pland and far plane will be drawn. D3DXMatrixPerspectiveFovLH(&Projection, 0.4f*3.14f, Width/Height, 1.0f, 1000.0f); Here we multiply the space matrices together, and put the outcome into our WVP (World, Space, View) matrix, and set the "WVP" matrix in our effect file to the WVP matrix we just defined. WVP = World * View * Projection; fxWVPVar->SetMatrix((float*)&WVP); We have finished creating our spaces! We can move on to the fun of translating, rotating, and scaling! Here's the final code: main.cpp #include <Windows.h> #include <d3d10.h> #include <d3dx10.h> #include <string> #pragma comment(lib, "D3D10.lib") #pragma comment(lib, "d3dx10d.lib") LPCTSTR WndClassName = L"firstwindow"; HWND hwnd = NULL; const int Width = 800; const int Height = 600; bool InitializeWindow(HINSTANCE hInstance, int ShowWnd, int width, int height, bool windowed); HRESULT hr; ID3D10Device* d3dDevice; IDXGISwapChain* SwapChain; ID3D10RenderTargetView* RenderTargetView; ID3D10Effect* FX; ID3D10InputLayout* VertexLayout; ID3D10Buffer* VertexBuffer; ID3D10Buffer* IndexBuffer; ID3D10EffectTechnique* Technique; ID3D10DepthStencilView* DepthStencilView; ID3D10Texture2D* DepthStencilBuffer; ////////////////////new////////////////////////////////////////////////////////////////////// ID3D10EffectMatrixVariable* fxWVPVar; D3DXMATRIX WVP; D3DXMATRIX World; D3DXMATRIX View; D3DXMATRIX Projection; D3DXVECTOR3 Position; D3DXVECTOR3 Target; D3DXVECTOR3 Up; ////////////////////new////////////////////////////////////////////////////////////////////// bool InitializeDirect3dApp(HINSTANCE hInstance); bool InitScene(); void DrawScene(); bool ReleaseObjects(); int messageloop(); LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); struct Vertex { D3DXVECTOR3 pos; D3DXCOLOR color; }; 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(!InitializeDirect3dApp(hInstance)) { MessageBox(0, L"Direct3D Initialization - Failed", L"Error", MB_OK); return 0; } if(!InitScene()) { MessageBox(0, L"Scene Initialization - Failed", L"Error", MB_OK); return 0; } messageloop(); if(!ReleaseObjects()) { MessageBox(0, L"Object Releasing - Failed", L"Error", MB_OK); return 0; } 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"Window Title", 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 InitializeDirect3dApp(HINSTANCE hInstance) { UINT createDeviceFlags = 0; D3D10_DRIVER_TYPE driverTypes[] = { D3D10_DRIVER_TYPE_HARDWARE, D3D10_DRIVER_TYPE_REFERENCE, }; UINT numDriverTypes = sizeof( driverTypes ) / sizeof( driverTypes[0] ); DXGI_SWAP_CHAIN_DESC scd; scd.BufferDesc.Width = Width; scd.BufferDesc.Height = Height; scd.BufferDesc.RefreshRate.Numerator = 60; scd.BufferDesc.RefreshRate.Denominator = 1; scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; scd.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; scd.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; //no multisampling scd.SampleDesc.Count = 1; scd.SampleDesc.Quality = 0; scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; scd.BufferCount = 1; scd.OutputWindow = hwnd; scd.Windowed = true; scd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; scd.Flags = 0; D3D10CreateDeviceAndSwapChain(0, D3D10_DRIVER_TYPE_HARDWARE, 0, 0, D3D10_SDK_VERSION, &scd, &SwapChain, &d3dDevice); ID3D10Texture2D* backBuffer; SwapChain->GetBuffer(0, _uuidof(ID3D10Texture2D), reinterpret_cast<void**>(&backBuffer)); d3dDevice->CreateRenderTargetView(backBuffer, 0, &RenderTargetView); backBuffer->Release(); D3D10_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 = D3D10_USAGE_DEFAULT; depthStencilDesc.BindFlags = D3D10_BIND_DEPTH_STENCIL; depthStencilDesc.CPUAccessFlags = 0; depthStencilDesc.MiscFlags = 0; d3dDevice->CreateTexture2D(&depthStencilDesc, NULL, &DepthStencilBuffer); d3dDevice->CreateDepthStencilView(DepthStencilBuffer, NULL, &DepthStencilView); d3dDevice->OMSetRenderTargets(1, &RenderTargetView, DepthStencilView); // Setup the viewport D3D10_VIEWPORT vp; vp.Width = Width; vp.Height = Height; vp.MinDepth = 0.0f; vp.MaxDepth = 1.0f; vp.TopLeftX = 0; vp.TopLeftY = 0; d3dDevice->RSSetViewports( 1, &vp ); ////////////////////new////////////////////////////////////////////////////////////////////// D3DXMatrixIdentity( &World ); D3DXMatrixIdentity( &View ); D3DXMatrixIdentity( &Projection ); Position = D3DXVECTOR3( 0.0f, 0.0f, -1.0f ); Target = D3DXVECTOR3( 0.0f, 0.0f, 0.0f ); Up = D3DXVECTOR3( 0.0f, 1.0f, 0.0f ); D3DXMatrixLookAtLH( &View, &Position, &Target, &Up ); ////////////////////new////////////////////////////////////////////////////////////////////// return true; } bool InitScene() { Vertex vertices[] = { {D3DXVECTOR3(-0.5f, -0.5f, 0.5f), D3DXCOLOR (1.0f, 0.0f, 0.0f, 1.0f)}, {D3DXVECTOR3(-0.5f, 0.5f, 0.5f), D3DXCOLOR (0.0f, 1.0f, 0.0f, 1.0f)}, {D3DXVECTOR3( 0.5f, 0.5f, 0.5f), D3DXCOLOR (0.0f, 0.0f, 1.0f, 1.0f)}, {D3DXVECTOR3( 0.5f, -0.5f, 0.5f), D3DXCOLOR (1.0f, 1.0f, 0.0f, 1.0f)} }; D3D10_BUFFER_DESC bd; bd.Usage = D3D10_USAGE_IMMUTABLE; bd.ByteWidth = sizeof( Vertex ) * 4; bd.BindFlags = D3D10_BIND_VERTEX_BUFFER; bd.CPUAccessFlags = 0; bd.MiscFlags = 0; D3D10_SUBRESOURCE_DATA InitData; InitData.pSysMem = vertices; d3dDevice->CreateBuffer( &bd, &InitData, &VertexBuffer ); DWORD indices[] = { 0, 1, 2, 0, 2, 3, }; D3D10_BUFFER_DESC ibd; ibd.Usage = D3D10_USAGE_IMMUTABLE; ibd.ByteWidth = sizeof(DWORD) * 2 * 3; ibd.BindFlags = D3D10_BIND_INDEX_BUFFER; ibd.CPUAccessFlags = 0; ibd.MiscFlags = 0; D3D10_SUBRESOURCE_DATA iinitData; iinitData.pSysMem = indices; d3dDevice->CreateBuffer(&ibd, &iinitData, &IndexBuffer); UINT stride = sizeof( Vertex ); UINT offset = 0; d3dDevice->IASetVertexBuffers( 0, 1, &VertexBuffer, &stride, &offset ); d3dDevice->IASetIndexBuffer(IndexBuffer, DXGI_FORMAT_R32_UINT, 0); D3D10_INPUT_ELEMENT_DESC layout[] = { {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 }, {"COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0} }; ID3D10Blob* compilationErrors = 0; HRESULT hr = 0; hr = D3DX10CreateEffectFromFile( L"vertex.fx", NULL, NULL, "fx_4_0", D3D10_SHADER_ENABLE_STRICTNESS, 0, d3dDevice, NULL, NULL, &FX, &compilationErrors, NULL ); if(FAILED(hr)) { MessageBoxA(0, (char*)compilationErrors->GetBufferPointer(), 0, 0); compilationErrors->Release(); return false; } Technique = FX->GetTechniqueByName( "Tech" ); ////////////////////new////////////////////////////////////////////////////////////////////// fxWVPVar = FX->GetVariableByName("WVP")->AsMatrix(); ////////////////////new////////////////////////////////////////////////////////////////////// D3D10_PASS_DESC PassDesc; Technique->GetPassByIndex( 0 )->GetDesc( &PassDesc ); d3dDevice->CreateInputLayout( layout, 2, PassDesc.pIAInputSignature, PassDesc.IAInputSignatureSize, &VertexLayout ); d3dDevice->IASetInputLayout( VertexLayout ); d3dDevice->IASetPrimitiveTopology( D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST ); return true; } bool ReleaseObjects() { if( d3dDevice ) d3dDevice->ClearState(); if( VertexBuffer ) VertexBuffer->Release(); if( VertexLayout ) VertexLayout->Release(); if( FX ) FX->Release(); if( RenderTargetView ) RenderTargetView->Release(); if( SwapChain ) SwapChain->Release(); if( d3dDevice ) d3dDevice->Release(); return true; } void DrawScene() { //Draw Scene Here D3DXCOLOR bgColor( 0.0f, 0.0f, 0.0f, 1.0f); d3dDevice->ClearRenderTargetView( RenderTargetView, bgColor ); d3dDevice->ClearDepthStencilView(DepthStencilView, D3D10_CLEAR_DEPTH|D3D10_CLEAR_STENCIL, 1.0f, 0); ////////////////////new////////////////////////////////////////////////////////////////////// D3DXMatrixPerspectiveFovLH(&Projection, 0.4f*3.14f, Width/Height, 1.0f, 1000.0f); WVP = World * View * Projection; fxWVPVar->SetMatrix((float*)&WVP); ////////////////////new////////////////////////////////////////////////////////////////////// D3D10_TECHNIQUE_DESC techDesc; Technique->GetDesc( &techDesc ); for( UINT p = 0; p < techDesc.Passes; ++p ) { Technique->GetPassByIndex( p )->Apply( 0 ); d3dDevice->DrawIndexed(6, 0, 0); } 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 DrawScene(); } } return msg.wParam; } LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch( msg ) { case WM_KEYDOWN: if( wParam == VK_ESCAPE ){ if(MessageBox(0, L"Are you sure you want to exit?", L"Really?", MB_YESNO | MB_ICONQUESTION) == IDYES) DestroyWindow(hwnd); } return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, msg, wParam, lParam); } vertex.fx cbuffer cbPerObject { float4x4 WVP; }; struct VS_OUTPUT //output structure for vertex shader { float4 Pos : SV_POSITION; float4 Color : COLOR0; }; // Vertex Shader VS_OUTPUT VS(float4 inPos : POSITION, float4 inColor : COLOR) { VS_OUTPUT output = (VS_OUTPUT)0; output.Pos = mul(inPos, WVP); output.Color = inColor; return output; //send color and position to pixel shader } // Pixel Shader float4 PS(VS_OUTPUT input) : SV_Target { return input.Color; // Set the color of the pixel to what we defined for the vertex. } technique10 Tech { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } }