Direct3D中的Pick技术(转)

2013-12-1 admin 转载

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

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

标签: 游戏开发 算法 DirectX

发表评论:

Powered by emlog | |

浙ICP备17021512号 |浙公网安备 33010602008237号