鼠标选取3D物体的问题 - 为什么选不到?

jxc 2005-04-11 07:26:50
下面是某个例子的代码,为什么实际选取不到呢?
我用的是VC6 , DX8.1

long cApp::GetCharacterAt(long XPos, long YPos)
{
D3DXVECTOR3 vecRay, vecDir;
D3DXVECTOR3 vecMeshRay, vecMeshDir;
D3DXVECTOR3 vecTemp;
D3DXMATRIX matProj, matView, *matWorld;
D3DXMATRIX matInv;
DWORD FaceIndex;
BOOL Hit;
float u, v, Dist;
sCharacter *CharPtr;
sMesh *MeshPtr;

// Get parent character object
if((CharPtr = m_CharController.GetParentCharacter()) == NULL)
return -1;

// Get the project, view, and inversed view matrices
m_Graphics.GetDeviceCOM()->GetTransform(D3DTS_PROJECTION, \
&matProj);

// Compute the vector of the pick ray in screen space
vecTemp.x = (((2.0f * (float)XPos) / \
(float)m_Graphics.GetWidth()) - 1.0f) / \
matProj._11;
vecTemp.y = -(((2.0f * (float)YPos) / \
(float)m_Graphics.GetHeight()) - 1.0f) / \
matProj._22;
vecTemp.z = 1.0f;

m_Graphics.GetDeviceCOM()->GetTransform(D3DTS_VIEW, \
&matView);
D3DXMatrixInverse(&matInv, NULL, &matView);

// Transform the screen space ray
vecRay.x = matInv._41;
vecRay.y = matInv._42;
vecRay.z = matInv._43;

vecDir.x = vecTemp.x * matInv._11 + \
vecTemp.y * matInv._21 + \
vecTemp.z * matInv._31;
vecDir.y = vecTemp.x * matInv._12 + \
vecTemp.y * matInv._22 + \
vecTemp.z * matInv._32;
vecDir.z = vecTemp.x * matInv._13 + \
vecTemp.y * matInv._23 + \
vecTemp.z * matInv._33;

// Scan through each character and intersect check
while(CharPtr != NULL) {

// Scan through character meshes
MeshPtr = CharPtr->Object.GetMesh()->GetParentMesh();
while(MeshPtr != NULL) {

// Transform ray and direction by object's
// world transformation matrix
matWorld = CharPtr->Object.GetMatrix();
D3DXMatrixInverse(&matInv, NULL, matWorld);

D3DXVec3TransformCoord(&vecMeshRay, &vecRay, &matInv);
D3DXVec3TransformNormal(&vecMeshDir, &vecDir, &matInv);

// Check for intersection
D3DXIntersect(MeshPtr->m_Mesh, &vecMeshRay,&vecMeshDir, \
&Hit, &FaceIndex, &u, &v, &Dist,NULL,NULL);

// Check if ray hit character and return ID if so
if(Hit == TRUE)
return CharPtr->ID;

// Go to next mesh
MeshPtr = MeshPtr->m_Next;
}

// Go to next character
CharPtr = CharPtr->Next;
}

return -1; // Return no hit
}
...全文
1133 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
pzh508 2005-04-24
  • 打赏
  • 举报
回复
to jxc(GameHeart) :
恩,今天仔细检测了一下,是有一些不准确,不过判断方法应该是没有错误的,我在dx2004、dx9.0b下用那个方法判断没有一点问题,估计就是MESH数据结构不同造成的! *_* )
pzh508 2005-04-24
  • 打赏
  • 举报
回复
to happy__888([顾问团]寻开心):
有道理,dx8和8.1当中skinmesh的数据处理不一样,所以有可能在使用D3DXIntersect函数时其函数里面得到MESH的数据有差错导致的
寻开心 2005-04-22
  • 打赏
  • 举报
回复
不是那个函数的问题,你完全可以在pick的例子来测试那个d3dx函数的

觉得和变换矩阵的获取方法有关系,在dx8和8.1当中skinmesh的处理方式不同,差异应该是在这里
jxc 2005-04-22
  • 打赏
  • 举报
回复
昨天和happy__888交流了一下,现在的观点是认为DX8和DX8.1的差异造成的,在DX8下一点问题都没有。
原作者有相应的fix方法,可惜google上查到的网址已经失效了。
pzh508 改后的代码虽然能pick到,但好像有点问题,有时pick的不是鼠标点击的那个。
pzh508 2005-04-22
  • 打赏
  • 举报
回复
to happy__888([顾问团]寻开心) :
我知道,其实它原来的源代码就是这样做的,事实上也应该经过World变换后才行,但实际的结果就是pick不到,我也没有搞懂为什么,所以后来我才换成自定义的函数就可以pick到,
请注意:那条射线的变换方法是一样的,没有改变,单单就没有使用D3DXIntersect这个函数而已
pzh508 2005-04-21
  • 打赏
  • 举报
回复
to KingofMagic(大魔头) :
为什么会“3D中pick时,如果有物体旋转时不能旋转视点,否则pick就会出错”??
视点旋转了,则view矩阵也变了,那么射线也相应变了(物体旋转,射线也得变换),所以pick也照样准确的啊,怎么会出错?
pzh508 2005-04-21
  • 打赏
  • 举报
回复
已经改好了,发到你的邮箱了,你自己看看吧,
还有我刚开始跟你说的那种方法其实在它这个例子里是不行的,因为它用了D3D相交方法,而我那个算法是和包围盒的相交
(没有想到Progam role-playing-games with directx 里面竟然还有这样的代码,不错呀)
寻开心 2005-04-21
  • 打赏
  • 举报
回复
看了代码,对应改造成为下面这样就可以了
matWorld = CharPtr->Object.GetMatrix(); // 获取world矩阵
D3DXMATRIX matWorldInv ;
D3DXMatrixInverse(&matWorldInv, NULL, matWorld); // 获取world逆矩阵
D3DXVec3TransformCoord(&vecMeshRay, &vecRay, &matWorldInv); // 用逆矩阵变换射线的两个端点
D3DXVec3TransformNormal(&vecMeshDir, &vecDir, &matWorldInv); //

//用变换后的射线进行检测
D3DXIntersect(MeshPtr->m_Mesh, &vecMeshRay,&vecMeshDir, \
&Hit, &FaceIndex, &u, &v, &Dist, NULL, NULL);
寻开心 2005-04-21
  • 打赏
  • 举报
回复
dxsdk里面的函数没有问题,是你们自己理解的问题

在pick的例子当中,运动的是视点不是物体
所以在处理当中简化了对world矩阵的处理

因此无论你对物体做移动,拉伸还是旋转操作都会导致原版的代码无效的


dxsdk的例子就是演示特定功能的,不要把他们想象成为通用
对于pick来说,如果设置了非单位的变换矩阵,那么在调用dxsdk的辅助函数计算相交的时候
对于射线必须使用world变换阵的逆矩阵处理一下才可以
jxc 2005-04-21
  • 打赏
  • 举报
回复
太意外了吧? 竟然是D3DX库函数的问题??
---------------------------------
D3DXIntersect(MeshPtr->m_Mesh, &vecMeshRay,&vecMeshDir, &Hit, &FaceIndex, &u, &v, &Dist,NULL,NULL);

被 pzh508(小猪) 改成自定义的检测函数就好了...


他的代码如下(没有版权吧?呵呵):
---------------------------------
long cApp::GetCharacterAt(long XPos, long YPos)
{
D3DXVECTOR3 vecRay, vecDir;
D3DXVECTOR3 vecMeshRay, vecMeshDir;
D3DXVECTOR3 vecTemp;
D3DXMATRIX matProj, matView, *matWorld;
D3DXMATRIX matInv;
DWORD FaceIndex;
BOOL Hit = FALSE ;
float u, v, Dist;
sCharacter *CharPtr;
sMesh *MeshPtr;

// Get parent character object
if((CharPtr = m_CharController.GetParentCharacter()) == NULL)
return -1;

// Get the project, view, and inversed view matrices
m_Graphics.GetDeviceCOM()->GetTransform(D3DTS_PROJECTION,&matProj);

// Compute the vector of the pick ray in screen space
vecTemp.x = (((2.0f * (float)XPos) /(float)m_Graphics.GetWidth()) - 1.0f) /matProj._11;
vecTemp.y = -(((2.0f * (float)YPos) /(float)m_Graphics.GetHeight()) - 1.0f) /matProj._22;
vecTemp.z = 1.0f;

m_Graphics.GetDeviceCOM()->GetTransform(D3DTS_VIEW, &matView);
D3DXMatrixInverse(&matInv, NULL, &matView);

// Transform the screen space ray
vecRay.x = matInv._41;
vecRay.y = matInv._42;
vecRay.z = matInv._43;

vecDir.x = vecTemp.x * matInv._11 + vecTemp.y * matInv._21 +vecTemp.z * matInv._31;
vecDir.y = vecTemp.x * matInv._12 +vecTemp.y * matInv._22 +vecTemp.z * matInv._32;
vecDir.z = vecTemp.x * matInv._13 +vecTemp.y * matInv._23 +vecTemp.z * matInv._33;

// Scan through each character and intersect check
while(CharPtr != NULL)
{
// Scan through character meshes
MeshPtr = CharPtr->Object.GetMesh()->GetParentMesh();
while(MeshPtr != NULL)
{
// Transform ray and direction by object's world transformation matrix
matWorld = CharPtr->Object.GetMatrix();
D3DXMatrixInverse(&matInv, NULL, matWorld);
D3DXVec3TransformCoord(&vecRay, &vecRay, &matInv);
D3DXVec3TransformNormal(&vecDir, &vecDir, &matInv);


LPD3DXBASEMESH pMesh = MeshPtr->m_Mesh ;
LPDIRECT3DVERTEXBUFFER8 pVB;
LPDIRECT3DINDEXBUFFER8 pIB;
pMesh->GetVertexBuffer( &pVB );
pMesh->GetIndexBuffer( &pIB );
WORD* pIndices;
D3DVERTEX* pVertices;

pIB->Lock( 0, 0, (BYTE**)&pIndices, 0 );
pVB->Lock( 0, 0, (BYTE**)&pVertices, 0 );


DWORD dwNumFaces = MeshPtr->m_Mesh->GetNumFaces();
FLOAT fBary1, fBary2;
FLOAT fDist;
for( DWORD i=0; i<dwNumFaces; i++ )
{
D3DXVECTOR3 v0 = pVertices[pIndices[3*i+0]].p;
D3DXVECTOR3 v1 = pVertices[pIndices[3*i+1]].p;
D3DXVECTOR3 v2 = pVertices[pIndices[3*i+2]].p;

// Check if the pick ray passes through this point
if( IntersectTriangle( vecRay, vecDir, v0, v1, v2,&fDist, &fBary1, &fBary2 ) )
{
Hit = TRUE ;
}
}


//一般情况下不要使用D3D的函数
// D3DXIntersect(MeshPtr->m_Mesh, &vecMeshRay,&vecMeshDir, &Hit, &FaceIndex, &u, &v, &Dist,NULL,NULL);

// Check if ray hit character and return ID if so
if(Hit == TRUE)
return CharPtr->ID;

// Go to next mesh
MeshPtr = MeshPtr->m_Next;
}

// Go to next character
CharPtr = CharPtr->Next;
}

return -1; // Return no hit
}



BOOL cApp::IntersectTriangle( const D3DXVECTOR3& orig,
const D3DXVECTOR3& dir, D3DXVECTOR3& v0,
D3DXVECTOR3& v1, D3DXVECTOR3& v2,
FLOAT* t, FLOAT* u, FLOAT* v )
{
// Find vectors for two edges sharing vert0
D3DXVECTOR3 edge1 = v1 - v0;
D3DXVECTOR3 edge2 = v2 - v0;

// Begin calculating determinant - also used to calculate U parameter
D3DXVECTOR3 pvec;
D3DXVec3Cross( &pvec, &dir, &edge2 );

// If determinant is near zero, ray lies in plane of triangle
FLOAT det = D3DXVec3Dot( &edge1, &pvec );

D3DXVECTOR3 tvec;
if( det > 0 )
{
tvec = orig - v0;
}
else
{
tvec = v0 - orig;
det = -det;
}

if( det < 0.0001f )
return FALSE;

// Calculate U parameter and test bounds
*u = D3DXVec3Dot( &tvec, &pvec );
if( *u < 0.0f || *u > det )
return FALSE;

// Prepare to test V parameter
D3DXVECTOR3 qvec;
D3DXVec3Cross( &qvec, &tvec, &edge1 );

// Calculate V parameter and test bounds
*v = D3DXVec3Dot( &dir, &qvec );
if( *v < 0.0f || *u + *v > det )
return FALSE;

// Calculate t, scale parameters, ray intersects triangle
*t = D3DXVec3Dot( &edge2, &qvec );
FLOAT fInvDet = 1.0f / det;
*t *= fInvDet;
*u *= fInvDet;
*v *= fInvDet;

return TRUE;
}

jxc 2005-04-20
  • 打赏
  • 举报
回复
代码是摘自Progam role-playing-games with directx 的battle的例子.
KingofMagic 2005-04-19
  • 打赏
  • 举报
回复
3D中pick时,如果有物体旋转时不能旋转视点,否则pick就会出错,只能旋转物体!你可能就是这个原因。当不旋转物体时可以pick到,但是旋转后有些就pick不到,是这样吧?
pzh508 2005-04-19
  • 打赏
  • 举报
回复
不可能的啊,发给我瞧瞧,我的邮箱pzh508@avl.com.cn
jxc 2005-04-14
  • 打赏
  • 举报
回复
我试过还是不行,哪位帮我看看?我提供完整的源代码
我的msn: iamjxc@hotmail.com
jxc 2005-04-13
  • 打赏
  • 举报
回复
各位星级的英雄,请指点一下啊.
pzh508 2005-04-13
  • 打赏
  • 举报
回复
我一直都是这样做的,没有出现过pick不到的情况
pzh508 2005-04-13
  • 打赏
  • 举报
回复
换成这样的方式试试:
……
D3DXMatrixInverse(&matInv, NULL, &matView);
(前面算view的逆矩阵的不变)

//到这里然后先不算射线方向原点,而是遍历物体,得出物体的逆World矩阵再算射线原点
while(CharPtr != NULL)
{
……
matWorld = CharPtr->Object.GetMatrix();
d3dxmatrix matWorldInv ;
D3DXMatrixInverse(&matWorldInv , NULL, matWorld);
d3dxmatrix m ;
D3DXMatrixMultiply(&m,&matInv,&matWorldInv );
vecDir.x = vecTemp.x*m._11 + vecTemp.y*m._21 + vecTemp.z*m._31;
vecDir.y = vecTemp.x*m._12 + vecTemp.y*m._22 + vecTemp.z*m._32;
vecDir.z = vecTemp.x*m._13 + vecTemp.y*m._23 + vecTemp.z*m._33;
vecRay.x = m._41;
vecRay.y = m._42;
vecRay.z = m._43;
D3DXIntersect(MeshPtr->m_Mesh, &vecRay,&vecDir, \
&Hit, &FaceIndex, &u, &v, &Dist,NULL,NULL);
……

}


CATIA V5 培训教程 CATIAV培训教程全文共36页,当前为第1页。 培训大纲 一 CATIA基础知识 0.5天 草图绘制(SKETCHER) 0.5天 零件设计 1、 实体设计(PART DESIGN) 1.5天 2、 曲面设计(GENERATIVE SHAPE DESIGN) 1.5天 四 装配设计(ASSEMBLY DESIGN) 1天 五 工程图设计(DRATFING) 1天 六 培训测试和总结 1天 CATIAV培训教程全文共36页,当前为第2页。 培训要求 掌握CATIA软件各模块的进入方式,鼠标的使用方法。 掌握草图的绘制及尺寸标注 掌握基本的零件设计及修饰方法 掌握曲面的基本设计及修饰方法 掌握装配的基本操作及检查干涉 掌握基本的工程图的绘制方法 1:安装CD1 2:插入CD2直到安装完成。如果不想安装CD3 SP1.那将CD1中的CRACK下的文件复制到:X你的安装目录下:...\B17\intel_a\code\bin然后运行进行破解。 3:安装CD3 SP1 。然后破解,用CD3光盘中的CRACK才行。方法同上。搞定。 CATIAV培训教程全文共36页,当前为第3页。 培训补充 安装软件要点: 1、解压后,先安装CD1中的软件,点击"setup",安装到61%后停止,提示切换CD2,点击任务管理器,强行退出; 2、安装CD2中的软件,点击"setup",直至安装结束,到此时CATIA程序已经安装完毕,最后提示不要启动中的" "可以择。 3、打开CD1中的CRACK中的解密文件,然后找到安装目录下的相同文件,打开用以替代即可解密。 4、打开CD3中的CRACK中的解密文件,然后找到安装目录下的相同文件,打开用以替代即可打补丁。 注意:第一个安装目录可择D盘,第二个及CD2中的安装盘符就不用择,一切默认即可。 保存文件提示: 1、保存—择路径—输入文件名—择保存格式,一般另存可igs、model、stp,Stp用于高低版本转换,前两者常用于面保存。 2、左键物体后,按键盘上的delete键客删除图形。 CATIAV培训教程全文共36页,当前为第4页。 1 用户界面介绍 1).菜单区、工具条区、目录树区、命令操作提示区、命令输入区(按着Ctrl键,滚动鼠标中建,就可以对目录树文字大小进行更改) 菜单区 目录树区 命令输入区 工具条区 命令操作提示区 罗盘 CATIAV培训教程全文共36页,当前为第5页。 2 各种工作台的进入方式 a 菜单区中文件菜单中择新建 b 菜单区中开始菜单中择 c 快捷菜单中直接 3 鼠标使用技巧 a 物体 左键(单击) b 移动物体 中键(按住) c 旋转物体 中键+左键或右键(按住)(可使用罗盘顶点旋转) d 缩放物体 中键+左键或右键(单击)上下移动 e 调整物体(或旋转)中心 中键(单击) 4 罗盘(或指南针)的使用技巧 a 自由旋转 移动顶端圆点 b 平移 抓住任一条线移动 c 旋转 抓住任一平面上的弧线转动 d 平面移动 抓住任一平面移动 CATIAV培训教程全文共36页,当前为第6页。 e 单一物体移动 放置其在物体上,移动 5 快捷菜单的制作和使用 在工具下的定制/自定义对话框内制作常用模块的快捷菜单条 6、 新建文件时的注意事项 输入零部件名称下边有3个择项,注意用第二项(创建几何图形集),不要择其他项。 7、制作圆角时无对话框或者无栅格出现? 在菜单区点击右键,打开草图工具条即可。 8、CATIA软件打开很慢,看是否正在打开,可右键点击任务栏中的任务管理器,看是否CNEXT.exe正在运行。 9、双击命令为多次重复操作,单击命令按钮只操作一次。 CATIAV培训教程全文共36页,当前为第7页。 Sketcher 草图绘制器 CATIA V5 培训教程 CATIAV培训教程全文共36页,当前为第8页。 一 草图 概述 1)草图模块的进入方式 a) 开始菜单中机械设计中的草图绘制器 b) 使用图标按钮 注意:进入草图绘制模块之前必须择草绘平面 2)主要工具条简介 分四类 轮廓 、操作 、约束、草图工具 3)双击按钮时多重操作,单击时只操作一次 。 CATIAV培训教程全文共36页,当前为第9页。 二 主要工具按钮功能介绍 A. 轮廓工具条,共八类工具 1. 点的创建 点击位置创建点 利用坐标值创建点 曲线上创建等距离点 创建曲线相交点 创建投影点 CATIAV培训教程全文共36页,当前为第10页。 2. 线的创建 两点间创建线 无穷线 绘图工具条 角平分线 公切线 垂线 CATIAV培训教程全文共36页,当前为第11页。 3 圆锥曲线创建 1 3 2 4 3 2 1 1 2 3 4 5 1 2 3 4 5 抛物线 椭圆 双曲线

8,305

社区成员

发帖
与我相关
我的任务
社区描述
游戏开发相关内容讨论专区
社区管理员
  • 游戏开发
  • 呆呆敲代码的小Y
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧