12.混合
在这里,我们将学习一种名为“混合”的技术!这将使我们能够渲染“透明”基本体。
本课程建立在上一个课程“纹理”的基础上。我们将在课程中添加混合元素,使两个盒子看起来像是由彩色玻璃或其他东西制成的。
我们还将了解渲染透明对象时的一个问题,即它们有时对彼此透明,有时对彼此根本不透明。
源码下载:https://www.braynzarsoft.net/file/12
介绍
我们将学习如何实现混合效果,使我们的基元看起来透明。我们还将讨论渲染多个透明基本体时的一个问题,有时它看起来是透明的,但有时看起来是不透明的,或者至少对它后面的透明对象是不透明的。
混合方程式
在Direct3D中,为了创建透明的错觉,我们使用了一个等式,该等式将获取渲染目标上透明基本体后面的像素,并将其颜色与当前透明基本体像素混合。现在我将解释混合方程式:
(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使用两种不同的混合方程式。一个用于颜色,一个用于alpha。对于颜色和alpha,有两个不同的方程,因为如果需要,我们可以使用不同的运算符和不同的混合因子对它们进行不同的处理。这两个等式如下:
(FC) = (SP) (X) (SBF) (+) (DP) (X) (DPF)
(FA) = (SA)(SBF) (+) (DA)(DBF)
进制(+)运算符可以是以下运算符之一:
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;
我们使用混合因子来实现混合时的不同效果。我们可以使用D3D11_BLEND枚举类型设置混合因子。播放以下内容以查看混合时可以获得的不同效果:
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-数据源为黑色(0,0,0)。无预混合操作。
- D3D11_BLEND_ONE-数据源为白色(1,1,1)。无预混合操作。
- D3D11_BLEND_SRC_COLOR-数据源是来自像素着色器的颜色数据(RGB)。无预混合操作。
- D3D11_BLEND_INV_SRC_COLOR-数据源是来自像素着色器的颜色数据(RGB)。预混合操作反转数据,生成1-RGB。
- D3D11_BLEND_SRC_ALPHA-数据源是来自像素着色器的ALPHA数据(A)。无预混合操作。
- D3D11_BLEND_INV_SRC_ALPHA-数据源是来自像素着色器的ALPHA数据(A)。预混合操作反转数据,生成1-A。
- D3D11_BLEND_DEST_ALPHA-数据源是来自rendertarget的ALPHA数据。无预混合操作。
- D3D11_BLEND_INV_DEST_ALPHA-数据源是来自rendertarget的ALPHA数据。预混合操作反转数据,生成1-A。
- D3D11_BLEND_DEST_COLOR-数据源是来自渲染目标的颜色数据。无预混合操作。
- D3D11_BLEND_INV_DEST_COLOR-数据源是来自渲染目标的颜色数据。预混合操作反转数据,生成1-RGB。
- D3D11_BLEND_SRC_ALPHA_SAT-数据源是来自像素着色器的ALPHA数据。预混合操作将数据钳制为1或更小。
- D3D11_BLEND_BLEND_FACTOR-数据源是使用ID3D10Device::OMSetBlendState设置的混合因子。无预混合操作。
- D3D11_BLEND_INV_BLEND_FACTOR-数据源是使用ID3D10Device::OMSetBlendState设置的混合因子。预混合操作反转混合因子,生成1-blend_factor。
- D3D11_BLEND_SRC1_COLOR-数据源都是由像素着色器输出的颜色数据。没有预混合操作。此选项支持双光源颜色混合。
- D3D11_BLEND_INV_SRC1_COLOR-数据源都是由像素着色器输出的颜色数据。预混合操作反转数据,生成1-RGB。此选项支持双光源颜色混合。
- D3D11_BLEND_SRC1_ALPHA-数据源是像素着色器输出的ALPHA数据。没有预混合操作。此选项支持双光源颜色混合。
- D3D11_BLEND_INV_SRC1_ALPHA-数据源是像素着色器输出的ALPHA数据。预混合操作反转数据,生成1-A。此选项支持双光源颜色混合。
在我们需要创建一个混合描述,它告诉direct3d我们将如何混合我们的像素。要创建混合描述,我们需要填写D3D11_blend_DESC结构:
typedef struct D3D11_BLEND_DESC {
BOOL AlphaToCoverageEnable;
BOOL IndependentBlendEnable;
D3D11_RENDER_TARGET_BLEND_DESC RenderTarget[8];
} D3D11_BLEND_DESC;
- AlphaToCoverageEnable-多采样技术适用于铁丝网之类的东西,我们将在后面的课程中详细讨论这一点,指定true以启用。
- IndependentBlendEnable-我们可以一次与多个渲染目标混合,特别是8个。将其设置为false将仅与下面数组中的RenderTarget[0]描述混合,并忽略1-7个渲染目标描述。
- RenderTarget[8]-正如我们刚才提到的,我们能够与多个渲染目标混合,事实上,我们可以与8个不同的渲染目标混合。这是一个最多包含8个D3D11_RENDER_TARGET_BLEND_DESC结构的数组,其中每个元素都是该渲染目标的混合描述。
- BlendEnable-指定true可启用此渲染目标的混合。
- SrcBlend-这是我们的源混合因子(SBF)。我们可以将其设置为任何枚举的D3D11_BLEND类型。
- DestBlend-这是我们的目的地混合因子(DBF)。我们可以将其设置为任何枚举的D3D11_BLEND类型。
- BlendOp-这里是我们指定要使用的混合操作的地方,我们之前讨论过。将其设置为任何D3D11_BLEND_OP枚举类型。
- SrcBlendAlpha-这是alpha通道(SBF)的源混合因子。我们可以将其设置为任何枚举的D3D11_BLEND类型。
- DestBlendAlpha-这是alpha通道(SBF)的目标混合因子。我们可以将其设置为任何枚举的D3D11_BLEND类型。
- BlendOpAlpha-在这里我们指定用于alpha通道的混合操作。将其设置为任何D3D10_BLEND_OP枚举类型。
- RenderTargetWriteMask-这是我们指定要混合的通道的位置。我们可以通过指定以下标志之一来选择R、G、B、A、All或它们的组合:
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;
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;
透明对象的深度顺序
现在,我将解释一个小问题,如果我们想看到透明对象的背面,或者如果场景中有多个透明对象,我们必须处理这个问题。
正如你现在所知道的,当渲染透明对象时,我们在渲染目标上取任何已经准备好的东西,并将透明对象与之混合。这就是为什么首先渲染场景中的所有不透明对象,然后渲染透明对象非常重要,这样透明对象就可以与不透明对象混合。但是,在渲染透明对象时,这可能会遇到问题。把这节课想成两个方框。当我们第一次渲染长方体时,环绕第二个长方体的第一个长方体从第二个框后面开始,并在代码中首先渲染。这样,当渲染第二个长方体时,它能够与第一个长方体混合,因为第一个长方已经在渲染目标上。但是,当第一个长方体围绕第二个长方体旋转并位于第二个框之前时,它将不会与第二个方框混合,因为第二个箱子还没有在要混合的渲染目标上(第一个箱子在第二个盒子之前渲染)。
为了解决这个问题,我们将找到两个盒子和相机之间的距离。无论哪个长方体离摄影机更远,都将首先进行渲染。如果有许多透明对象,最好创建一个向量,并在每帧从离摄影机最远到最近的位置组织该向量,并从头到尾从该向量绘制透明对象。
好吧,我们已经解决了这个问题。但实际上还有一个问题,那就是我们的盒子自己的基元的绘制顺序。当我们画方框时,它们看起来是不透明的,除非另一个方框从它后面经过。这是因为剔除。默认情况下,direct3d会逆时针剔除面。这意味着,如果从相机位置逆时针绘制三角形顶点,将看不到该三角形。因此,默认情况下,您只能看到顺时针绘制的三角形。因此,默认情况下,我们看不到长方体的背面,因此当绘制长方体的正面时,没有背面可供混合。我们可以关闭剔除顺序,这样三角形的两侧都将被绘制到渲染目标,无论它们面向哪个方向。但这还不足以完成我们的混合盒课程。这样做的一个问题是,有些面会在其他面之前绘制,所以当在其他面前面绘制的面更靠近相机时,它们当时没有其他面可以混合,所以盒子的侧面有时看起来不透明,而其他时候看起来不可见。
最后,为了解决最后一个问题,我们可以对长方体进行两次绘制,首先我们绘制它,这样我们可以看到面的背面(或长方体的内表面),所以当绘制长方体的正面(外表面)时,它有背面可以与之融合。然后我们可以画出盒子的正面(或外面)。为此,我们可以创建两个渲染状态。一个用于逆时针剔除,一个用于顺时针剔除。然后,我们将在第一次使用逆时针剔除的情况下绘制第一个长方体(因为我们以顺时针顺序定义了它的面,并且我们需要先绘制长方体的内部),然后在启用顺时针剔除的条件下第二次绘制第一个框体。我将对渲染状态进行一些解释,但我们很快就会有一堂关于渲染状态的课,所以我不会在这节课中过多深入。
好啊最后经过所有这些解释(如果你没有通读所有这些,不用担心,因为混合并不是一件很复杂的事情),我们终于可以进入代码了!
全局声明
ID3D11BlendState* Transparency;
ID3D11RasterizerState* CCWcullMode;
ID3D11RasterizerState* CWcullMode;
清除
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**************////////////////////
}
混合方程
现在,在init scene函数的底部,我们将定义我们的混合方程,然后创建它。我们可以通过调用ID3D11Device::CreateBlendState()来创建混合状态,其中第一个参数是指向混合描述的指针,第二个是指向ID3D11BlendState接口的指针。
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剔除模式。这样我们就可以画两次盒子,每个盒子旋转时,我们可以从正面看到盒子的背面。我们填写光栅化器状态描述,它是D3D11_RASTERIZER_DESC结构。我们很快将在一节课中介绍这一点。然后我们可以通过调用方法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);
绘制函数
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);
}
禁用启用混合
好的,我们函数中的前三行。记住,混合的工作原理是采用渲染目标上已经存在的内容,并将当前对象的颜色与已经存在的颜色混合。因此,在这种情况下,我们需要确保首先渲染不透明对象,以便透明对象可以与不透明对象混合。
第一行是一个混合因素,我们在本课开始时谈到了这一点。我们将使用此混合因子来确定方框的透明度。此混合因子表示当前基本体上的红色、绿色和蓝色将是25%透明的。这也可能意味着,如果要更改混合描述,基本体将是75%透明的,甚至没有透明。
下一行将禁用混合状态,以便我们可以绘制不透明对象。我们可以通过将此处的前两个参数设置为NULL,将第三个设置为0xffffff来关闭混合。然后我们通过调用方法来启用混合。
ID3D11DeviceContext::OMSetBlendState()方法将我们选择的混合状态绑定到管道的OM阶段,在那里它将使用混合方程来实现透明效果(混合并不总是透明的,您可以使用混合做很多事情)。第一个参数是ID3D11BlendState对象,第二个参数是4个浮点(RGBA)的数组,最后一个参数与采样覆盖有关,默认值为0xffffffff。
float blendFactor[] = {0.75f, 0.75f, 0.75f, 1.0f};
d3d11DevCon->OMSetBlendState(0, 0, 0xffffffff);
//Render opaque objects//
d3d11DevCon->OMSetBlendState(Transparency, blendFactor, 0xffffffff);
深度顺序
接下来,我们将找到哪个立方体离相机更远,所以我们可以先渲染那个立方体,这样离相机更近的立方体可以与离相机更远的立方体混合。首先,我们找到两个盒子离相机的距离(cube1Dist和cube2Dist实际上是实际距离的平方。然而,sqrt()是一个昂贵的函数,我们不需要确切的距离,但我们需要找到哪一个离相机更远。所以,如果你需要找到两个向量之间的距离,这就是你的方法,只需记住找到答案的平方根,就可以找到确切的距离。)。然后,我们检查cube1Dist是否小于cube2Dist,如果是,我们创建一个临时矩阵来保存cube1World,同时交换cube1Dorld和cube2World。
我们可以只交换cube1World和cube2World,因为我们渲染的几何图形对两者来说都是完全相同的,它们都是长方体,除了它们的世界矩阵之外,它们周围的一切都完全相同。在更灵活的版本中,您可以将所有透明对象放入一个结构向量(您定义的结构,如它们的位置、几何图形、纹理等)中,然后组织向量,使离相机最远的对象位于向量中的第一个,离相机最近的对象位于矢量中的最后一个。然后,从第一个到最后一个渲染矢量中的对象。
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;
}
两次绘制盒子
接下来我们需要画出透明的盒子。首先,我们通过调用方法ID3D11DeviceContext::RSSetState()来设置光栅化器状态,并将我们的rasterizer state对象作为参数。然后我们画盒子。我们一开始就已经讨论过为什么我们要两次画这两个方框。这样我们就可以通过盒子的正面看到盒子的背面。
//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**************////////////////////
这里似乎有很多信息,但实际上,混合并不是一件很难理解的事情,所以我希望你能从中得到什么!
练习
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 );
}