精华内容
下载资源
问答
  • D3D11绘图基础:旋转的彩色立方体

    热门讨论 2012-12-16 05:08:24
    D3D11绘图基础,实现一个简单的场景:旋转的彩色立方体的源代码。
  • D3D11地形渲染

    2012-05-15 22:04:23
    设计了一种基于GPU编程实现的大规模地形场景的实时绘制与漫游算法。利用GPU端完成地形网格更新、地形块的自动选取、高度图和纹理图采样等大部分计算工作,大大减轻了CPU端的计算负载。
  • D3D11 包围体

    2017-12-13 18:49:25
    场景中有上千个模型,并且每个模型有上千个三角形。若仅仅使用前一章节中的拾取方法,则完成一个拾取操作将耗时5s。在单一帧内耗时5s是让人难以接受的,因此引进了包围体方式。 这里讲学习如何创建以及使用边界...

    若场景中有上千个模型,并且每个模型有上千个三角形。若仅仅使用前一章节中的拾取方法,则完成一个拾取操作将耗时5s。在单一帧内耗时5s是让人难以接受的,因此引进了包围体方式。

    这里将介绍如何创建以及使用包围盒以及包围球。包围盒比包围球跟更为精确,但是耗时比包围球多。

    这里会使用之前介绍过的高分辨率定时器来计算每次拾取操作的耗时。


    介绍:

    包围体用于加速类似拾取与碰撞测试操作。本章会渲染1000个瓶子(之前仅仅只有20个)。若在前一章节中运行1000个瓶子,会发现每次拾取一个瓶子时,游戏会冻结一小段时间。要解决这种问题,就引入了包围体方式,这种方式只测试包围盒中的一小部分三角形而不是去测试每个对象中的所有三角形,或者是只测试拾取射线是否位于模型的包围球范围之内,这种方式会极大提高速度。

    这里会创建一个包围盒以及一个包围球体,之后,在真实复杂模型中,做一个既有包围盒又有包围球体的边界模型,它包含非常少的需要测试的三角形。一般不去渲染包围体,只用于测试。

    包围体:

    包围体用于拾取以及碰撞测试操作。它耗时少的原因是要么提供更少的几何体(包围盒和包围网格)来测试,要么是提供更为有效的测试方法(包围球)。虽然速度是提高了,但是精准度降低了,球体精准度比包围盒或包围网格都低。

    虽然如此,但是精准度的事情是不需要担心的。首先,低精准度或许正是游戏中所需要的效果,对某些对象来说,在拾取时通过预估它的位置来让对象更为容易拾取。但真正不需要担心低精准度的原因是,因为低精准度下仍然可以对模型做出精准的测试。只测试对象的包围体而不是测试模型的每个三角形来实现。若包围体被拾取,就能够测试实际的模型。仍然可以获取高性能的包围球以及模型的测试精准度。

    包围球由球的半径来表示(x)


    包围球由球的半径来表示。这是检测拾取或碰撞的最快方式。当测试拾取时,要做的就是查看拾取法线是否在对象中心的球体半径之内。针对碰撞测试而言,只需要测试两个对象中心的距离小于它们的包围球半径之和。

    使用包围球测试拾取,首先要找到法线上距离对象中心最近的点。当创建包围球时会创建一个名为objectCenterOffset的向量。这是因为模型在本地空间中或许没有以中心点(0,0,0)为圆心,同时会使用对象世界空间作为模型的中心点,这就导致模型的真实中心错误。

    objectCenterOffset是添加到对象世界空间的向量,因此当检测拾取时能够通过它使用到对象的真实中心,否则包围球不会正确地覆盖到模型。



    可以找到射线上距离对象中心最近的点,使用这个方程式:(N是法线上距离对象中心最近的点,prO拾取射线的位置或原点,prD是拾取法线的目的,oP是对象的位置)

    N = prO + Dot((oP - prO), prD) / Dot(prD, prD) * prD;

    在得到法线上距离对象位置最近的点之后,之后就是得到它们之间的距离,可使用xna数学库的向量函数XMVector3Length()返回一个包含分量x,y,z和w的向量值,它是两点的距离,可作为该函数的参数使用。可从返回值向量中解析出一个分量得到标量值,该值就是两点之间的距离,若要得到x的值,则使用函数XMVectorGetX,获取y,z和w值方法类似,把XMVectorGetX改为XMVectorGetY,XMVectorGetZ,XMVectorGetW即可。

    最后,要判断一下XMVector3Length()的返回值是否小于物体包围球的值,若是,则表示拾取射线与包围球有相交,随后进行更为准确的检测,比如使用实际模型进行检测。

    包围盒

    包围盒一般都用两个顶点或向量来描述,一个最小一个最大,通过遍历整个模型的顶点来找到最小和最大的x,y,z值,并分别存入最小向量和最大向量中,本章中会使用这两个向量来创建一个真实的盒子网格以便检测和拾取射线的相交性。

    有两种包围,轴对齐包围盒(AABB)以及定向包围盒(OBB)。轴对齐包围盒的所有面都是与世界空间的轴对齐的,而定向包围盒的面都是与物体空间轴对齐的,也就是相对世界空间可以任意旋转;定向包围盒具有方向性,可以旋转,轴对齐包围盒不能旋转,如下,从左到右分别为球体,轴对称包围盒,定向包围盒,可参考网址



    包围盒在长条形的模型上表现一般更为精准,比如铅笔之类的模型。由于若有拾取射线相交,则它需要一一测试构成包围盒的12个三角形,因此会比包围球要求更多的计算时间。检测射线是否和三角形相交比仅仅测试射线到一个点的距离要花费更多的计算时间,但是相比测试模型中成千个三角形来说,只测试12个三角形的相交还是要快很多的。

    检测拾取包围盒与检测拾取模型是一样的,因此可以使用同一个拾取方法。

    包围模型(包围网格)

    在模型编程中创建这些东西。若有一个含有大量三角形的复杂模型,仅仅使用包围盒或包围球也不会很准确的,同时会消耗很长的时间去测试实际模型的拾取或碰撞,这时候就需要使用包围模型来解决了。这是在模型编程中做的,且不会渲染到场景中去。它的目的为了做测试,且它的形状和要测试的模型一模一样,但是包含的要测试的三角形要少的多。

    包围模型测试方法除为了加速流程而包含更少的三角形外,其他和原始模型一样。


    子集:

    还有一些小子集的包围体,假设有一个第一人称射击游戏,并想把爆头设计为致命伤害,而射击到四肢时设计为少量伤害。为了实现这个功能,需要为该模型上的每个子集创建各自的包围体。整个模型有一个包围盒,当包围盒通过拾取测试后,就要进一步做四肢,身体或头部的拾取测试。在测试完所有子集包围体后,可在子集包围体下执行的操作。



    模型新添加的全局变量

    为加载的模型添加全局变量。这些全局变量是和包围体子集有关的。第一个float值表示模型包围球的半径。接下来的两个变量保存包围盒几何体,最后一个向量表示模型本地空间(边界盒在世界空间中的默认中心)中的(0,0,0)和模型真实中心的偏移,通过该向量能够让模型包围球以模型真实中心为中心,而不仅仅以模型本地空间的(0,0,0)点为中心。

    瓶子数量设为1000个,可更好体现不同的拾取方法间差异(包围盒,包围球和模型)

    XMMATRIX bottleWorld[1000];
    int* bottleHit = new int[1000];
    int numBottles = 1000;
    
    float bottleBoundingSphere = 0.0f;
    std::vector<XMFLOAT3> bottleBoundingBoxVertPosArray;
    std::vector<DWORD> bottleBoundingBoxVertIndexArray;
    XMVECTOR bottleCenterOffset;


    三个全局声明

    第一个用于在键盘按下p键时切换不同的拾取方法(eg.包围球,包围盒,模型);第一个用于计算开始拾取到拾取结束的时间,以便可在秒级直观看到使用包围体比直接拾取模型的速度要快的多,当做拾取操作时不再会冻帧了。最后一个用于在键p按下时跟踪按键状态,避免p在按下时每帧都使用不同的拾取方法。

    int pickWhat = 0;
    
    double pickOpSpeed = 0.0f;
    
    bool isPDown = false;


    CreateBoundingVolumes()函数原型

    下面是给模型创建包围体的函数原型,第一个参数用于存储模型顶点位置的数组向量。第二个参数为返回的数组,存储包围盒顶点位置。第三个参数为包围盒的索引数组,用于拾取操作。第四个为float型值,存储包围球的半径值,第五个向量表示模型空间模型的真实中心。

    void CreateBoundingVolumes(std::vector<XMFLOAT3> &vertPosArray,    // The array containing our models vertex positions
        std::vector<XMFLOAT3>& boundingBoxVerts,                            // Array we want to store the bounding box's vertex positions
        std::vector<DWORD>& boundingBoxIndex,                            // This is our bounding box's index array
        float &boundingSphere,                                            // The float containing the radius of our bounding sphere
        XMVECTOR &objectCenterOffset);                                    // A vector containing the distance between the models actual center and (0, 0, 0) in model space


    拾取包围体

    下面是检测输入,在前面章节中是使用鼠标单击来检测拾取。这里会遍历每个要检测拾取的模型,并进行拾取操作。

    代码行double pickOpStartTime = GetTIme();该行保存开始拾取操作时刻的时间。在拾取操作完成后,会有一行代码pickOpSpeed = GetTime() - pickOpStartTime;用于获取拾取操作的耗时,该耗时pickOpSpeed会显示在屏幕上。

    if(mouseCurrState.rgbButtons[0])
        {
            if(isShoot == false)
            {    
                POINT mousePos;
    
                GetCursorPos(&mousePos);            
                ScreenToClient(hwnd, &mousePos);
    
                int mousex = mousePos.x;
                int mousey = mousePos.y;        
    
                float tempDist;
                float closestDist = FLT_MAX;
                int hitIndex;
    
                XMVECTOR prwsPos, prwsDir;
                pickRayVector(mousex, mousey, prwsPos, prwsDir);
    
                double pickOpStartTime = GetTime();        // Get the time before we start our picking operation
    
                for(int i = 0; i < numBottles; i++)
                {
                    if(bottleHit[i] == 0) // No need to check bottles already hit
                    {        
                        tempDist = FLT_MAX;
    
                        if(pickWhat == 0)
                        {                        
                            float pRToPointDist = 0.0f; // Closest distance from the pick ray to the objects center
    
                            XMVECTOR bottlePos = XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f);
                            XMVECTOR pOnLineNearBottle = XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f);
    
                            // For the Bounding Sphere to work correctly, we need to make sure we are testing
                            // the distance from the objects "actual" center and the pick ray. We have stored
                            // the distance from (0, 0, 0) in the objects model space to the object "actual"
                            // center in bottleCenterOffset. So now we just need to add that difference to
                            // the bottles world space position, this way the bounding sphere will be centered
                            // on the object real center.
                            bottlePos = XMVector3TransformCoord(bottlePos, bottleWorld[i]) + bottleCenterOffset;
    
                            // This equation gets the point on the pick ray which is closest to bottlePos
                            pOnLineNearBottle = prwsPos + XMVector3Dot((bottlePos - prwsPos), prwsDir) / XMVector3Dot(prwsDir, prwsDir) * prwsDir;
    
                            // Now we get the distance between bottlePos and pOnLineNearBottle
                            // This line is slightly less accurate, but it offers a performance increase by
                            // estimating the distance using XMVector3LengthEst()
                            //pRToPointDist = XMVectorGetX(XMVector3LengthEst(pOnLineNearBottle - bottlePos));                
                            pRToPointDist = XMVectorGetX(XMVector3Length(pOnLineNearBottle - bottlePos));
    
                            // If the distance between the closest point on the pick ray (pOnLineNearBottle) to bottlePos
                            // is less than the bottles bounding sphere (represented by a float called bottleBoundingSphere)
                            // then we know the pick ray has intersected with the bottles bounding sphere, and we can move on
                            // to testing if the pick ray has actually intersected with the bottle itself.
                            if(pRToPointDist < bottleBoundingSphere)
                            {
                                // This line is the distance to the pick ray intersection with the sphere
                                //tempDist = XMVectorGetX(XMVector3Length(pOnLineNearBottle - prwsPos));
    
                                // Check for picking with the actual model now
                                tempDist = pick(prwsPos, prwsDir, bottleVertPosArray, bottleVertIndexArray, bottleWorld[i]);
                            }
                        }
    
                        // Bounding Box picking test
                        if(pickWhat == 1)
                            tempDist = pick(prwsPos, prwsDir, bottleBoundingBoxVertPosArray, bottleBoundingBoxVertIndexArray, bottleWorld[i]);
    
                        // Check for picking directly with the model without bounding volumes testing first
                        if(pickWhat == 2)
                            tempDist = pick(prwsPos, prwsDir, bottleVertPosArray, bottleVertIndexArray, bottleWorld[i]);
    
                        if(tempDist < closestDist)
                        {
                            closestDist = tempDist;
                            hitIndex = i;
                        }
                    }
                }
    
                // This is the time in seconds it took to complete the picking process
                pickOpSpeed = GetTime() - pickOpStartTime;
    
                if(closestDist < FLT_MAX)
                {
                    bottleHit[hitIndex] = 1;
                    pickedDist = closestDist;
                    score++;
                }        
    
                isShoot = true;
            }
        }

    为拾取操作选择最好的包围体

    这里增加一个选项用于选择使用哪种方式检测拾取操作,这里有三种方式可供选择:

    若pickWhat为0,则会使用包围球方式来检测拾取。若模型的包围球被拾取,则会进一步使用更为准确的拾取方式去检测模型。这是最快的检测方法。

    第二种方式一般会比包围球方式更准确(没有直接检测模型),尤其针对长条形的模型。使用这种方式检测拾取会耗费更长的时间。

    最后,若pickWhat为2,则会不使用包围体情况下直接检测拾取模型。这需要耗费几秒的时间。

                        if(pickWhat == 0)
                        {    
                            float pRToPointDist = 0.0f; // Closest distance from the pick ray to the objects center
    
                            XMVECTOR bottlePos = XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f);
                            XMVECTOR pOnLineNearBottle = XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f);
    
                            // For the Bounding Sphere to work correctly, we need to make sure we are testing
                            // the distance from the objects "actual" center and the pick ray. We have stored
                            // the distance from (0, 0, 0) in the objects model space to the object "actual"
                            // center in bottleCenterOffset. So now we just need to add that difference to
                            // the bottles world space position, this way the bounding sphere will be centered
                            // on the object real center.
                            bottlePos = XMVector3TransformCoord(bottlePos, bottleWorld[i]) + bottleCenterOffset;
    
                            // This equation gets the point on the pick ray which is closest to bottlePos
                            pOnLineNearBottle = prwsPos + XMVector3Dot((bottlePos - prwsPos), prwsDir) / XMVector3Dot(prwsDir, prwsDir) * prwsDir;
    
                            // Now we get the distance between bottlePos and pOnLineNearBottle
                            // This line is slightly less accurate, but it offers a performance increase by
                            // estimating the distance using XMVector3LengthEst()
                            //pRToPointDist = XMVectorGetX(XMVector3LengthEst(pOnLineNearBottle - bottlePos));                
                            pRToPointDist = XMVectorGetX(XMVector3Length(pOnLineNearBottle - bottlePos));
    
                            // If the distance between the closest point on the pick ray (pOnLineNearBottle) to bottlePos
                            // is less than the bottles bounding sphere (represented by a float called bottleBoundingSphere)
                            // then we know the pick ray has intersected with the bottles bounding sphere, and we can move on
                            // to testing if the pick ray has actually intersected with the bottle itself.
                            if(pRToPointDist < bottleBoundingSphere)
                            {
                                // This line is the distance to the pick ray intersection with the sphere
                                //tempDist = XMVectorGetX(XMVector3Length(pOnLineNearBottle - prwsPos));
    
                                // Check for picking with the actual model now
                                tempDist = pick(prwsPos, prwsDir, bottleVertPosArray, bottleVertIndexArray, bottleWorld[i]);
                            }
                        }
    
                        // Bounding Box picking test
                        if(pickWhat == 1)
                            tempDist = pick(prwsPos, prwsDir, bottleBoundingBoxVertPosArray, bottleBoundingBoxVertIndexArray, bottleWorld[i]);
    
                        // Check for picking directly with the model without bounding volumes testing first
                        if(pickWhat == 2)
                            tempDist = pick(prwsPos, prwsDir, bottleVertPosArray, bottleVertIndexArray, bottleWorld[i]);



    CreateBoundingVolumes()函数

    当为模型创建包围体时调用该函数。首先是为了得到包含最大和最小x,y和z值的两个点。遍历数组vertPosArray中的每个顶点,并检测最小x,然后再检测y,然后再检测z;并将它们的位置值(x,y或z)与minVertex中的x,y,z对比,若前者小于后者,则将前者赋值给后者,最后得到最小位置值。最大位置值的获取同样使用该方法。在获取两点后,若将该两点作为盒子的对角来创建盒子,那么所创建的盒子就能够紧密覆盖整个模型。

    随后,还可在包围球上使用该两点。首先找到这两点的中点位置,并存储在变量objectCenterOffset中,之后在世界空间中可用它来确认包围球是以对象真实中心为中心的,而不仅是以物体模型空间的点(0,0,0)为中心。获取物体的真实中心后,就能够创建包围球了。所要做的就是得到模型中心分别到最小和最大顶点的距离,可调用xna数学库函数XMVector3Length()来获取最小和最大向量间的距离。

    随后在向量boundingBoxVerts中保存8个用来构建包围盒的顶点,同时这些顶点由最小和最大向量构成,最后创建包围盒,并在boundingBoxIndex中保存包围盒顶点索引。

    void CreateBoundingVolumes(std::vector<XMFLOAT3> &vertPosArray,
        std::vector<XMFLOAT3>& boundingBoxVerts,
        std::vector<DWORD>& boundingBoxIndex,
        float &boundingSphere,
        XMVECTOR &objectCenterOffset)
    {
        D3DXVECTOR3 minVertex = D3DXVECTOR3(FLT_MAX, FLT_MAX, FLT_MAX);
        D3DXVECTOR3 maxVertex = D3DXVECTOR3(-FLT_MAX, -FLT_MAX, -FLT_MAX);
    
        for(UINT i = 0; i < vertPosArray.size(); i++)
        {        
            // The minVertex and maxVertex will most likely not be actual vertices in the model, but vertices
            // that use the smallest and largest x, y, and z values from the model to be sure ALL vertices are
            // covered by the bounding volume
    
            //Get the smallest vertex 
            minVertex.x = min(minVertex.x, vertPosArray[i].x);    // Find smallest x value in model
            minVertex.y = min(minVertex.y, vertPosArray[i].y);    // Find smallest y value in model
            minVertex.z = min(minVertex.z, vertPosArray[i].z);    // Find smallest z value in model
    
            //Get the largest vertex 
            maxVertex.x = max(maxVertex.x, vertPosArray[i].x);    // Find largest x value in model
            maxVertex.y = max(maxVertex.y, vertPosArray[i].y);    // Find largest y value in model
            maxVertex.z = max(maxVertex.z, vertPosArray[i].z);    // Find largest z value in model
        }
    
        // Compute distance between maxVertex and minVertex
        float distX = (maxVertex.x - minVertex.x) / 2.0f;
        float distY = (maxVertex.y - minVertex.y) / 2.0f;
        float distZ = (maxVertex.z - minVertex.z) / 2.0f;    
    
        // Now store the distance between (0, 0, 0) in model space to the models real center
        objectCenterOffset = XMVectorSet(maxVertex.x - distX, maxVertex.y - distY, maxVertex.z - distZ, 0.0f);
    
        // Compute bounding sphere (distance between min and max bounding box vertices)
        // boundingSphere = sqrt(distX*distX + distY*distY + distZ*distZ) / 2.0f;
        boundingSphere = XMVectorGetX(XMVector3Length(XMVectorSet(distX, distY, distZ, 0.0f)));    
    
        // Create bounding box    
        // Front Vertices
        boundingBoxVerts.push_back(XMFLOAT3(minVertex.x, minVertex.y, minVertex.z));
        boundingBoxVerts.push_back(XMFLOAT3(minVertex.x, maxVertex.y, minVertex.z));
        boundingBoxVerts.push_back(XMFLOAT3(maxVertex.x, maxVertex.y, minVertex.z));
        boundingBoxVerts.push_back(XMFLOAT3(maxVertex.x, minVertex.y, minVertex.z));
    
        // Back Vertices
        boundingBoxVerts.push_back(XMFLOAT3(minVertex.x, minVertex.y, maxVertex.z));
        boundingBoxVerts.push_back(XMFLOAT3(maxVertex.x, minVertex.y, maxVertex.z));
        boundingBoxVerts.push_back(XMFLOAT3(maxVertex.x, maxVertex.y, maxVertex.z));
        boundingBoxVerts.push_back(XMFLOAT3(minVertex.x, maxVertex.y, maxVertex.z));
    
        DWORD* i = new DWORD[36];
    
        // Front Face
        i[0] = 0; i[1] = 1; i[2] = 2;
        i[3] = 0; i[4] = 2; i[5] = 3;
    
        // Back Face
        i[6] = 4; i[7]  = 5; i[8]  = 6;
        i[9] = 4; i[10] = 6; i[11] = 7;
    
        // Top Face
        i[12] = 1; i[13] = 7; i[14] = 6;
        i[15] = 1; i[16] = 6; i[17] = 2;
    
        // Bottom Face
        i[18] = 0; i[19] = 4; i[20] = 5;
        i[21] = 0; i[22] = 5; i[23] = 3;
    
        // Left Face
        i[24] = 4; i[25] = 7; i[26] = 1;
        i[27] = 4; i[28] = 1; i[29] = 0;
    
        // Right Face
        i[30] = 3; i[31] = 2; i[32] = 6;
        i[33] = 3; i[34] = 6; i[35] = 5;
    
        for(int j = 0; j < 36; j++)
            boundingBoxIndex.push_back(i[j]);
    }


    创建瓶子的包围体

    使用函数CreateBoundingVolumes()函数创建瓶子包围体,首先传入瓶子顶点位置,后面的参数是用于保存包围体信息。

    CreateBoundingVolumes(bottleVertPosArray, bottleBoundingBoxVertPosArray, bottleBoundingBoxVertIndexArray, bottleBoundingSphere, bottleCenterOffset);

    新的文本信息

    在RenderText()函数中显示与本章节额外的信息。显示当前正在使用的拾取方法,首先判断pickWhat值并设置字符串pickWhatStr到当前正在使用的拾取方法。之后显示拾取方法所用的时间,以秒为单位。

        // Display which picking method we are doing
        std::wstring pickWhatStr;
        if(pickWhat == 0)
            pickWhatStr = L"Bounding Sphere";
        if(pickWhat == 1)
            pickWhatStr = L"Bounding Box";
        if(pickWhat == 2)
            pickWhatStr = L"Model";
    
        //Create our string
        std::wostringstream printString; 
        printString << text << inInt << L"\n"
            << L"Score: " << score << L"\n"
            << L"Picked Dist: " << pickedDist << L"\n"
            << L"Pick Operation Speed: " << pickOpSpeed << L"\n"
            << L"Picking Method (P): " << pickWhatStr;






    代码实例:

    #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")
    ///**************new**************
    #pragma comment (lib, "dinput8.lib")
    #pragma comment (lib, "dxguid.lib")
    ///**************new**************
    
    #include <windows.h>
    #include "Resource.h"
    #include <d3d11.h>
    #include <d3dx11.h>
    #include <d3dx10.h>
    #include <xnamath.h>
    #include <D3D10_1.h>
    #include <DXGI.h>
    #include <D2D1.h>
    #include <sstream>
    #include <dwrite.h>
    ///**************new**************
    #include <dinput.h>
    ///**************new**************
    ///**************new**************
    #include <vector>
    #include <fstream>
    #include <istream>
    ///**************new**************
    //全局描述符
    IDXGISwapChain* SwapChain;
    ID3D11Device* d3d11Device;
    ID3D11DeviceContext* d3d11DevCon;
    ID3D11RenderTargetView* renderTargetView;
    
    //索引缓冲
    //ID3D11Buffer* squareIndexBuffer;
    
    //深度值-20170927
    ID3D11DepthStencilView* depthStencilView;
    ID3D11Texture2D* depthStencilBuffer;
    
    //着色器
    //ID3D11Buffer* squareVertBuffer;
    ID3D11VertexShader* VS;
    ID3D11PixelShader* PS;
    ID3D11PixelShader* D2D_PS;
    ID3D10Blob* D2D_PS_Buffer;
    ID3D10Blob* VS_Buffer;
    ID3D10Blob* PS_Buffer;
    ID3D11InputLayout* vertLayout;
    
    ///
    ID3D11Buffer* cbPerObjectBuffer;
    ID3D11BlendState* d2dTransparency;
    ID3D11RasterizerState* CCWcullMode;
    ID3D11RasterizerState* CWcullMode;
    //ID3D11ShaderResourceView* CubesTexture;
    ID3D11SamplerState* CubesTexSamplerState;
    
    ID3D11Buffer* cbPerFrameBuffer;
    
    ID3D10Device1 *d3d101Device;
    IDXGIKeyedMutex *keyedMutex11;
    IDXGIKeyedMutex *keyedMutex10;
    ID2D1RenderTarget *D2DRenderTarget;
    ID2D1SolidColorBrush *Brush;
    ID3D11Texture2D *BackBuffer11;
    ID3D11Texture2D *sharedTex11;
    ID3D11Buffer *d2dVertBuffer;
    ID3D11Buffer *d2dIndexBuffer;
    ID3D11ShaderResourceView *d2dTexture;
    IDWriteFactory *DWriteFactory;
    IDWriteTextFormat *TextFormat;
    ///**************new**************
    IDirectInputDevice8* DIKeyboard;
    IDirectInputDevice8* DIMouse;
    ///**************new**************
    ID3D11Buffer* sphereIndexBuffer;
    ID3D11Buffer* sphereVertBuffer;
    
    ID3D11VertexShader* SKYMAP_VS;
    ID3D11PixelShader* SKYMAP_PS;
    ID3D10Blob* SKYMAP_VS_Buffer;
    ID3D10Blob* SKYMAP_PS_Buffer;
    
    ID3D11ShaderResourceView* smrv;
    
    ID3D11DepthStencilState* DSLessEqual;
    ID3D11RasterizerState* RSCullNone;
    ///**************new**************
    ID3D11BlendState* Transparency;
    //网格变量,每个被加载的网格需要它自己的集
    ID3D11Buffer* meshVertBuff;
    ID3D11Buffer* meshIndexBuff;
    ///**************new**************
    std::vector<XMFLOAT3> groundVertPosArray;
    std::vector<DWORD> groundVertIndexArray;
    ///**************new**************
    XMMATRIX meshWorld;
    int meshSubsets = 0;
    std::vector<int> meshSubsetIndexStart;
    std::vector<int> meshSubsetTexture;
    
    ///**************new**************
    //Bottle mesh variables//
    ID3D11Buffer* bottleVertBuff;
    ID3D11Buffer* bottleIndexBuff;
    std::vector<XMFLOAT3> bottleVertPosArray;
    std::vector<DWORD> bottleVertIndexArray;
    int bottleSubsets = 0;
    std::vector<int> bottleSubsetIndexStart;
    std::vector<int> bottleSubsetTexture;
    XMMATRIX bottleWorld[1000];
    int* bottleHit = new int[1000];
    int numBottles = 1000;
    ///**************new**************
    float bottleBoundingSphere = 0.0f;
    std::vector<XMFLOAT3> bottleBoundingBoxVertPosArray;
    std::vector<DWORD> bottleBoundingBoxVertIndexArray;
    XMVECTOR bottleCenterOffset;
    //纹理和材质变量,用于所有的网格的加载
    std::vector<ID3D11ShaderResourceView*> meshSRV;
    std::vector<std::wstring> textureNameArray;
    ///**************new**************
    std::wstring printText;
    /
    LPCTSTR WndClassName = L"firstwindow";
    HWND hwnd = NULL;
    HRESULT hr;
    
    const int Width = 1920; //设置宽
    const int Height = 1200; // 设置高
    
    ///**************new**************
    DIMOUSESTATE mouseLastState;
    LPDIRECTINPUT8 DirectInput;
    
    float rotx = 0;
    float rotz = 0;
    float scaleX = 1.0f;
    float scaleY = 1.0f;
    
    XMMATRIX Rotationx;
    //XMMATRIX Rotationy;
    XMMATRIX Rotationz;
    XMMATRIX Rotationy;
    ///**************new**************
    ///四个空间以及相机属性
    XMMATRIX WVP;
    //立方体
    //XMMATRIX cube1World;
    //XMMATRIX cube2World;
    //
    //XMMATRIX World;
    XMMATRIX camView;
    XMMATRIX camProjection;
    
    XMMATRIX d2dWorld;
    XMVECTOR camPosition;
    XMVECTOR camTarget;
    XMVECTOR camUp;
    ///**************new**************
    XMVECTOR DefaultForward = XMVectorSet(0.0f,0.0f,1.0f, 0.0f);
    XMVECTOR DefaultRight = XMVectorSet(1.0f,0.0f,0.0f, 0.0f);
    XMVECTOR camForward = XMVectorSet(0.0f,0.0f,1.0f, 0.0f);
    XMVECTOR camRight = XMVectorSet(1.0f,0.0f,0.0f, 0.0f);
    
    XMMATRIX camRotationMatrix;
    //XMMATRIX groundWorld;
    
    float moveLeftRight = 0.0f;
    float moveBackForward = 0.0f;
    
    float camYaw = 0.0f;
    float camPitch = 0.0f;
    ///**************new**************
    int NumSphereVertices;
    int NumSphereFaces;
    
    XMMATRIX sphereWorld;
    ///**************new**************
    XMMATRIX Rotation;
    XMMATRIX Scale;
    XMMATRIX Translation;
    ///**************new**************
    bool isShoot = false;
    
    int ClientWidth = 0;
    int ClientHeight = 0;
    
    int score = 0;
    float pickedDist = 0.0f;
    ///**************new**************
    int pickWhat = 0;
    
    double pickOpSpeed = 0.0f;
    
    bool isPDown = false;
    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);
    ///**************new**************
    void UpdateCamera();
    
    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消息,比如一个按键按下(也叫事件)以及程序操作流程。
    ///**************new**************
    bool InitDirectInput(HINSTANCE hInstance);
    void DetectInput(double time);
    ///**************new**************
    void CreateSphere(int LatLines, int LongLines);
    ///**************new**************
    void pickRayVector(float mouseX, float mouseY, XMVECTOR& pickRayInWorldSpacePos, XMVECTOR& pickRayInWorldSpaceDir);
    float pick(XMVECTOR pickRayInWorldSpacePos,
    	XMVECTOR pickRayInWorldSpaceDir,
    	std::vector<XMFLOAT3>& vertPosArray,
    	std::vector<DWORD>& indexPosArray,
    	XMMATRIX& worldSpace);
    bool PointInTriangle(XMVECTOR& triV1, XMVECTOR& triV2, XMVECTOR& triV3, XMVECTOR& point );
    ///**************new**************
    void CreateBoundingVolumes(std::vector<XMFLOAT3> &vertPosArray,    // 包含模型顶点位置的数组
        std::vector<XMFLOAT3>& boundingBoxVerts,                            // 存储包围盒顶点位置的数组
        std::vector<DWORD>& boundingBoxIndex,                            // 存储包围盒索引的数组
        float &boundingSphere,                                            // 存储包围球半径的浮点型
        XMVECTOR &objectCenterOffset);                                    // 用于保存模型空间中模型质心到(0,0,0)的距离
    LRESULT CALLBACK WndProc(HWND hWnd,
    	UINT msg,
    	WPARAM wParam,
    	LPARAM lParam);
    
    ///new
    //创建效果常量缓冲的结构体
    struct cbPerObject
    {
    	XMMATRIX WVP;
    	XMMATRIX World;
    
    	///**************new**************
    	//用于像素着色器
    	XMFLOAT4 difColor;
    	BOOL hasTexture;
    	///**************new**************
    	//Because of HLSL structure packing, we will use windows BOOL
    	//instead of bool because HLSL packs things into 4 bytes, and
    	//bool is only one byte, where BOOL is 4 bytes
    	BOOL hasNormMap;
    	///**************new**************
    };
    
    cbPerObject cbPerObj;
    
    ///**************new**************
    //创建材质结构体
    struct SurfaceMaterial
    {
    	std::wstring matName;
    	XMFLOAT4 difColor;
    	int texArrayIndex;
    	///**************new**************
    	int normMapTexArrayIndex;
    	bool hasNormMap;
    	///**************new**************
    	bool hasTexture;
    	bool transparent;
    };
    
    std::vector<SurfaceMaterial> material;
    
    //自创建surfaceMaterial结构体后,定义函数LoadObjModel
    bool LoadObjModel(std::wstring filename,			//.obj filename
    	ID3D11Buffer** vertBuff,					//mesh vertex buffer
    	ID3D11Buffer** indexBuff,					//mesh index buffer
    	std::vector<int>& subsetIndexStart,			//start index of each subset
    	std::vector<int>& subsetMaterialArray,		//index value of material for each subset
    	std::vector<SurfaceMaterial>& material,		//vector of material structures
    	int& subsetCount,							//Number of subsets in mesh
    	bool isRHCoordSys,							//true if model was created in right hand coord system
    	bool computeNormals,						//true to compute the normals, false to use the files normals
    	///**************new**************
    	std::vector<XMFLOAT3>& vertPosArray,		//Used for CPU to do calculations on the Geometry
    	std::vector<DWORD>& vertIndexArray);		//Also used for CPU caculations on geometry
    ///**************new**************
    struct Light
    {
    	Light()
    	{
    		ZeroMemory(this, sizeof(Light));
    	}
    	XMFLOAT3 pos;
    	float range;
    	XMFLOAT3 dir;
    	float cone;
    	XMFLOAT3 att;
    	float pad2;
    	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,
    		float tx, float ty, float tz)
    		: pos(x,y,z), texCoord(u, v), normal(nx, ny, nz),
    		tangent(tx, ty, tz){}
    	XMFLOAT3 pos;
    	XMFLOAT2 texCoord;
    	XMFLOAT3 normal;
    	///**************new**************
    	XMFLOAT3 tangent;
    	XMFLOAT3 biTangent;
    	///**************new**************
    };
    
    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},
    	///**************new**************
    	{ "TANGENT", 0, DXGI_FORMAT_R32G32B32_FLOAT,    0, 32, D3D11_INPUT_PER_VERTEX_DATA, 0}
    	///**************new**************
    };
    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, L"Window Initialization - Failed",
    			L"Error", MB_OK);
    		return 0;
    	}
    
    	/new
    	if (!InitializeDirect3d11App(hInstance)) // 初始化D3D
    	{
    		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;
    	}
    
    	///**************new**************
    	if(!InitDirectInput(hInstance))
    	{
    		MessageBox(0, L"Direct Input Initialization - Failed",
    			L"Error", MB_OK);
    		return 0;
    	}
    	///**************new**************
    
    	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 + 1);
    	//附加到窗口的菜单名字,不需要的话设置为NULL
    	wc.lpszMenuName = NULL;
    	//对类进行命名
    	wc.lpszClassName = WndClassName;
    	//指定任务栏的图标,使用上面的IDI_图标
        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"picking bottle bounding box",
    		WS_OVERLAPPEDWINDOW, 
    		CW_USEDEFAULT, 
    		CW_USEDEFAULT, 
    		width,
    		height, 
    		NULL,
    		NULL,
    		hInstance,
    		NULL
    		);
    
    	if (!hwnd)
    	{
    		MessageBox(NULL, L"Error registering class", L"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;
    	///**************new**************
    	swapChainDesc.Windowed = true; 
    	///**************new**************
    	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<IUnknown **>(&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;
    }
    
    ///**************new**************
    bool InitDirectInput(HINSTANCE hInstance)
    {
        hr = DirectInput8Create(hInstance,
            DIRECTINPUT_VERSION,
            IID_IDirectInput8,
            (void**)&DirectInput,
            NULL); 
    
        hr = DirectInput->CreateDevice(GUID_SysKeyboard,
            &DIKeyboard,
            NULL);
    
        hr = DirectInput->CreateDevice(GUID_SysMouse,
            &DIMouse,
            NULL);
    
        hr = DIKeyboard->SetDataFormat(&c_dfDIKeyboard);
        hr = DIKeyboard->SetCooperativeLevel(hwnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE);
    
        hr = DIMouse->SetDataFormat(&c_dfDIMouse);
    	hr = DIMouse->SetCooperativeLevel(hwnd, DISCL_NONEXCLUSIVE | DISCL_NOWINKEY | DISCL_FOREGROUND);
    
        return true;
    }
    
    void UpdateCamera()
    {
    	camRotationMatrix = XMMatrixRotationRollPitchYaw(camPitch, camYaw, 0);
    	camTarget = XMVector3TransformCoord(DefaultForward, camRotationMatrix );
    	camTarget = XMVector3Normalize(camTarget);
    
    	XMMATRIX RotateYTempMatrix;
    	RotateYTempMatrix = XMMatrixRotationY(camYaw);
    
    	camRight = XMVector3TransformCoord(DefaultRight, RotateYTempMatrix);
    	camUp = XMVector3TransformCoord(camUp, RotateYTempMatrix);
    	camForward = XMVector3TransformCoord(DefaultForward, RotateYTempMatrix);
    
    	camPosition += moveLeftRight*camRight;
    	camPosition += moveBackForward*camForward;
    
    	moveLeftRight = 0.0f;
    	moveBackForward = 0.0f;
    
    	camTarget = camPosition + camTarget;	
    
    	camView = XMMatrixLookAtLH( camPosition, camTarget, camUp );
    }
    void DetectInput(double time)
    {
        DIMOUSESTATE mouseCurrState;
    
        BYTE keyboardState[256];
    
        DIKeyboard->Acquire();
        DIMouse->Acquire();
    
        DIMouse->GetDeviceState(sizeof(DIMOUSESTATE), &mouseCurrState);
    
        DIKeyboard->GetDeviceState(sizeof(keyboardState),(LPVOID)&keyboardState);
    
        if(keyboardState[DIK_ESCAPE] & 0x80)
            PostMessage(hwnd, WM_DESTROY, 0, 0);
    
    	float speed = 10.0f * time;
    
    	if(keyboardState[DIK_A] & 0x80)
    	{
    		moveLeftRight -= speed;
    	}
    	if(keyboardState[DIK_D] & 0x80)
    	{
    		moveLeftRight += speed;
    	}
    	if(keyboardState[DIK_W] & 0x80)
    	{
    		moveBackForward += speed;
    	}
    	if(keyboardState[DIK_S] & 0x80)
    	{
    		moveBackForward -= speed;
    	}
        if(keyboardState[DIK_P] & 0x80)
        {
            if(!isPDown)
            {
                pickWhat++;
                if(pickWhat == 3)
                    pickWhat = 0;
                isPDown = true;
            }
        }
        if(!(keyboardState[DIK_P] & 0x80))
        {
            isPDown = false;
        }
    	///**************new**************
    	if(mouseCurrState.rgbButtons[0])
    	{
    		if(isShoot == false)
    		{	
    			POINT mousePos;
    
    			GetCursorPos(&mousePos);			
    			ScreenToClient(hwnd, &mousePos);
    
    			int mousex = mousePos.x;
    			int mousey = mousePos.y;		
    
    			float tempDist;
    			float closestDist = FLT_MAX;
    			int hitIndex;
    
    			XMVECTOR prwsPos, prwsDir;
    			pickRayVector(mousex, mousey, prwsPos, prwsDir);
    
                double pickOpStartTime = GetTime();        // 获取拾取操作前的时刻
    			for(int i = 0; i < numBottles; i++)
    			{
    				if(bottleHit[i] == 0) //No need to check bottles already hit
    				{
                        tempDist = FLT_MAX;
    
                        if(pickWhat == 0)
                        {                        
                            float pRToPointDist = 0.0f; // 拾取射线到物体质心的最近距离
    
                            XMVECTOR bottlePos = XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f);
                            XMVECTOR pOnLineNearBottle = XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f);
    
                            // 为了确保包围球起作用,必须确保检测的是物体质心到拾取射线的距离
    						// 变量bottleCenterOffset中保存物体模型空间中心点(0,0,0)到物体质心的距离,
    						// 因此要将该距离添加到瓶子世界空间位置上,这样包围球就会以物体质心为中心了。
                            bottlePos = XMVector3TransformCoord(bottlePos, bottleWorld[i]) + bottleCenterOffset;
    
                            // 该方程得到拾取射线上距离bottlePos最近的点
                            pOnLineNearBottle = prwsPos + XMVector3Dot((bottlePos - prwsPos), prwsDir) / XMVector3Dot(prwsDir, prwsDir) * prwsDir;
    
                            // 这里得到bottlePos与pOnLineNearBottle之间的距离
                            // 这种方式会有点失去准确度,但是通过使用函数XMVector3LengthEst()预估距离来提升性能
                            // 
                            //pRToPointDist = XMVectorGetX(XMVector3LengthEst(pOnLineNearBottle - bottlePos));                
                            pRToPointDist = XMVectorGetX(XMVector3Length(pOnLineNearBottle - bottlePos));
    
                            // 若拾取射线上距离bottlePos最近的点到bottlePose的距离比瓶子包围体半径(bottleBoundingSphere)小
                            // 则可知拾取射线与瓶子包围体相交,之后进一步检测拾取射线是否与瓶子真正相交。
                            if(pRToPointDist < bottleBoundingSphere)
                            {
                                // 这里是拾取法线和球体相交的距离
                                //tempDist = XMVectorGetX(XMVector3Length(pOnLineNearBottle - prwsPos));
    
                                // 检测拾取真实模型
                                tempDist = pick(prwsPos, prwsDir, bottleVertPosArray, bottleVertIndexArray, bottleWorld[i]);
                            }
                        }
    
                        // 包围盒拾取测试
                        if(pickWhat == 1)
                            tempDist = pick(prwsPos, prwsDir, bottleBoundingBoxVertPosArray, bottleBoundingBoxVertIndexArray, bottleWorld[i]);
    
                        // 无包围体,直接检测拾取模型
                        if(pickWhat == 2)
                            tempDist = pick(prwsPos, prwsDir, bottleVertPosArray, bottleVertIndexArray, bottleWorld[i]);
    
                        if(tempDist < closestDist)
                        {
                            closestDist = tempDist;
                            hitIndex = i;
                        }
                    }
                }
    
                // 完成检测流程耗时
                pickOpSpeed = GetTime() - pickOpStartTime;
    
    			if(closestDist < FLT_MAX)
    			{
    				bottleHit[hitIndex] = 1;
    				pickedDist = closestDist;
    				score++;
    			}
    
    			isShoot = true;
    		}
    	}
    	if(!mouseCurrState.rgbButtons[0])
    	{
    		isShoot = false;
    	}
    	///**************new**************
    	if((mouseCurrState.lX != mouseLastState.lX) || (mouseCurrState.lY != mouseLastState.lY))
    	{
    		camYaw += mouseLastState.lX * 0.001f;
    
    		camPitch += mouseCurrState.lY * 0.001f;
    
    		mouseLastState = mouseCurrState;
    	}
    
    	UpdateCamera();
    
    
        return;
    }
    ///**************new**************
    void CreateBoundingVolumes(std::vector<XMFLOAT3> &vertPosArray,
        std::vector<XMFLOAT3>& boundingBoxVerts,
        std::vector<DWORD>& boundingBoxIndex,
        float &boundingSphere,
        XMVECTOR &objectCenterOffset)
    {
        D3DXVECTOR3 minVertex = D3DXVECTOR3(FLT_MAX, FLT_MAX, FLT_MAX);
        D3DXVECTOR3 maxVertex = D3DXVECTOR3(-FLT_MAX, -FLT_MAX, -FLT_MAX);
    
        for(UINT i = 0; i < vertPosArray.size(); i++)
        {        
            // minVertex与maxVertex很有可能不是模型内真实的顶点, 但是
            // 使用模型上的最小和最大的x,y和z值,可确定所有顶点被包围体覆盖
        
    
            //获取最小的向量
            minVertex.x = min(minVertex.x, vertPosArray[i].x);    // 找到模型中最小的x值
            minVertex.y = min(minVertex.y, vertPosArray[i].y);    // 找到模型中最小的y值
            minVertex.z = min(minVertex.z, vertPosArray[i].z);    // 找到模型中最小的z值
    
            //获取最大的向量
            maxVertex.x = max(maxVertex.x, vertPosArray[i].x);    // 找到模型中最大的x值
            maxVertex.y = max(maxVertex.y, vertPosArray[i].y);    // 找到模型中最大的y值
            maxVertex.z = max(maxVertex.z, vertPosArray[i].z);    // 找到模型中最大的z值
        }
    
        // 计算maxVertex和minVertex之间的距离
        float distX = (maxVertex.x - minVertex.x) / 2.0f;
        float distY = (maxVertex.y - minVertex.y) / 2.0f;
        float distZ = (maxVertex.z - minVertex.z) / 2.0f;    
    
        // 保存模型空间内点(0,0,0)到模型质心的距离
        objectCenterOffset = XMVectorSet(maxVertex.x - distX, maxVertex.y - distY, maxVertex.z - distZ, 0.0f);
    
        // 计算包围球(最小和最大包围盒向量的距离)
        // boundingSphere = sqrt(distX*distX + distY*distY + distZ*distZ) / 2.0f;
        boundingSphere = XMVectorGetX(XMVector3Length(XMVectorSet(distX, distY, distZ, 0.0f)));    
    
        // 创建包围盒 
        // 前顶点
        boundingBoxVerts.push_back(XMFLOAT3(minVertex.x, minVertex.y, minVertex.z));
        boundingBoxVerts.push_back(XMFLOAT3(minVertex.x, maxVertex.y, minVertex.z));
        boundingBoxVerts.push_back(XMFLOAT3(maxVertex.x, maxVertex.y, minVertex.z));
        boundingBoxVerts.push_back(XMFLOAT3(maxVertex.x, minVertex.y, minVertex.z));
    
        // 后顶点
        boundingBoxVerts.push_back(XMFLOAT3(minVertex.x, minVertex.y, maxVertex.z));
        boundingBoxVerts.push_back(XMFLOAT3(maxVertex.x, minVertex.y, maxVertex.z));
        boundingBoxVerts.push_back(XMFLOAT3(maxVertex.x, maxVertex.y, maxVertex.z));
        boundingBoxVerts.push_back(XMFLOAT3(minVertex.x, maxVertex.y, maxVertex.z));
    
        DWORD* i = new DWORD[36];
    
        // Front Face
        i[0] = 0; i[1] = 1; i[2] = 2;
        i[3] = 0; i[4] = 2; i[5] = 3;
    
        // Back Face
        i[6] = 4; i[7]  = 5; i[8]  = 6;
        i[9] = 4; i[10] = 6; i[11] = 7;
    
        // Top Face
        i[12] = 1; i[13] = 7; i[14] = 6;
        i[15] = 1; i[16] = 6; i[17] = 2;
    
        // Bottom Face
        i[18] = 0; i[19] = 4; i[20] = 5;
        i[21] = 0; i[22] = 5; i[23] = 3;
    
        // Left Face
        i[24] = 4; i[25] = 7; i[26] = 1;
        i[27] = 4; i[28] = 1; i[29] = 0;
    
        // Right Face
        i[30] = 3; i[31] = 2; i[32] = 6;
        i[33] = 3; i[34] = 6; i[35] = 5;
    
        for(int j = 0; j < 36; j++)
            boundingBoxIndex.push_back(i[j]);
    }
    ///**************new**************
    void CleanUp()
    {
    	///**************new**************
    	SwapChain->SetFullscreenState(false, NULL);
    	PostMessage(hwnd, WM_DESTROY, 0, 0);
    	///**************new**************
    	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();
        ///**************new**************
        DIKeyboard->Unacquire();
        DIMouse->Unacquire();
        DirectInput->Release();
    	sphereIndexBuffer->Release();
    	sphereVertBuffer->Release();
    
    	SKYMAP_VS->Release();
    	SKYMAP_PS->Release();
    	SKYMAP_VS_Buffer->Release();
    	SKYMAP_PS_Buffer->Release();
    
    	smrv->Release();
    
    	DSLessEqual->Release();
    	RSCullNone->Release();
    
    	///**************new**************
    	meshVertBuff->Release();
    	meshIndexBuff->Release();
    	///**************new**************
    	bottleVertBuff->Release();
    	bottleIndexBuff->Release();
    	///**************new**************
    }
    
    ///**************new**************
    void pickRayVector(float mouseX, float mouseY, XMVECTOR& pickRayInWorldSpacePos, XMVECTOR& pickRayInWorldSpaceDir)
    {
    	XMVECTOR pickRayInViewSpaceDir = XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f);
    	XMVECTOR pickRayInViewSpacePos = XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f);
    
    	float PRVecX, PRVecY, PRVecZ;
    
    	//Transform 2D pick position on screen space to 3D ray in View space
    	PRVecX =  ((( 2.0f * mouseX) / ClientWidth ) - 1 ) / camProjection(0,0);
    	PRVecY = -((( 2.0f * mouseY) / ClientHeight) - 1 ) / camProjection(1,1);
    	PRVecZ =  1.0f;	//View space's Z direction ranges from 0 to 1, so we set 1 since the ray goes "into" the screen
    
    	pickRayInViewSpaceDir = XMVectorSet(PRVecX, PRVecY, PRVecZ, 0.0f);
    
        pickRayInViewSpaceDir = XMVector3Normalize(pickRayInViewSpaceDir);
    	//Uncomment this line if you want to use the center of the screen (client area)
    	//to be the point that creates the picking ray (eg. first person shooter)
    	//pickRayInViewSpaceDir = XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f);
    
    	// Transform 3D Ray from View space to 3D ray in World space
    	XMMATRIX pickRayToWorldSpaceMatrix;
    	XMVECTOR matInvDeter;	//We don't use this, but the xna matrix inverse function requires the first parameter to not be null
    
    	pickRayToWorldSpaceMatrix = XMMatrixInverse(&matInvDeter, camView);	//Inverse of View Space matrix is World space matrix
    
    	pickRayInWorldSpacePos = XMVector3TransformCoord(pickRayInViewSpacePos, pickRayToWorldSpaceMatrix);
    	pickRayInWorldSpaceDir = XMVector3TransformNormal(pickRayInViewSpaceDir, pickRayToWorldSpaceMatrix);
    }
    
    float pick(XMVECTOR pickRayInWorldSpacePos,
    	XMVECTOR pickRayInWorldSpaceDir, 
    	std::vector<XMFLOAT3>& vertPosArray,
    	std::vector<DWORD>& indexPosArray, 
    	XMMATRIX& worldSpace)
    { 		
    	//Loop through each triangle in the object
    	for(int i = 0; i < indexPosArray.size()/3; i++)
    	{
    		//Triangle's vertices V1, V2, V3
    		XMVECTOR tri1V1 = XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f);
    		XMVECTOR tri1V2 = XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f);
    		XMVECTOR tri1V3 = XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f);
    
    		//Temporary 3d floats for each vertex
    		XMFLOAT3 tV1, tV2, tV3;
    
    		//Get triangle 
    		tV1 = vertPosArray[indexPosArray[(i*3)+0]];
    		tV2 = vertPosArray[indexPosArray[(i*3)+1]];
    		tV3 = vertPosArray[indexPosArray[(i*3)+2]];
    
    		tri1V1 = XMVectorSet(tV1.x, tV1.y, tV1.z, 0.0f);
    		tri1V2 = XMVectorSet(tV2.x, tV2.y, tV2.z, 0.0f);
    		tri1V3 = XMVectorSet(tV3.x, tV3.y, tV3.z, 0.0f);
    
    		//Transform the vertices to world space
    		tri1V1 = XMVector3TransformCoord(tri1V1, worldSpace);
    		tri1V2 = XMVector3TransformCoord(tri1V2, worldSpace);
    		tri1V3 = XMVector3TransformCoord(tri1V3, worldSpace);
    
    		//Find the normal using U, V coordinates (two edges)
    		XMVECTOR U = XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f);
    		XMVECTOR V = XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f);
    		XMVECTOR faceNormal = XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f);
    
    		U = tri1V2 - tri1V1;
    		V = tri1V3 - tri1V1;
    
    		//Compute face normal by crossing U, V
    		faceNormal = XMVector3Cross(U, V);
    
    		faceNormal = XMVector3Normalize(faceNormal);
    
    		//Calculate a point on the triangle for the plane equation
    		XMVECTOR triPoint = tri1V1;
    
    		//Get plane equation ("Ax + By + Cz + D = 0") Variables
    		float tri1A = XMVectorGetX(faceNormal);
    		float tri1B = XMVectorGetY(faceNormal);
    		float tri1C = XMVectorGetZ(faceNormal);
    		float tri1D = (-tri1A*XMVectorGetX(triPoint) - tri1B*XMVectorGetY(triPoint) - tri1C*XMVectorGetZ(triPoint));
    
    		//Now we find where (on the ray) the ray intersects with the triangles plane
    		float ep1, ep2, t = 0.0f;
    		float planeIntersectX, planeIntersectY, planeIntersectZ = 0.0f;
    		XMVECTOR pointInPlane = XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f);
    
    		ep1 = (XMVectorGetX(pickRayInWorldSpacePos) * tri1A) + (XMVectorGetY(pickRayInWorldSpacePos) * tri1B) + (XMVectorGetZ(pickRayInWorldSpacePos) * tri1C);
    		ep2 = (XMVectorGetX(pickRayInWorldSpaceDir) * tri1A) + (XMVectorGetY(pickRayInWorldSpaceDir) * tri1B) + (XMVectorGetZ(pickRayInWorldSpaceDir) * tri1C);
    
    		//Make sure there are no divide-by-zeros
    		if(ep2 != 0.0f)
    			t = -(ep1 + tri1D)/(ep2);
    
    		if(t > 0.0f)    //Make sure you don't pick objects behind the camera
    		{
    			//Get the point on the plane
    			planeIntersectX = XMVectorGetX(pickRayInWorldSpacePos) + XMVectorGetX(pickRayInWorldSpaceDir) * t;
    			planeIntersectY = XMVectorGetY(pickRayInWorldSpacePos) + XMVectorGetY(pickRayInWorldSpaceDir) * t;
    			planeIntersectZ = XMVectorGetZ(pickRayInWorldSpacePos) + XMVectorGetZ(pickRayInWorldSpaceDir) * t;
    
    			pointInPlane = XMVectorSet(planeIntersectX, planeIntersectY, planeIntersectZ, 0.0f);
    
    			//Call function to check if point is in the triangle
    			if(PointInTriangle(tri1V1, tri1V2, tri1V3, pointInPlane))
    			{
    				//Return the distance to the hit, so you can check all the other pickable objects in your scene
    				//and choose whichever object is closest to the camera
    				return t/2.0f;
    			}
    		}
    	}
    	//return the max float value (near infinity) if an object was not picked
    	return FLT_MAX;
    }
    
    
    bool PointInTriangle(XMVECTOR& triV1, XMVECTOR& triV2, XMVECTOR& triV3, XMVECTOR& point )
    {
    	//To find out if the point is inside the triangle, we will check to see if the point
    	//is on the correct side of each of the triangles edges.
    
    	XMVECTOR cp1 = XMVector3Cross((triV3 - triV2), (point - triV2));
    	XMVECTOR cp2 = XMVector3Cross((triV3 - triV2), (triV1 - triV2));
    	if(XMVectorGetX(XMVector3Dot(cp1, cp2)) >= 0)
    	{
    		cp1 = XMVector3Cross((triV3 - triV1), (point - triV1));
    		cp2 = XMVector3Cross((triV3 - triV1), (triV2 - triV1));
    		if(XMVectorGetX(XMVector3Dot(cp1, cp2)) >= 0)
    		{
    			cp1 = XMVector3Cross((triV2 - triV1), (point - triV1));
    			cp2 = XMVector3Cross((triV2 - triV1), (triV3 - triV1));
    			if(XMVectorGetX(XMVector3Dot(cp1, cp2)) >= 0)
    			{
    				return true;
    			}
    			else
    				return false;
    		}
    		else
    			return false;
    	}
    	return false;
    }
    ///**************new**************
    bool LoadObjModel(std::wstring filename, 
    	ID3D11Buffer** vertBuff, 
    	ID3D11Buffer** indexBuff,
    	std::vector<int>& subsetIndexStart,
    	std::vector<int>& subsetMaterialArray,
    	std::vector<SurfaceMaterial>& material, 
    	int& subsetCount,
    	bool isRHCoordSys,
    	bool computeNormals,
    	///**************new**************
    	std::vector<XMFLOAT3>& vertPosArray,
    	std::vector<DWORD>& vertIndexArray)
    	///**************new**************
    {
    	HRESULT hr = 0;
    
    	std::wifstream fileIn (filename.c_str());	//Open file
    	std::wstring meshMatLib;					//String to hold our obj material library filename
    
    	//存储我们模型的信息的数组
    	std::vector<DWORD> indices;
    	std::vector<XMFLOAT3> vertPos;
    	std::vector<XMFLOAT3> vertNorm;
    	std::vector<XMFLOAT2> vertTexCoord;
    	std::vector<std::wstring> meshMaterials;
    
    	//顶点定义索引
    	std::vector<int> vertPosIndex;
    	std::vector<int> vertNormIndex;
    	std::vector<int> vertTCIndex;
    
    	//如果没有定义纹理坐标或发现,确保有一个默认的值
    	bool hasTexCoord = false;
    	bool hasNorm = false;
    
    	//用于存储向量的临时变量
    	std::wstring meshMaterialsTemp;
    	int vertPosIndexTemp;
    	int vertNormIndexTemp;
    	int vertTCIndexTemp;
    
    	wchar_t checkChar;		//The variable we will use to store one char from file at a time
    	std::wstring face;		//Holds the string containing our face vertices
    	int vIndex = 0;			//Keep track of our vertex index count
    	int triangleCount = 0;	//Total Triangles
    	int totalVerts = 0;
    	int meshTriangles = 0;
    
    	//检测文件是否被打开
    	if (fileIn)
    	{
    		while(fileIn)
    		{			
    			checkChar = fileIn.get();	//Get next char
    
    			switch (checkChar)
    			{		
    			case '#':
    				checkChar = fileIn.get();
    				while(checkChar != '\n')
    					checkChar = fileIn.get();
    				break;
    			case 'v':	//获取向量描述符
    				checkChar = fileIn.get();
    				if(checkChar == ' ')	//v - vert position
    				{
    					float vz, vy, vx;
    					fileIn >> vx >> vy >> vz;	//Store the next three types
    
    					if(isRHCoordSys)	//If model is from an RH Coord System
    						vertPos.push_back(XMFLOAT3( vx, vy, vz * -1.0f));	//Invert the Z axis
    					else
    						vertPos.push_back(XMFLOAT3( vx, vy, vz));
    				}
    				if(checkChar == 't')	//vt - vert tex coords
    				{			
    					float vtcu, vtcv;
    					fileIn >> vtcu >> vtcv;		//Store next two types
    
    					if(isRHCoordSys)	//If model is from an RH Coord System
    						vertTexCoord.push_back(XMFLOAT2(vtcu, 1.0f-vtcv));	//Reverse the "v" axis
    					else
    						vertTexCoord.push_back(XMFLOAT2(vtcu, vtcv));	
    
    					hasTexCoord = true;	//We know the model uses texture coords
    				}
    				//由于我们在后来计算法线,我们不必在此检测法线
    				//In the file, but i'll do it here anyway
    				if(checkChar == 'n')	//vn - vert normal
    				{
    					float vnx, vny, vnz;
    					fileIn >> vnx >> vny >> vnz;	//Store next three types
    
    					if(isRHCoordSys)	//If model is from an RH Coord System
    						vertNorm.push_back(XMFLOAT3( vnx, vny, vnz * -1.0f ));	//Invert the Z axis
    					else
    						vertNorm.push_back(XMFLOAT3( vnx, vny, vnz ));	
    
    					hasNorm = true;	//We know the model defines normals
    				}
    				break;
    
    				//新组(子集)
    			case 'g':	//g - defines a group
    				checkChar = fileIn.get();
    				if(checkChar == ' ')
    				{
    					subsetIndexStart.push_back(vIndex);		//Start index for this subset
    					subsetCount++;
    				}
    				break;
    
    				//获取面索引
    			case 'f':	//f - defines the faces
    				checkChar = fileIn.get();
    				if(checkChar == ' ')
    				{
    					face = L"";
    					std::wstring VertDef;	//Holds one vertex definition at a time
    					triangleCount = 0;
    
    					checkChar = fileIn.get();
    					while(checkChar != '\n')
    					{
    						face += checkChar;			//Add the char to our face string
    						checkChar = fileIn.get();	//Get the next Character
    						if(checkChar == ' ')		//If its a space...
    							triangleCount++;		//Increase our triangle count
    					}
    
    					//Check for space at the end of our face string
    					if(face[face.length()-1] == ' ')
    						triangleCount--;	//Each space adds to our triangle count
    
    					triangleCount -= 1;		//Ever vertex in the face AFTER the first two are new faces
    
    					std::wstringstream ss(face);
    
    					if(face.length() > 0)
    					{
    						int firstVIndex, lastVIndex;	//Holds the first and last vertice's index
    
    						for(int i = 0; i < 3; ++i)		//First three vertices (first triangle)
    						{
    							ss >> VertDef;	//Get vertex definition (vPos/vTexCoord/vNorm)
    
    							std::wstring vertPart;
    							int whichPart = 0;		//(vPos, vTexCoord, or vNorm)
    
    							//Parse this string
    							for(int j = 0; j < VertDef.length(); ++j)
    							{
    								if(VertDef[j] != '/')	//If there is no divider "/", add a char to our vertPart
    									vertPart += VertDef[j];
    
    								//If the current char is a divider "/", or its the last character in the string
    								if(VertDef[j] == '/' || j ==  VertDef.length()-1)
    								{
    									std::wistringstream wstringToInt(vertPart);	//Used to convert wstring to int
    
    									if(whichPart == 0)	//If vPos
    									{
    										wstringToInt >> vertPosIndexTemp;
    										vertPosIndexTemp -= 1;		//subtract one since c++ arrays start with 0, and obj start with 1
    
    										//Check to see if the vert pos was the only thing specified
    										if(j == VertDef.length()-1)
    										{
    											vertNormIndexTemp = 0;
    											vertTCIndexTemp = 0;
    										}
    									}
    
    									else if(whichPart == 1)	//If vTexCoord
    									{
    										if(vertPart != L"")	//Check to see if there even is a tex coord
    										{
    											wstringToInt >> vertTCIndexTemp;
    											vertTCIndexTemp -= 1;	//subtract one since c++ arrays start with 0, and obj start with 1
    										}
    										else	//If there is no tex coord, make a default
    											vertTCIndexTemp = 0;
    
    										//If the cur. char is the second to last in the string, then
    										//there must be no normal, so set a default normal
    										if(j == VertDef.length()-1)
    											vertNormIndexTemp = 0;
    
    									}								
    									else if(whichPart == 2)	//If vNorm
    									{
    										std::wistringstream wstringToInt(vertPart);
    
    										wstringToInt >> vertNormIndexTemp;
    										vertNormIndexTemp -= 1;		//subtract one since c++ arrays start with 0, and obj start with 1
    									}
    
    									vertPart = L"";	//Get ready for next vertex part
    									whichPart++;	//Move on to next vertex part					
    								}
    							}
    
    							//Check to make sure there is at least one subset
    							if(subsetCount == 0)
    							{
    								subsetIndexStart.push_back(vIndex);		//Start index for this subset
    								subsetCount++;
    							}
    
    							//Avoid duplicate vertices
    							bool vertAlreadyExists = false;
    							if(totalVerts >= 3)	//Make sure we at least have one triangle to check
    							{
    								//Loop through all the vertices
    								for(int iCheck = 0; iCheck < totalVerts; ++iCheck)
    								{
    									//If the vertex position and texture coordinate in memory are the same
    									//As the vertex position and texture coordinate we just now got out
    									//of the obj file, we will set this faces vertex index to the vertex's
    									//index value in memory. This makes sure we don't create duplicate vertices
    									if(vertPosIndexTemp == vertPosIndex[iCheck] && !vertAlreadyExists)
    									{
    										if(vertTCIndexTemp == vertTCIndex[iCheck])
    										{
    											indices.push_back(iCheck);		//Set index for this vertex
    											vertAlreadyExists = true;		//If we've made it here, the vertex already exists
    										}
    									}
    								}
    							}
    
    							//If this vertex is not already in our vertex arrays, put it there
    							if(!vertAlreadyExists)
    							{
    								vertPosIndex.push_back(vertPosIndexTemp);
    								vertTCIndex.push_back(vertTCIndexTemp);
    								vertNormIndex.push_back(vertNormIndexTemp);
    								totalVerts++;	//We created a new vertex
    								indices.push_back(totalVerts-1);	//Set index for this vertex
    							}							
    
    							//If this is the very first vertex in the face, we need to
    							//make sure the rest of the triangles use this vertex
    							if(i == 0)
    							{
    								firstVIndex = indices[vIndex];	//The first vertex index of this FACE
    
    							}
    
    							//If this was the last vertex in the first triangle, we will make sure
    							//the next triangle uses this one (eg. tri1(1,2,3) tri2(1,3,4) tri3(1,4,5))
    							if(i == 2)
    							{								
    								lastVIndex = indices[vIndex];	//The last vertex index of this TRIANGLE
    							}
    							vIndex++;	//Increment index count
    						}
    
    						meshTriangles++;	//One triangle down
    
    						//If there are more than three vertices in the face definition, we need to make sure
    						//we convert the face to triangles. We created our first triangle above, now we will
    						//create a new triangle for every new vertex in the face, using the very first vertex
    						//of the face, and the last vertex from the triangle before the current triangle
    						for(int l = 0; l < triangleCount-1; ++l)	//Loop through the next vertices to create new triangles
    						{
    							//First vertex of this triangle (the very first vertex of the face too)
    							indices.push_back(firstVIndex);			//Set index for this vertex
    							vIndex++;
    
    							//Second Vertex of this triangle (the last vertex used in the tri before this one)
    							indices.push_back(lastVIndex);			//Set index for this vertex
    							vIndex++;
    
    							//Get the third vertex for this triangle
    							ss >> VertDef;
    
    							std::wstring vertPart;
    							int whichPart = 0;
    
    							//Parse this string (same as above)
    							for(int j = 0; j < VertDef.length(); ++j)
    							{
    								if(VertDef[j] != '/')
    									vertPart += VertDef[j];
    								if(VertDef[j] == '/' || j ==  VertDef.length()-1)
    								{
    									std::wistringstream wstringToInt(vertPart);
    
    									if(whichPart == 0)
    									{
    										wstringToInt >> vertPosIndexTemp;
    										vertPosIndexTemp -= 1;
    
    										//Check to see if the vert pos was the only thing specified
    										if(j == VertDef.length()-1)
    										{
    											vertTCIndexTemp = 0;
    											vertNormIndexTemp = 0;
    										}
    									}
    									else if(whichPart == 1)
    									{
    										if(vertPart != L"")
    										{
    											wstringToInt >> vertTCIndexTemp;
    											vertTCIndexTemp -= 1;
    										}
    										else
    											vertTCIndexTemp = 0;
    										if(j == VertDef.length()-1)
    											vertNormIndexTemp = 0;
    
    									}								
    									else if(whichPart == 2)
    									{
    										std::wistringstream wstringToInt(vertPart);
    
    										wstringToInt >> vertNormIndexTemp;
    										vertNormIndexTemp -= 1;
    									}
    
    									vertPart = L"";
    									whichPart++;							
    								}
    							}					
    
    							//Check for duplicate vertices
    							bool vertAlreadyExists = false;
    							if(totalVerts >= 3)	//Make sure we at least have one triangle to check
    							{
    								for(int iCheck = 0; iCheck < totalVerts; ++iCheck)
    								{
    									if(vertPosIndexTemp == vertPosIndex[iCheck] && !vertAlreadyExists)
    									{
    										if(vertTCIndexTemp == vertTCIndex[iCheck])
    										{
    											indices.push_back(iCheck);			//Set index for this vertex
    											vertAlreadyExists = true;		//If we've made it here, the vertex already exists
    										}
    									}
    								}
    							}
    
    							if(!vertAlreadyExists)
    							{
    								vertPosIndex.push_back(vertPosIndexTemp);
    								vertTCIndex.push_back(vertTCIndexTemp);
    								vertNormIndex.push_back(vertNormIndexTemp);
    								totalVerts++;					//New vertex created, add to total verts
    								indices.push_back(totalVerts-1);		//Set index for this vertex
    							}
    
    							//Set the second vertex for the next triangle to the last vertex we got		
    							lastVIndex = indices[vIndex];	//The last vertex index of this TRIANGLE
    
    							meshTriangles++;	//New triangle defined
    							vIndex++;		
    						}
    					}
    				}
    				break;
    
    			case 'm':	//mtllib - material library filename
    				checkChar = fileIn.get();
    				if(checkChar == 't')
    				{
    					checkChar = fileIn.get();
    					if(checkChar == 'l')
    					{
    						checkChar = fileIn.get();
    						if(checkChar == 'l')
    						{
    							checkChar = fileIn.get();
    							if(checkChar == 'i')
    							{
    								checkChar = fileIn.get();
    								if(checkChar == 'b')
    								{
    									checkChar = fileIn.get();
    									if(checkChar == ' ')
    									{
    										//Store the material libraries file name
    										fileIn >> meshMatLib;
    									}
    								}
    							}
    						}
    					}
    				}
    
    				break;
    
    			case 'u':	//usemtl - which material to use
    				checkChar = fileIn.get();
    				if(checkChar == 's')
    				{
    					checkChar = fileIn.get();
    					if(checkChar == 'e')
    					{
    						checkChar = fileIn.get();
    						if(checkChar == 'm')
    						{
    							checkChar = fileIn.get();
    							if(checkChar == 't')
    							{
    								checkChar = fileIn.get();
    								if(checkChar == 'l')
    								{
    									checkChar = fileIn.get();
    									if(checkChar == ' ')
    									{
    										meshMaterialsTemp = L"";	//Make sure this is cleared
    
    										fileIn >> meshMaterialsTemp; //Get next type (string)
    
    										meshMaterials.push_back(meshMaterialsTemp);
    									}
    								}
    							}
    						}
    					}
    				}
    				break;
    
    			default:				
    				break;
    			}
    		}
    	}
    	else	//If we could not open the file
    	{
    		SwapChain->SetFullscreenState(false, NULL);	//Make sure we are out of fullscreen
    
    		//create message
    		std::wstring message = L"Could not open: ";
    		message += filename;
    
    		MessageBox(0, message.c_str(),	//display message
    			L"Error", MB_OK);
    
    		return false;
    	}
    
    	subsetIndexStart.push_back(vIndex); //There won't be another index start after our last subset, so set it here
    
    	//sometimes "g" is defined at the very top of the file, then again before the first group of faces.
    	//This makes sure the first subset does not conatain "0" indices.
    	if(subsetIndexStart[1] == 0)
    	{
    		subsetIndexStart.erase(subsetIndexStart.begin()+1);
    		meshSubsets--;
    	}
    
    	//Make sure we have a default for the tex coord and normal
    	//if one or both are not specified
    	if(!hasNorm)
    		vertNorm.push_back(XMFLOAT3(0.0f, 0.0f, 0.0f));
    	if(!hasTexCoord)
    		vertTexCoord.push_back(XMFLOAT2(0.0f, 0.0f));
    
    	//Close the obj file, and open the mtl file
    	fileIn.close();
    	fileIn.open(meshMatLib.c_str());
    
    	std::wstring lastStringRead;
    	int matCount = material.size();	//total materials
    
    	//kdset - 若没有设置漫反射颜色,则使用环境光颜色(通常是一样的)
    	//If the diffuse color WAS set, then we don't need to set our diffuse color to ambient
    	bool kdset = false;
    
    	if (fileIn)
    	{
    		while(fileIn)
    		{
    			checkChar = fileIn.get();	//Get next char
    
    			switch (checkChar)
    			{
                	//Check for comment
    			case '#':
    				checkChar = fileIn.get();
    				while(checkChar != '\n')
    					checkChar = fileIn.get();
    				break;
    
    				//Set diffuse color
    			case 'K':
    				checkChar = fileIn.get();
    				if(checkChar == 'd')	//Diffuse Color
    				{
    					checkChar = fileIn.get();	//remove space
    
    					fileIn >> material[matCount-1].difColor.x;
    					fileIn >> material[matCount-1].difColor.y;
    					fileIn >> material[matCount-1].difColor.z;
    
    					kdset = true;
    				}
    
    				//Ambient Color (We'll store it in diffuse if there isn't a diffuse already)
    				if(checkChar == 'a')	
    				{					
    					checkChar = fileIn.get();	//remove space
    					if(!kdset)
    					{
    						fileIn >> material[matCount-1].difColor.x;
    						fileIn >> material[matCount-1].difColor.y;
    						fileIn >> material[matCount-1].difColor.z;
    					}
    				}
    				break;
    
    				//Check for transparency
    			case 'T':
    				checkChar = fileIn.get();
    				if(checkChar == 'r')
    				{
    					checkChar = fileIn.get();	//remove space
    					float Transparency;
    					fileIn >> Transparency;
    
    					material[matCount-1].difColor.w = Transparency;
    
    					if(Transparency > 0.0f)
    						material[matCount-1].transparent = true;
    				}
    				break;
    
    				//Some obj files specify d for transparency
    			case 'd':
    				checkChar = fileIn.get();
    				if(checkChar == ' ')
    				{
    					float Transparency;
    					fileIn >> Transparency;
    
    					//'d' - 0 being most transparent, and 1 being opaque, opposite of Tr
    					Transparency = 1.0f - Transparency;
    
    					material[matCount-1].difColor.w = Transparency;
    
    					if(Transparency > 0.0f)
    						material[matCount-1].transparent = true;					
    				}
    				break;
    
    				//Get the diffuse map (texture)
    			case 'm':
    				checkChar = fileIn.get();
    				if(checkChar == 'a')
    				{
    					checkChar = fileIn.get();
    					if(checkChar == 'p')
    					{
    						checkChar = fileIn.get();
    						if(checkChar == '_')
    						{
    							//map_Kd - Diffuse map
    							checkChar = fileIn.get();
    							if(checkChar == 'K')
    							{
    								checkChar = fileIn.get();
    								if(checkChar == 'd')
    								{
    									std::wstring fileNamePath;
    
    									fileIn.get();	//Remove whitespace between map_Kd and file
    
    									//Get the file path - We read the pathname char by char since
    									//pathnames can sometimes contain spaces, so we will read until
    									//we find the file extension
    									bool texFilePathEnd = false;
    									while(!texFilePathEnd)
    									{
    										checkChar = fileIn.get();
    
    										fileNamePath += checkChar;
    
    										if(checkChar == '.')
    										{
    											for(int i = 0; i < 3; ++i)
    												fileNamePath += fileIn.get();
    
    											texFilePathEnd = true;
    										}							
    									}
    
    									//check if this texture has already been loaded
    									bool alreadyLoaded = false;
    									for(int i = 0; i < textureNameArray.size(); ++i)
    									{
    										if(fileNamePath == textureNameArray[i])
    										{
    											alreadyLoaded = true;
    											material[matCount-1].texArrayIndex = i;
    											material[matCount-1].hasTexture = true;
    										}
    									}
    
    									//if the texture is not already loaded, load it now
    									if(!alreadyLoaded)
    									{
    										ID3D11ShaderResourceView* tempMeshSRV;
    										hr = D3DX11CreateShaderResourceViewFromFile( d3d11Device, fileNamePath.c_str(),
    											NULL, NULL, &tempMeshSRV, NULL );
    										if(SUCCEEDED(hr))
    										{
    											textureNameArray.push_back(fileNamePath.c_str());
    											material[matCount-1].texArrayIndex = meshSRV.size();
    											meshSRV.push_back(tempMeshSRV);
    											material[matCount-1].hasTexture = true;
    										}
    									}	
    								}
    							}
    							//map_d - alpha map
    							else if(checkChar == 'd')
    							{
    								//Alpha maps are usually the same as the diffuse map
    								//So we will assume that for now by only enabling
    								//transparency for this material, as we will already
    								//be using the alpha channel in the diffuse map
    								material[matCount-1].transparent = true;
    							}
    							///**************new**************
    							//map_bump - bump map (we're usinga normal map though)
    							else if(checkChar == 'b')
    							{
    								checkChar = fileIn.get();
    								if(checkChar == 'u')
    								{
    									checkChar = fileIn.get();
    									if(checkChar == 'm')
    									{
    										checkChar = fileIn.get();
    										if(checkChar == 'p')
    										{
    											std::wstring fileNamePath;
    
    											fileIn.get();	//Remove whitespace between map_bump and file
    
    											//Get the file path - We read the pathname char by char since
    											//pathnames can sometimes contain spaces, so we will read until
    											//we find the file extension
    											bool texFilePathEnd = false;
    											while(!texFilePathEnd)
    											{
    												checkChar = fileIn.get();
    
    												fileNamePath += checkChar;
    
    												if(checkChar == '.')
    												{
    													for(int i = 0; i < 3; ++i)
    														fileNamePath += fileIn.get();
    
    													texFilePathEnd = true;
    												}							
    											}
    
    											//check if this texture has already been loaded
    											bool alreadyLoaded = false;
    											for(int i = 0; i < textureNameArray.size(); ++i)
    											{
    												if(fileNamePath == textureNameArray[i])
    												{
    													alreadyLoaded = true;
    													material[matCount-1].normMapTexArrayIndex = i;
    													material[matCount-1].hasNormMap = true;
    												}
    											}
    
    											//if the texture is not already loaded, load it now
    											if(!alreadyLoaded)
    											{
    												ID3D11ShaderResourceView* tempMeshSRV;
    												hr = D3DX11CreateShaderResourceViewFromFile( d3d11Device, fileNamePath.c_str(),
    													NULL, NULL, &tempMeshSRV, NULL );
    												if(SUCCEEDED(hr))
    												{
    													textureNameArray.push_back(fileNamePath.c_str());
    													material[matCount-1].normMapTexArrayIndex = meshSRV.size();
    													meshSRV.push_back(tempMeshSRV);
    													material[matCount-1].hasNormMap = true;
    												}
    											}	
    										}
    									}
    								}
    							}
    							///**************new**************
    						}
    					}
    				}
    				break;
    
    			case 'n':	//newmtl - Declare new material
    				checkChar = fileIn.get();
    				if(checkChar == 'e')
    				{
    					checkChar = fileIn.get();
    					if(checkChar == 'w')
    					{
    						checkChar = fileIn.get();
    						if(checkChar == 'm')
    						{
    							checkChar = fileIn.get();
    							if(checkChar == 't')
    							{
    								checkChar = fileIn.get();
    								if(checkChar == 'l')
    								{
    									checkChar = fileIn.get();
    									if(checkChar == ' ')
    									{
    										//New material, set its defaults
    										SurfaceMaterial tempMat;
    										material.push_back(tempMat);
    										fileIn >> material[matCount].matName;
    										material[matCount].transparent = false;
    										material[matCount].hasTexture = false;
    										///**************new**************
    										material[matCount].hasNormMap = false;
    										material[matCount].normMapTexArrayIndex = 0;
    										///**************new**************
    										material[matCount].texArrayIndex = 0;
    										matCount++;
    										kdset = false;
    									}
    								}
    							}
    						}
    					}
    				}
    				break;
    
    			default:
    				break;
    			}
    		}
    	}	
    	else
    	{
    		SwapChain->SetFullscreenState(false, NULL);	//Make sure we are out of fullscreen
    
    		std::wstring message = L"Could not open: ";
    		message += meshMatLib;
    
    		MessageBox(0, message.c_str(),
    			L"Error", MB_OK);
    
    		return false;
    	}
    
    	//Set the subsets material to the index value
    	//of the its material in our material array
    	for(int i = 0; i < meshSubsets; ++i)
    	{
    		bool hasMat = false;
    		for(int j = 0; j < material.size(); ++j)
    		{
    			if(meshMaterials[i] == material[j].matName)
    			{
    				subsetMaterialArray.push_back(j);
    				hasMat = true;
    			}
    		}
    		if(!hasMat)
    			subsetMaterialArray.push_back(0); //Use first material in array
    	}
    
    	std::vector<Vertex> vertices;
    	Vertex tempVert;
    
    	//Create our vertices using the information we got 
    	//from the file and store them in a vector
    	for(int j = 0 ; j < totalVerts; ++j)
    	{
    		tempVert.pos = vertPos[vertPosIndex[j]];
    		tempVert.normal = vertNorm[vertNormIndex[j]];
    		tempVert.texCoord = vertTexCoord[vertTCIndex[j]];
    
    		vertices.push_back(tempVert);
    
    		///**************new**************
    		//Copy just the vertex positions to the vector
    		vertPosArray.push_back(tempVert.pos);
    		///**************new**************
    	}
    
    	///**************new**************
    	//Copy the index list to the array
    	vertIndexArray = indices;
    	///**************new**************
    	//Compute Normals///
    	//If computeNormals was set to true then we will create our own
    	//normals, if it was set to false we will use the obj files normals
    	if(computeNormals)
    	{
    		std::vector<XMFLOAT3> tempNormal;
    
    		//normalized and unnormalized normals
    		XMFLOAT3 unnormalized = XMFLOAT3(0.0f, 0.0f, 0.0f);
    
    		///**************new**************
    		//tangent stuff
    		std::vector<XMFLOAT3> tempTangent;
    		XMFLOAT3 tangent = XMFLOAT3(0.0f, 0.0f, 0.0f);
    		float tcU1, tcV1, tcU2, tcV2;
    		///**************new**************
    		//Used to get vectors (sides) from the position of the verts
    		float vecX, vecY, vecZ;
    
    		//Two edges of our triangle
    		XMVECTOR edge1 = XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f);
    		XMVECTOR edge2 = XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f);
    
    		//Compute face normals
    		for(int i = 0; i < meshTriangles; ++i)
    		{
    			//Get the vector describing one edge of our triangle (edge 0,2)
    			vecX = vertices[indices[(i*3)]].pos.x - vertices[indices[(i*3)+2]].pos.x;
    			vecY = vertices[indices[(i*3)]].pos.y - vertices[indices[(i*3)+2]].pos.y;
    			vecZ = vertices[indices[(i*3)]].pos.z - vertices[indices[(i*3)+2]].pos.z;		
    			edge1 = XMVectorSet(vecX, vecY, vecZ, 0.0f);	//Create our first edge
    
    			//Get the vector describing another edge of our triangle (edge 2,1)
    			vecX = vertices[indices[(i*3)+2]].pos.x - vertices[indices[(i*3)+1]].pos.x;
    			vecY = vertices[indices[(i*3)+2]].pos.y - vertices[indices[(i*3)+1]].pos.y;
    			vecZ = vertices[indices[(i*3)+2]].pos.z - vertices[indices[(i*3)+1]].pos.z;		
    			edge2 = XMVectorSet(vecX, vecY, vecZ, 0.0f);	//Create our second edge
    
    			//Cross multiply the two edge vectors to get the un-normalized face normal
    			XMStoreFloat3(&unnormalized, XMVector3Cross(edge1, edge2));
    
    			tempNormal.push_back(unnormalized);
    
    			///**************new**************
    			//Find first texture coordinate edge 2d vector
    			tcU1 = vertices[indices[(i*3)]].texCoord.x - vertices[indices[(i*3)+2]].texCoord.x;
    			tcV1 = vertices[indices[(i*3)]].texCoord.y - vertices[indices[(i*3)+2]].texCoord.y;
    
    			//Find second texture coordinate edge 2d vector
    			tcU2 = vertices[indices[(i*3)+2]].texCoord.x - vertices[indices[(i*3)+1]].texCoord.x;
    			tcV2 = vertices[indices[(i*3)+2]].texCoord.y - vertices[indices[(i*3)+1]].texCoord.y;
    
    			//Find tangent using both tex coord edges and position edges
    			tangent.x = (tcV1 * XMVectorGetX(edge1) - tcV2 * XMVectorGetX(edge2)) * (1.0f / (tcU1 * tcV2 - tcU2 * tcV1));
    			tangent.y = (tcV1 * XMVectorGetY(edge1) - tcV2 * XMVectorGetY(edge2)) * (1.0f / (tcU1 * tcV2 - tcU2 * tcV1));
    			tangent.z = (tcV1 * XMVectorGetZ(edge1) - tcV2 * XMVectorGetZ(edge2)) * (1.0f / (tcU1 * tcV2 - tcU2 * tcV1));
    
    			tempTangent.push_back(tangent);
    			///**************new**************
    		}
    
    		//Compute vertex normals (normal Averaging)
    		XMVECTOR normalSum = XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f);
    		XMVECTOR tangentSum = XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f);
    		int facesUsing = 0;
    		float tX, tY, tZ;	//temp axis variables
    
    		//Go through each vertex
    		for(int i = 0; i < totalVerts; ++i)
    		{
    			//Check which triangles use this vertex
    			for(int j = 0; j < meshTriangles; ++j)
    			{
    				if(indices[j*3] == i ||
    					indices[(j*3)+1] == i ||
    					indices[(j*3)+2] == i)
    				{
    					tX = XMVectorGetX(normalSum) + tempNormal[j].x;
    					tY = XMVectorGetY(normalSum) + tempNormal[j].y;
    					tZ = XMVectorGetZ(normalSum) + tempNormal[j].z;
    
    					normalSum = XMVectorSet(tX, tY, tZ, 0.0f);	//If a face is using the vertex, add the unormalized face normal to the normalSum
    					///**************new**************		
    					//We can reuse tX, tY, tZ to sum up tangents
    					tX = XMVectorGetX(tangentSum) + tempTangent[j].x;
    					tY = XMVectorGetY(tangentSum) + tempTangent[j].y;
    					tZ = XMVectorGetZ(tangentSum) + tempTangent[j].z;
    
    					tangentSum = XMVectorSet(tX, tY, tZ, 0.0f); //sum up face tangents using this vertex
    					///**************new**************
    					facesUsing++;
    				}
    			}
    
    			//Get the actual normal by dividing the normalSum by the number of faces sharing the vertex
    			normalSum = normalSum / facesUsing;
    			///**************new**************
    			tangentSum = tangentSum / facesUsing;
    			///**************new**************
    
    			//Normalize the normalSum vector
    			normalSum = XMVector3Normalize(normalSum);
    			///**************new**************
    			tangentSum =  XMVector3Normalize(tangentSum);
    			///**************new**************
    
    			//Store the normal in our current vertex
    			vertices[i].normal.x = XMVectorGetX(normalSum);
    			vertices[i].normal.y = XMVectorGetY(normalSum);
    			vertices[i].normal.z = XMVectorGetZ(normalSum);
    
    			///**************new**************
    			vertices[i].tangent.x = XMVectorGetX(tangentSum);
    			vertices[i].tangent.y = XMVectorGetY(tangentSum);
    			vertices[i].tangent.z = XMVectorGetZ(tangentSum);
    			///**************new**************
    			//Clear normalSum and facesUsing for next vertex
    			normalSum = XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f);
    			///**************new**************
    			tangentSum = XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f);
    			///**************new**************
    			facesUsing = 0;
    
    		}
    	}
    
    	//Create index buffer
    	D3D11_BUFFER_DESC indexBufferDesc;
    	ZeroMemory( &indexBufferDesc, sizeof(indexBufferDesc) );
    
    	indexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
    	indexBufferDesc.ByteWidth = sizeof(DWORD) * meshTriangles*3;
    	indexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
    	indexBufferDesc.CPUAccessFlags = 0;
    	indexBufferDesc.MiscFlags = 0;
    
    	D3D11_SUBRESOURCE_DATA iinitData;
    
    	iinitData.pSysMem = &indices[0];
    	d3d11Device->CreateBuffer(&indexBufferDesc, &iinitData, indexBuff);
    
    	//Create Vertex Buffer
    	D3D11_BUFFER_DESC vertexBufferDesc;
    	ZeroMemory( &vertexBufferDesc, sizeof(vertexBufferDesc) );
    
    	vertexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
    	vertexBufferDesc.ByteWidth = sizeof( Vertex ) * totalVerts;
    	vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
    	vertexBufferDesc.CPUAccessFlags = 0;
    	vertexBufferDesc.MiscFlags = 0;
    
    	D3D11_SUBRESOURCE_DATA vertexBufferData; 
    
    	ZeroMemory( &vertexBufferData, sizeof(vertexBufferData) );
    	vertexBufferData.pSysMem = &vertices[0];
    	hr = d3d11Device->CreateBuffer( &vertexBufferDesc, &vertexBufferData, vertBuff);
    
    	return true;
    }
    ///**************new**************
    
    void CreateSphere(int LatLines, int LongLines)
    {
    	NumSphereVertices = ((LatLines-2) * LongLines) + 2;
    	NumSphereFaces  = ((LatLines-3)*(LongLines)*2) + (LongLines*2);
    
    	float sphereYaw = 0.0f;
    	float spherePitch = 0.0f;
    
    	std::vector<Vertex> vertices(NumSphereVertices);
    
    	XMVECTOR currVertPos = XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f);
    
    	vertices[0].pos.x = 0.0f;
    	vertices[0].pos.y = 0.0f;
    	vertices[0].pos.z = 1.0f;
    
    	for(DWORD i = 0; i < LatLines-2; ++i)
    	{
    		spherePitch = (i+1) * (3.14f/(LatLines-1));
    		Rotationx = XMMatrixRotationX(spherePitch);
    		for(DWORD j = 0; j < LongLines; ++j)
    		{
    			sphereYaw = j * (6.28f/(LongLines));
    			Rotationy = XMMatrixRotationZ(sphereYaw);
    			currVertPos = XMVector3TransformNormal( XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f), (Rotationx * Rotationy) );	
    			currVertPos = XMVector3Normalize( currVertPos );
    			vertices[i*LongLines+j+1].pos.x = XMVectorGetX(currVertPos);
    			vertices[i*LongLines+j+1].pos.y = XMVectorGetY(currVertPos);
    			vertices[i*LongLines+j+1].pos.z = XMVectorGetZ(currVertPos);
    		}
    	}
    
    	vertices[NumSphereVertices-1].pos.x =  0.0f;
    	vertices[NumSphereVertices-1].pos.y =  0.0f;
    	vertices[NumSphereVertices-1].pos.z = -1.0f;
    
    
    	D3D11_BUFFER_DESC vertexBufferDesc;
    	ZeroMemory( &vertexBufferDesc, sizeof(vertexBufferDesc) );
    
    	vertexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
    	vertexBufferDesc.ByteWidth = sizeof( Vertex ) * NumSphereVertices;
    	vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
    	vertexBufferDesc.CPUAccessFlags = 0;
    	vertexBufferDesc.MiscFlags = 0;
    
    	D3D11_SUBRESOURCE_DATA vertexBufferData; 
    
    	ZeroMemory( &vertexBufferData, sizeof(vertexBufferData) );
    	vertexBufferData.pSysMem = &vertices[0];
    	hr = d3d11Device->CreateBuffer( &vertexBufferDesc, &vertexBufferData, &sphereVertBuffer);
    
    
    	std::vector<DWORD> indices(NumSphereFaces * 3);
    
    	int k = 0;
    	for(DWORD l = 0; l < LongLines-1; ++l)
    	{
    		indices[k] = 0;
    		indices[k+1] = l+1;
    		indices[k+2] = l+2;
    		k += 3;
    	}
    
    	indices[k] = 0;
    	indices[k+1] = LongLines;
    	indices[k+2] = 1;
    	k += 3;
    
    	for(DWORD i = 0; i < LatLines-3; ++i)
    	{
    		for(DWORD j = 0; j < LongLines-1; ++j)
    		{
    			indices[k]   = i*LongLines+j+1;
    			indices[k+1] = i*LongLines+j+2;
    			indices[k+2] = (i+1)*LongLines+j+1;
    
    			indices[k+3] = (i+1)*LongLines+j+1;
    			indices[k+4] = i*LongLines+j+2;
    			indices[k+5] = (i+1)*LongLines+j+2;
    
    			k += 6; // next quad
    		}
    
    		indices[k]   = (i*LongLines)+LongLines;
    		indices[k+1] = (i*LongLines)+1;
    		indices[k+2] = ((i+1)*LongLines)+LongLines;
    
    		indices[k+3] = ((i+1)*LongLines)+LongLines;
    		indices[k+4] = (i*LongLines)+1;
    		indices[k+5] = ((i+1)*LongLines)+1;
    
    		k += 6;
    	}
    
    	for(DWORD l = 0; l < LongLines-1; ++l)
    	{
    		indices[k] = NumSphereVertices-1;
    		indices[k+1] = (NumSphereVertices-1)-(l+1);
    		indices[k+2] = (NumSphereVertices-1)-(l+2);
    		k += 3;
    	}
    
    	indices[k] = NumSphereVertices-1;
    	indices[k+1] = (NumSphereVertices-1)-LongLines;
    	indices[k+2] = NumSphereVertices-2;
    
    	D3D11_BUFFER_DESC indexBufferDesc;
    	ZeroMemory( &indexBufferDesc, sizeof(indexBufferDesc) );
    
    	indexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
    	indexBufferDesc.ByteWidth = sizeof(DWORD) * NumSphereFaces * 3;
    	indexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
    	indexBufferDesc.CPUAccessFlags = 0;
    	indexBufferDesc.MiscFlags = 0;
    
    	D3D11_SUBRESOURCE_DATA iinitData;
    
    	iinitData.pSysMem = &indices[0];
    	d3d11Device->CreateBuffer(&indexBufferDesc, &iinitData, &sphereIndexBuffer);
    
    }
    void InitD2DScreenTexture()
    {
    	//创建顶点缓冲
    	Vertex v[] =
    	{
    		// Front Face
    		Vertex(-1.0f, -1.0f, -1.0f, 0.0f, 1.0f,-1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f),
    		Vertex(-1.0f,  1.0f, -1.0f, 0.0f, 0.0f,-1.0f,  1.0f, -1.0f, 0.0f, 0.0f, 0.0f),
    		Vertex( 1.0f,  1.0f, -1.0f, 1.0f, 0.0f, 1.0f,  1.0f, -1.0f, 0.0f, 0.0f, 0.0f),
    		Vertex( 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.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();
    	//编译着色器
    	CreateSphere(10, 10);
    
    	///**************new**************
    	if(!LoadObjModel(L"ground.obj", &meshVertBuff, &meshIndexBuff, meshSubsetIndexStart, meshSubsetTexture, material, meshSubsets, true, true, groundVertPosArray, groundVertIndexArray))
    		return false;	
    	if(!LoadObjModel(L"bottle.obj", &bottleVertBuff, &bottleIndexBuff, bottleSubsetIndexStart, bottleSubsetTexture, material, bottleSubsets, true, true, bottleVertPosArray, bottleVertIndexArray))
    		return false;
    	///**************new**************
        // 获取包围体信息
        CreateBoundingVolumes(bottleVertPosArray, bottleBoundingBoxVertPosArray, bottleBoundingBoxVertIndexArray, bottleBoundingSphere, bottleCenterOffset);
    	///**************new**************
    	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);
    	/// new
    	hr = D3DX11CompileFromFile(L"Effects.fx", 0, 0, "D2D_PS", "ps_4_0", 0, 0, 0, &D2D_PS_Buffer, 0, 0);
    	hr = D3DX11CompileFromFile(L"Effects.fx", 0, 0, "SKYMAP_VS", "vs_4_0", 0, 0, 0, &SKYMAP_VS_Buffer, 0, 0);
    	hr = D3DX11CompileFromFile(L"Effects.fx", 0, 0, "SKYMAP_PS", "ps_4_0", 0, 0, 0, &SKYMAP_PS_Buffer, 0, 0);
    
    	///**************new**************
    	//创建着色器对象
    	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);
    	hr = d3d11Device->CreateVertexShader(SKYMAP_VS_Buffer->GetBufferPointer(), SKYMAP_VS_Buffer->GetBufferSize(), NULL, &SKYMAP_VS);
    	hr = d3d11Device->CreatePixelShader(SKYMAP_PS_Buffer->GetBufferPointer(), SKYMAP_PS_Buffer->GetBufferSize(), NULL, &SKYMAP_PS);
    	///**************new**************
    	///**************new**************
    	//设置顶点和像素着色器
    	d3d11DevCon->VSSetShader(VS, 0, 0);
    	d3d11DevCon->PSSetShader(PS, 0, 0);
    
    	///**************new**************
    	light.pos = XMFLOAT3(0.0f, 7.0f, 0.0f);
    	light.dir = XMFLOAT3(0.5f, 0.75f, -0.5f);
    	light.range = 1000.0f;
    	light.cone = 12.0f;
    	light.att = XMFLOAT3(0.4f, 0.02f, 0.000f);
    	light.ambient = XMFLOAT4(0.2f, 0.2f, 0.2f, 1.0f);
    	light.diffuse = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
    
    	//Create the Input Layout
    	//创建输入布局
    	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, 5.0f, -8.0f, 0.0f );
    	//camPosition = XMVectorSet(0.0f, 0.0f, -0.5f, 0.0f);
    	camTarget = XMVectorSet( 0.0f, 0.5f, 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;
    	
    	d3d11Device->CreateBlendState(&blendDesc, &d2dTransparency);
    	
    	///**************new**************
    	ZeroMemory( &rtbd, sizeof(rtbd) );
    
    	rtbd.BlendEnable			 = true;
    	rtbd.SrcBlend				 = D3D11_BLEND_INV_SRC_ALPHA;
    	rtbd.DestBlend				 = D3D11_BLEND_SRC_ALPHA;
    	rtbd.BlendOp				 = D3D11_BLEND_OP_ADD;
    	rtbd.SrcBlendAlpha			 = D3D11_BLEND_INV_SRC_ALPHA;
    	rtbd.DestBlendAlpha			 = D3D11_BLEND_SRC_ALPHA;
    	rtbd.BlendOpAlpha			 = D3D11_BLEND_OP_ADD;
    	rtbd.RenderTargetWriteMask	 = D3D10_COLOR_WRITE_ENABLE_ALL;
    
    	blendDesc.AlphaToCoverageEnable = false;
    	blendDesc.RenderTarget[0] = rtbd;
    
    	d3d11Device->CreateBlendState(&blendDesc, &Transparency);
    	///**************new**************
    	//加载图像纹理
    	//hr = 
    //#if 1
    //	hr = D3DX11CreateShaderResourceViewFromFile(d3d11Device, L"grass.jpg",
    //	NULL, NULL, &CubesTexture, NULL);
    	///**************new**************
    	//告诉D3D我们正在加载一个立方体纹理
    	D3DX11_IMAGE_LOAD_INFO loadSMInfo;
    	loadSMInfo.MiscFlags = D3D11_RESOURCE_MISC_TEXTURECUBE;
    
    	//加载纹理
    	ID3D11Texture2D* SMTexture = 0;
    	hr = D3DX11CreateTextureFromFile(d3d11Device, L"skymap.dds",
    		&loadSMInfo, 0, (ID3D11Resource**)&SMTexture, 0);
    
    	//创建纹理描述符
    	D3D11_TEXTURE2D_DESC SMTextureDesc;
    	SMTexture->GetDesc(&SMTextureDesc);
    
    	//告诉D3D我们有一个立方体纹理,它是一个2D纹理的数组
    	D3D11_SHADER_RESOURCE_VIEW_DESC SMViewDesc;
    	SMViewDesc.Format = SMTextureDesc.Format;
    	SMViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE;
    	SMViewDesc.TextureCube.MipLevels = SMTextureDesc.MipLevels;
    	SMViewDesc.TextureCube.MostDetailedMip = 0;
    
    	//创建资源视图
    	hr = d3d11Device->CreateShaderResourceView(SMTexture, &SMViewDesc, &smrv);
    	///**************new**************
    
    	//配置采样状态
    	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);
    
    	///**************new**************
    	cmdesc.CullMode = D3D11_CULL_NONE;
    	hr = d3d11Device->CreateRasterizerState(&cmdesc, &RSCullNone);
    
    	D3D11_DEPTH_STENCIL_DESC dssDesc;
    	ZeroMemory(&dssDesc, sizeof(D3D11_DEPTH_STENCIL_DESC));
    	dssDesc.DepthEnable = true;
    	dssDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
    	dssDesc.DepthFunc = D3D11_COMPARISON_LESS_EQUAL;
    
    	d3d11Device->CreateDepthStencilState(&dssDesc, &DSLessEqual);
    
    	///**************new**************
    	float bottleXPos = -30.0f;
    	float bottleZPos = 30.0f;
    	float bxadd = 0.0f;
    	float bzadd = 0.0f;
    
    	for(int i = 0; i < numBottles; i++)
    	{
    		bottleHit[i] = 0;
    
    		//set the loaded bottles world space
    		bottleWorld[i] = XMMatrixIdentity();
    
    		bxadd++;
    
    		if(bxadd == 10)
    		{
    			bzadd -= 1.0f;
    			bxadd = 0;
    		}
    
    		Rotation = XMMatrixRotationY(3.14f);
    		Scale = XMMatrixScaling( 1.0f, 1.0f, 1.0f );
    		Translation = XMMatrixTranslation( bottleXPos + bxadd*10.0f, 4.0f, bottleZPos + bzadd*10.0f );
    
    		bottleWorld[i] = Rotation * Scale * Translation;
    	}
    	///**************new**************
    	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()
    {
    	//Reset cube1World
    //	groundWorld = XMMatrixIdentity();
    
    	//Define cube1's world space matrix
    	///**************new**************
    //	Scale = XMMatrixScaling( 500.0f, 10.0f, 500.0f );
    //	Translation = XMMatrixTranslation( 0.0f, 10.0f, 0.0f );
    
    	//Set cube1's world space using the transformations
    //	groundWorld = Scale * Translation;
    
    	//复位球面世界
    	sphereWorld = XMMatrixIdentity();
    
    	//Define sphereWorld's world space matrix
    	Scale = XMMatrixScaling( 5.0f, 5.0f, 5.0f );
    	//Make sure the sphere is always centered around camera
    	Translation = XMMatrixTranslation( XMVectorGetX(camPosition), XMVectorGetY(camPosition), XMVectorGetZ(camPosition) );
    
    	//Set sphereWorld's world space using the transformations
    	sphereWorld = Scale * Translation;
    
    	///**************new**************
    	meshWorld = XMMatrixIdentity();
    
    	//Define cube1's world space matrix
    	Rotation = XMMatrixRotationY(3.14f);
    	Scale = XMMatrixScaling( 1.0f, 1.0f, 1.0f );
    	Translation = XMMatrixTranslation( 0.0f, 0.0f, 0.0f );
    
    	meshWorld = Rotation * Scale * Translation;
    	///**************new**************
    	///**************new**************
    //	light.pos.x = XMVectorGetX(camPosition);
    //	light.pos.y = XMVectorGetY(camPosition);
    //	light.pos.z = XMVectorGetZ(camPosition);
    
    //	light.dir.x = XMVectorGetX(camTarget) - light.pos.x;
    //	light.dir.y = XMVectorGetY(camTarget) - light.pos.y;
    //	light.dir.z = XMVectorGetZ(camTarget) - light.pos.z;
    	///**************new**************
    }
    
    ///**************new**************
    void RenderText(std::wstring text, int inInt)
    //void RenderText(std::wstring text)
    {
    	//释放D3D11设备
        d3d11DevCon->PSSetShader(D2D_PS, 0, 0);
    	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));
    
    
        ///**************new**************
        // 显示当前正在使用的拾取方法
        std::wstring pickWhatStr;
        if(pickWhat == 0)
            pickWhatStr = L"Bounding Sphere";
        if(pickWhat == 1)
            pickWhatStr = L"Bounding Box";
        if(pickWhat == 2)
            pickWhatStr = L"Model";
    	//创建字符串
    	std::wostringstream printString;
        ///**************new**************
    	printString << text << inInt << L"\n"
    		<< L"Score: " << score << L"\n"
            << L"Picked Dist: " << pickedDist << L"\n"
            << L"Pick Operation Speed: " << pickOpSpeed << L"\n"
            << L"Picking Method (P): " << pickWhatStr;
    	///**************new**************
        printText = printString.str();
    
    	//设置字体颜色
        D2D1_COLOR_F FontColor = D2D1::ColorF(1.0f, 1.0f, 1.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(d2dTransparency, 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.1f, 0.1f, 0.1f, 1.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);
    	d3d11DevCon->VSSetShader(VS, 0, 0);
    	d3d11DevCon->PSSetShader(PS, 0, 0);
    
        //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 = groundWorld * camView * camProjection;
    //	cbPerObj.WVP = XMMatrixTranspose(WVP);	
    //	cbPerObj.World = XMMatrixTranspose(groundWorld);	
    //	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(CCWcullMode);
    //	d3d11DevCon->DrawIndexed( 6, 0, 0 );
    
    	///**************new**************
    	//绘制我们模型的非透明子集
    	for(int i = 0; i < meshSubsets; ++i)
    	{
    		//设置地面索引缓冲
    		d3d11DevCon->IASetIndexBuffer( meshIndexBuff, DXGI_FORMAT_R32_UINT, 0);
    		//设置地面顶点缓冲
    		d3d11DevCon->IASetVertexBuffers( 0, 1, &meshVertBuff, &stride, &offset );
    
    		//设置WVP矩阵并发送它到效果文件中的常量缓冲中
    		WVP = meshWorld * camView * camProjection;
    		cbPerObj.WVP = XMMatrixTranspose(WVP);	
    		cbPerObj.World = XMMatrixTranspose(meshWorld);	
    		cbPerObj.difColor = material[meshSubsetTexture[i]].difColor;
    		cbPerObj.hasTexture = material[meshSubsetTexture[i]].hasTexture;
    		///**************new**************
    		cbPerObj.hasNormMap = material[meshSubsetTexture[i]].hasNormMap;
    		///**************new**************
    		d3d11DevCon->UpdateSubresource( cbPerObjectBuffer, 0, NULL, &cbPerObj, 0, 0 );
    		d3d11DevCon->VSSetConstantBuffers( 0, 1, &cbPerObjectBuffer );
    		d3d11DevCon->PSSetConstantBuffers( 1, 1, &cbPerObjectBuffer );
    		if(material[meshSubsetTexture[i]].hasTexture)
    			d3d11DevCon->PSSetShaderResources( 0, 1, &meshSRV[material[meshSubsetTexture[i]].texArrayIndex] );
    		///**************new**************
    		if(material[meshSubsetTexture[i]].hasNormMap)
    			d3d11DevCon->PSSetShaderResources( 1, 1, &meshSRV[material[meshSubsetTexture[i]].normMapTexArrayIndex] );
    		///**************new**************
    		d3d11DevCon->PSSetSamplers( 0, 1, &CubesTexSamplerState );
    
    		d3d11DevCon->RSSetState(RSCullNone);
    		int indexStart = meshSubsetIndexStart[i];
    		int indexDrawAmount =  meshSubsetIndexStart[i+1] - meshSubsetIndexStart[i];
    		if(!material[meshSubsetTexture[i]].transparent)
    			d3d11DevCon->DrawIndexed( indexDrawAmount, indexStart, 0 );
    	}
    	///**************new**************
    	///**************new**************
    	//draw bottle's nontransparent subsets
    	for(int j = 0; j < numBottles; j++)
    	{
    		if(bottleHit[j] == 0)
    		{
    			for(int i = 0; i < bottleSubsets; ++i)
    			{
    				//Set the grounds index buffer
    				d3d11DevCon->IASetIndexBuffer( bottleIndexBuff, DXGI_FORMAT_R32_UINT, 0);
    				//Set the grounds vertex buffer
    				d3d11DevCon->IASetVertexBuffers( 0, 1, &bottleVertBuff, &stride, &offset );
    
    				//Set the WVP matrix and send it to the constant buffer in effect file
    				WVP = bottleWorld[j] * camView * camProjection;
    				cbPerObj.WVP = XMMatrixTranspose(WVP);	
    				cbPerObj.World = XMMatrixTranspose(bottleWorld[j]);	
    				cbPerObj.difColor = material[bottleSubsetTexture[i]].difColor;
    				cbPerObj.hasTexture = material[bottleSubsetTexture[i]].hasTexture;
    				cbPerObj.hasNormMap = material[bottleSubsetTexture[i]].hasNormMap;
    				d3d11DevCon->UpdateSubresource( cbPerObjectBuffer, 0, NULL, &cbPerObj, 0, 0 );
    				d3d11DevCon->VSSetConstantBuffers( 0, 1, &cbPerObjectBuffer );
    				d3d11DevCon->PSSetConstantBuffers( 1, 1, &cbPerObjectBuffer );
    				if(material[bottleSubsetTexture[i]].hasTexture)
    					d3d11DevCon->PSSetShaderResources( 0, 1, &meshSRV[material[bottleSubsetTexture[i]].texArrayIndex] );
    				if(material[bottleSubsetTexture[i]].hasNormMap)
    					d3d11DevCon->PSSetShaderResources( 1, 1, &meshSRV[material[bottleSubsetTexture[i]].normMapTexArrayIndex] );
    				d3d11DevCon->PSSetSamplers( 0, 1, &CubesTexSamplerState );
    
    				d3d11DevCon->RSSetState(RSCullNone);
    				int indexStart = bottleSubsetIndexStart[i];
    				int indexDrawAmount =  bottleSubsetIndexStart[i+1] - bottleSubsetIndexStart[i];
    				if(!material[bottleSubsetTexture[i]].transparent)
    					d3d11DevCon->DrawIndexed( indexDrawAmount, indexStart, 0 );
    			}
    		}
    	}
    
    	/绘制天空的球面//
    	//设置球面的索引缓冲
    	d3d11DevCon->IASetIndexBuffer( sphereIndexBuffer, DXGI_FORMAT_R32_UINT, 0);
    	//设置球面的顶点缓冲
    	d3d11DevCon->IASetVertexBuffers( 0, 1, &sphereVertBuffer, &stride, &offset );
    
    	//设置WVP矩阵并将它发送给效果文件中的常量缓冲
    	WVP = sphereWorld * camView * camProjection;
    	cbPerObj.WVP = XMMatrixTranspose(WVP);	
    	cbPerObj.World = XMMatrixTranspose(sphereWorld);	
    	d3d11DevCon->UpdateSubresource( cbPerObjectBuffer, 0, NULL, &cbPerObj, 0, 0 );
    	d3d11DevCon->VSSetConstantBuffers( 0, 1, &cbPerObjectBuffer );
    	//发送我们的天空贴图资源视图到像素着色器
    	d3d11DevCon->PSSetShaderResources( 0, 1, &smrv );
    	d3d11DevCon->PSSetSamplers( 0, 1, &CubesTexSamplerState );
    
    	//设置新的VS和PS着色器
    	d3d11DevCon->VSSetShader(SKYMAP_VS, 0, 0);
    	d3d11DevCon->PSSetShader(SKYMAP_PS, 0, 0);
    	//设置新的深度模板和RS状态
    	d3d11DevCon->OMSetDepthStencilState(DSLessEqual, 0);
    	d3d11DevCon->RSSetState(RSCullNone);
    	d3d11DevCon->DrawIndexed( NumSphereFaces * 3, 0, 0 );	
    
    	//设置默认的VS,PS着色器和深度模板状态
    	d3d11DevCon->VSSetShader(VS, 0, 0);
    	d3d11DevCon->PSSetShader(PS, 0, 0);
    	d3d11DevCon->OMSetDepthStencilState(NULL, 0);
    
    	///**************new**************	
    	//绘制我们的模型的透明度子集
    	//设置我们的混合状态
    	d3d11DevCon->OMSetBlendState(Transparency, NULL, 0xffffffff);
    
    	for(int i = 0; i < meshSubsets; ++i)
    	{
    		//设置地面索引缓冲
    		d3d11DevCon->IASetIndexBuffer( meshIndexBuff, DXGI_FORMAT_R32_UINT, 0);
    		//设置地面顶点缓冲
    		d3d11DevCon->IASetVertexBuffers( 0, 1, &meshVertBuff, &stride, &offset );
    
    		//设置WVP矩阵并将它发送给效果文件中的常量缓冲中
    		WVP = meshWorld * camView * camProjection;
    		cbPerObj.WVP = XMMatrixTranspose(WVP);	
    		cbPerObj.World = XMMatrixTranspose(meshWorld);	
    		cbPerObj.difColor = material[meshSubsetTexture[i]].difColor;
    		cbPerObj.hasTexture = material[meshSubsetTexture[i]].hasTexture;
    		///**************new**************
    		cbPerObj.hasNormMap = material[meshSubsetTexture[i]].hasNormMap;
    		///**************new**************
    		d3d11DevCon->UpdateSubresource( cbPerObjectBuffer, 0, NULL, &cbPerObj, 0, 0 );
    		d3d11DevCon->VSSetConstantBuffers( 0, 1, &cbPerObjectBuffer );
    		d3d11DevCon->PSSetConstantBuffers( 1, 1, &cbPerObjectBuffer );
    		if(material[meshSubsetTexture[i]].hasTexture)
    			d3d11DevCon->PSSetShaderResources( 0, 1, &meshSRV[material[meshSubsetTexture[i]].texArrayIndex] );
    		///**************new**************
    		if(material[meshSubsetTexture[i]].hasNormMap)
    			d3d11DevCon->PSSetShaderResources( 1, 1, &meshSRV[material[meshSubsetTexture[i]].normMapTexArrayIndex] );
    		///**************new**************
    		d3d11DevCon->PSSetSamplers( 0, 1, &CubesTexSamplerState );
    
    		d3d11DevCon->RSSetState(RSCullNone);
    		int indexStart = meshSubsetIndexStart[i];
    		int indexDrawAmount =  meshSubsetIndexStart[i+1] - meshSubsetIndexStart[i];
    		if(material[meshSubsetTexture[i]].transparent)
    			d3d11DevCon->DrawIndexed( indexDrawAmount, indexStart, 0 );
    	}
    	///**************new**************	
    	RenderText(L"FPS: ", fps);
    
    	//Present the backbuffer to the screen
    	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,则在读取之后会被删除
    		*/
    		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()将会让窗口做一些解析,类似键盘的虚拟键值转换到字符形式。
    			//而DispatchMessage()则发送消息到窗口过程WndProc。
    			TranslateMessage(&msg);
    			DispatchMessage(&msg);
    		}
    		else //若没有窗口消息,则运行游戏
     ///**************new**************
    		{
      			frameCount++;
     	 		if(GetTime() > 1.0f)
                {
                    fps = frameCount;
                    frameCount = 0;
                    StartTimer();
                }    
    
                frameTime = GetFrameTime();
    		
                ///**************new**************
                DetectInput(frameTime);
                ///**************new**************
                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, L"Are you sure you want to exit?",
    				L"Really?", MB_YESNO | MB_ICONASTERISK) == IDYES)
    			{
    				DestroyWindow(hwnd);
    			}
    			return 0;
    
    		}
    		break;
    
    	case WM_DESTROY:
    		PostQuitMessage(0);
    		return 0;
    		break;
    		///**************new**************
    	case WM_SIZE:
    		ClientWidth  = LOWORD(lParam);
    		ClientHeight = HIWORD(lParam);
    		return 0;
    		break;
    	default:
    		break;
    	}
    
    	//调用默认窗口过程函数
    	return DefWindowProc(hwnd,
    		msg,
    		wParam,
    		lParam);
    }



    效果文件:

    struct Light
    {
    	float3 pos;
    	float  range;
    	float3 dir;
    	float cone;
    	float3 att;
    	float4 ambient;
    	float4 diffuse;
    };
    
    cbuffer cbPerFrame
    {
        Light light;
    };
    
    cbuffer cbPerObject
    {
        float4x4 WVP;
        float4x4 World;
    
    	float4 difColor;
    	bool hasTexture;
    	bool hasNormMap;
    };
    
    Texture2D ObjTexture;
    Texture2D ObjNormMap;
    SamplerState ObjSamplerState;
    TextureCube SkyMap;
    
    struct VS_OUTPUT
    {
    	float4 Pos : SV_POSITION;
    	float4 worldPos : POSITION;
    	float2 TexCoord : TEXCOORD;
    	float3 normal : NORMAL;
    	float3 tangent : TANGENT;
    };
    
    struct SKYMAP_VS_OUTPUT	//output structure for skymap vertex shader
    {
    	float4 Pos : SV_POSITION;
    	float3 texCoord : TEXCOORD;
    };
    
    VS_OUTPUT VS(float4 inPos : POSITION, float2 inTexCoord : TEXCOORD, float3 normal : NORMAL, float3 tangent : TANGENT)
    {
        VS_OUTPUT output;
    
        output.Pos = mul(inPos, WVP);
    	output.worldPos = mul(inPos, World);
    
    	output.normal = mul(normal, World);
    
    	output.tangent = mul(tangent, World);
        output.TexCoord = inTexCoord;
    
        return output;
    }
    
    
    SKYMAP_VS_OUTPUT SKYMAP_VS(float3 inPos : POSITION, float2 inTexCoord : TEXCOORD, float3 normal : NORMAL, float3 tangent : TANGENT)
    {
    	SKYMAP_VS_OUTPUT output = (SKYMAP_VS_OUTPUT)0;
    
    	//Set Pos to xyww instead of xyzw, so that z will always be 1 (furthest from camera)
    	output.Pos = mul(float4(inPos, 1.0f), WVP).xyww;
    
    	output.texCoord = inPos;
    
    	return output;
    }
    
    float4 PS(VS_OUTPUT input) : SV_TARGET
    {
    	input.normal = normalize(input.normal);
    
    	//Set diffuse color of material
    	float4 diffuse = difColor;
    
    	//If material has a diffuse texture map, set it now
    	if(hasTexture == true)
    		diffuse = ObjTexture.Sample( ObjSamplerState, input.TexCoord );
    
    	//If material has a normal map, we can set it now
    	if(hasNormMap == true)
    	{
    		//Load normal from normal map
    		float4 normalMap = ObjNormMap.Sample( ObjSamplerState, input.TexCoord );
    
    		//Change normal map range from [0, 1] to [-1, 1]
    		normalMap = (2.0f*normalMap) - 1.0f;
    
    		//Make sure tangent is completely orthogonal to normal
    		input.tangent = normalize(input.tangent - dot(input.tangent, input.normal)*input.normal);
    
    		//Create the biTangent
    		float3 biTangent = cross(input.normal, input.tangent);
    
    		//Create the "Texture Space"
    		float3x3 texSpace = float3x3(input.tangent, biTangent, input.normal);
    
    		//Convert normal from normal map to texture space and store in input.normal
    		input.normal = normalize(mul(normalMap, texSpace));
    	}
    
    	float3 finalColor;
    
    	finalColor = diffuse * light.ambient;
    	finalColor += saturate(dot(light.dir, input.normal) * light.diffuse * diffuse);
    	
    	return float4(finalColor, diffuse.a);
    }
    
    float4 SKYMAP_PS(SKYMAP_VS_OUTPUT input) : SV_Target
    {
    	return SkyMap.Sample(ObjSamplerState, input.texCoord);
    }
    
    float4 D2D_PS(VS_OUTPUT input) : SV_TARGET
    {
        float4 diffuse = ObjTexture.Sample( ObjSamplerState, input.TexCoord );
    
        return diffuse;
    }
    
    


    效果:






    参考网址













    展开全文
  • D3D11 简单光照

    2017-10-16 16:21:33
    有四种类型光照以及三种光源。本章将介绍使用一个“定向”光源如何实现简单光照。在随后的章节会介绍其他两种类型的光源和镜面光照。 光照对于视频游戏的真实外观和感觉是非常重要的。...当为一个电影做场景

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

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

    由于固定功能管线从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)

    镜面反射光:

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

    自发光:

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


    光源类型:

    定向光源(平行光):


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

    点光源:


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

    聚光灯:



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


    法线

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

    法线向量


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

    面法线


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

    法线平均


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


    全局声明

    声明一个存储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 <windows.h>
    #include "Resource.h"
    #include <d3d11.h>
    #include <d3dx11.h>
    #include <d3dx10.h>
    #include <xnamath.h>
    #include <D3D10_1.h>
    #include <DXGI.h>
    #include <D2D1.h>
    #include <sstream>
    #include <dwrite.h>
    //全局描述符
    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<IUnknown **>(&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);
    }



    效果图:




    参考网址


    展开全文
  • D3D11 点光源

    2017-10-19 10:31:00
    点光源是定向光源的一个进步,意味着它要进行更多的计算,以及更真实的场景。 点光源因子 当创建一个点光源时要声明一对值。要定义它 位置,范围以及衰减 位置 它由一个叫pos的3d向量组成,第一个值为x轴,第二...

    本章节会讲解如何创建一个简单的点光源,它会获取第一个立方的位置并绕着第二个立方体中心旋转。

    点光源是定向光源的一个进步,意味着它要进行更多的计算,以及更真实的场景。

    点光源因子

    当创建一个点光源时要声明一对值。要定义它 位置,范围以及衰减

    位置

    它由一个叫pos的3d向量组成,第一个值为x轴,第二个为y轴,第三个为z轴。但是点光源没有像定向光源和聚光灯一样的一个方向。由于它是向各个方向发散的,但是必须要有一个位置。

    范围

    范围由一个叫做range的float值声明。来自点光源的光线不会像平行光一样永远延续。因此,我们必须给它一个范围,在该范围之外的任何像素或物体不会被点亮。

    衰减

    它有一个名为att的3D向量构成。它三个值分别为att0,att1,att2。衰减Attenuation也叫做衰减因子,用于控制光的强度变化,或随着光源距离的越来越远就越低。衰减计算公式如下:

    Attenuation = att0 + (att1 * d) + (att2 * d²)

    d表示光源和像素之间的距离。下面解释每个因子的详细信息:

    att0 - 常量

    由于该值不会被任何值相乘,它叫做常量,也就是说它不会随着像素和光源的距离的改变而改变。该值用于对在光源范围内的所有物体给定一个最小光量。若将该值设为1.0f,那么在光源范围内的所有物体将会有全颜色或全光线。

    att1-线性量

    该变量会与光源和像素之间的距离相乘。这使得该值变成一个线性量,这也就表示这会随着光源和像素的距离越来越亮而逐渐降低一个像素获取到的光量。这也许是最实际的因素。

    att2-指数量

    该值与d的平方相乘,这使得该值成为了指数量。使用该值会给非常接近光源的物体大量的光线,但是随着它们远离光源,接收的光线RAPIDLY会在一个小的距离内逐渐减少,随后慢慢地减少。

    点光源方程

    它实际不是一个方程,而更像是一些了的步骤和方程来实现点光源。

    来自光线位置向量的像素方向

    首先创建一个向量用于描述撞击像素的光线方向。如下:

    lightToPixelVec = light.pos - input.worldPos;

    在上一章节的平行光源中,只需要发送来自VS阶段的屏幕空间向量位置。然而,我们的光线位置是在世界空间被定义的,所以我们必须像发送向量的屏幕空间一样来发送来自VS阶段的世界空间位置向量。在上一章节我们发送世界空间的向量法线,所以对理解发送世界空间中的向量实际位置到PS是没有问题的。

    像素的位置和光线的位置之间的距离

    现在我们使用刚创建的向量来找到像素位置和光线位置之间的距离。随后决定该像素是否位于光线范围之内。可以使用length()来查找使用HSLS语言中的向量长度。

    d = length(lightToPixelVec);

    若d值大于光线的范围因子,那么像素不会接收到任何来自光源的光线,且我们能够返回环境光值。

    规范化向量lightToPixelVec

    现在需要规范化该向量以便在后面的函数使用。可通过在上面获取到的距离来除以它的方法来规范化该向量。

    lightToPixelVec /= d; 

    光线强度

    现在要找出有多大强度的光线撞击像素的表面。若光线正照射变量的正上方,那么表面将会接收到所有的光线,若光源在后面或者平行于表面,那么该表面不会接收到光线。可通过将光线照相像素的方向成语像素法线来得到该因子。

    howMuchLight = dot(lightToPixelVec, input.normal);

    添加光线强度到像素

    首先会检测一下以便确认howMuchLight是否大于0,若是大于0,则表示光线是撞击在表面的前面。随后将光线强度因子与像素相加。因此,我们将会将光线强度(howMuchLight)与我们像素的漫反射颜色值相乘以及与我们光线的漫反射颜色相乘。

    finalColor += howMuchLight * diffuse * light.diffuse;

    添加衰减因子

    最后我们必须要做的就是实现我们的点光源,在我们的衰减因子内的因子。可通过将我们的像素颜色与衰减因子相除来做到,它决定了像素获得的最终光量,光量是根据它距离光源有多远来决定。

    finalColor /= light.att[0] + (light.att[1] * d) + (light.att[2] * (d*d));

    光照结构体

    将光照结构体改造了以下,添加了三个新的成员。一个是位置,一个是范围,还有一个是衰减因子。

    struct Light
    {
        Light()
        {
            ZeroMemory(this, sizeof(Light));
        }
        XMFLOAT3 dir;
        float pad1;
        ///**************new**************
        XMFLOAT3 pos;
        float range;
        XMFLOAT3 att;
        float pad2;
        ///**************new**************
        XMFLOAT4 ambient;
        XMFLOAT4 diffuse;
    };

    描述光照

    将pos初值设为0,0,0(在随后会更新该值),它的范围是100.0f,它的衰减att1为0.2f,会给它一个常量衰减因子。

    light.pos = XMFLOAT3(0.0f, 0.0f, 0.0f);
    light.range = 100.0f;
    light.att = XMFLOAT3(0.0f, 0.2f, 0.0f);
    light.ambient = XMFLOAT4(0.3f, 0.3f, 0.3f, 1.0f);
    light.diffuse = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);

    更新光线位置

    我们将会让我们的点光源获取到第一个立方体的位置,它会绕着中心立方体转。首先创建一个新的向量,它会保存我们的第一个立方体位置,随后将光线位置的每个x,y,和z值设置为世界空间中的第一个立方体位置的x,y和z值。

    XMVECTOR lightVector = XMVectorSet( 0.0f, 0.0f, 0.0f, 0.0f );
    
    lightVector = XMVector3TransformCoord(lightVector,cube1World);
    
    light.pos.x = XMVectorGetX(lightVector);
    light.pos.y = XMVectorGetY(lightVector);
    light.pos.z = XMVectorGetZ(lightVector);

    效果文件

    新的HLSL光线结构体,包含一个位置,范围和衰减因子

    struct Light
    {
        float3 dir;
        float3 pos;
        float  range;
        float3 att;
        float4 ambient;
        float4 diffuse;
    };

    就像前面所说的,现在传入我们的向量世界位置,以及来自VS阶段的真实世界的向量法线。

    VS_OUTPUT VS(float4 inPos : POSITION, float2 inTexCoord : TEXCOORD, float3 normal : NORMAL)
    {
        VS_OUTPUT output;
    
        output.Pos = mul(inPos, WVP);
        
        output.worldPos = mul(inPos, World);
        output.normal = mul(normal, World);
    
        output.TexCoord = inTexCoord;
    
        return output;
    }


    下面是新的PS阶段,它会实现我们的点光源。

    float4 PS(VS_OUTPUT input) : SV_TARGET
    {
        input.normal = normalize(input.normal);
    
        float4 diffuse = ObjTexture.Sample( ObjSamplerState, input.TexCoord );
    
        float3 finalColor = float3(0.0f, 0.0f, 0.0f);
        
        //Create the vector between light position and pixels position
        float3 lightToPixelVec = light.pos - input.worldPos;
            
        //Find the distance between the light pos and pixel pos
        float d = length(lightToPixelVec);
        
        //Create the ambient light
        float3 finalAmbient = diffuse * light.ambient;
    
        //If pixel is too far, return pixel color with ambient light
        if( d > light.range )
            return float4(finalAmbient, diffuse.a);
            
        //Turn lightToPixelVec into a unit length vector describing
        //the pixels direction from the lights position
        lightToPixelVec /= d; 
        
        //Calculate how much light the pixel gets by the angle
        //in which the light strikes the pixels surface
        float howMuchLight = dot(lightToPixelVec, input.normal);
    
        //If light is striking the front side of the pixel
        if( howMuchLight > 0.0f )
        {    
            //Add light to the finalColor of the pixel
            finalColor += howMuchLight * diffuse * light.diffuse;
            
            //Calculate Light's Falloff factor
            finalColor /= light.att[0] + (light.att[1] * d) + (light.att[2] * (d*d));
        }    
            
        //make sure the values are between 1 and 0, and add the ambient
        finalColor = saturate(finalColor + finalAmbient);
        
        //Return Final Color
        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 <windows.h>
    #include "Resource.h"
    #include <d3d11.h>
    #include <d3dx11.h>
    #include <d3dx10.h>
    #include <xnamath.h>
    #include <D3D10_1.h>
    #include <DXGI.h>
    #include <D2D1.h>
    #include <sstream>
    #include <dwrite.h>
    //全局描述符
    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 pad1;
        ///**************new**************
        XMFLOAT3 pos;
        float range;
        XMFLOAT3 att;
        float pad2;
        ///**************new**************
    	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, 
    		"Point Lighting", 
    		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<IUnknown **>(&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);
    
        ///**************new**************
        light.pos = XMFLOAT3(0.0f, 0.0f, 0.0f);
        light.range = 100.0f;
        light.att = XMFLOAT3(0.0f, 0.2f, 0.0f);
        light.ambient = XMFLOAT4(0.3f, 0.3f, 0.3f, 1.0f);
    	light.diffuse = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
        ///**************new**************
    	//创建顶点缓冲
    	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;
    
        ///**************new**************
        //复位光源位置
        XMVECTOR lightVector = XMVectorSet( 0.0f, 0.0f, 0.0f, 0.0f );
    
        lightVector = XMVector3TransformCoord(lightVector,cube1World);
    
        light.pos.x = XMVectorGetX(lightVector);
        light.pos.y = XMVectorGetY(lightVector);
        light.pos.z = XMVectorGetZ(lightVector);
        ///**************new**************
    	
    	//复位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, 1.0f, 1.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);
    }



    效果文件:

    struct Light
    {
        float3 dir;
        float3 pos;
        float  range;
        float3 att;
        float4 ambient;
        float4 diffuse;
    };
    
    cbuffer cbPerFrame
    {
        Light light;
    };
    
    cbuffer cbPerObject
    {
        float4x4 WVP;
        float4x4 World;
    };
    
    Texture2D ObjTexture;
    SamplerState ObjSamplerState;
    
    struct VS_OUTPUT
    {
        float4 Pos : SV_POSITION;
        float4 worldPos : 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.worldPos = mul(inPos, World);
        output.normal = mul(normal, World);
        output.TexCoord = inTexCoord;
    
        return output;
    }
    
    float4 PS(VS_OUTPUT input) : SV_TARGET
    {
        input.normal = normalize(input.normal);
    
        float4 diffuse = ObjTexture.Sample( ObjSamplerState, input.TexCoord );
    
        float3 finalColor = float3(0.0f, 0.0f, 0.0f);
        
        //Create the vector between light position and pixels position
        float3 lightToPixelVec = light.pos - input.worldPos;
            
        //Find the distance between the light pos and pixel pos
        float d = length(lightToPixelVec);
        
        //Create the ambient light
        float3 finalAmbient = diffuse * light.ambient;
    
        //If pixel is too far, return pixel color with ambient light
        if( d > light.range )
            return float4(finalAmbient, diffuse.a);
            
        //Turn lightToPixelVec into a unit length vector describing
        //the pixels direction from the lights position
        lightToPixelVec /= d; 
        
        //Calculate how much light the pixel gets by the angle
        //in which the light strikes the pixels surface
        float howMuchLight = dot(lightToPixelVec, input.normal);
    
        //If light is striking the front side of the pixel
        if( howMuchLight > 0.0f )
        {    
            //Add light to the finalColor of the pixel
            finalColor += howMuchLight * diffuse * light.diffuse;
            
            //Calculate Light's Falloff factor
            finalColor /= light.att[0] + (light.att[1] * d) + (light.att[2] * (d*d));
        }    
            
        //make sure the values are between 1 and 0, and add the ambient
        finalColor = saturate(finalColor + finalAmbient);
        
        //Return Final Color
        return float4(finalColor, diffuse.a);
    }
    
    float4 D2D_PS(VS_OUTPUT input) : SV_TARGET
    {
        input.normal = normalize(input.normal);
    
        float4 diffuse = ObjTexture.Sample( ObjSamplerState, input.TexCoord );
    
        return diffuse;
    }
    
    


    效果:




    参考网址






    展开全文
  • D3D11的深度模板缓冲

    千次阅读 2017-09-27 11:35:54
    创建深度模板缓冲,随后创建深度模板视图并将它绑定到管线的OM阶段。...实现一个深度模板缓冲对于directx中渲染3D场景来说是必备的。 深度模板视图 深度模板视图就是让管线的OM阶段检测渲染目标上所有的像素片段

    创建深度模板缓冲,随后创建深度模板视图并将它绑定到管线的OM阶段。绑定深度模板视图到OM阶段将会运行它检测渲染目标上的每个像素片段的深度值。若在渲染目标上的点内有不止一个像素片段,深度值最低的像素(离屏幕最近)片段将会绘制,而其他的会被丢弃。

    实现一个深度模板缓冲对于directx中渲染3D场景来说是必备的。


    深度模板视图

    深度模板视图就是让管线的OM阶段检测渲染目标上所有的像素片段的深度模板值。一个像素片段就是一个具有写到屏幕上的潜在可能性的像素。比如一个球和一个盒子。球位于盒子后面,当它们通过渲染管线时,球的像素与盒子的像素都会倍放入到渲染目标上。这些像素就是所谓的像素片段。当像素到达OM阶段时,OM阶段回将像素片段的深度值与已经存储在位置中的像素片段进行对比。若新来的像素片段深度值小于已经保存的像素片段值,那么已经保存的像素片段值会被丢弃,新来的像素片段值会被保存到渲染目标上。因此回到球和盒子,假设球先渲染。在渲染目标上此时还没有几何体,因此整个球将会渲染上。但是当盒子的像素到达OM阶段时,OM阶段会对比新来的盒子的像素片段的深度值与之前就存在这儿的球的像素值。因为盒子是位于球的前面的,所以球的像素片段会被丢弃,且会将盒子的像素片段保存到渲染目标上。在所有的几何体绘制完毕后,最终还保留在渲染目标上的像素就是将要被显示在屏幕上的像素。

    关于深度视图的模板部分是为高级技术准备的,比如镜像,随后会提到。


    全局声明

    声明两个结构对象。一个用于存储深度模板视图,一个用于存储深度模板缓冲

    ID3D11DepthStencilView* depthStencilView;
    ID3D11Texture2D* depthStencilBuffer;

    深度模板缓冲描述

    现在进入到d3d初始化部分,在创建深度模板缓冲前,需要先定义它。可通过填充结构体D3D11_TEXTURE2D_DESC来定义它,就像之前填充后缓冲一样。在这儿唯一要提及的事情是绑定标志和格式。格式提供了两个变量空间:深度为24位,模板为8位。绑定标志表示该纹理会被绑定到OM阶段作为深度模板缓冲。

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


    创建深度模板视图

    使用设备接口的CreateTexture2D方法创建深度模板缓冲。随后再创建深度模板视图并绑定到管线的OM阶段,通过调用设备接口的CreateDepthStencilView()方法实现。第一个参数是深度模板缓冲描述符,第二个参数是深度模板状态,设为NULL。第三个参数为深度模板缓冲。

    d3d11Device->CreateTexture2D(&depthStencilDesc, NULL, &depthStencilBuffer);
    d3d11Device->CreateDepthStencilView(depthStencilBuffer, NULL, &depthStencilView);


    绑定深度模板视图

    最后就是绑定深度模板视图到管线的OM阶段了。在之前的例子中该函数OMSetRenderTargets因为没有创建深度模板视图,因此设为NULL。在此就可将深度模板视图添加上去了。

    d3d11DevCon->OMSetRenderTargets( 1, &renderTargetView, depthStencilView );


    添加深度值到视口

    现在到创建以及描述视口的地方了,应该告诉OM去将像素Z值或深度值转换为0~1之间的值。其中0表示最近,1表示最远。

    viewport.MinDepth = 0.0f;
    viewport.MaxDepth = 1.0f;


    销毁

    别忘记释放COM对象

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

    释放深度模板视图

    最后要确保清掉了每一帧的深度模板视图,就像对渲染目标视图所做的一样。在这儿使用函数ClearDepthStencilView()方法来实现。第一个参数为想要清理的深度模板视图,第二个参数为枚举类型,是一个逻辑或的结果,指定了深度模板视图要清理的哪一部分,第三个参数是想要清理到的深度值。在此设为1.0f是因为1.0f是图像所具备的最大深度值。这确保所有的对象绘制在屏幕上。若在这儿设为0.0f,则不会绘制任何图像到屏幕上,因为所有的像素片段深度值都是位于0~1之间的。最后一个参数值是设置模板的所到达的地方。在这儿设为0,是因为还没有使用模板。

    d3d11DevCon->ClearDepthStencilView(depthStencilView, D3D11_CLEAR_DEPTH|D3D11_CLEAR_STENCIL, 1.0f, 0);


    参考网址


    代码实例:

    #include "stdafx.h"
    #pragma comment(lib, "d3d11.lib")
    #pragma comment(lib, "d3dx11.lib")
    #pragma comment(lib, "d3dx10.lib")
    
    #include <windows.h>
    #include "Resource.h"
    #include <d3d11.h>
    #include <d3dx11.h>
    #include <d3dx10.h>
    #include <xnamath.h>
    
    //全局描述符
    IDXGISwapChain* SwapChain;
    ID3D11Device* d3d11Device;
    ID3D11DeviceContext* d3d11DevCon;
    ID3D11RenderTargetView* renderTargetView;
    
    //索引缓冲
    ID3D11Buffer* squareIndexBuffer;
    ID3D11Buffer* squareVertBuffer;
    
    //深度值-20170927
    ID3D11DepthStencilView* depthStencilView;
    ID3D11Texture2D* depthStencilBuffer;
    
    //着色器
    ID3D11Buffer* triangleVertBuffer;
    ID3D11VertexShader* VS;
    ID3D11PixelShader* PS;
    ID3D10Blob* VS_Buffer;
    ID3D10Blob* PS_Buffer;
    ID3D11InputLayout* vertLayout;
    #if 0
    float red = 0.0f;
    float green = 0.0f;
    float blue = 0.0f;
    int colormodr = 1;
    int colormodg = 1;
    int colormodb = 1;
    #endif
    /
    LPCTSTR WndClassName = "firstwindow";
    HWND hwnd = NULL;
    HRESULT hr;
    
    const int Width = 800; //设置宽
    const int Height = 800; // 设置高
    //函数声明
    bool InitializeDirect3d11App(HINSTANCE hInstance);
    //void ReleaseObjects();
    void CleanUp();
    bool InitScene();
    void UpdateScene();
    void DrawScene();
    
    // 初始化窗口
    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);
    
    //顶点结构体以及顶点布局(输入布局)
    struct Vertex
    {
    	Vertex(){}
    	Vertex(float x, float y, float z,
    		float cr, float cg, float cb, float ca)
    		:pos(x, y, z), color(cr, cg, cb, ca){}
    	XMFLOAT3 pos;
    	XMFLOAT4 color;
    };
    
    D3D11_INPUT_ELEMENT_DESC layout[] = {
    	{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
    	{ "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, 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 Initilization - 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, (LPCTSTR)IDI_SMALL);
    
    	/*定义光标图标
    	*IDC_APPSTARTING 标准箭头以及小型沙漏光标
    	*IDC_ARROW 标准箭头光标
    	*IDC_CROSS 十字线光标
    	*IDC_HAND 手型光标
    	*IDC_NO 斜线圈光标
    	*IDC_WAIT 沙漏光标
    	*/
    	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    	//hbrBackground是一个刷子的句柄,可使得背景黑色。
    	wc.hbrBackground = (HBRUSH)(COLOR_BTNSHADOW + 2);
    	//附加到窗口的菜单名字,不需要的话设置为NULL
    	wc.lpszMenuName = NULL;
    	//对类进行命名
    	wc.lpszClassName = WndClassName;
    	//指定任务栏的图标,使用上面的IDI_图标
    	wc.hIconSm = LoadIcon(NULL, (LPCTSTR)IDI_MYICON);
    	//注册类。若失败则会获得一个错误,若成功,则继续创建窗口
    	if (!RegisterClassEx(&wc))
    	{
    		MessageBox(NULL, "Error registering class", "Error", MB_OK | MB_ICONERROR);
    		return 1;
    	}
    
    	//创建窗口
    	hwnd = CreateWindowEx(NULL, WndClassName, "Drawing Square", 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_R8G8B8A8_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;
    
    
    	//创建交换链
    	D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, NULL, NULL, NULL,
    		D3D11_SDK_VERSION, &swapChainDesc, &SwapChain, &d3d11Device, NULL, &d3d11DevCon);
    
    	//创建后缓冲
    	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);
    
    	//设置渲染目标
    	d3d11DevCon->OMSetRenderTargets(1, &renderTargetView, depthStencilView);
    
    	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();
    }
    
    void ReleaseObjects()
    {
    //释放创建的COM对象
    	SwapChain->Release();
    	d3d11Device->Release();
    	d3d11DevCon->Release();
    }
    
    bool InitScene()
    {
    	//编译着色器
    	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);
    
    	//创建着色器对象
    	hr = d3d11Device->CreateVertexShader(VS_Buffer->GetBufferPointer(), VS_Buffer->GetBufferSize(), NULL, &VS);
    	hr = d3d11Device->CreatePixelShader(PS_Buffer->GetBufferPointer(), PS_Buffer->GetBufferSize(), NULL, &PS);
    
    	//设置顶点和像素着色器
    	d3d11DevCon->VSSetShader(VS, 0, 0);
    	d3d11DevCon->PSSetShader(PS, 0, 0);
    
    	//创建顶点缓冲
    	Vertex v[] = {
    		Vertex(-0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f),
    		Vertex(-0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f),
    		Vertex(0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f),
    		Vertex(0.5f, -0.5f, 0.5f, 0.0f, 1.0f, 0.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, &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) * 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, &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;
    	viewport.MaxDepth = 1;
    	//设置视口
    	d3d11DevCon->RSSetViewports(1, &viewport);
    	return true;
    }
    
    void UpdateScene()
    {
    	// 更新场景颜色
    #if 0
    	red += colormodr * 0.00005f;
    	green += colormodg * 0.00002f;
    	blue += colormodb * 0.00001f;
    
    	if (red >= 1.0f || red <= 0.0f)
    		colormodr *= -1;
    	if (green >= 1.0f || green <= 0.0f)
    		colormodg *= -1;
    	if (blue >= 1.0f || blue <= 0.0f)
    		colormodb *= -1;
    #endif
    }
    
    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);
    	//绘制三角形
    	d3d11DevCon->DrawIndexed(6, 0, 0);
    	//画三角形
    	//d3d11DevCon->Draw(3, 0);
    
    	//将后缓冲呈现到屏幕
    	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 //若没有窗口消息,则运行游戏
    		{
    			 // run game code
    			UpdateScene();
    			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);
    		break;
    
    	default:
    		break;
    	}
    
    	//调用默认窗口过程函数
    	return DefWindowProc(hwnd,
    		msg,
    		wParam,
    		lParam);
    }


    效果图看上去与上一篇类似,本质上是不同的:





    展开全文
  • D3D11游戏编程】学习笔记十二:光照模型

    万次阅读 热门讨论 2012-12-25 06:05:48
     从这一篇开始,我们逐渐进入D3D11中有意思的部分。之前的场景绘制,要么为每个顶点指定单一的颜色,要么在线框模式下渲染。从现在起我们开始学习光照,这样场景就更加具有真实感了。  1. 法线的引入
  • ELIXIR引擎 Elixir Engine是使用DirectX 11用C ++编写的Windows版...场景保存和加载 OBJ模型加载 使用通用图片文件(.jpg,.png,.dds等) 通过编辑器操纵游戏对象 三种支持的语言英语,日语和西班牙语。 ##屏幕截图
  • D3D11之坐标空间的转换

    千次阅读 2018-01-16 15:59:26
    世界坐标系转换其实就是将顶点从几何模型坐标系移到世界坐标系中,在游戏里就是构建游戏场景,将物品放置到一个场景里。通常在世界坐标系转换时,还将通过改变大小来控制基元物件的放大或缩小,通过改变方向来设置...
  • (注:【D3D11游戏编程】学习笔记系列由CSDN作者BonChoix所写,转载请注明出处:http://blog.csdn.net/BonChoix,谢谢~)  在这篇文章中,我们来实现一个简单的第一个称摄像机。在之前所有的程序中,为了方便从...
  • 使用场景: 主播在直播游戏的时候,如果游戏是全屏模式,主播无法看到直播软件中的聊天消息。...2.dll中hook了D3D11的渲染函数(比如Present) 3.直播软件中获取聊天消息的rgba数据,并通过IPC将数据传递到dl...
  • (注:【D3D11游戏编程】学习笔记系列由CSDN作者BonChoix所写,转载请注明出处:http://blog.csdn.net/BonChoix,谢谢~)  雾效是3D渲染中用来模拟现实中大气现象的一种常见手段。最直接的用途就是实现带雾天气...
  • 创建一个D3D11应用程序流程

    千次阅读 2017-09-22 16:58:28
    也就是所谓的双缓冲,当渲染场景时,是渲染到后缓冲的,因此当呈现后缓冲到显示器时,它会完整地被画出来。若不使用这种方式,就会看到扫描线,就是看到程序在绘画场景时的样子,通常是从上到下的。 2.是一个用来...
  • (注:【D3D11游戏编程】学习... 在D3D11中,“混合”发生在像素着色器阶段的下一阶段,即Output Merger Stage。整个场景在全部经历过像素着色器阶段后,对应于屏幕上每一点像素,可能有多个片段(Fragment)。如下
  • 接下来让我们更进一步,再来设想一个更复杂的场景,还是之前那个一个线程(CPU线程)+命令列表(GPU线程)渲染一个正方体,另一个线程+命令列表渲染一个球体的例子,当然我们还要加入一个线程+命令队列渲染一个平面...
  • D3D11游戏编程】学习笔记七:3D渲染管线

    万次阅读 多人点赞 2012-12-15 07:32:58
    (注:【D3D11游戏编程】学习笔记系列由CSDN作者BonChoix所写,转载请注明出处:http://blog.csdn.net/BonChoix,谢谢~)    3D图形学研究的基本内容,即给定场景的描述,包括各个物体的材质、纹理、坐标等,...
  • D3D11游戏编程】学习笔记十四:纹理基础

    万次阅读 热门讨论 2012-12-29 03:17:45
    (注:【D3D11游戏编程】学习笔记系列由CSDN作者BonChoix所写,转载请注明出处:http://blog.csdn.net/BonChoix,谢谢~)  光照和材质的加入使得场景的真实感大大增加,但仅仅这些依然不足以表现出真实世界中...
  • 这儿介绍在3D场景中如何转换一个几何体。转换利用矩阵,使用xna数学库提供的函数来实现。 转换 在d3d中使用4x4的矩阵来做转换。这是因为它们使用4维度,3空间,x,y,z和1个变化,这1个变化是用字母w表示,w...
  • (注:【D3D11游戏编程】学习笔记系列由CSDN作者BonChoix所写,转载请注明出处:http://blog.csdn.net/BonChoix,谢谢~)    在前面两篇介绍Cube Mapping的文章中,我们所使用到的Cube Map都是事先制作好的,...
  • 渲染一个彩色立方体,这是个很经典的案例,上一篇文章成功地渲染了一个三角形,这次是个...世界空间:是将场景中的所有对象共享于一个坐标下。 相机空间:也用于整个场景,但原点位于相机处。 投影空间:相机空间应用
  • 基于D11的教程(初始化Direct3D) 本章学习目标 了解渲染管线、设备、交换链、上下文的概念 代码时间 预备小知识: 在VS2019中,选择【使用C++的桌面开发】会默认选中一个叫做Windows 10 SDK的组件。这个SDK已经...
  • 资源类型(十四)

    2019-04-26 11:03:05
    资源是可以通过Direct3D管道访问的内存区域。...D3D11和D3D10资源的不同: 下面是D3D11支持的新数据类型: 读写缓冲区和纹理 结构体缓冲区 字节地址缓冲区 追加和消费缓冲区 无序访问缓冲区和纹理 ...

空空如也

空空如也

1 2
收藏数 40
精华内容 16
热门标签
关键字:

d3d11场景