D3D11 拾取

来源:互联网 发布:淘宝店在那搞活动 编辑:程序博客网 时间:2024/05/16 11:11

本章节是基于法线贴图章节的。

这里将介绍如何将2d屏幕位置(以像素为单位,鼠标所在的位置)转换为世界空间中的3d射线,随后检测该射线是否会和屏幕上的其他物体相交。(本例中假设物体是瓶子)。
若射线和瓶子相交,就会显示出相机到瓶子的距离,并增加分数,且删除瓶子,不让它再次显示以避免射线与它再次相交检测。

D3D11中的拾取操作比D3D10要多一个步骤,因为在D3D11中没有网格接口,之前的网格接口是有一个方法可用于检测射线是否和一个物体相交的。因此,现在就需要自己实现这个功能。


拾取3D物体
要拾取一个3D物体,需要遵循以下步骤:
a.获取屏幕空间鼠标位置的2D向量(x,y)值。
b.将屏幕空间鼠标的2D向量转换为视图空间射线的3D向量(x,y,z)。
c.将视图空间的射线转换为世界空间的射线。
d.将模型空间或本地空间的模型或物体顶点位置转换到世界空间。
e.遍历模型中每个三角形以找出和射线相交的三角形。(在D3D10中可通过网格接口提供的一个方法来跳过该步骤)。
1.获取屏幕空间的鼠标位置
调用两个函数来获取屏幕空间的鼠标位置:GetCursorPos()和ScreenToClient()。它们将鼠标的x和y位置存储进一个类型为POINT的变量中。该变量就表示鼠标的位置,且是以像素为单位衡量的,在这将客户窗口的左上角位置表示为(0,0),右下角为(clientWidth,clientHeight)。随后再将x和y坐标传到另外一个函数,该函数会将坐标值转换为视图空间射线的3D向量值,然后再将视图空间的3D射线转换为世界空间的3D射线。
2.将2D屏幕空间射线转换为3D视图空间射线
首先会将拾取处点的x-和y-轴转换为视图空间坐标。视图空间的x和y轴范围为从-1到1,z轴上范围从0到1。为了能够转换成功,这里是将拾取到的x和y位置乘以2,再除以客户窗口的宽和高,然后减1。举个栗子,假设窗口的宽高是800,600,鼠标点击在位置(100,100)处。先找到视图空间中的x轴,首先用100乘以2,得200。然后,用200除以窗口的宽(800),得0.25,最后减去1,就得到-0.75。这样做完后,该点的x轴已经成功转化到视图空间了,该值范围是-1到1。对Y轴也是类似处理过程。下面的方程是屏幕空间x和y轴,减去1之后它们将转换到视图空间中去:
ViewSpaceX = (2 * PickedPointX) / ClientWidthViewSpaceY = (2 * PickedPointY) / ClientHeight



现在来解决视图空间的z轴,它有两种方式可以来解决:一是直接将z设为1且修改ViewSpaceX和ViewSpaceY的方程式,二是在本质上解决z的问题:z轴实际上是相机原点到投射窗口的距离。这个投射距离可以使用方程式Z=cotangent(angle/2)来获到。angle是以弧度为单位的视图垂直视觉域,在前面使用函数XMMatrixPerspectiveFovLH()设置camProjection时已经设置好了。在本章代码中,设置该视觉角度的垂直域为0.4f*3.14。可使用1/tangent来获得cotangent,z的方程式如下:
ViewSpaceZ = 1 / tan((0.4 * 3.14) / 2)


上面是本质上解决z轴的问题,现在通过直接设z轴为1,并修改x和y轴的两个方程式来解决z轴问题。下面两个方程式是通过使用投射矩阵来获得视图空间x和y轴的值,在本章中用camProjection表示投射矩阵。针对ViewSpaceX,除以camProjection(0,0),它的值为1/(ratio*tangent(angle/2))。针对ViewSpaceY,除以camProjection(1,1),它的值是1/tangent(angent/2)。如下:
ViewSpaceX = ((2 * PickedPointX) / ClientWidth)  / camProjection(0,0)ViewSpaceY = ((2 * PickedPointY) / ClientHeight) / camProjection(1,1)ViewSpaceZ = 1


第一人称射击拾取
如果要使用屏幕中心(就像第一人称射击中一样)来作为拾取点。由于在x和y轴上范围都是从-1到1,z轴上范围是从0到1,可使用(0,0,1)作为视图空间点。这么做有效是因为这直接进入了相机原点的视图空间,它的点坐标为(0,0,0)。因为创建法线实际上只使用两个点(原点和方向)就可以了,所以可设置z为任意大于0的值。因此,如下第一人称射击代码类似如下:

ViewSpaceX = 0ViewSpaceY = 0ViewSpaceZ = 1


3.视图空间到世界空间
还记得之前章节的从本地空间转换到世界空间再转换到视图空间最后转换到屏幕空间的过程,只是让它们有序的相乘而已。现在是要反过来从视图空间转换到世界空间,那么就需要找到视图空间矩阵的逆,实际它就是世界空间的矩阵。可使用函数XMMatrixInverse()来找到视图空间矩阵的逆,第一个参数不会使用,第二个参数是相机的视图空间矩阵。该函数不能将第一个参数设为null,即使不需要它也不能将它设为null。第一个参数为逆行列式向量,在用视图矩阵的逆得到世界矩阵后,就可使用世界空间矩阵来转换视图空间的射线位置和方向了,最后才能够得到世界空间射线。
4.将顶点转换到世界空间
转换工作还没完成,这里做最后的转换。首先需要获取到构建模型的顶点位置(在模型世界中),并将它们转换到世界空间中。这步可能发生的问题就是从模型获取顶点位置时。在D3D10中,可通过直接使用网格接口提供的方法来使用模型世界空间的矩阵,该方法会检测射线是否和模型相交。但是在D3D11中,网格接口已经被抛弃,因此就需要自己来获取顶点位置信息,并检测它们的相交。其实获取顶点位置不是很难,但是由于cpu只能从阶段缓冲中读取且被cpu读取的缓冲是不能直接绑定到渲染阶段的,因此是没法从顶点缓冲中获取到顶点位置信息的。所以当为模型创建顶点和索引并把它们放入到顶点和索引缓冲中时,还需要创建两个数组或向量来保存索引和顶点的位置。随后再使用这些顶点数组中的位置信息来获得模型中三角形的位置信息,以及使用索引来找到构建每个三角形的顶点。在做完这些后才能够将模型世界空间矩阵的顶点转换进世界空间。
还有就是,由于检测拾取射线是否和物体相交都使用同一个拾取射线,因此这些工作只需要在每次点击时做一次就可以了。但是从第4步开始,需要为要检测的每个模型或模型的子集做这些步骤。
5.检测拾取射线和对象(模型)之间的相交
本步骤可分解为以下更小的步骤:
a. 首先实现平面三角方程(Ax+By+Cz+D=0)
b.找到射线和三角形相交的射线上的位置
c.找到射线与三角形相交的点。
d.找到相交点是否在三角形内
1.实现三角平面方程(Ax+By+Cz+D = 0)
为了找到三角形所在(由三角形法线描述)的平面,首先要获取三角形的两个边,u和v。随后会使用这两条边来获取到三角形的法线,它表示平面,和方程式的A,B,C。可使用以下的方程式来获得面法线:
faceNormal = (V2 - V1) x (V3 - V1)


“x“符号是向量的叉乘符号,可用下面代码来实现叉乘:

//Gets the two edgesU = TriangleVertex2 - TriangleVertex1;V = TriangleVertex3 - TriangleVertex1;//Gets the triangles normalfaceNormal = XMVector3Cross(U, V);//Normalize the normalfaceNormal = XMVector3Normalize(faceNormal);


现在得到了平面方程式的A,B,C,也就是平面法线的x,y和z。现在需要得到方程式的x,y和z。这只是平面上的另外一个点,且由于三个顶点构成面,所以在代码中,将会使用第一个向量来构建三角形。方程式如下:
(faceNormal.x * TriangleVertex1.x) + (faceNormal.y * TriangleVertex1.y) + (faceNormal.z * TriangleVertex1.z) + D = 0



最后就是得到D。这是一个代数问题,首先两边都减去D,如下:

Ax + By + Cz = -D


得到负D,但是需要的是正D。两边都乘以-1就可以了。

-1 * (Ax + By + Cz) = D//Turns into:-Ax - By - Cz = D//In Code:    D = -(faceNormal.x * TriangleVertex1.x) - (faceNormal.y * TriangleVertex1.y) - (faceNormal.z * TriangleVertex1.z)



现在得到平面方程式了,就可以找到射线和平面的相交点了。
2.找到射线和平面相交点。
现在假设有一个值为t,表示射线原点(相机的位置)到三角形平面相交点的距离。若t为正,则可得相交点发生于相机前,或t为负,则可知相交点发生在相机后,随后跳过(除非想要拾取相机后的物体)。在拾取射线平行于平面时,要小心除以0的情况发生。为了得到t可使用如下方程式:
t = -(A*x2 + B*y2 + C*z2 + D) / (A*(x1-x2) + B*(y1-y2) + C*(z1-z2))


其中x1,y1,z1为射线原点,x2,y2和z2为射线方向。为了让代码易读,将方程式分为两部分:ep1和ep2。将位置和射线原点代入到平面方程式中分别得到ep1和ep2:
ep1 = (pickRayInWorldSpacePos.x * (Ax)) + (pickRayInWorldSpacePos.y * (By)) + (pickRayInWorldSpacePos.z * (Cz));ep2 = (pickRayInWorldSpaceDir.x * (Ax)) + (pickRayInWorldSpaceDir.y * (By)) + (pickRayInWorldSpaceDir.z * (Cz));


在得到ep1和ep2后,t就如下可得:
t = -(ep1 + D)/(ep2)

为了防止除以0的情况发生,以免向量吞掉整个世界(除以0),在跑该方程式之前要检测ep2以确保不等于0。


3.找到三角平面上的点,该点是拾取射线相交的地方。
可使用下面的方程式来找到该点的x,y和z值。
planeIntersectX = pickRayInWorldSpacePos.x + pickRayInWorldSpaceDir.x * t;planeIntersectY = pickRayInWorldSpacePos.y + pickRayInWorldSpaceDir.y * t;planeIntersectZ = pickRayInWorldSpacePos.z + pickRayInWorldSpaceDir.z * t;


4.找到射线和三角平面相交的点。

有很多方式获取得到该点:

一是找到三角形的区域,使用相交点和三个顶点来创建三个更小的三角形,它们构建第一个三角形(该三角形就是正在检测的用于交互的)。将这三个更小的三角形的区域叠加起来,若它们的和与第一个三角形区域相等,则可判断点在三角形内。

二是使用重心坐标,这有一点困难,但是是最有效的方式。
这里用的方式就是检测构成交点所在三角形的三天边的每一条边。若相交点位于每条边的对的一面,则它在三角形内,反之,则它就是在三角形的外并退出。
这里启发一下如何使用重心坐标来完成这个任务。
为了检测相交点是否在正确的三角形的边上,还需要一个在线的正确边上的点。会使用第三个或者未使用的三角形的角(未使用的是说在检测时在边内是没有用的)。创建两个叉积,第一个使用两个顶点的点和边,第二个使用第三个顶点和两个顶点的边。会得到这两个叉乘的点积,且若结果大于或等于0,则该点可知是在正确的边上;反之,点在三角形的边外并退出。
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;


模型的顶点位置和索引数组
针对读取模型顶点位置和顶点索引信息,由于不能直接使用CPU读取保存的D3D缓冲,所以就需要创建向量来保存它们。如下是地面模型的两个向量:
std::vector<XMFLOAT3> groundVertPosArray;std::vector<DWORD> groundVertIndexArray;


瓶子模型成员
下面是瓶子模型所需要的变量和结构体。注意怎样声明瓶子世界矩阵的数组和命名为bottleHit的整型数组以及numBottles变量的。这是因为将会在屏幕内显示20个瓶子:
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[20];int* bottleHit = new int[20];int numBottles = 20;




新的全局变量
有许多新的全局变量,首先是isShoot。当鼠标按钮第一次按下时该变量会为true,不按下则为false。这么做是因为只想要能够每点击一次就拾取一次。后面是两个整型,以像素为单位保存客户窗口的宽度和高度,这些值会随着屏幕尺寸的调整而改变。当启动程序的时候会自动发出WM_SIZE窗口消息,所以当程序启动时会填充这些变量;若没这机制,则一开始要手动填充了,若是在窗口化模式下(因为边框和应用程序窗口的顶部会占用掉一小部分空间),可能不会100%准确。后面是全局变量用以跟踪分数(拾取的瓶子的数量),最后是相机到最近的拾取物体的距离(只有在物体被拾取时,才会更新)
bool isShoot = false;int ClientWidth = 0;int ClientHeight = 0;int score = 0;float pickedDist = 0.0f;


新的函数原型
三个新的函数原型。第一个用于计算世界空间拾取法线(拾取法线是从鼠标光标的2d坐标系得到的);第二个函数计算物体是否被拾取,它调用最后一个函数。最后一个函数被前面的拾取函数调用,它判断一个点是否位于三角形内部(确保该点一定是在三角形平面上的)。
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 );


====》校订20171211...

新的LoadObjModel()函数原型

添加了两个新的参数用以获得模型顶点位置和索引并做一些类似检测射线和模型相交的操作,是因为无法从D3D缓冲中读取绑定到管线的顶点和索引信息才添加的。
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**************////////////////////


初始化Direct输入
需要修改函数来初始化direct的输入,以便当运行程序时能够看到鼠标,因为到目前为止(是因为实现了direct输入),是将鼠标的合作级别设为独占型的,无法看到光标,但是现在将设置它为非独占的,以便能够看到光标。
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);    ///////////////**************new**************////////////////////    hr = DIMouse->SetCooperativeLevel(hwnd, DISCL_NONEXCLUSIVE | DISCL_NOWINKEY | DISCL_FOREGROUND);    ///////////////**************new**************////////////////////    return true;}


检测输入
现在检测左鼠标按钮是否按下,左鼠标按钮由mouseCurrState.rgbButtons[0]表示。这里要使用到全局变量isShoot,按钮当前一直保持按下状态时,检测程序会一直输出按钮按下事件。代码中发现鼠标按钮按下时,会检测isShoot,若为false,则设置isShoot为true。用这种方式,在下一个轮回到来时,若鼠标按钮仍然保持按下状态,就不会再去检测拾取操作了,由于只要每次点击只检测一次拾取操作。当按钮释放时,isShoot会再次被设为false。
声明一个POINT类型的变量用于存储鼠标位置。随后获取鼠标位置,并将那些位置值转化为客户窗口位置(确保在窗口模式下客户窗口和显示器屏幕对齐)
再声明了几个变量,变量tempDist会存储当前被检测物体的拾取距离,若当前物体被检测发现没有被拾取到,则该值设为FLT_MAX,也就是最大float值。下一个变量是到最近被拾取的物体的距离,下一个为hitIndex,它会存储被拾取的最近距离瓶子的索引值。用后面两个变量来控制只拾取最近距离的瓶子。
随后,再声明两个向量,用于保存世界空间的拾取射线位置和方向,调用函数来将显示器上的鼠标光标的位置转换为两个3d向量,这两个向量用来描述世界空间的拾取射线位置和方向。
下面是一个遍历,检测物体和拾取射线的相交。首先在循环中调用函数来检测当前物体是否被拾取,并将它的拾取距离存储在tempDist变量中。下一步,若tempDist小于cloestDist,则可知当前被拾取的物体比最后一个物体距离相机更近,并更新cloestDist和hitIndex的值。


在检测完每个模型后,通过确认closestDist值小于FLAT_MAT来确认物体被拾取。若物体被拾取后,在这部分代码中就可以做一些在物体被拾取时想做一些事情,比如在本章节中,会确保被拾取的瓶子不再显示,或通过设置bottleHit值为1确保不再去检测它的拾取,再增加相应的分数,设置pickedDist为相机到瓶子的距离,并显示在屏幕上。
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;    }    ///////////////**************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);            for(int i = 0; i < numBottles; i++)            {                if(bottleHit[i] == 0) //No need to check bottles already hit                {                    tempDist = pick(prwsPos, prwsDir, bottleVertPosArray, bottleVertIndexArray, bottleWorld[i]);                    if(tempDist < closestDist)                    {                        closestDist = tempDist;                        hitIndex = i;                    }                }            }            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;}


销毁
别忘了释放瓶子的顶点和索引缓冲
void CleanUp(){    SwapChain->SetFullscreenState(false, NULL);    PostMessage(hwnd, WM_DESTROY, 0, 0);    //Release the COM Objects we created    SwapChain->Release();    d3d11Device->Release();    d3d11DevCon->Release();    renderTargetView->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();    cbPerFrameBuffer->Release();    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();    meshVertBuff->Release();    meshIndexBuff->Release();    ///////////////**************new**************////////////////////    bottleVertBuff->Release();    bottleIndexBuff->Release();    ///////////////**************new**************////////////////////}


pickRayVector()函数
该函数会将光标位置转换为世界空间的3d射线,这在上面解释过了,这里不再赘述了。
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);    //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);}Pick()函数该函数会检测物体是否与拾取射线相交。返回float型,表示相机到被拾取的物体的距离。若物体未拾取,则返回FLT_MAXfloat 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;}




PointInTriangle()函数
判断三角形所在平面上点是否在三角形内,若点在内,则返回true,否则返回false。
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;}



更新的LoadObjModel()函数
该函数有两个向量参数,一个用于存储模型顶点位置一个用于存储索引数组
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**************////////////////////{


存储模型的顶点位置列表和索引列表
在vertPosArray向量中存储顶点位置,在vertIndexArray中存储索引列表。
 
//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**************////////////////////


加载模型
添加两个参数来加载模型,分别是存储顶点位置和索引列表向量。
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;


设置瓶子世界空间矩阵
在InitScene函数的最后,使用循环来遍历每个瓶子的世界空间矩阵,并将它们有序设置,因此可以将瓶子排列在世界中。
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;    }


RenderText()函数
显示分数以及显示相机与拾取物体的距离,可修改函数RenderText()
std::wostringstream printString; printString << text << inInt << L"\n"    << L"Score: " << score << L"\n"    << L"Picked Dist: " << pickedDist;


DrawScene()函数
这里显示瓶子。首先遍历每个瓶子,若瓶子还没有被点击,则让它显示。注意这里没有显示瓶子的透明部分,这是因为已经知道瓶子没有透明部分,所以不浪费空间了。
 //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 );            }        }    }


WndProc()函数
现在进入到窗口流程函数来检测窗口消息。需要检测窗口缩放消息,当程序首次启动时,该消息会自动发送,还有就是在每次改变窗口大小时都会发送,因此就需要将更新新的高度和宽度信息到全局变量ClientWidth和ClientHeight中。
LRESULT CALLBACK WndProc(HWND hwnd,    UINT msg,    WPARAM wParam,    LPARAM lParam){    switch( msg )    {    case WM_KEYDOWN:        if( wParam == VK_ESCAPE ){            DestroyWindow(hwnd);        }        return 0;    case WM_DESTROY:        PostQuitMessage(0);        return 0;    ///////////////**************new**************////////////////////    case WM_SIZE:        ClientWidth  = LOWORD(lParam);        ClientHeight = HIWORD(lParam);        return 0;    }    ///////////////**************new**************////////////////////    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 materialfloat4 diffuse = difColor;//If material has a diffuse texture map, set it nowif(hasTexture == true)diffuse = ObjTexture.Sample( ObjSamplerState, input.TexCoord );//If material has a normal map, we can set it nowif(hasNormMap == true){//Load normal from normal mapfloat4 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 normalinput.tangent = normalize(input.tangent - dot(input.tangent, input.normal)*input.normal);//Create the biTangentfloat3 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.normalinput.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;}


代码实例:

#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;//深度值-20170927ID3D11DepthStencilView* 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[20];int* bottleHit = new int[20];int numBottles = 20;///////////////**************new**************//////////////////////纹理和材质变量,用于所有的网格的加载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**************////////////////////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**************////////////////////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 bytesBOOL 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结构体后,定义函数LoadObjModelbool LoadObjModel(std::wstring filename,//.obj filenameID3D11Buffer** vertBuff,//mesh vertex bufferID3D11Buffer** indexBuff,//mesh index bufferstd::vector<int>& subsetIndexStart,//start index of each subsetstd::vector<int>& subsetMaterialArray,//index value of material for each subsetstd::vector<SurfaceMaterial>& material,//vector of material structuresint& subsetCount,//Number of subsets in meshbool isRHCoordSys,//true if model was created in right hand coord systembool 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 Geometrystd::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以及窗口显示方式的nShowCmdint 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;}/////newif (!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是一个指向处理窗口消息函数的指针,设置窗口处理函数的函数名WndProcwc.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);//附加到窗口的菜单名字,不需要的话设置为NULLwc.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",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和DirectWriteInitD2D_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; //绑定到OMdepthStencilDesc.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 factoryID2D1Factory *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);//DirectWritehr = 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;}///////////////**************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);for(int i = 0; i < numBottles; i++){if(bottleHit[i] == 0) //No need to check bottles already hit{tempDist = pick(prwsPos, prwsDir, bottleVertPosArray, bottleVertIndexArray, bottleWorld[i]);if(tempDist < closestDist){closestDist = tempDist;hitIndex = i;}}}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 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 1Transparency->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();/// newcbPerFrameBuffer->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 spacePRVecX =  ((( 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 screenpickRayInViewSpaceDir = XMVectorSet(PRVecX, PRVecY, PRVecZ, 0.0f);//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 spaceXMMATRIX pickRayToWorldSpaceMatrix;XMVECTOR matInvDeter;//We don't use this, but the xna matrix inverse function requires the first parameter to not be nullpickRayToWorldSpaceMatrix = XMMatrixInverse(&matInvDeter, camView);//Inverse of View Space matrix is World space matrixpickRayInWorldSpacePos = 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 objectfor(int i = 0; i < indexPosArray.size()/3; i++){//Triangle's vertices V1, V2, V3XMVECTOR 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 vertexXMFLOAT3 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 spacetri1V1 = 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, VfaceNormal = XMVector3Cross(U, V);faceNormal = XMVector3Normalize(faceNormal);//Calculate a point on the triangle for the plane equationXMVECTOR triPoint = tri1V1;//Get plane equation ("Ax + By + Cz + D = 0") Variablesfloat 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 planefloat 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-zerosif(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 planeplaneIntersectX = 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 triangleif(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 camerareturn t/2.0f;}}}//return the max float value (near infinity) if an object was not pickedreturn 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;}elsereturn false;}elsereturn 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 filestd::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 timestd::wstring face;//Holds the string containing our face verticesint vIndex = 0;//Keep track of our vertex index countint triangleCount = 0;//Total Trianglesint totalVerts = 0;int meshTriangles = 0;//检测文件是否被打开if (fileIn){while(fileIn){checkChar = fileIn.get();//Get next charswitch (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 typesif(isRHCoordSys)//If model is from an RH Coord SystemvertPos.push_back(XMFLOAT3( vx, vy, vz * -1.0f));//Invert the Z axiselsevertPos.push_back(XMFLOAT3( vx, vy, vz));}if(checkChar == 't')//vt - vert tex coords{float vtcu, vtcv;fileIn >> vtcu >> vtcv;//Store next two typesif(isRHCoordSys)//If model is from an RH Coord SystemvertTexCoord.push_back(XMFLOAT2(vtcu, 1.0f-vtcv));//Reverse the "v" axiselsevertTexCoord.push_back(XMFLOAT2(vtcu, vtcv));hasTexCoord = true;//We know the model uses texture coords}//由于我们在后来计算法线,我们不必在此检测法线//In the file, but i'll do it here anywayif(checkChar == 'n')//vn - vert normal{float vnx, vny, vnz;fileIn >> vnx >> vny >> vnz;//Store next three typesif(isRHCoordSys)//If model is from an RH Coord SystemvertNorm.push_back(XMFLOAT3( vnx, vny, vnz * -1.0f ));//Invert the Z axiselsevertNorm.push_back(XMFLOAT3( vnx, vny, vnz ));hasNorm = true;//We know the model defines normals}break;//新组(子集)case 'g'://g - defines a groupcheckChar = fileIn.get();if(checkChar == ' '){subsetIndexStart.push_back(vIndex);//Start index for this subsetsubsetCount++;}break;//获取面索引case 'f'://f - defines the facescheckChar = fileIn.get();if(checkChar == ' '){face = L"";std::wstring VertDef;//Holds one vertex definition at a timetriangleCount = 0;checkChar = fileIn.get();while(checkChar != '\n'){face += checkChar;//Add the char to our face stringcheckChar = fileIn.get();//Get the next Characterif(checkChar == ' ')//If its a space...triangleCount++;//Increase our triangle count}//Check for space at the end of our face stringif(face[face.length()-1] == ' ')triangleCount--;//Each space adds to our triangle counttriangleCount -= 1;//Ever vertex in the face AFTER the first two are new facesstd::wstringstream ss(face);if(face.length() > 0){int firstVIndex, lastVIndex;//Holds the first and last vertice's indexfor(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 stringfor(int j = 0; j < VertDef.length(); ++j){if(VertDef[j] != '/')//If there is no divider "/", add a char to our vertPartvertPart += VertDef[j];//If the current char is a divider "/", or its the last character in the stringif(VertDef[j] == '/' || j ==  VertDef.length()-1){std::wistringstream wstringToInt(vertPart);//Used to convert wstring to intif(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 specifiedif(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 defaultvertTCIndexTemp = 0;//If the cur. char is the second to last in the string, then//there must be no normal, so set a default normalif(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 partwhichPart++;//Move on to next vertex part}}//Check to make sure there is at least one subsetif(subsetCount == 0){subsetIndexStart.push_back(vIndex);//Start index for this subsetsubsetCount++;}//Avoid duplicate verticesbool vertAlreadyExists = false;if(totalVerts >= 3)//Make sure we at least have one triangle to check{//Loop through all the verticesfor(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 verticesif(vertPosIndexTemp == vertPosIndex[iCheck] && !vertAlreadyExists){if(vertTCIndexTemp == vertTCIndex[iCheck]){indices.push_back(iCheck);//Set index for this vertexvertAlreadyExists = true;//If we've made it here, the vertex already exists}}}}//If this vertex is not already in our vertex arrays, put it thereif(!vertAlreadyExists){vertPosIndex.push_back(vertPosIndexTemp);vertTCIndex.push_back(vertTCIndexTemp);vertNormIndex.push_back(vertNormIndexTemp);totalVerts++;//We created a new vertexindices.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 vertexif(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 trianglefor(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 vertexvIndex++;//Second Vertex of this triangle (the last vertex used in the tri before this one)indices.push_back(lastVIndex);//Set index for this vertexvIndex++;//Get the third vertex for this triangless >> 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 specifiedif(j == VertDef.length()-1){vertTCIndexTemp = 0;vertNormIndexTemp = 0;}}else if(whichPart == 1){if(vertPart != L""){wstringToInt >> vertTCIndexTemp;vertTCIndexTemp -= 1;}elsevertTCIndexTemp = 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 verticesbool 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 vertexvertAlreadyExists = 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 vertsindices.push_back(totalVerts-1);//Set index for this vertex}//Set the second vertex for the next triangle to the last vertex we gotlastVIndex = indices[vIndex];//The last vertex index of this TRIANGLEmeshTriangles++;//New triangle definedvIndex++;}}}break;case 'm'://mtllib - material library filenamecheckChar = 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 namefileIn >> meshMatLib;}}}}}}break;case 'u'://usemtl - which material to usecheckChar = 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 clearedfileIn >> 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 messagestd::wstring message = L"Could not open: ";message += filename;MessageBox(0, message.c_str(),//display messageL"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 specifiedif(!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 filefileIn.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 ambientbool kdset = false;if (fileIn){while(fileIn){checkChar = fileIn.get();//Get next charswitch (checkChar){            //Check for commentcase '#':checkChar = fileIn.get();while(checkChar != '\n')checkChar = fileIn.get();break;//Set diffuse colorcase 'K':checkChar = fileIn.get();if(checkChar == 'd')//Diffuse Color{checkChar = fileIn.get();//remove spacefileIn >> 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 spaceif(!kdset){fileIn >> material[matCount-1].difColor.x;fileIn >> material[matCount-1].difColor.y;fileIn >> material[matCount-1].difColor.z;}}break;//Check for transparencycase 'T':checkChar = fileIn.get();if(checkChar == 'r'){checkChar = fileIn.get();//remove spacefloat 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 transparencycase 'd':checkChar = fileIn.get();if(checkChar == ' '){float Transparency;fileIn >> Transparency;//'d' - 0 being most transparent, and 1 being opaque, opposite of TrTransparency = 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 mapcheckChar = 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 extensionbool 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 loadedbool 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 nowif(!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 mapelse 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 mapmaterial[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 extensionbool 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 loadedbool 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 nowif(!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 materialcheckChar = 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 defaultsSurfaceMaterial 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 fullscreenstd::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 arrayfor(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 vectorfor(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 vectorvertPosArray.push_back(tempVert.pos);///////////////**************new**************////////////////////}///////////////**************new**************//////////////////////Copy the index list to the arrayvertIndexArray = 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 normalsif(computeNormals){std::vector<XMFLOAT3> tempNormal;//normalized and unnormalized normalsXMFLOAT3 unnormalized = XMFLOAT3(0.0f, 0.0f, 0.0f);///////////////**************new**************//////////////////////tangent stuffstd::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 vertsfloat vecX, vecY, vecZ;//Two edges of our triangleXMVECTOR edge1 = XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f);XMVECTOR edge2 = XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f);//Compute face normalsfor(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 normalXMStoreFloat3(&unnormalized, XMVector3Cross(edge1, edge2));tempNormal.push_back(unnormalized);///////////////**************new**************//////////////////////Find first texture coordinate edge 2d vectortcU1 = 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 vectortcU2 = 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 edgestangent.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 vertexfor(int i = 0; i < totalVerts; ++i){//Check which triangles use this vertexfor(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 tangentstX = 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 vertexnormalSum = normalSum / facesUsing;///////////////**************new**************////////////////////tangentSum = tangentSum / facesUsing;///////////////**************new**************//////////////////////Normalize the normalSum vectornormalSum = XMVector3Normalize(normalSum);///////////////**************new**************////////////////////tangentSum =  XMVector3Normalize(tangentSum);///////////////**************new**************//////////////////////Store the normal in our current vertexvertices[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 vertexnormalSum = 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 bufferD3D11_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 BufferD3D11_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 FaceVertex(-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**************///////////////////////////////////**************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);/// newhr = 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);///newhr = 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);//创建缓冲用来发送到效果文件的cbufferD3D11_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);#if 1///////////////**************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**************////////////////////#endif//配置采样状态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 spacebottleWorld[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 matrixScale = XMMatrixScaling( 5.0f, 5.0f, 5.0f );//Make sure the sphere is always centered around cameraTranslation = XMMatrixTranslation( XMVectorGetX(camPosition), XMVectorGetY(camPosition), XMVectorGetZ(camPosition) );//Set sphereWorld's world space using the transformationssphereWorld = Scale * Translation;///////////////**************new**************////////////////////meshWorld = XMMatrixIdentity();//Define cube1's world space matrixRotation = 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));//创建字符串std::wostringstream printString;    ///////////////**************new**************////////////////////printString << text << inInt << L"\n"<< L"Score: " << score << L"\n"<< L"Picked Dist: " << pickedDist;///////////////**************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);//newconstbuffPerFrame.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 subsetsfor(int j = 0; j < numBottles; j++){if(bottleHit[j] == 0){for(int i = 0; i < bottleSubsets; ++i){//Set the grounds index bufferd3d11DevCon->IASetIndexBuffer( bottleIndexBuff, DXGI_FORMAT_R32_UINT, 0);//Set the grounds vertex bufferd3d11DevCon->IASetVertexBuffers( 0, 1, &bottleVertBuff, &stride, &offset );//Set the WVP matrix and send it to the constant buffer in effect fileWVP = 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 screenSwapChain->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();            ///////////////**************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);}



效果:




参考网址


===》校订20171212

原创粉丝点击