This tutorial is part of a Collection: 02. DirectX 10 - Braynzar Soft Tutorials
1385
views
06. Color!
Here is a short lesson on what we need to do to get some color in our scene. This lesson builds off of the last one, begin drawing.
We will do a some modifying in the effect file. Other than that, its a pretty easy lesson. I'm going to start by explaining the effect file. The first thing you'll notice in the effect file is there is a new structure. What this structure does is create a type for the Vertex Shader to return. This way we can return the position of the vertices and their color. These are the two values that will be passed from the vertex shader to the pixel shader right now. struct VS_OUTPUT { float4 Pos : SV_POSITION; float4 Color : COLOR0; }; The next thing in our effect file, is we have changed the type from "float4" to "VS_OUTPUT". This is declaring the return type of this function as our newly created type from above. Now we can return more than just the vertex position, we can also return the color. inPos, is the variable our position will be stored in because we said in our code that the position will be sent to the "POSITION" in the pipeline. Same thing for inColor, because our color element in our vertex will be sent to "COLOR" in the pipeline. Then in the vs function, the first line is just creating a new VS_OUTPUT type, called output and setting it to null(0). After that we set the Pos member of the output type to the inPos we got from our vertex buffer. next line is the same thing but with color. After all that, we return the output type, which contains our position and color variables for our vertex. VS_OUTPUT VS(float4 inPos : POSITION, float4 inColor : COLOR) { VS_OUTPUT output = (VS_OUTPUT)0; output.Pos = inPos; //No calculations done here, just returns the position of the vertices output.Color = inColor; return output; //send color and position to pixel shader } The last thing we changed in the effect file, is our Pixel Shader. We changed the parameters to accept an "input" of type "VS_OUTPUT", which is what the Vertex Shader will send. In our PS function, we just return the color of our vertex, and after the pixel shader, the colors of each vertex will be interpolated accross our primitive, and you can see the effect when we run our app. float4 PS(VS_OUTPUT input) : SV_Target { return input.Color; // Set the color of the pixel to what we defined for the vertex. } Now into our main application. First thing we did here was add a new member to our vertex structure called "color" of type D3DXCOLOR. Pretty simple. D3DXCOLOR color; Next we jump down to our initScene function. Here we updated our vertex buffer content and defined colors along with the position of our vertices. Vertex vertices[] = { {D3DXVECTOR3(0.0f, 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)} }; Lets look at our layout description. We have a new element in our vertex structure, so we need to add a new element to our D3D10_INPUT_ELEMENT_DESC array. The first parameter is "COLOR", which is saying this element in the vertex structure will be sent to the COLOR variable in the vertex shader. The third parameter is the just the rgba type, then we have a 0 for the fourth type, and a 12 for the 5th type. We put a 12 here because it is where this element starts in bytes in the vertex structure. 0-12 is the position of the vertex, so 12 to the end is the color of our vertex. Thats all thats new here. {"COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0} Here is an important part, don't forget this. the second parameter in the CreateInputLayout function is the number of elements in our vertex structure. We have 2 now, so we need to set the second parameter here to 2. d3dDevice->CreateInputLayout( layout, 2, PassDesc.pIAInputSignature, PassDesc.IAInputSignatureSize, &VertexLayout ); There it is! We now have control over the color of our vertices! If your having linker errors, don't forget to go to project properties, linker, input, additional dependencies and add d3dx10d.lib;d3d10.lib;. Like always, questions or comments are more than welcome! 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; ID3D10DepthStencilView* DepthStencilView; ID3D10Effect* FX; ID3D10InputLayout* VertexLayout; ID3D10Buffer* VertexBuffer; ID3D10EffectTechnique* Technique; 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; ///////////////new////////////////////////////////////////////////////////////////// D3DXCOLOR color; ///////////////new////////////////////////////////////////////////////////////////// }; 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(); d3dDevice->OMSetRenderTargets(1, &RenderTargetView, NULL); // 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 ); return true; } bool InitScene() { ///////////////new////////////////////////////////////////////////////////////////// Vertex vertices[] = { {D3DXVECTOR3(0.0f, 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)} }; ///////////////new////////////////////////////////////////////////////////////////// D3D10_BUFFER_DESC bd; bd.Usage = D3D10_USAGE_DEFAULT; bd.ByteWidth = sizeof( Vertex ) * 3; bd.BindFlags = D3D10_BIND_VERTEX_BUFFER; bd.CPUAccessFlags = 0; bd.MiscFlags = 0; D3D10_SUBRESOURCE_DATA InitData; InitData.pSysMem = vertices; d3dDevice->CreateBuffer( &bd, &InitData, &VertexBuffer ); UINT stride = sizeof( Vertex ); UINT offset = 0; d3dDevice->IASetVertexBuffers( 0, 1, &VertexBuffer, &stride, &offset ); D3D10_INPUT_ELEMENT_DESC layout[] = { {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 }, ///////////////new////////////////////////////////////////////////////////////////// {"COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0} ///////////////new////////////////////////////////////////////////////////////////// }; ID3D10Blob* compilationErrors = 0; HRESULT hr = 0; ///////////////new////////////////////////////////////////////////////////////////// hr = D3DX10CreateEffectFromFile( L"vertex.fx", NULL, NULL, "fx_4_0", D3D10_SHADER_ENABLE_STRICTNESS, 0, d3dDevice, NULL, NULL, &FX, &compilationErrors, NULL ); ///////////////new////////////////////////////////////////////////////////////////// if(FAILED(hr)) { MessageBoxA(0, (char*)compilationErrors->GetBufferPointer(), 0, 0); compilationErrors->Release(); return false; } Technique = FX->GetTechniqueByName( "Tech" ); D3D10_PASS_DESC PassDesc; Technique->GetPassByIndex( 0 )->GetDesc( &PassDesc ); ///////////////new////////////////////////////////////////////////////////////////// d3dDevice->CreateInputLayout( layout, 2, PassDesc.pIAInputSignature, PassDesc.IAInputSignatureSize, &VertexLayout ); ///////////////new////////////////////////////////////////////////////////////////// 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 ); D3D10_TECHNIQUE_DESC techDesc; Technique->GetDesc( &techDesc ); for( UINT p = 0; p < techDesc.Passes; ++p ) { Technique->GetPassByIndex( p )->Apply( 0 ); d3dDevice->Draw( 3, 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 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 = inPos; //No calculations done here, just returns the position of the vertices 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() ) ); } }
Sign in to comment