Direct3D中的Pick技术

来源:互联网 发布:python 查看数据类型 编辑:程序博客网 时间:2024/05/01 20:48

------------------------

pick.h

------------------------

 

#pragma once
#include <vector>
using std::vector;

 

struct PickResult
{
 DWORD dwFace;                 // mesh face that was intersected
 FLOAT fBary1, fBary2;         // barycentric coords of intersection
 FLOAT fDist;                  // distance from ray origin to intersection
 FLOAT tu, tv;                 // texture coords of intersection
 RenderObject *object;
 float3 hitpoint;
};

 

struct D3DVERTEX
{
 float3 p;
 float3 normal;
 FLOAT       tu, tv;
 static const DWORD FVF;//Flexible Vertex Format
};


class Pick
{


public:


 Pick(void);
 ~Pick(void);
 vector<PickResult>  Excute(int mouseX,int mouseY,Camera* camer);
 void SetMesh(vector<RenderObject*> objects);


private:


 vector<RenderObject*> normalObjects;
 HRESULT CreateRay(int mouseX,int mouseY);
 vector<PickResult> m_IntersectionArray;
 float3 vPickRayDir;//射线的方向向量
 float3 vPickRayOrig;//射线的起始点
 Camera* m_pCamera;


};

----------------------

pick.cpp

----------------------

 

#include "stdafx.h"
#include "Pick.h"
#define MAX_INTERSECTIONS 16


Pick::Pick(void)
{  
}

 

Pick::~Pick(void)
{
}

 

void Pick::SetMesh(vector<RenderObject*> objects)
{
    normalObjects=objects;
}

 

HRESULT Pick::CreateRay(int mouseX,int mouseY)
{
 //获取投影矩阵
 float4x4 matProj=m_pCamera->GetMatProj();
 //计算从屏幕坐标到投影矩阵坐标
 float3 v;
 float width=D3Dsystem::GetInstance()->GetDeviceWidth();
 float height=D3Dsystem::GetInstance()->GetDeviceHeight();
 v.x =(((2.0f*mouseX)/width)-1)/matProj._11;
 v.y =-(((2.0f*mouseY)/height)-1)/matProj._22;
 v.z =1.0f;
 //获取视图矩阵的逆矩阵
 float4x4 matView=m_pCamera->GetMatView();
 float4x4 m;
 D3DXMatrixInverse( &m, NULL, &matView );//计算逆矩阵
 D3DXVec3TransformNormal(&vPickRayDir,&v,&m);
 D3DXVec3Normalize(&vPickRayDir,&vPickRayDir);
 float3 o = float3(0,0,0);
 D3DXVec3TransformCoord(&vPickRayOrig,&o,&m);//(x, y, z, 1):w=1
 return S_OK;
}

 

bool SortFunction(const PickResult &r0,const PickResult &r1)
{

 return r0.fDist< r1.fDist ? true:false;
}

 

vector<PickResult> Pick::Excute(int mouseX,int mouseY,Camera* camer)
{  

 m_pCamera=camer;
 m_IntersectionArray.clear();//清除拾取记录
 CreateRay(mouseX,mouseY);   
 HRESULT hr=S_OK;
 DWORD*      pIndices;
 FLOAT u, v, fDist;
 for (int i=0;i<normalObjects.size();i++)
 {

   ObjectFrame *frame=normalObjects[i]->GetObjectFrame();
   int numVertex=frame->numvertex;
   int numIndex=frame->numIndex;
   DWORD dwNumFaces=frame->dwNumFaces;
   if(1>numIndex)
   {
    continue;
   }
   pIndices=new DWORD[numIndex];
   int maxWORD = 1<<16;
   if(numVertex < maxWORD)
   {
     for(int i=0;i<numIndex;i++)
     {
      pIndices[i]= ((WORD*)(frame->pIndex))[i];
     }
   }
   else
   {
     for(int i=0;i<numIndex;i++)
     {
      pIndices[i]=frame->pIndex[i];
     }
   }
   for (DWORD f=0;f<dwNumFaces;f++)
   {
    float3 vert[3];
    for(int j=0;j<3;j++)
    {  
     //通过一个矩阵来变换一个三维向量 outV srcV Matri
     float3 v0 = frame->pVertex[pIndices[3*f+j]].p;
     D3DXVec3TransformCoord(&vert[j],&v0,&normalObjects[i]->GetTransform()); 
    }
    if(D3DXIntersectTri(  &vert[0], &vert[1], &vert[2],&vPickRayOrig, &vPickRayDir, &u, &v,&fDist )  && fDist>=0)
    {
     PickResult Intersection;
     Intersection.dwFace = f;
     Intersection.fBary1 = u;
     Intersection.fBary2 = v;
     Intersection.fDist = fDist;
     Intersection.object=normalObjects[i];
     Intersection.hitpoint=vert[0] + (vert[1]-vert[0])*u + (vert[2]-vert[0])*v ;
     m_IntersectionArray.push_back(Intersection);
    }
   }
      SAFE_DELETE_ARRAY(pIndices); 
    }


 std::sort(m_IntersectionArray.begin(),m_IntersectionArray.end(),SortFunction);
 return m_IntersectionArray;


}