This tutorial is part of a Collection: 02. DirectX 10 - Braynzar Soft Tutorials
1349
views
14. Pixel Clipping
Here is a very short lessons on how to create a wire box type thing using the HLSL clip() function in an effect file.
We will use the code from the textures lesson in this lesson. It is a very simple lesson that teaches you about a function called "clip" in the effect file. What this function does is blocks certain pixels from being processed in the pixel shader. generally you will use it to clip pixels with a close-to-zero alpha value. an example of the function looks like this: clip (alpha - .25) Although you are able to do the same thing using blending, this way is much more quick and efficient, as you do not have to do blending calculations, and you are able to stop pixels that you don't want on the screen from further processing. Lets go through the code The first new line is initializes a direct3d interface called ID3D10RasterizerState which we will use to store our no culling rasterizer state into. We have already covered render states in lesson 11, so if you don't remember you can look back. ID3D10RasterizerState* noCull; Now lets go down to the InitializeDirect3dApp function, where at the bottom we create a new render state to turn off backface culling. As I said a moment ago, we have already covered render states, so you should be able to understand what is happening here. First we fill out a D3D10_RASTERIZER_DESC structure with our no culling render state information. then we use that description to create our render state noCull. Thats all we change in the InitializeDirect3dApp function. D3D10_RASTERIZER_DESC rastDesc; ZeroMemory(&rastDesc, sizeof(D3D10_RASTERIZER_DESC)); rastDesc.FillMode = D3D10_FILL_SOLID; rastDesc.CullMode = D3D10_CULL_NONE; d3dDevice->CreateRasterizerState(&rastDesc, &noCull); Since ID3D10RasterizerState is a COM Interface, we need to release it in order to prevent a memory leak. We will do this in our ReleaseObjects() function. if( noCull) noCull->Release(); Here we are in our DrawScene function, where we are changing the render states. The first line sets the render state to the default direct3d render state, which uses backface culling. In this application we don't need this line, i just included it to refresh you on how to go about changing render states. After setting our render state to the default, we will draw all our objects that will use the default render state. After drawing those, we set the render state to turn off backface culling. Since we will be seeing through our wire box, we will want to see the other side of the box as it spins, so that is why we turn off backface culling. After turning it off, we draw our primitives. That is all the new code in our main app. Next we go into our effect file. d3dDevice->RSSetState(noCull); //Draw objects that will use backface culling d3dDevice->RSSetState(noCull); Here is our pixel shader. As you can see, we have added a new line, which calls the clip() function. After we load the corresponding texel from our image, we call the clip function to check if the alpha value of that texel is less than .25. If it is, we stop the processing the pixel move on, valuable time. We want to do this test as early on in the pixel shader to stop unnecessary processing for a pixel that will eventually be discarded anyway. You may wonder why we say less than .25 for the alpha value. We do this because after filtering, the alpha channel and colors can get a little blurred, making texels that once had a zero alpha, have a greater than zero alpha. So we want to clip pixels with an alpha value close to zero, but not exactly zero. // Pixel Shader float4 PS(VS_OUTPUT input) : SV_Target { float4 diffuse = DiffuseMap.Sample( TriLinearSample, input.texCoord ); clip (diffuse.a - .25); return diffuse; // Set the color of the pixel to the corresponding texel in the loaded image is. } There, now we have another fun thing to play with when making our video games, told you it was a short lesson! 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; ID3D10ShaderResourceView* DiffuseMapResourceView; ID3D10EffectShaderResourceVariable* fxDiffuseMapVar; ////////////////////new////////////////////////////////////////////////////////////////////// ID3D10RasterizerState* noCull; ////////////////////new////////////////////////////////////////////////////////////////////// ID3D10EffectMatrixVariable* fxWVPVar; D3DXMATRIX WVP; D3DXMATRIX World; D3DXMATRIX View; D3DXMATRIX Projection; D3DXVECTOR3 Position; D3DXVECTOR3 Target; D3DXVECTOR3 Up; D3DXMATRIX Rotation; D3DXMATRIX Scale; D3DXMATRIX Translation; D3DXMATRIX Transformations; float rot = 0.01f; 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 { Vertex(){} Vertex(float x, float y, float z, float u, float v) : pos(x,y,z), texCoord(u,v){} D3DXVECTOR3 pos; D3DXVECTOR2 texCoord; }; 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 ); D3DXMatrixIdentity( &World ); Position = D3DXVECTOR3( 0.0f, 6.0f, -14.0f ); Target = D3DXVECTOR3( 0.0f, 0.0f, 0.0f ); Up = D3DXVECTOR3( 0.0f, 1.0f, 0.0f ); D3DXMatrixLookAtLH( &View, &Position, &Target, &Up ); ////////////////////new////////////////////////////////////////////////////////////////////// D3D10_RASTERIZER_DESC rastDesc; ZeroMemory(&rastDesc, sizeof(D3D10_RASTERIZER_DESC)); rastDesc.FillMode = D3D10_FILL_SOLID; rastDesc.CullMode = D3D10_CULL_NONE; d3dDevice->CreateRasterizerState(&rastDesc, &noCull); ////////////////////new////////////////////////////////////////////////////////////////////// return true; } bool InitScene() { Vertex v[24]; // Front Face v[0] = Vertex(-1.0f, -1.0f, -1.0f, 0.0f, 1.0f); v[1] = Vertex(-1.0f, 1.0f, -1.0f, 0.0f, 0.0f); v[2] = Vertex( 1.0f, 1.0f, -1.0f, 1.0f, 0.0f); v[3] = Vertex( 1.0f, -1.0f, -1.0f, 1.0f, 1.0f); // Back Face v[4] = Vertex(-1.0f, -1.0f, 1.0f, 1.0f, 1.0f); v[5] = Vertex( 1.0f, -1.0f, 1.0f, 0.0f, 1.0f); v[6] = Vertex( 1.0f, 1.0f, 1.0f, 0.0f, 0.0f); v[7] = Vertex(-1.0f, 1.0f, 1.0f, 1.0f, 0.0f); // Top Face v[8] = Vertex(-1.0f, 1.0f, -1.0f, 0.0f, 1.0f); v[9] = Vertex(-1.0f, 1.0f, 1.0f, 0.0f, 0.0f); v[10] = Vertex( 1.0f, 1.0f, 1.0f, 1.0f, 0.0f); v[11] = Vertex( 1.0f, 1.0f, -1.0f, 1.0f, 1.0f); // Bottom Face v[12] = Vertex(-1.0f, -1.0f, -1.0f, 1.0f, 1.0f); v[13] = Vertex( 1.0f, -1.0f, -1.0f, 0.0f, 1.0f); v[14] = Vertex( 1.0f, -1.0f, 1.0f, 0.0f, 0.0f); v[15] = Vertex(-1.0f, -1.0f, 1.0f, 1.0f, 0.0f); // Left Face v[16] = Vertex(-1.0f, -1.0f, 1.0f, 0.0f, 1.0f); v[17] = Vertex(-1.0f, 1.0f, 1.0f, 0.0f, 0.0f); v[18] = Vertex(-1.0f, 1.0f, -1.0f, 1.0f, 0.0f); v[19] = Vertex(-1.0f, -1.0f, -1.0f, 1.0f, 1.0f); // Right Face v[20] = Vertex( 1.0f, -1.0f, -1.0f, 0.0f, 1.0f); v[21] = Vertex( 1.0f, 1.0f, -1.0f, 0.0f, 0.0f); v[22] = Vertex( 1.0f, 1.0f, 1.0f, 1.0f, 0.0f); v[23] = Vertex( 1.0f, -1.0f, 1.0f, 1.0f, 1.0f); D3D10_BUFFER_DESC vbd; vbd.Usage = D3D10_USAGE_IMMUTABLE; vbd.ByteWidth = sizeof(Vertex) * 24; vbd.BindFlags = D3D10_BIND_VERTEX_BUFFER; vbd.CPUAccessFlags = 0; vbd.MiscFlags = 0; D3D10_SUBRESOURCE_DATA vinitData; vinitData.pSysMem = v; d3dDevice->CreateBuffer(&vbd, &vinitData, &VertexBuffer); DWORD i[36]; // Front Face i[0] = 0; i[1] = 1; i[2] = 2; i[3] = 0; i[4] = 2; i[5] = 3; // Back Face i[6] = 4; i[7] = 5; i[8] = 6; i[9] = 4; i[10] = 6; i[11] = 7; // Top Face i[12] = 8; i[13] = 9; i[14] = 10; i[15] = 8; i[16] = 10; i[17] = 11; // Bottom Face i[18] = 12; i[19] = 13; i[20] = 14; i[21] = 12; i[22] = 14; i[23] = 15; // Left Face i[24] = 16; i[25] = 17; i[26] = 18; i[27] = 16; i[28] = 18; i[29] = 19; // Right Face i[30] = 20; i[31] = 21; i[32] = 22; i[33] = 20; i[34] = 22; i[35] = 23; D3D10_BUFFER_DESC ibd; ibd.Usage = D3D10_USAGE_IMMUTABLE; ibd.ByteWidth = sizeof(DWORD) * 36; ibd.BindFlags = D3D10_BIND_INDEX_BUFFER; ibd.CPUAccessFlags = 0; ibd.MiscFlags = 0; D3D10_SUBRESOURCE_DATA iinitData; iinitData.pSysMem = i; 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 }, {"TEXCOORD", 0, DXGI_FORMAT_R32G32_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; } ////////////////////new////////////////////////////////////////////////////////////////////// D3DX10CreateShaderResourceViewFromFile(d3dDevice, L"Wire_Fence.png", 0, 0, &DiffuseMapResourceView, 0 ); ////////////////////new////////////////////////////////////////////////////////////////////// Technique = FX->GetTechniqueByName( "Tech" ); fxWVPVar = FX->GetVariableByName("WVP")->AsMatrix(); fxDiffuseMapVar = FX->GetVariableByName("DiffuseMap")->AsShaderResource(); 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( IndexBuffer ) IndexBuffer->Release(); if( VertexLayout ) VertexLayout->Release(); if( FX ) FX->Release(); if( RenderTargetView ) RenderTargetView->Release(); if( SwapChain ) SwapChain->Release(); if( d3dDevice ) d3dDevice->Release(); if( DiffuseMapResourceView ) DiffuseMapResourceView->Release(); ////////////////////new////////////////////////////////////////////////////////////////////// if( noCull) noCull->Release(); ////////////////////new////////////////////////////////////////////////////////////////////// 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); D3DXMatrixPerspectiveFovLH(&Projection, 0.4f*3.14f, Width/Height, 1.0f, 1000.0f); D3DXVECTOR3 rotaxis(0.0f, 1.0f, 0.0f); D3DXMatrixRotationAxis(&Rotation, &rotaxis, rot); D3DXMatrixTranslation( &Translation, 0.0f, 0.0f, 4.0f ); Transformations =Translation * Rotation; rot += .0005f; WVP = World * Transformations * View * Projection; fxWVPVar->SetMatrix((float*)&WVP); fxDiffuseMapVar->SetResource(DiffuseMapResourceView); D3D10_TECHNIQUE_DESC techDesc; Technique->GetDesc( &techDesc ); ////////////////////new////////////////////////////////////////////////////////////////////// d3dDevice->RSSetState(noCull); //Draw objects that will use backface culling ////////////////////new////////////////////////////////////////////////////////////////////// ////////////////////new////////////////////////////////////////////////////////////////////// d3dDevice->RSSetState(noCull); ////////////////////new////////////////////////////////////////////////////////////////////// //draw first cube for( UINT p = 0; p < techDesc.Passes; ++p ) { Technique->GetPassByIndex( p )->Apply( 0 ); d3dDevice->DrawIndexed(36, 0, 0); } D3DXMatrixRotationAxis(&Rotation, &rotaxis, -rot); D3DXMatrixScaling( &Scale, 1.3f, 1.3f, 1.3f ); Transformations = Rotation * Scale; WVP = World * Transformations * View * Projection; fxWVPVar->SetMatrix((float*)&WVP); //draw second cube for( UINT p = 0; p < techDesc.Passes; ++p ) { Technique->GetPassByIndex( p )->Apply( 0 ); d3dDevice->DrawIndexed(36, 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; }; Texture2D DiffuseMap; SamplerState TriLinearSample { Filter = MIN_MAG_MIP_LINEAR; }; struct VS_OUTPUT //output structure for vertex shader { float4 Pos : SV_POSITION; float2 texCoord : TEXCOORD; }; // Vertex Shader VS_OUTPUT VS(float4 inPos : POSITION, float2 inTexCoord : TEXCOORD) { VS_OUTPUT output = (VS_OUTPUT)0; output.Pos = mul(inPos, WVP); output.texCoord = inTexCoord; return output; //send color and position to pixel shader } // Pixel Shader float4 PS(VS_OUTPUT input) : SV_Target { float4 diffuse = DiffuseMap.Sample( TriLinearSample, input.texCoord ); clip (diffuse.a - .25); return diffuse; // Set the color of the pixel to the corresponding texel in the loaded image is. } technique10 Tech { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } }
Sign in to comment