叶子的小屋
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;

}