This tutorial is part of a Collection: 03. DirectX 11 - Braynzar Soft Tutorials
13239
views
12. Blending
Here we will learn about a technique called "blending"! This will give us the ability to render "transparent" primitives. This lesson builds off the last lesson "Textures". We will add blending to our lesson, so the two boxes will look like they are made of stained glass or something. We will also learn about a problem when rendering transparent objects, where they are transparent to each other sometimes, and sometimes they are not transparent to each other at all.
DX11_Lesson_12_Blend...zip 85.9 kb
1319 downloads
##Introduction## We will learn how to impliment a blending effect to make our primitives appear transparent. We will also cover a problem when rendering more than one transparent primitive, where sometimes it appears transparent but other times appears opaque, or at least opaque to the transparent objects behind it. ##The Blending Equation.## In Direct3D, to create the illusion of transparency, we use an equation, which will take the pixels behind the transparent primitive on the render target and blend their colors with the current transparent primitives pixels. I will now explain the blending equation: (FC) - Final Color (SP) - Source Pixel (DP) - Destination Pixel (SBF) - Source Blend Factor (DBF) - Destination Blend Factor (FA) - Final Alpha (SA) - Source Alpha (DA) - Destination Alpha (+) - Binaray Operator described below (X) - Cross Multiply Matrices Direct3d uses two different blending equations. One for color, and one for alpha. There are two different equations for color and alpha because we are able to process them both differently if we want, using different operators and different blend factors. The two equationes are as follows: (FC) = (SP) (X) (SBF) (+) (DP) (X) (DPF) (FA) = (SA)(SBF) (+) (DA)(DBF) The binary (+) operator can be one of the following: typedef enum D3D11_BLEND_OP { D3D11_BLEND_OP_ADD = 1, D3D11_BLEND_OP_SUBTRACT = 2, D3D11_BLEND_OP_REV_SUBTRACT = 3, D3D11_BLEND_OP_MIN = 4, D3D11_BLEND_OP_MAX = 5 } D3D11_BLEND_OP; Play with them to get an idea of the different effects they cause. We use the blend factors to achieve different effects when blending. We can set the blend factors with the D3D11_BLEND enumerated type. Play with the following to see the different effects we can get when blending: typedef enum D3D11_BLEND { D3D11_BLEND_ZERO = 1, D3D11_BLEND_ONE = 2, D3D11_BLEND_SRC_COLOR = 3, D3D11_BLEND_INV_SRC_COLOR = 4, D3D11_BLEND_SRC_ALPHA = 5, D3D11_BLEND_INV_SRC_ALPHA = 6, D3D11_BLEND_DEST_ALPHA = 7, D3D11_BLEND_INV_DEST_ALPHA = 8, D3D11_BLEND_DEST_COLOR = 9, D3D11_BLEND_INV_DEST_COLOR = 10, D3D11_BLEND_SRC_ALPHA_SAT = 11, D3D11_BLEND_BLEND_FACTOR = 14, D3D11_BLEND_INV_BLEND_FACTOR = 15, D3D11_BLEND_SRC1_COLOR = 16, D3D11_BLEND_INV_SRC1_COLOR = 17, D3D11_BLEND_SRC1_ALPHA = 18, D3D11_BLEND_INV_SRC1_ALPHA = 19 } D3D11_BLEND; **D3D11_BLEND_ZERO -** *The data source is the color black (0, 0, 0, 0). No pre-blend operation.* **D3D11_BLEND_ONE -** *The data source is the color white (1, 1, 1, 1). No pre-blend operation.* **D3D11_BLEND_SRC_COLOR -** *The data source is color data (RGB) from a pixel shader. No pre-blend operation.* **D3D11_BLEND_INV_SRC_COLOR -** *The data source is color data (RGB) from a pixel shader. The pre-blend operation inverts the data, generating 1 - RGB.* **D3D11_BLEND_SRC_ALPHA -** *The data source is alpha data (A) from a pixel shader. No pre-blend operation.* **D3D11_BLEND_INV_SRC_ALPHA -** *The data source is alpha data (A) from a pixel shader. The pre-blend operation inverts the data, generating 1 - A.* **D3D11_BLEND_DEST_ALPHA -** *The data source is alpha data from a rendertarget. No pre-blend operation.* **D3D11_BLEND_INV_DEST_ALPHA -** *The data source is alpha data from a rendertarget. The pre-blend operation inverts the data, generating 1 - A.* **D3D11_BLEND_DEST_COLOR -** *The data source is color data from a rendertarget. No pre-blend operation.* **D3D11_BLEND_INV_DEST_COLOR -** *The data source is color data from a rendertarget. The pre-blend operation inverts the data, generating 1 - RGB.* **D3D11_BLEND_SRC_ALPHA_SAT -** *The data source is alpha data from a pixel shader. The pre-blend operation clamps the data to 1 or less.* **D3D11_BLEND_BLEND_FACTOR -** *The data source is the blend factor set with ID3D10Device::OMSetBlendState. No pre-blend operation.* **D3D11_BLEND_INV_BLEND_FACTOR -** *The data source is the blend factor set with ID3D10Device::OMSetBlendState. The pre-blend operation inverts the blend factor, generating 1 - blend_factor.* **D3D11_BLEND_SRC1_COLOR -** *The data sources are both color data output by a pixel shader. There is no pre-blend operation. This options supports dual-source color blending.* **D3D11_BLEND_INV_SRC1_COLOR -** *The data sources are both color data output by a pixel shader. The pre-blend operation inverts the data, generating 1 - RGB. This options supports dual-source color blending.* **D3D11_BLEND_SRC1_ALPHA -** *The data sources are alpha data output by a pixel shader. There is no pre-blend operation. This options supports dual-source color blending.* **D3D11_BLEND_INV_SRC1_ALPHA -** *The data sources are alpha data output by a pixel shader. The pre-blend operation inverts the data, generating 1 - A. This options supports dual-source color blending.* ^^^From msdn^^^ Now we need to create a blend description, which tells direct3d how we will be blending our pixels. To create a blend description, we need to fill out a D3D11_BLEND_DESC structure: typedef struct D3D11_BLEND_DESC { BOOL AlphaToCoverageEnable; BOOL IndependentBlendEnable; D3D11_RENDER_TARGET_BLEND_DESC RenderTarget[8]; } D3D11_BLEND_DESC; **AlphaToCoverageEnable -** *Multisampling technique usefull for things like wire fences and stuff, we'll talk about this more in a later lesson, specify true to enable.* **IndependentBlendEnable -** *We are able to blend with more than one render target at a time, specifically 8. Setting this to false will only blend to the RenderTarget[0] description in the array below, and ignore the 1-7 render target descriptions.* **RenderTarget[8] -** *As we mentioned a moment ago, we are able to blend with more than one render target, in fact, we can blend with 8 different render targets. This is an array of up to 8 D3D11_RENDER_TARGET_BLEND_DESC structures, where each element is a blending description for that render target.* typedef struct D3D11_RENDER_TARGET_BLEND_DESC { BOOL BlendEnable; D3D11_BLEND SrcBlend; D3D11_BLEND DestBlend; D3D11_BLEND_OP BlendOp; D3D11_BLEND SrcBlendAlpha; D3D11_BLEND DestBlendAlpha; D3D11_BLEND_OP BlendOpAlpha; UINT8 RenderTargetWriteMask; } D3D11_RENDER_TARGET_BLEND_DESC; **BlendEnable -** *Specify true to enable blending for this render target.* **SrcBlend -** *This is our source blend factor (SBF). We can set this to any of the enumerated D3D11_BLEND types.* **DestBlend -** *This is our destination blend factor (DBF). We can set this to any of the enumerated D3D11_BLEND types.* **BlendOp -** *Here is where we specify the blending operation to use which we discussed earlier. Set this to any of the D3D11_BLEND_OP enumerated types.* **SrcBlendAlpha -** *This is our source blend factor for the alpha channel (SBF). We can set this to any of the enumerated D3D11_BLEND types.* **DestBlendAlpha -** *This is our destination blend factor for the alpha channel (SBF). We can set this to any of the enumerated D3D11_BLEND types.* **BlendOpAlpha -** *Here we specify the blending operation to use for the alpha channels. set this to any of the D3D10_BLEND_OP enumerated types.* **RenderTargetWriteMask -** *This is where we specify which channel to blend. We are able to choose R, G, B, A, All of them, or a combination of them by specifying one of the following flags:* typedef enum D3D11_COLOR_WRITE_ENABLE { D3D11_COLOR_WRITE_ENABLE_RED = 1, D3D11_COLOR_WRITE_ENABLE_GREEN = 2, D3D11_COLOR_WRITE_ENABLE_BLUE = 4, D3D11_COLOR_WRITE_ENABLE_ALPHA = 8, D3D11_COLOR_WRITE_ENABLE_ALL = ( D3D11_COLOR_WRITE_ENABLE_RED | D3D11_COLOR_WRITE_ENABLE_GREEN | D3D11_COLOR_WRITE_ENABLE_BLUE | D3D11_COLOR_WRITE_ENABLE_ALPHA ) } D3D11_COLOR_WRITE_ENABLE; ##Transparent Object's Depth Order.## Now I will explain a little problem we must deal with if we either want to see the backside of a transparent object, or if there are multiple transparent objects in a scene. As by now you know, When rendering a transparent object, We take whatever is ALREADY on the render target and blend the transparent objects with that. This is why it is important to render ALL opaque objects in the scene first, then render the transparent objects, so that the transparent objects can blend with the opaque objects. But, this is where we can run into a problem when rendering the transparent objects. Think about this lessons two boxes. When we first render the boxes, the first box that orbits the second box starts out behind the second box, and is rendered first in code. So that when the second box is rendered, it is able to blend with the first box, since the first box is already on the render target. However, when the first box rotates around the second box, and comes in front of the second box, It will not be blending with the second box, since the second box was not already on the render target to be blended with (the first box is rendered before the second box). To solve this problem, we will find the distance between both boxes and the camera. Whichever box is further from the camera will be rendered first. If you have many transparent objects, it would be best to create a vector, and organize the vector every frame, from the furthest from the camera to the closest, and draw the transparent objects from the vector from beginning to end. Well, we have that problem taken care of. But there is actually one more problem, and that has to do with the order our boxes own primitives are drawn. When we draw our box, they appear to be opaque, except for when the other box passes behind it. This happens because of culling. by default, direct3d culls counter-clockwise faces. this means that if you drew the triangles vertices counter-clockwise from the cameras position, You will not see that triangle. So by default, you can only see triangles that were drawn clockwise. So by default, we cannot see the back side of the box, so when the front side of the box is drawn, there is not backside to blend with. We can turn off the culling order, so that both sides of the triangle will be drawn to the render target, no matter which way they are facing. But this is not enough to complete our blending box lesson. A problem with this, is that some faces will be drawn before the others, so when the faces that are drawn before the others are closer to the camera, they don't have the other faces to blend with at the time, so the box's sides will sometimes appeare opaque, and other times appear invisible. Now finally, to fix this last problem, we can the box twice, first we draw it so that we can see the back sides of the faces (Or inside faces of the box), so when the front side (outside faces) of the box is drawn, it has the back sides to blend with. Then we can draw the front sides (or outside faces) of the box. To do this, we can create two render states. One for counter clockwise culling, and one for clockwise culling. Then we will draw the first box the first time with counter clockwise culling (since we defined its faces in a clockwise order, and we need to draw the inside of the box first), then draw the first box a second time with clockwise culling enabled. I will explain a little about the render states, but We will very soon have a lesson on render states, so i will not go into too much depth in this lesson. OK! Finally! After all that explaining (if you didn't read through all of that, no worries, as blending is not a very complicated thing), we can finally move onto the code! ##Global Declarations## We create one interface to hold our blend state, and two interfaces for our rasterizer states, one for counter clockwise culling, and the other for clockwise. ID3D11BlendState* Transparency; ID3D11RasterizerState* CCWcullMode; ID3D11RasterizerState* CWcullMode; ##Clean Up## Don't Forget ;) 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(); ///////////////**************new**************//////////////////// Transparency->Release(); CCWcullMode->Release(); CWcullMode->Release(); ///////////////**************new**************//////////////////// } ##The Blending Equation## Now, at the bottom of our init scene function, we will define our blending equation, then create it. We can create the blending State by calling the ID3D11Device::CreateBlendState(), where the first parameter is a pointer to our blending description, and the second is a pointer to an ID3D11BlendState interface. D3D11_BLEND_DESC blendDesc; ZeroMemory( &blendDesc, sizeof(blendDesc) ); D3D11_RENDER_TARGET_BLEND_DESC rtbd; ZeroMemory( &rtbd, sizeof(rtbd) ); rtbd.BlendEnable = true; rtbd.SrcBlend = D3D11_BLEND_SRC_COLOR; rtbd.DestBlend = D3D11_BLEND_BLEND_FACTOR; rtbd.BlendOp = D3D11_BLEND_OP_ADD; rtbd.SrcBlendAlpha = D3D11_BLEND_ONE; rtbd.DestBlendAlpha = D3D11_BLEND_ZERO; rtbd.BlendOpAlpha = D3D11_BLEND_OP_ADD; rtbd.RenderTargetWriteMask = D3D10_COLOR_WRITE_ENABLE_ALL; blendDesc.AlphaToCoverageEnable = false; blendDesc.RenderTarget[0] = rtbd; d3d11Device->CreateBlendState(&blendDesc, &Transparency); ##CW & CCW Culling## Here, we create the two rasterizer states, CW and CCW cull modes. This is so we can draw our boxes twice each, so we can see the backside of the boxes through the front side while they spin. We fill out a rasterizer state description, which is a D3D11_RASTERIZER_DESC structure. We will cover this in a lesson ver soon. Then we can create the rasterizer state by calling the method ID3D11Device::CreateRasterizerState() D3D11_RASTERIZER_DESC cmdesc; ZeroMemory(&cmdesc, sizeof(D3D11_RASTERIZER_DESC)); cmdesc.FillMode = D3D11_FILL_SOLID; cmdesc.CullMode = D3D11_CULL_BACK; cmdesc.FrontCounterClockwise = true; hr = d3d11Device->CreateRasterizerState(&cmdesc, &CCWcullMode); cmdesc.FrontCounterClockwise = false; hr = d3d11Device->CreateRasterizerState(&cmdesc, &CWcullMode); ##DrawScene() Function## Let's take a look at our DrawScene() function. 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**************//////////////////// //"fine-tune" the blending equation float blendFactor[] = {0.75f, 0.75f, 0.75f, 1.0f}; //Set the default blend state (no blending) for opaque objects d3d11DevCon->OMSetBlendState(0, 0, 0xffffffff); //Render opaque objects// //Set the blend state for transparent objects d3d11DevCon->OMSetBlendState(Transparency, blendFactor, 0xffffffff); //*****Transparency Depth Ordering*****// //Find which transparent object is further from the camera //So we can render the objects in depth order to the render target //Find distance from first cube to camera XMVECTOR cubePos = XMVectorZero(); cubePos = XMVector3TransformCoord(cubePos, cube1World); float distX = XMVectorGetX(cubePos) - XMVectorGetX(camPosition); float distY = XMVectorGetY(cubePos) - XMVectorGetY(camPosition); float distZ = XMVectorGetZ(cubePos) - XMVectorGetZ(camPosition); float cube1Dist = distX*distX + distY*distY + distZ*distZ; //Find distance from second cube to camera cubePos = XMVectorZero(); cubePos = XMVector3TransformCoord(cubePos, cube2World); distX = XMVectorGetX(cubePos) - XMVectorGetX(camPosition); distY = XMVectorGetY(cubePos) - XMVectorGetY(camPosition); distZ = XMVectorGetZ(cubePos) - XMVectorGetZ(camPosition); float cube2Dist = distX*distX + distY*distY + distZ*distZ; //If the first cubes distance is less than the second cubes if(cube1Dist < cube2Dist) { //Switch the order in which the cubes are drawn XMMATRIX tempMatrix = cube1World; cube1World = cube2World; cube2World = tempMatrix; } ///////////////**************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 ); d3d11DevCon->PSSetShaderResources( 0, 1, &CubesTexture ); d3d11DevCon->PSSetSamplers( 0, 1, &CubesTexSamplerState ); ///////////////**************new**************//////////////////// //Counter clockwise culling first because we need the back side of //the cube to be rendered first, so the front side can blend with it d3d11DevCon->RSSetState(CCWcullMode); ///////////////**************new**************//////////////////// //Draw the first cube d3d11DevCon->DrawIndexed( 36, 0, 0 ); ///////////////**************new**************//////////////////// d3d11DevCon->RSSetState(CWcullMode); d3d11DevCon->DrawIndexed( 36, 0, 0 ); ///////////////**************new**************//////////////////// WVP = cube2World * camView * camProjection; cbPerObj.WVP = XMMatrixTranspose(WVP); d3d11DevCon->UpdateSubresource( cbPerObjectBuffer, 0, NULL, &cbPerObj, 0, 0 ); d3d11DevCon->VSSetConstantBuffers( 0, 1, &cbPerObjectBuffer ); d3d11DevCon->PSSetShaderResources( 0, 1, &CubesTexture ); d3d11DevCon->PSSetSamplers( 0, 1, &CubesTexSamplerState ); ///////////////**************new**************//////////////////// d3d11DevCon->RSSetState(CCWcullMode); ///////////////**************new**************//////////////////// //Draw the second cube d3d11DevCon->DrawIndexed( 36, 0, 0 ); ///////////////**************new**************//////////////////// d3d11DevCon->RSSetState(CWcullMode); d3d11DevCon->DrawIndexed( 36, 0, 0 ); ///////////////**************new**************//////////////////// //Present the backbuffer to the screen SwapChain->Present(0, 0); } ##Enabling & Disabling Blending## ( ID3D11DeviceContext::OMSetBlendState() ) Ok, the first three new lines in our function. Remember, blending works by taking whats already on the render target, and blending the current objects colors with whats already there. So, this being the case, we need to make sure we render the opaque objects first, so that the transparent objects can blend with the opaque objects. The first line is a blend factor, which we talked about at the beginning of this lesson. We will use this blend factor to determine the transparency of our boxes. This blend factor says that the red, green, and blue colors on the current primitive will be 25% transparent. This could also mean that the primitive will be 75% transparent, or even nothing if you were to change the blending description. The next line will disable the blend state, so that we can draw our opaque objects. We can turn off blending by setting the first two parameters here to NULL, and the third to 0xffffffff. Then we turn blending on, by calling the method. The ID3D11DeviceContext::OMSetBlendState() method binds the blend state of our choice to the OM stage of the pipeline, where it will use the blending equation to impliment the transparent effect (blending is not always transparent, you can do many things with blending). The first parameter is the ID3D11BlendState object, the second is an array of 4 floats (RGBA), and the last has to do with sample coveraging, 0xffffffff is the default. float blendFactor[] = {0.75f, 0.75f, 0.75f, 1.0f}; d3d11DevCon->OMSetBlendState(0, 0, 0xffffffff); //Render opaque objects// d3d11DevCon->OMSetBlendState(Transparency, blendFactor, 0xffffffff); ##Depth Ordering## Next we will find which cube is further from the camera, so we can render that one first, so that the cube closer to the camer can blend with the cube thats further away. First we find the distances of both boxes from the camera (cube1Dist and cube2Dist are actually the square of the actual distance. However, sqrt() is an expensive function, and we do not need the exact distances, but we need to find which one is further from the camera. So, if you ever need to find the distance between two vectors, this is how you do it, just remember to find the square root of the answer to find the exact distance.). We then check to see if cube1Dist is smaller than cube2Dist, and if it is, we create a temporary matrix to hold cube1World while we swap cube1World and cube2World. We are able to just swap cube1World and cube2World, as the geometry we are rendering is the exact same for both, they are both boxes and everything about them is the exact same except for their world matrix. In a more flexible verision of this, you would want to put all your transparent objects into a vector of structures (a structure you define, like their position, geometry, textures, etc.), then organize the vector so that the furthest object from the camera is the first in the vector, and the closest to the camera is the last in the vector. Then you would render the objects in the vector from the first to the last. XMVECTOR cubePos = XMVectorZero(); cubePos = XMVector3TransformCoord(cubePos, cube1World); float distX = XMVectorGetX(cubePos) - XMVectorGetX(camPosition); float distY = XMVectorGetY(cubePos) - XMVectorGetY(camPosition); float distZ = XMVectorGetZ(cubePos) - XMVectorGetZ(camPosition); float cube1Dist = distX*distX + distY*distY + distZ*distZ; cubePos = XMVectorZero(); cubePos = XMVector3TransformCoord(cubePos, cube2World); distX = XMVectorGetX(cubePos) - XMVectorGetX(camPosition); distY = XMVectorGetY(cubePos) - XMVectorGetY(camPosition); distZ = XMVectorGetZ(cubePos) - XMVectorGetZ(camPosition); float cube2Dist = distX*distX + distY*distY + distZ*distZ; if(cube1Dist < cube2Dist) { XMMATRIX tempMatrix = cube1World; cube1World = cube2World; cube2World = tempMatrix; } ##Drawing Both Boxes Twice## Next we need to draw our transparent boxes. First we set the rasterizer state by calling the method ID3D11DeviceContext::RSSetState(), and putting our Rasterizer State object as the argument. Then we draw the box. We already talked about, at the beginning why we are drawing both boxes twice. It's so we can see the backside of the box through the front side of the box. //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 ); d3d11DevCon->PSSetShaderResources( 0, 1, &CubesTexture ); d3d11DevCon->PSSetSamplers( 0, 1, &CubesTexSamplerState ); ///////////////**************new**************//////////////////// //Counter clockwise culling first because we need the back side of //the cube to be rendered first, so the front side can blend with it d3d11DevCon->RSSetState(CCWcullMode); ///////////////**************new**************//////////////////// //Draw the first cube d3d11DevCon->DrawIndexed( 36, 0, 0 ); ///////////////**************new**************//////////////////// d3d11DevCon->RSSetState(CWcullMode); d3d11DevCon->DrawIndexed( 36, 0, 0 ); ///////////////**************new**************//////////////////// WVP = cube2World * camView * camProjection; cbPerObj.WVP = XMMatrixTranspose(WVP); d3d11DevCon->UpdateSubresource( cbPerObjectBuffer, 0, NULL, &cbPerObj, 0, 0 ); d3d11DevCon->VSSetConstantBuffers( 0, 1, &cbPerObjectBuffer ); d3d11DevCon->PSSetShaderResources( 0, 1, &CubesTexture ); d3d11DevCon->PSSetSamplers( 0, 1, &CubesTexSamplerState ); ///////////////**************new**************//////////////////// d3d11DevCon->RSSetState(CCWcullMode); ///////////////**************new**************//////////////////// //Draw the second cube d3d11DevCon->DrawIndexed( 36, 0, 0 ); ///////////////**************new**************//////////////////// d3d11DevCon->RSSetState(CWcullMode); d3d11DevCon->DrawIndexed( 36, 0, 0 ); ///////////////**************new**************//////////////////// It might seem like there was a lot of information here, but really, blending is not a very difficult thing to understand, so i hope you got what you could out of this! ##Exercise:## 1. Play with the blending description and blend factor! 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; ID3D11ShaderResourceView* CubesTexture; ID3D11SamplerState* CubesTexSamplerState; ///////////////**************new**************//////////////////// ID3D11BlendState* Transparency; ID3D11RasterizerState* CCWcullMode; ID3D11RasterizerState* CWcullMode; ///////////////**************new**************//////////////////// //Global Declarations - Others// LPCTSTR WndClassName = L"firstwindow"; HWND hwnd = NULL; HRESULT hr; const int Width = 300; const int Height = 300; XMMATRIX WVP; XMMATRIX cube1World; XMMATRIX cube2World; XMMATRIX camView; XMMATRIX camProjection; XMVECTOR camPosition; XMVECTOR camTarget; XMVECTOR camUp; XMMATRIX Rotation; XMMATRIX Scale; XMMATRIX Translation; float rot = 0.01f; //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 u, float v) : pos(x,y,z), texCoord(u, v){} XMFLOAT3 pos; XMFLOAT2 texCoord; }; D3D11_INPUT_ELEMENT_DESC layout[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "TEXCOORD", 0, DXGI_FORMAT_R32G32_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(); ///////////////**************new**************//////////////////// Transparency->Release(); CCWcullMode->Release(); CWcullMode->Release(); ///////////////**************new**************//////////////////// } 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); //Create the vertex buffer Vertex v[] = { // Front Face Vertex(-1.0f, -1.0f, -1.0f, 0.0f, 1.0f), Vertex(-1.0f, 1.0f, -1.0f, 0.0f, 0.0f), Vertex( 1.0f, 1.0f, -1.0f, 1.0f, 0.0f), Vertex( 1.0f, -1.0f, -1.0f, 1.0f, 1.0f), // Back Face Vertex(-1.0f, -1.0f, 1.0f, 1.0f, 1.0f), Vertex( 1.0f, -1.0f, 1.0f, 0.0f, 1.0f), Vertex( 1.0f, 1.0f, 1.0f, 0.0f, 0.0f), Vertex(-1.0f, 1.0f, 1.0f, 1.0f, 0.0f), // Top Face Vertex(-1.0f, 1.0f, -1.0f, 0.0f, 1.0f), Vertex(-1.0f, 1.0f, 1.0f, 0.0f, 0.0f), Vertex( 1.0f, 1.0f, 1.0f, 1.0f, 0.0f), Vertex( 1.0f, 1.0f, -1.0f, 1.0f, 1.0f), // Bottom Face Vertex(-1.0f, -1.0f, -1.0f, 1.0f, 1.0f), Vertex( 1.0f, -1.0f, -1.0f, 0.0f, 1.0f), Vertex( 1.0f, -1.0f, 1.0f, 0.0f, 0.0f), Vertex(-1.0f, -1.0f, 1.0f, 1.0f, 0.0f), // Left Face Vertex(-1.0f, -1.0f, 1.0f, 0.0f, 1.0f), Vertex(-1.0f, 1.0f, 1.0f, 0.0f, 0.0f), Vertex(-1.0f, 1.0f, -1.0f, 1.0f, 0.0f), Vertex(-1.0f, -1.0f, -1.0f, 1.0f, 1.0f), // Right Face Vertex( 1.0f, -1.0f, -1.0f, 0.0f, 1.0f), Vertex( 1.0f, 1.0f, -1.0f, 0.0f, 0.0f), Vertex( 1.0f, 1.0f, 1.0f, 1.0f, 0.0f), Vertex( 1.0f, -1.0f, 1.0f, 1.0f, 1.0f), }; DWORD indices[] = { // Front Face 0, 1, 2, 0, 2, 3, // Back Face 4, 5, 6, 4, 6, 7, // Top Face 8, 9, 10, 8, 10, 11, // Bottom Face 12, 13, 14, 12, 14, 15, // Left Face 16, 17, 18, 16, 18, 19, // Right Face 20, 21, 22, 20, 22, 23 }; 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 ) * 24; vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; vertexBufferDesc.CPUAccessFlags = 0; vertexBufferDesc.MiscFlags = 0; 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 camPosition = XMVectorSet( 0.0f, 3.0f, -8.0f, 0.0f ); 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); hr = D3DX11CreateShaderResourceViewFromFile( d3d11Device, L"braynzar.jpg", NULL, NULL, &CubesTexture, NULL ); // Describe the Sample State D3D11_SAMPLER_DESC sampDesc; ZeroMemory( &sampDesc, sizeof(sampDesc) ); sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER; sampDesc.MinLOD = 0; sampDesc.MaxLOD = D3D11_FLOAT32_MAX; //Create the Sample State hr = d3d11Device->CreateSamplerState( &sampDesc, &CubesTexSamplerState ); ///////////////**************new**************//////////////////// //Define the Blending Equation D3D11_BLEND_DESC blendDesc; ZeroMemory( &blendDesc, sizeof(blendDesc) ); D3D11_RENDER_TARGET_BLEND_DESC rtbd; ZeroMemory( &rtbd, sizeof(rtbd) ); rtbd.BlendEnable = true; rtbd.SrcBlend = D3D11_BLEND_SRC_COLOR; rtbd.DestBlend = D3D11_BLEND_BLEND_FACTOR; rtbd.BlendOp = D3D11_BLEND_OP_ADD; rtbd.SrcBlendAlpha = D3D11_BLEND_ONE; rtbd.DestBlendAlpha = D3D11_BLEND_ZERO; rtbd.BlendOpAlpha = D3D11_BLEND_OP_ADD; rtbd.RenderTargetWriteMask = D3D10_COLOR_WRITE_ENABLE_ALL; blendDesc.AlphaToCoverageEnable = false; blendDesc.RenderTarget[0] = rtbd; d3d11Device->CreateBlendState(&blendDesc, &Transparency); //Create the Counter Clockwise and Clockwise Culling States D3D11_RASTERIZER_DESC cmdesc; ZeroMemory(&cmdesc, sizeof(D3D11_RASTERIZER_DESC)); cmdesc.FillMode = D3D11_FILL_SOLID; cmdesc.CullMode = D3D11_CULL_BACK; cmdesc.FrontCounterClockwise = true; hr = d3d11Device->CreateRasterizerState(&cmdesc, &CCWcullMode); cmdesc.FrontCounterClockwise = false; hr = d3d11Device->CreateRasterizerState(&cmdesc, &CWcullMode); ///////////////**************new**************//////////////////// return true; } 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; } 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**************//////////////////// //"fine-tune" the blending equation float blendFactor[] = {0.75f, 0.75f, 0.75f, 1.0f}; //Set the default blend state (no blending) for opaque objects d3d11DevCon->OMSetBlendState(0, 0, 0xffffffff); //Render opaque objects// //Set the blend state for transparent objects d3d11DevCon->OMSetBlendState(Transparency, blendFactor, 0xffffffff); //*****Transparency Depth Ordering*****// //Find which transparent object is further from the camera //So we can render the objects in depth order to the render target //Find distance from first cube to camera XMVECTOR cubePos = XMVectorZero(); cubePos = XMVector3TransformCoord(cubePos, cube1World); float distX = XMVectorGetX(cubePos) - XMVectorGetX(camPosition); float distY = XMVectorGetY(cubePos) - XMVectorGetY(camPosition); float distZ = XMVectorGetZ(cubePos) - XMVectorGetZ(camPosition); float cube1Dist = distX*distX + distY*distY + distZ*distZ; //Find distance from second cube to camera cubePos = XMVectorZero(); cubePos = XMVector3TransformCoord(cubePos, cube2World); distX = XMVectorGetX(cubePos) - XMVectorGetX(camPosition); distY = XMVectorGetY(cubePos) - XMVectorGetY(camPosition); distZ = XMVectorGetZ(cubePos) - XMVectorGetZ(camPosition); float cube2Dist = distX*distX + distY*distY + distZ*distZ; //If the first cubes distance is less than the second cubes if(cube1Dist < cube2Dist) { //Switch the order in which the cubes are drawn XMMATRIX tempMatrix = cube1World; cube1World = cube2World; cube2World = tempMatrix; } ///////////////**************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 ); d3d11DevCon->PSSetShaderResources( 0, 1, &CubesTexture ); d3d11DevCon->PSSetSamplers( 0, 1, &CubesTexSamplerState ); ///////////////**************new**************//////////////////// //Counter clockwise culling first because we need the back side of //the cube to be rendered first, so the front side can blend with it d3d11DevCon->RSSetState(CCWcullMode); ///////////////**************new**************//////////////////// //Draw the first cube d3d11DevCon->DrawIndexed( 36, 0, 0 ); ///////////////**************new**************//////////////////// d3d11DevCon->RSSetState(CWcullMode); d3d11DevCon->DrawIndexed( 36, 0, 0 ); ///////////////**************new**************//////////////////// WVP = cube2World * camView * camProjection; cbPerObj.WVP = XMMatrixTranspose(WVP); d3d11DevCon->UpdateSubresource( cbPerObjectBuffer, 0, NULL, &cbPerObj, 0, 0 ); d3d11DevCon->VSSetConstantBuffers( 0, 1, &cbPerObjectBuffer ); d3d11DevCon->PSSetShaderResources( 0, 1, &CubesTexture ); d3d11DevCon->PSSetSamplers( 0, 1, &CubesTexSamplerState ); ///////////////**************new**************//////////////////// d3d11DevCon->RSSetState(CCWcullMode); ///////////////**************new**************//////////////////// //Draw the second cube d3d11DevCon->DrawIndexed( 36, 0, 0 ); ///////////////**************new**************//////////////////// d3d11DevCon->RSSetState(CWcullMode); 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; }; Texture2D ObjTexture; SamplerState ObjSamplerState; struct VS_OUTPUT { float4 Pos : SV_POSITION; float2 TexCoord : TEXCOORD; }; VS_OUTPUT VS(float4 inPos : POSITION, float2 inTexCoord : TEXCOORD) { VS_OUTPUT output; output.Pos = mul(inPos, WVP); output.TexCoord = inTexCoord; return output; } float4 PS(VS_OUTPUT input) : SV_TARGET { return ObjTexture.Sample( ObjSamplerState, input.TexCoord ); }
How can i access pixel colors of destination pixel in pixel shader in order to use my specific blending equation i want to add in pixel shader ,
When control goes to pixel shader i only have the source pixel position and color, i want to know what is the color of destination pixel at that time..?
on Sep 26 `17
AkshitVerma
I don't understand why you ahve to change the position between two cubes in the case of you have already make sure the render order!
on Nov 13 `17
benyang
Sign in to comment