D3D11 简单光照

有四种类型光照以及三种光源。本章将介绍使用一个“定向”光源如何实现简单光照。在随后的章节会介绍其他两种类型的光源和镜面光照。

光照对于视频游戏的真实外观和感觉是非常重要的。

由于固定功能管线从directx10中删除了,因此现在需要人工实现光照了。一般地,光照模型越精确,计算量就越大以及越复杂。在视频游戏中,在保持游戏运行在30fps及以上同时,需要找到一种方式来实现光照。当为一个电影做场景模型时,由于每一帧都是提前渲染好的,能够承担只花费数小时而不是好几天来渲染一帧。本节将会学习到如何实现简单光照,定向光照,也叫做平行光照。

当为了找到光击中的像素颜色而做计算时,在颜色变量中的颜色值可能比1大或比0小。为了解决这个问题,就要使用HLSL语言中叫做saturate的函数。

光照类型

可将不同种类的光照分为以下四组:

环境光:

环境光是场景的一部分,它不是由光源直接照射但是也不是漆黑一片,它可以由其他物体反射或折射的光构成。环境光一般来说是场景中的最低量的光。在现实生活中,环境光就是各种界面反射的光线,它会点亮整个空间,但它不是由光源直射造成的。就像之前所说,动画能够承担复杂的光照模型,且能够计算空间中的所有的光线并点亮整个空间,但是在视频游戏中,没有时间来做这些计算,因此,可以使用一个简单的示例来确保场景部分获得一点能够看清所有事物的光即可。为了获得这个值,做了一个叉乘,是由光的环境颜色和材质的漫反射颜色分量进行叉乘。

比如,LightAmbient(0.5,0.5,0.5)*MaterialDiffuse(0.75,1.0,0.5)=(0.375,0.5,0.25)

漫反射光:

当光撞击物体表面时,在屏幕上所有角度反射的光。在这种情况下,不需要将相机的位置考虑进去。当看到物体被这种光击中时,和我们所观察物体的角度是没有关系的,它仍然会有相同量的光线被反射并进入我们的眼睛。为了找到这个值,首先找出像素是否直接在光源的光线中并且通过lambert的cos法则计算光量:inLight = max(lightDirection*surfaceNormal, 0),随后我们做一个叉乘,由光的漫反射值和材质漫反射值以及表面在光照中的多少的分量叉乘。

比如:inLight = lightDirection(1.0, 1.0, 1.0) * surfaceNormal(1.0,1.0,1.0) = 1(为了简单一点,这里surfaceNormal与lightDirection一样)

1*LightDiffuse(1.0,1.0,1.0)*MaterialDiffuse(0.75,1.0,0.5) = (0.75, 1.0, 0.5)

镜面反射光:

镜面反射光计算量是最大的,它是发生在镜面上的光反射现象。若使用得当,会让整个场景看起来更为真实。

自发光:

自发光与其他光都不一样,是因为它不参与光照的计算。


光源类型:

定向光源(平行光):

D3D11 简单光照_第1张图片

定向光源,也就是大家所熟知的平行光,它没有衰减没有范围,只有方向和颜色。真实世界中的太阳光就是定向光源。但在大尺度的宇宙空间来说,它实际是点光源。

点光源:

D3D11 简单光照_第2张图片

它有一个位置,有一个衰减点或范围,有颜色。它是全方向位的发光。它和定向光源很类似,但是不同点就是远离点光源的物体无法接收到该光源发出的光。还有就是,当计算定向光源时,同样的光源向量就可以用来发现场景中的物体界面是否处于光照内,而对于点光源,它的光源向量是随着点的位置不同而不同的。房间中的一个灯泡或者大尺度上的太阳都是点光源的例子。

聚光灯:

D3D11 简单光照_第3张图片


聚光灯有颜色,方向和位置。它是计算量最大的光源。它是由内锥和外锥构成的,并由内到外衰减。


法线

法线用来定义一个界面正面向哪个方向。这儿,使用它们来确定表面是否位于光中,且表面接收到的光量。转换真实世界的向量使得法线向量不是单位长度,意思是法线向量的值大于1或小于0。为了解决这个问题,调用HLSL语言中的normalize的函数来处理。

法线向量

D3D11 简单光照_第4张图片

当定义顶点时就定义了法线。随后对界面上的每个像素使用该法线以决定像素接收到的光照量。然而,若要创建一个球面的物体时,就要使用法线平均技术来使得球面看起来光滑。反之,若没有使用法线平均技术,则每个三角形的整个表面都会被点亮,而且是独立于周围三角形的,使得球面看起来坑坑洼洼的像波浪一样。

面法线

D3D11 简单光照_第5张图片

面法线和顶点法线是类似的,只是它是决定了一个面的要面对的方向。实际在创建一个物体时,不会去定义面法线的,只会创建顶点法线,再将平均化顶点法线而做成面法线。

法线平均

D3D11 简单光照_第6张图片

法线平均技术可使得光看起来少一点坑坑洼洼的像波浪一样。为了获得法线的平均值,我们获取每个面的法线向量,随后将它们平均。之后,光就会逐渐移动到每一个面上。


全局声明

声明一个存储cbperframe的缓冲,用于传到像素着色器中。

ID3D11Buffer* cbPerFrameBuffer;


更新常量缓冲区

随后发生世界空间的矩阵到效果文件,做这些是为了确保在世界空间中的光能够撞击到物体上。我们将使用世界矩阵来重置世界空间中物体的法线。一个实例就是,当实现一个相机时,实际发生的事情是整个世界都移动到相机周围,而不是相机绕着世界转。因此,当我们实现定向光源时,在剩余世界中光的方向不会改变,所以我们需要计算世界空间的光;或它会看起来光的方向像是随着相机移动的。

struct cbPerObject
{
    XMMATRIX  WVP;
    XMMATRIX  World;
};

光的结构体

我们需要创建一个光的结构体,它要和效果文件中的结构能够匹配。我们需要发送该结构体到像素着色器来填充效果文件的光结构体以实现光照。首先清空结构体,随后创建一个光照结构体。它有成员方向direction,填充pad,环境光ambient,以及漫反射光diffuse。

已经知道方向,环境光,和漫反射光的作用,但是pad是干啥的呢?HLSL将结构体封装为4D的向量。不允许将单个变量分裂为两个4D向量。这就是为什么要使用pad变量。第一个变量dir是XMFLOAT3类型。这是一个3D向量,还记得HLSL如何将变量封装进4D向量吗?下一个成员原本将会是一个XMFLOAT4变量,它是一个4D向量。在它们之间若没有pad变量,当dir成员发送到HLSL中去时,它下一个ambient成员的第一个数字将会被封装进dir成员的4D向量中。因此,要阻止发生这种情况,我们添加了一个pad变量,为的是让它封装进包含dir成员的4D向量的第四个数据位上。

在创建该结构体后,声明一个新的Lighth对象。

struct Light
{
    Light()
    {
        ZeroMemory(this, sizeof(Light));
    }
    XMFLOAT3 dir;
    float pad;
    XMFLOAT4 ambient;
    XMFLOAT4 diffuse;
};

Light light;

cbPerFrame Structure


这就是我们要发送给像素着色器PS常量缓冲区的结构体。就像名字所表示的,我们将在每帧更新并发送该结构体给到PS常量缓冲区,不像其他的,我们是在每个对象一次发送到VS的。

struct cbPerFrame
{
    Light  light;
};

cbPerFrame constbuffPerFrame;
The UpdateScene() Functions New Parameter

time为函数UpdateScene()接收的新变量。会传入函数GetFrameTime()返回的值,并随后使用该值变量来更新场景。

void UpdateScene(double time)


更新顶点结构体以及顶点布局

既然已经实现了光照,就需要在顶点结构体中添加一个新的成员。该成员会保持法线数据,以便我们能够决定光是否照亮表面以及光量多少。

struct Vertex    //Overloaded Vertex Structure
{
    Vertex(){}
    Vertex(float x, float y, float z,
        float u, float v,
        float nx, float ny, float nz)
        : pos(x,y,z), texCoord(u, v), normal(nx, ny, nz){}

    XMFLOAT3 pos;
    XMFLOAT2 texCoord;
    XMFLOAT3 normal;
};

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 },  
    { "NORMAL",     0, DXGI_FORMAT_R32G32B32_FLOAT,    0, 20, D3D11_INPUT_PER_VERTEX_DATA, 0}
};


清除:

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();
    Transparency->Release();
    CCWcullMode->Release();
    CWcullMode->Release();

    d3d101Device->Release();
    keyedMutex11->Release();
    keyedMutex10->Release();
    D2DRenderTarget->Release();    
    Brush->Release();
    BackBuffer11->Release();
    sharedTex11->Release();
    DWriteFactory->Release();
    TextFormat->Release();
    d2dTexture->Release();

    ///////////////**************new**************////////////////////
    cbPerFrameBuffer->Release();
    ///////////////**************new**************////////////////////
}


定义光照

随后进入InitScene()函数,在这儿给direction,ambient,和diffuse成员赋值。可以给漫反射光diffuse一个白光,和一个黑色的环境光ambient(以便当光没有照射在表面时,它看起来会比光IS照射到表面时更暗。)

light.dir = XMFLOAT3(0.25f, 0.5f, -1.0f);
light.ambient = XMFLOAT4(0.2f, 0.2f, 0.2f, 1.0f);
light.diffuse = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);


添加法线数据到立方体

如何获取到这些法线数据呢?这里就是取每个顶点的位置,由于它们到立方体中心的距离(0,0,0)都是相等的。大多数时候,不会有这么好运气来取到该数值,当时当我们在加载模型时,一般导出模型的程序也会一起导出法线值。大部分时间它们会导出面法线,因此就需要我们将它平均一下以得到顶点法线。

Vertex v[] =
{
    // Front Face
    Vertex(-1.0f, -1.0f, -1.0f, 0.0f, 1.0f,-1.0f, -1.0f, -1.0f),
    Vertex(-1.0f,  1.0f, -1.0f, 0.0f, 0.0f,-1.0f,  1.0f, -1.0f),
    Vertex( 1.0f,  1.0f, -1.0f, 1.0f, 0.0f, 1.0f,  1.0f, -1.0f),
    Vertex( 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f, -1.0f),

    // Back Face
    Vertex(-1.0f, -1.0f, 1.0f, 1.0f, 1.0f,-1.0f, -1.0f, 1.0f),
    Vertex( 1.0f, -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f),
    Vertex( 1.0f,  1.0f, 1.0f, 0.0f, 0.0f, 1.0f,  1.0f, 1.0f),
    Vertex(-1.0f,  1.0f, 1.0f, 1.0f, 0.0f,-1.0f,  1.0f, 1.0f),

    // Top Face
    Vertex(-1.0f, 1.0f, -1.0f, 0.0f, 1.0f,-1.0f, 1.0f, -1.0f),
    Vertex(-1.0f, 1.0f,  1.0f, 0.0f, 0.0f,-1.0f, 1.0f,  1.0f),
    Vertex( 1.0f, 1.0f,  1.0f, 1.0f, 0.0f, 1.0f, 1.0f,  1.0f),
    Vertex( 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f),

    // Bottom Face
    Vertex(-1.0f, -1.0f, -1.0f, 1.0f, 1.0f,-1.0f, -1.0f, -1.0f),
    Vertex( 1.0f, -1.0f, -1.0f, 0.0f, 1.0f, 1.0f, -1.0f, -1.0f),
    Vertex( 1.0f, -1.0f,  1.0f, 0.0f, 0.0f, 1.0f, -1.0f,  1.0f),
    Vertex(-1.0f, -1.0f,  1.0f, 1.0f, 0.0f,-1.0f, -1.0f,  1.0f),

    // Left Face
    Vertex(-1.0f, -1.0f,  1.0f, 0.0f, 1.0f,-1.0f, -1.0f,  1.0f),
    Vertex(-1.0f,  1.0f,  1.0f, 0.0f, 0.0f,-1.0f,  1.0f,  1.0f),
    Vertex(-1.0f,  1.0f, -1.0f, 1.0f, 0.0f,-1.0f,  1.0f, -1.0f),
    Vertex(-1.0f, -1.0f, -1.0f, 1.0f, 1.0f,-1.0f, -1.0f, -1.0f),

    // Right Face
    Vertex( 1.0f, -1.0f, -1.0f, 0.0f, 1.0f, 1.0f, -1.0f, -1.0f),
    Vertex( 1.0f,  1.0f, -1.0f, 0.0f, 0.0f, 1.0f,  1.0f, -1.0f),
    Vertex( 1.0f,  1.0f,  1.0f, 1.0f, 0.0f, 1.0f,  1.0f,  1.0f),
    Vertex( 1.0f, -1.0f,  1.0f, 1.0f, 1.0f, 1.0f, -1.0f,  1.0f),
};

再深入该函数,将会看到我们已经创建了一个新的缓冲区用于保持cbPerFrame结构体,它会存储我们的光照数据。随后将该缓冲发送给像素着色器以实现每个像素的光照。

ZeroMemory(&cbbd, sizeof(D3D11_BUFFER_DESC));

cbbd.Usage = D3D11_USAGE_DEFAULT;
cbbd.ByteWidth = sizeof(cbPerFrame);
cbbd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
cbbd.CPUAccessFlags = 0;
cbbd.MiscFlags = 0;

hr = d3d11Device->CreateBuffer(&cbbd, NULL, &cbPerFrameBuffer);


D2D的FPS矩形的世界空间矩阵

确保为D2D的矩形纹理设置了World矩阵,否则它会使用最后设置的World矩阵。由于World矩阵位于屏幕空间,所以它也是一个空矩阵,因此只能够使用空的WVP矩阵。

WVP =  XMMatrixIdentity();
    ///////////////**************new**************////////////////////
cbPerObj.World = XMMatrixTranspose(WVP);    
///////////////**************new**************////////////////////
cbPerObj.WVP = XMMatrixTranspose(WVP);    
d3d11DevCon->UpdateSubresource( cbPerObjectBuffer, 0, NULL, &cbPerObj, 0, 0 );
d3d11DevCon->VSSetConstantBuffers( 0, 1, &cbPerObjectBuffer );
d3d11DevCon->PSSetShaderResources( 0, 1, &d2dTexture );
d3d11DevCon->PSSetSamplers( 0, 1, &CubesTexSamplerState );

设置光照

最后发送包含光照数据的缓冲区到像素着色器常量缓冲。必须每帧都做一次该操作,由于场景中的每个物体光照都是一样的。实际上,由于光照一点都不会改变,我们本来只需要在初始化场景时做这些就可以了,但是这会在你想要改变光照时让你改变光照。因此现在就把它放在效果文件上了。

constbuffPerFrame.light = light;
d3d11DevCon->UpdateSubresource( cbPerFrameBuffer, 0, NULL, &constbuffPerFrame, 0, 0 );
d3d11DevCon->PSSetConstantBuffers(0, 1, &cbPerFrameBuffer);    


设置World矩阵

现在我们需要把WVP和World矩阵都发送到效果文件。在世界空间中我们将会使用World矩阵来转换物体法线,以便实现正确光照。

WVP = cube1World * camView * camProjection;    
cbPerObj.World = XMMatrixTranspose(cube1World);    
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 );

d3d11DevCon->RSSetState(CWcullMode);
d3d11DevCon->DrawIndexed( 36, 0, 0 );

WVP = cube2World * camView * camProjection;    
cbPerObj.World = XMMatrixTranspose(cube2World);    
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 );

d3d11DevCon->RSSetState(CWcullMode);
d3d11DevCon->DrawIndexed( 36, 0, 0 );

效果文件

当程序发送光照数据到像素着色器时,我们将会创建一个Light结构体以保存光照数据。该光照结构体非常简单,只包含有方向,环境光,以及漫反射光。

struct Light
{
    float3 dir;
    float4 ambient;
    float4 diffuse;
};

下面是我们的新cbPerObject常量缓冲,它会为我们的物体世界空间保存一个矩阵。

cbuffer cbPerObject
{
    float4x4 WVP;
    float4x4 World;
};

记得以前说过根据常量缓冲更新的频率来分离它吗?我们为光照创建一个新的常量缓冲区,是因为我们仅仅需要每帧更新该缓冲区一次,由于在场景中所以的物体将会使用该光照。

cbuffer cbPerFrame
{
    Light light;
};

需要在VS_OUTPUT结构体中包含一个新的成员,它是发送到像素着色器的每个像素的法线数据。我们将会使用这些法线数据来计算有多少的光击中物体的表面。

现在需要将物体法线和物体世界空间做乘法,以便得到正确的光照。若我们将法线与WVP矩阵相乘,则不会得到正确的光照,并且当我们实现一个相机时,它会看起来就像平行光跟着相机转动,由于在技术上来说,WVP是相机空间。

struct VS_OUTPUT
{
    float4 Pos : SV_POSITION;
    float2 TexCoord : TEXCOORD;
    float3 normal : NORMAL;
};

VS_OUTPUT VS(float4 inPos : POSITION, float2 inTexCoord : TEXCOORD, float3 normal : NORMAL)
{
    VS_OUTPUT output;

    output.Pos = mul(inPos, WVP);

    output.normal = mul(normal, World);

    output.TexCoord = inTexCoord;

    return output;
}


现在终于到了实际计算场景中光照了,首先规范化法线,由于它可能不是单位长度。随后,找到纹理的漫反射颜色。随后创建一个新的变量以便在光计算结束后用于保存我们最终的颜色。

随后计算我们的光照模型的带漫反射的像素颜色。这将确保我们仍然能够看到不在光线中的那部分场景(当然,也行在一些游戏内不想让你看到光线外的事物)。

随后在已经确认撞击表面的光量之后再计算像素的最终颜色。通过这样来实现的:第一个dot,光照方向和表面法线相乘,随后将得到的dot再与光照的漫反射颜色相乘,最后再与像素纹理的漫反射颜色相乘。再做一个饱和化saturate以确保值不会超过1.0f,随后再与finalColor相加,finalColor是已经保存了漫反射光照的像素颜色值的。

最后,返回颜色。注意是怎样返回颜色的。我们必须总是从像素着色器返回一个float4类型,它包含了带α值的颜色。我们要做的所有事情就是为返回值的前面的三个值返回finalColor,并且纹理的α值用于对像素纹理起作用。

float4 PS(VS_OUTPUT input) : SV_TARGET
{
    input.normal = normalize(input.normal);

    float4 diffuse = ObjTexture.Sample( ObjSamplerState, input.TexCoord );

    float3 finalColor;

    finalColor = diffuse * light.ambient;
    finalColor += saturate(dot(light.dir, input.normal) * light.diffuse * diffuse);
    
    return float4(finalColor, diffuse.a);
}



示例代码:

#include "stdafx.h"
#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "d3dx11.lib")
#pragma comment(lib, "d3dx10.lib")

#pragma comment(lib, "D3D10_1.lib")
#pragma comment(lib, "DXGI.lib")
#pragma comment(lib, "D2D1.lib")
#pragma comment(lib, "dwrite.lib")

#include 
#include "Resource.h"
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
//全局描述符
IDXGISwapChain* SwapChain;
ID3D11Device* d3d11Device;
ID3D11DeviceContext* d3d11DevCon;
ID3D11RenderTargetView* renderTargetView;

//索引缓冲
ID3D11Buffer* squareIndexBuffer;

//深度值-20170927
ID3D11DepthStencilView* depthStencilView;
ID3D11Texture2D* depthStencilBuffer;

//着色器
ID3D11Buffer* squareVertBuffer;
ID3D11VertexShader* VS;
ID3D11PixelShader* PS;
ID3D10Blob* VS_Buffer;
ID3D10Blob* PS_Buffer;
ID3D11InputLayout* vertLayout;

///
ID3D11Buffer* cbPerObjectBuffer;
ID3D11BlendState* Transparency;
ID3D11RasterizerState* CCWcullMode;
ID3D11RasterizerState* CWcullMode;
ID3D11ShaderResourceView* CubesTexture;
ID3D11SamplerState* CubesTexSamplerState;

////*****new**********///
ID3D11Buffer* cbPerFrameBuffer;
ID3D11PixelShader* D2D_PS;
ID3D10Blob* D2D_PS_Buffer;
///**new******

// 设置线框
//ID3D11RasterizerState* WireFrame;

//无裁剪
//ID3D11RasterizerState* noCull;
#if 0
//混合设置
ID3D11BlendState* Transparency;
ID3D11RasterizerState* CCWcullMode;
ID3D11RasterizerState* CWcullMode;

//float red = 0.0f;
//float green = 0.0f;
//float blue = 0.0f;
//int colormodr = 1;
//int colormodg = 1;
//int colormodb = 1;
#endif

ID3D10Device1 *d3d101Device;
IDXGIKeyedMutex *keyedMutex11;
IDXGIKeyedMutex *keyedMutex10;
ID2D1RenderTarget *D2DRenderTarget;
ID2D1SolidColorBrush *Brush;
ID3D11Texture2D *BackBuffer11;
ID3D11Texture2D *sharedTex11;
ID3D11Buffer *d2dVertBuffer;
ID3D11Buffer *d2dIndexBuffer;
ID3D11ShaderResourceView *d2dTexture;
IDWriteFactory *DWriteFactory;
IDWriteTextFormat *TextFormat;
std::wstring printText;
/////
LPCTSTR WndClassName = "firstwindow";
HWND hwnd = NULL;
HRESULT hr;

const int Width = 800; //设置宽
const int Height = 800; // 设置高

///四个空间以及相机属性
XMMATRIX WVP;
//立方体
XMMATRIX cube1World;
XMMATRIX cube2World;
//
//XMMATRIX World;
XMMATRIX camView;
XMMATRIX camProjection;

XMMATRIX d2dWorld;
XMVECTOR camPosition;
XMVECTOR camTarget;
XMVECTOR camUp;

//相机
XMMATRIX Rotation;
XMMATRIX Scale;
XMMATRIX Translation;
float rot = 0.01f;

///////////////**************new**************////////////////////
double countsPerSecond = 0.0;
__int64 CounterStart = 0;

int frameCount = 0;
int fps = 0;

__int64 frameTimeOld = 0;
double frameTime;
///////////////**************new**************////////////////////
//Function Prototypes//
bool InitializeDirect3d11App(HINSTANCE hInstance);
void CleanUp();
bool InitScene();
void DrawScene();
bool InitD2D_D3D101_DWrite(IDXGIAdapter1 *Adapter);
void InitD2DScreenTexture();
///////////////**************new**************////////////////////
void UpdateScene(double time);
//void UpdateScene();
void RenderText(std::wstring text, int inInt);
//void RenderText(std::wstring text);

void StartTimer();
double GetTime();
double GetFrameTime();


// 初始化窗口
bool InitializeWindow(HINSTANCE hInstance,
	int ShowWnd,
	int width, int height,
	bool windowed);

//初始化消息循环函数
int messageloop();
//初始化窗口回调过程。Windows API是事件驱动型的编程模型。在该函数中捕获Windows消息,比如一个按键按下(也叫事件)以及程序操作流程。

LRESULT CALLBACK WndProc(HWND hWnd,
	UINT msg,
	WPARAM wParam,
	LPARAM lParam);

///new
//创建效果常量缓冲的结构体
struct cbPerObject
{
	XMMATRIX WVP;
	XMMATRIX World;

};

cbPerObject cbPerObj;

struct Light
{
	Light()
	{
		ZeroMemory(this, sizeof(Light));
	}
	XMFLOAT3 dir;
	float pad;
	XMFLOAT4 ambient;
	XMFLOAT4 diffuse;

};
Light light;

struct cbPerFrame
{
	Light light;
};

cbPerFrame constbuffPerFrame;


//顶点结构体以及顶点布局(输入布局)

struct Vertex
{
	Vertex(){}
	Vertex(float x, float y, float z,
		float u, float v,
		float nx, float ny, float nz)
		:pos(x, y, z), texCoord(u, v), normal(nx, ny, nz){}
	XMFLOAT3 pos;
	XMFLOAT2 texCoord;
	XMFLOAT3 normal;
};

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 },
	{ "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 20, D3D11_INPUT_PER_VERTEX_DATA, 0 }
};
UINT numElements = ARRAYSIZE(layout);

//主函数,传入应用程序句柄hInstance,前一个应用程序句柄hPrevInstance,传给函数处理的命令行lpCmdLine以及窗口显示方式的nShowCmd
int WINAPI WinMain(HINSTANCE hInstance,
	HINSTANCE hPrevInstance,
	LPSTR lpCmdLine,
	int nShowCmd)
{
	//创建并注册窗口
	if (!InitializeWindow(hInstance, nShowCmd, Width, Height, true))
	{
		MessageBox(0, "Window Initialization - Failed", "Error", MB_OK);
		return 0;
	}

	/////new
	if (!InitializeDirect3d11App(hInstance)) // 初始化D3D
	{
		MessageBox(0, "Direct3D Initialization - Failed", "Error", MB_OK);
		return 0;
	}

	if (!InitScene())
	{
		MessageBox(0, "Scene Initialization - Failed", "Error", MB_OK);
		return 0;
	}
	
	messageloop();
	CleanUp();
	//ReleaseObjects();

	return 0;
}
// windowed 若为true则为窗口模式显示,若为false则为全屏模式显示
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); //window类的大小
	/********windows类风格
	*CS_CLASSDC 一个使用该类创建的在所有窗口间共享的设备上下文
	*CS_DBLCLKS 在窗口上使能双击功能
	*CS_HREDRAW 若窗口的宽度有改变或者窗口水平地移动,窗口将会刷新
	*CS_NOCLOSE 窗口菜单上禁止关闭选项
	*CS_OWNDC   为每个窗口创建自己的设备上下文。正好与CS_CLASSDC相反
	*CS_PARENTDC 这会设置创建的子窗口的剪裁四边形到父窗口,这允许子窗口能够在父窗口上绘画
	*CS_VERDRAW 若在窗口的高度或窗口在垂直方向有移动窗口会重绘
	**/
	wc.style = CS_HREDRAW | CS_VREDRAW;
	//lpfnWndProc是一个指向处理窗口消息函数的指针,设置窗口处理函数的函数名WndProc
	wc.lpfnWndProc = WndProc;
	//cbClsExtra是WNDCLASSEX之后额外申请的字节数
	wc.cbClsExtra = NULL;
	//cbWndExtra指定窗口实例之后所申请的字节数
	wc.cbWndExtra = NULL;
	//当前窗口应用程序的句柄,通过给函数GetModuleHandle()函数第一个参数传入NULL可获取当前窗口应用程序。
	wc.hInstance = hInstance;

	//hIcon用来指定窗口标题栏左上角的图标。以下是一些标准图标:
	/*
	*IDI_APPLICATION 默认应用程序图标
	*IDI_HAND 手形状的图标
	*IDI_EXCLAMATION 感叹号图标
	*IDI_INFORMATION 星号图标
	*IDI_QUESTION 问号图标
	*IDI_WINLOGO 若使用的是XP则是默认应用程序图标,否则是窗口logo
	*/
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);

	/*定义光标图标
	*IDC_APPSTARTING 标准箭头以及小型沙漏光标
	*IDC_ARROW 标准箭头光标
	*IDC_CROSS 十字线光标
	*IDC_HAND 手型光标
	*IDC_NO 斜线圈光标
	*IDC_WAIT 沙漏光标
	*/
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	//hbrBackground是一个刷子的句柄,可使得背景黑色。
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 2);
	//附加到窗口的菜单名字,不需要的话设置为NULL
	wc.lpszMenuName = NULL;
	//对类进行命名
	wc.lpszClassName = WndClassName;
	//指定任务栏的图标,使用上面的IDI_图标
    wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
	//注册类。若失败则会获得一个错误,若成功,则继续创建窗口
	if (!RegisterClassEx(&wc))
	{
		MessageBox(NULL, "Error registering class", "Error", MB_OK | MB_ICONERROR);
		return 1;
	}
	//创建窗口
	hwnd = CreateWindowEx(
		NULL, 
		WndClassName, 
		"Rotating Cube", 
		WS_OVERLAPPEDWINDOW, 
		CW_USEDEFAULT, 
		CW_USEDEFAULT, 
		width,
		height, 
		NULL,
		NULL,
		hInstance,
		NULL
		);

	if (!hwnd)
	{
		MessageBox(NULL, "Error registering class", "Error", MB_OK | MB_ICONERROR);
		return 1;
	}

	//BOOL ShowWindow(HWND hWnd, int nCmdShow);
	//BOOL UpdateWindow(HWND hWnd);

	ShowWindow(hwnd, ShowWnd);
	UpdateWindow(hwnd);// 发送WM_PAINT消息到窗口过程,若窗口客户区没有任何东西要显示,则不发送消息。返回true,继续运行到mainloop中去。

	return true;
}

bool InitializeDirect3d11App(HINSTANCE hInstance)
{
	//声明缓冲
	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_B8G8R8A8_UNORM;
	bufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
	bufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;

	//声明交换链
	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;

	//创建DXGI factory来枚举显卡
	IDXGIFactory1 *DXGIFactory;
	HRESULT hr = CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void **)&DXGIFactory);

	//使用第一个显卡
	IDXGIAdapter1 *Adapter;
	hr = DXGIFactory->EnumAdapters1(0, &Adapter);
	DXGIFactory->Release();

	//创建D3D11设备和交换链
	//hr = D3D11C

	//创建交换链
	D3D11CreateDeviceAndSwapChain(Adapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, D3D11_CREATE_DEVICE_BGRA_SUPPORT, 
	NULL, NULL,	D3D11_SDK_VERSION, &swapChainDesc, &SwapChain, &d3d11Device, NULL, &d3d11DevCon);

	//初始化D2D D3D10.1和DirectWrite
	InitD2D_D3D101_DWrite(Adapter);

	//释放Adapter接口
	Adapter->Release();

	//创建后缓冲
	ID3D11Texture2D* BackBuffer;
	SwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&BackBuffer);

	//创建渲染目标
	d3d11Device->CreateRenderTargetView(BackBuffer, NULL, &renderTargetView);
	BackBuffer->Release();

	//创建深度模板缓冲
	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; //绑定到OM
	depthStencilDesc.CPUAccessFlags = 0;
	depthStencilDesc.MiscFlags = 0;

	//创建深度模板视图
	d3d11Device->CreateTexture2D(&depthStencilDesc, NULL, &depthStencilBuffer);
	d3d11Device->CreateDepthStencilView(depthStencilBuffer, NULL, &depthStencilView);


	return true;
}

bool InitD2D_D3D101_DWrite(IDXGIAdapter1 *Adapter)
{
	//创建D3D101设备
	hr = D3D10CreateDevice1(Adapter, D3D10_DRIVER_TYPE_HARDWARE, NULL, D3D10_CREATE_DEVICE_BGRA_SUPPORT,
		D3D10_FEATURE_LEVEL_9_3, D3D10_1_SDK_VERSION, &d3d101Device);

	//创建共享纹理,D3D101将会渲染它
	D3D11_TEXTURE2D_DESC sharedTexDesc;
	ZeroMemory(&sharedTexDesc, sizeof(sharedTexDesc));

	sharedTexDesc.Width = Width;
	sharedTexDesc.Height = Height;
	sharedTexDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;// DXGI_FORMAT_R8G8B8A8_UNORM;// DXGI_FORMAT_B8G8R8A8_UNORM;
	sharedTexDesc.MipLevels = 1;
	sharedTexDesc.ArraySize = 1;
	sharedTexDesc.SampleDesc.Count = 1;
	sharedTexDesc.Usage = D3D11_USAGE_DEFAULT;
	sharedTexDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
	sharedTexDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;

	hr = d3d11Device->CreateTexture2D(&sharedTexDesc, NULL, &sharedTex11);
	
	//为共享纹理获取key互斥量(为D3D11)
	hr = sharedTex11->QueryInterface(__uuidof(IDXGIKeyedMutex), (void **)&keyedMutex11);

	//获取共享句柄需要在D3D10.1中打开共享纹理
	IDXGIResource *sharedResource10;
	HANDLE sharedHandle10;

	hr = sharedTex11->QueryInterface(__uuidof(IDXGIResource), (void **)&sharedResource10);
	hr = sharedResource10->GetSharedHandle(&sharedHandle10);
	sharedResource10->Release();

	//在D3D10.1中为共享纹理打开界面
	IDXGISurface1 *sharedSurface10;
	hr = d3d101Device->OpenSharedResource(sharedHandle10, __uuidof(IDXGISurface1), (void **)(&sharedSurface10));
	hr = sharedSurface10->QueryInterface(__uuidof(IDXGIKeyedMutex), (void **)&keyedMutex10);

	//创建D2D factory
	ID2D1Factory *D2DFactory;
	hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, __uuidof(ID2D1Factory), (void **)&D2DFactory);
	D2D1_RENDER_TARGET_PROPERTIES renderTargetProperties;
	ZeroMemory(&renderTargetProperties, sizeof(renderTargetProperties));

	renderTargetProperties.type = D2D1_RENDER_TARGET_TYPE_HARDWARE;
	renderTargetProperties.pixelFormat = D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED);
	hr = D2DFactory->CreateDxgiSurfaceRenderTarget(sharedSurface10, &renderTargetProperties, &D2DRenderTarget);

	sharedSurface10->Release();
	D2DFactory->Release();

	//创建立体彩色画笔绘制一些东西
	hr = D2DRenderTarget->CreateSolidColorBrush(D2D1::ColorF(1.0f, 1.0f, 1.0f, 1.0f), &Brush);

	//DirectWrite
	hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), 
	reinterpret_cast(&DWriteFactory));
	hr = DWriteFactory->CreateTextFormat(
		L"Script",
		NULL,
        DWRITE_FONT_WEIGHT_REGULAR,
		DWRITE_FONT_STYLE_NORMAL,
		DWRITE_FONT_STRETCH_NORMAL,
		24.0f,
		L"en-us",
        &TextFormat
		);
    hr = TextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING);
    hr = TextFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_NEAR);

    d3d101Device->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_POINTLIST);    
	return true;
}

void CleanUp()
{
	SwapChain->Release();
	d3d11Device->Release();
	d3d11DevCon->Release();
	renderTargetView->Release();

	squareVertBuffer->Release();
	squareIndexBuffer->Release();

	//triangleVertBuffer->Release();
	VS->Release();
	PS->Release();
	VS_Buffer->Release();
	PS_Buffer->Release();
	vertLayout->Release();

	depthStencilView->Release();
	depthStencilBuffer->Release();

	//
	cbPerObjectBuffer->Release();

	//释放不裁剪对象
//	noCull->Release();
	//释放混合对象
#if 1
	Transparency->Release();
	CCWcullMode->Release();
	CWcullMode->Release();
#endif	
	//释放线框
	//WireFrame->Release();

	d3d101Device->Release();
	keyedMutex11->Release();
	keyedMutex10->Release();
	D2DRenderTarget->Release();
	Brush->Release();
//	BackBuffer11->Release();
	sharedTex11->Release();
	DWriteFactory->Release();
    TextFormat->Release();
	d2dTexture->Release();

	/// new
	cbPerFrameBuffer->Release();
}


void InitD2DScreenTexture()
{
	//创建顶点缓冲
	Vertex v[] =
	{
		//字体面
		Vertex(-1.0f, -1.0f, -1.0f, 0.0f, 1.0f, -1.0f, -1.0f, -1.0f),
		Vertex(-1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, -1.0f),
		Vertex(1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, -1.0f),
		Vertex(1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f, -1.0f),
	};

	DWORD indices[] = {
		//字体面
		0, 1, 2,
		0, 2, 3,
	};

	D3D11_BUFFER_DESC indexBufferDesc;
	ZeroMemory(&indexBufferDesc, sizeof(indexBufferDesc));

	indexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
	indexBufferDesc.ByteWidth = sizeof(DWORD) * 2 * 3;
	indexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
	indexBufferDesc.CPUAccessFlags = 0;
	indexBufferDesc.MiscFlags = 0;

	D3D11_SUBRESOURCE_DATA iinitData;
	iinitData.pSysMem = indices;
	d3d11Device->CreateBuffer(&indexBufferDesc, &iinitData, &d2dIndexBuffer);

	D3D11_BUFFER_DESC vertexBufferDesc;
	ZeroMemory(&vertexBufferDesc, sizeof(vertexBufferDesc));

	vertexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
	vertexBufferDesc.ByteWidth = sizeof(Vertex) * 4;
	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, &d2dVertBuffer);

	//从纹理D2D,创建一个着色器资源视图
	//因此,能够使用它来创建一个矩形纹理,用于覆盖场景
	d3d11Device->CreateShaderResourceView(sharedTex11, NULL, &d2dTexture);

}

//void ReleaseObjects()
//{
//释放创建的COM对象
//	SwapChain->Release();
//	d3d11Device->Release();
//	d3d11DevCon->Release();
//}

bool InitScene()
{
	//
	InitD2DScreenTexture();
	//编译着色器
	hr = D3DX11CompileFromFile("Effects.fx", 0, 0, "VS", "vs_4_0", 0, 0, 0, &VS_Buffer, 0, 0);
	hr = D3DX11CompileFromFile("Effects.fx", 0, 0, "PS", "ps_4_0", 0, 0, 0, &PS_Buffer, 0, 0);
	/// new
	hr = D3DX11CompileFromFile("Effects.fx", 0, 0, "D2D_PS", "ps_4_0", 0, 0, 0, &D2D_PS_Buffer, 0, 0);

	//创建着色器对象
	hr = d3d11Device->CreateVertexShader(VS_Buffer->GetBufferPointer(), VS_Buffer->GetBufferSize(), NULL, &VS);
	hr = d3d11Device->CreatePixelShader(PS_Buffer->GetBufferPointer(), PS_Buffer->GetBufferSize(), NULL, &PS);
	///new
	hr = d3d11Device->CreatePixelShader(D2D_PS_Buffer->GetBufferPointer(), D2D_PS_Buffer->GetBufferSize(), NULL, &D2D_PS);

	//设置顶点和像素着色器
	d3d11DevCon->VSSetShader(VS, 0, 0);
	d3d11DevCon->PSSetShader(PS, 0, 0);

	light.dir = XMFLOAT3(0.25f, 0.25f, -1.0f);
	light.ambient = XMFLOAT4(0.2f, 0.2f, 0.2f, 1.0f);
	light.diffuse = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);

	//创建顶点缓冲
	Vertex v[] = 
	{
		// Front Face
		Vertex(-1.0f, -1.0f, -1.0f, 0.0f, 1.0f, -1.0f, -1.0f, -1.0f),
		Vertex(-1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, -1.0f, -1.0f),
		Vertex(1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, -1.0f),
		Vertex(1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f, -1.0f),

		// Back Face
		Vertex(-1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f),
		Vertex(1.0f, -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f),
		Vertex(1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f),
		Vertex(-1.0f, 1.0f, 1.0f, 1.0f, 0.0f, -1.0f, 1.0f, 1.0f),

		// Top Face
		Vertex(-1.0f, 1.0f, -1.0f, 0.0f, 1.0f, -1.0f, 1.0f, -1.0f),
		Vertex(-1.0f, 1.0f, 1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f),
		Vertex(1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f),
		Vertex(1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f),

		// Bottom Face
		Vertex(-1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, -1.0f),
		Vertex(1.0f, -1.0f, -1.0f, 0.0f, 1.0f, 1.0f, -1.0f, -1.0f),
		Vertex(1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f),
		Vertex(-1.0f, -1.0f, 1.0f, 1.0f, 0.0f, -1.0f, -1.0f, 1.0f),

		// Left Face
		Vertex(-1.0f, -1.0f, 1.0f, 0.0f, 1.0f, -1.0f, -1.0f,1.0f),
		Vertex(-1.0f, 1.0f, 1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f),
		Vertex(-1.0f, 1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 1.0f, -1.0f),
		Vertex(-1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, -1.0f),

		// Right Face
		Vertex(1.0f, -1.0f, -1.0f, 0.0f, 1.0f, 1.0f, -1.0f, -1.0f),
		Vertex(1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f, -1.0f),
		Vertex(1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f),
		Vertex(1.0f, -1.0f, 1.0f, 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);

	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);

	//设置顶点缓冲
//	UINT stride = sizeof(Vertex);
//	UINT offset = 0;
//	d3d11DevCon->IASetVertexBuffers(0, 1, &squareVertBuffer, &stride, &offset);

	//创建输入布局
	d3d11Device->CreateInputLayout(layout, numElements, VS_Buffer->GetBufferPointer(),
		VS_Buffer->GetBufferSize(), &vertLayout);

	//设置输入布局
	d3d11DevCon->IASetInputLayout(vertLayout);
	
	//设置图元拓扑
	d3d11DevCon->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

	//创建视口
	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;
	//设置视口
	d3d11DevCon->RSSetViewports(1, &viewport);

	//创建缓冲用来发送到效果文件的cbuffer
	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);

	//创建缓冲用于每帧发送cbuffer到着色器文件
	ZeroMemory(&cbbd, sizeof(D3D11_BUFFER_DESC));
	cbbd.Usage = D3D11_USAGE_DEFAULT;
	cbbd.ByteWidth = sizeof(cbPerFrame);
	cbbd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
	cbbd.CPUAccessFlags = 0;
	cbbd.MiscFlags = 0;

	d3d11Device->CreateBuffer(&cbbd, NULL, &cbPerFrameBuffer);

	//相机信息
	//相机信息
	camPosition = XMVectorSet(0.0f, 3.0f, -8.0f, 0.0f);
	//camPosition = XMVectorSet(0.0f, 0.0f, -0.5f, 0.0f);
	camTarget = XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f);
	camUp = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);

	//设置视图矩阵
	camView = XMMatrixLookAtLH(camPosition, camTarget, camUp);

	//设置投影矩阵
	camProjection = XMMatrixPerspectiveFovLH(0.4f*3.14f, (float)Width / Height, 1.0f, 1000.0f);

	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;
    ///////////////**************new**************////////////////////
    rtbd.DestBlend                 = D3D11_BLEND_INV_SRC_ALPHA;
    ///////////////**************new**************////////////////////
    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;
	//加载图像纹理
	//hr = 
//#if 1
	hr = D3DX11CreateShaderResourceViewFromFile(d3d11Device, "Eye.png", 
	NULL, NULL, &CubesTexture, NULL);

	//配置采样状态
	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;

	//创建采样状态
	hr = d3d11Device->CreateSamplerState(&sampDesc, &CubesTexSamplerState);


	d3d11Device->CreateBlendState(&blendDesc, &Transparency);

	//创建逆时针和顺时针状态
	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);

	return true;
}

///////////////**************new**************////////////////////
void StartTimer()
{
    LARGE_INTEGER frequencyCount;
    QueryPerformanceFrequency(&frequencyCount);
    countsPerSecond = double(frequencyCount.QuadPart);

    QueryPerformanceCounter(&frequencyCount);
    CounterStart = frequencyCount.QuadPart;
}

double GetTime()
{
    LARGE_INTEGER currentTime;
    QueryPerformanceCounter(¤tTime);
    return double(currentTime.QuadPart-CounterStart)/countsPerSecond;
}

double GetFrameTime()
{
    LARGE_INTEGER currentTime;
    __int64 tickCount;
    QueryPerformanceCounter(¤tTime);

    tickCount = currentTime.QuadPart-frameTimeOld;
    frameTimeOld = currentTime.QuadPart;

    if(tickCount < 0.0f)
        tickCount = 0.0f;

    return float(tickCount)/countsPerSecond;
}
///////////////**************new**************////////////////////

///////////////**************new**************////////////////////
void UpdateScene(double time)
    ///////////////**************new**************////////////////////
//void UpdateScene()
{
	// 更新场景颜色
	//让立方体旋转起来
    rot += 1.005f*time;
  	//rot += .005f;
    if(rot > 6.28f)
		rot = 0.0f;

	//复位cube1World
	cube1World = XMMatrixIdentity();

	//定义cube1的世界空间矩阵
	XMVECTOR rotaxis = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
	Rotation = XMMatrixRotationAxis(rotaxis, rot);
	Translation = XMMatrixTranslation(0.0f, 0.0f, 4.0f);

	//用转换设置cube1的世界空间
	cube1World = Translation* Rotation;

	//复位cube2World
	cube2World = XMMatrixIdentity();
	
	//定义cube2的世界空间矩阵
	Rotation = XMMatrixRotationAxis(rotaxis, -rot);
	Scale = XMMatrixScaling(1.3f, 1.3f, 1.3f);

	//设置cube2的世界空间矩阵
	cube2World = Rotation * Scale;
}

///////////////**************new**************////////////////////
void RenderText(std::wstring text, int inInt)
//void RenderText(std::wstring text)
{
	//释放D3D11设备
	keyedMutex11->ReleaseSync(0);

	//使用D3D10.1设备
	keyedMutex10->AcquireSync(0, 5);

	//绘制D2D内容
	D2DRenderTarget->BeginDraw();
	//清空D2D背景色
	D2DRenderTarget->Clear(D2D1::ColorF(0.0f, 0.0f, 0.0f, 0.0f));

	//创建字符串
	std::wostringstream printString;
    ///////////////**************new**************////////////////////
    printString << text << inInt;
   //	printString << text;
    ///////////////**************new**************////////////////////
    printText = printString.str();

	//设置字体颜色
	D2D1_COLOR_F FontColor = D2D1::ColorF(1.0f, 0.0f, 0.0f,1.0f);

	//设置D2D绘制要用到的画笔颜色
	Brush->SetColor(FontColor);

	//创建D2D渲染区域
	D2D1_RECT_F layoutRect = D2D1::RectF(0, 0, Width, Height);

	//绘制文本
	D2DRenderTarget->DrawText(
		printText.c_str(),
		wcslen(printText.c_str()),
        TextFormat,
		layoutRect,
		Brush
		);

	D2DRenderTarget->EndDraw();

	//释放D3D10.1设备
	keyedMutex10->ReleaseSync(1);

	//使用D3D11设备
	keyedMutex11->AcquireSync(1, 5);

	//使用着色器资源表示d2d渲染目标来创建一个矩形纹理,该矩形是被渲染进屏幕空间的。使用α混合以便整个D2D
	//渲染目标的背景为不可见的,且只有使用D2D绘制的东西才可见(文本)。

	//为D2D渲染目标纹理对象设置混合状态
	d3d11DevCon->OMSetBlendState(Transparency, NULL, 0xffffffff);
   //Set d2d's pixel shader so lighting calculations are not done
    d3d11DevCon->PSSetShader(D2D_PS, 0, 0);
	//设置d2d索引缓冲
 
	d3d11DevCon->IASetIndexBuffer(d2dIndexBuffer, DXGI_FORMAT_R32_UINT, 0);

	//设置d2d顶点缓冲
	UINT stride = sizeof(Vertex);
	UINT offset = 0;
	d3d11DevCon->IASetVertexBuffers(0, 1, &d2dVertBuffer, &stride, &offset);

	WVP = XMMatrixIdentity();
	///new
	cbPerObj.World = XMMatrixTranspose(WVP);

	cbPerObj.WVP = XMMatrixTranspose(WVP);
	d3d11DevCon->UpdateSubresource(cbPerObjectBuffer, 0, NULL, &cbPerObj, 0, 0);
	d3d11DevCon->VSSetConstantBuffers(0, 1, &cbPerObjectBuffer);
	d3d11DevCon->PSSetShaderResources(0, 1, &d2dTexture);
	d3d11DevCon->PSSetSamplers(0, 1, &CubesTexSamplerState);

	d3d11DevCon->RSSetState(CWcullMode);

	//画第二个立方体
	d3d11DevCon->DrawIndexed(6, 0, 0);

}

void DrawScene()
{
	//将更新的颜色填充后缓冲
//	D3DXCOLOR bgColor(red, green, blue, 1.0f);
	float bgColor[4] = {(0.0f, 0.0f, 0.0f, 0.0f)};
	d3d11DevCon->ClearRenderTargetView(renderTargetView, bgColor);

	//刷新深度模板视图
	d3d11DevCon->ClearDepthStencilView(depthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
	
	//new
	constbuffPerFrame.light = light;
	d3d11DevCon->UpdateSubresource(cbPerFrameBuffer, 0, NULL, &constbuffPerFrame, 0, 0);
	d3d11DevCon->PSSetConstantBuffers(0, 1, &cbPerFrameBuffer);
	//复位顶点和像素着色器
	d3d11DevCon->VSSetShader(VS, 0, 0);
	d3d11DevCon->PSSetShader(PS, 0, 0);

	//使能默认光栅化状态
//	d3d11DevCon->RSSetState(NULL);


	//绘制使用背面裁剪的对象
	//关闭背面裁剪
   // d3d11DevCon->RSSetState(noCull);
	d3d11DevCon->OMSetRenderTargets( 1, &renderTargetView, depthStencilView );

	d3d11DevCon->OMSetBlendState(0, 0, 0xffffffff);

    //Set the cubes index buffer
	//设置立方体的索引缓冲
	d3d11DevCon->IASetIndexBuffer(squareIndexBuffer, DXGI_FORMAT_R32_UINT, 0);

	//设置立方体的顶点缓冲
	UINT stride = sizeof(Vertex);
	UINT offset = 0;
	d3d11DevCon->IASetVertexBuffers(0, 1, &squareVertBuffer, &stride, &offset);

	//设置WVP矩阵并将它送到效果文件中的常量缓冲中
	WVP = cube1World * camView * camProjection;
	cbPerObj.World = XMMatrixTranspose(cube1World);
	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);

	//逆时针剪裁先是因为需要立方体后边首先被渲染,所以前面会和它混合
	d3d11DevCon->RSSetState(CWcullMode);

	//绘制第一个立方体
	d3d11DevCon->DrawIndexed(36, 0, 0);

	//
	//d3d11DevCon->RSSetState(CWcullMode);
	//d3d11DevCon->DrawIndexed(36, 0, 0);

	//设置世界/视图/投影矩阵,随后发送到效果文件的常量缓冲中
	//World = XMMatrixIdentity();

	WVP = cube2World * camView * camProjection;
	cbPerObj.World = XMMatrixTranspose(cube2World);
	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);

	//
	d3d11DevCon->RSSetState(CWcullMode);
	//绘制第二个立方体
	d3d11DevCon->DrawIndexed(36, 0, 0);
	//绘制三角形
	//d3d11DevCon->DrawIndexed(6, 0, 0);
	//画三角形
	//d3d11DevCon->Draw(3, 0);
	//
	//d3d11DevCon->RSSetState(CWcullMode);
	//d3d11DevCon->DrawIndexed(36, 0, 0);
    ///////////////**************new**************////////////////////
	//
    RenderText(L"FPS: ", fps);
	//RenderText(L"hello world");
  ///////////////**************new**************////////////////////
	//将后缓冲呈现到屏幕
	SwapChain->Present(0, 0);
}

int messageloop(){
	MSG msg;
	ZeroMemory(&msg, sizeof(MSG));//清除结构体被设为NULL。

	while (true)
	{
		//使用PeekMessage()检查是否有消息传进来
		/*LPMSG lpMsg 消息结构体的指针
		*HWND hWnd 发送消息的窗口句柄。若设为NULL,那么它会从当前程序中接收来自任何一个窗口的消息
		*UINT wMsgFilterMin 指定消息范围内第一个要检查的消息的值。若wMsgFilterMin和wMsgFilterMax都设为0,那么PeekMessage将会检查素有的消息
		*UINT wMsgFilterMax 指定消息范围内最后一个要检测的消息的值
		*UINT wRemoveMsg 指定消息的处理方式。若设置为PM_REMOVE,则在读取之后会被删除
		*/
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			if (msg.message == WM_QUIT)
                break;
			//若消息为窗口消息,则解析并分发它。TranslateMessage()将会让窗口做一些解析,类似键盘的虚拟键值转换到字符形式。
			//而DispatchMessage()则发送消息到窗口过程WndProc。
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		else //若没有窗口消息,则运行游戏
 ///////////////**************new**************////////////////////
		{
  			frameCount++;
 	 		if(GetTime() > 1.0f)
            {
                fps = frameCount;
                frameCount = 0;
                StartTimer();
            }    

            frameTime = GetFrameTime();
		
            UpdateScene(frameTime);		
			DrawScene();

		}
	}
	return msg.wParam;
}

//窗口消息处理函数
//HWND hwnd 获取消息的窗口句柄
//UINT msg 消息的内容
/*
*WM_ACTIVE 当窗口激活时发送的消息
*WM_CLOSE 当窗口关闭时发送的消息
*WM_CREATE 当窗口创建时发送的消息
*WM_DESTROY 当窗口销毁时发送的消息
*/
//wParam和lParam时消息的额外信息。使用wParam来检测键盘输入消息
LRESULT CALLBACK WndProc(HWND hwnd,
	UINT msg,
	WPARAM wParam,
	LPARAM lParam)
{
	// 这是事件检测消息的地方,若escape键被按下,会显示一个消息框,询问是否真的退出。若点击yes,则程序关闭。若不点击,则消息框关闭。若消息包含WM_DESTROY
	// 则意味着窗口正在被销毁,返回0并且程序关闭
	switch (msg)
	{
	case WM_KEYDOWN:
		if (wParam == VK_ESCAPE)
		{
			if (MessageBox(0, "Are you sure you want to exit?",
				"Really?", MB_YESNO | MB_ICONASTERISK) == IDYES)
			{
				DestroyWindow(hwnd);
			}
			return 0;

		}
		break;

	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
		break;

	default:
		break;
	}

	//调用默认窗口过程函数
	return DefWindowProc(hwnd,
		msg,
		wParam,
		lParam);
}



效果图:




参考网址


你可能感兴趣的:(DIRECT3D,VR&VR)