高分求教将屏幕坐标转换成D3D世界坐标中的问提!

itbest 2004-10-30 11:44:34
高分求教将屏幕坐标转换成D3D世界坐标中的问提!
D3DXVECTOR3 ScreenTo3D(int iScreenX,int iScreenY,double f3DY)
{
D3DXVECTOR3 vPickRayDir;
D3DXVECTOR3 vPickRayOrig;
D3DXVECTOR3 vOut;
D3DXMATRIX matProj;
g_pD3DDevice->GetTransform( D3DTS_PROJECTION, &matProj );

POINT ptCursor;
ptCursor.x = iScreenX;
ptCursor.y = iScreenY;

// Compute the vector of the pick ray in screen space
D3DXVECTOR3 v;
v.x = ( ( ( 2.0f * ptCursor.x ) / 800 ) - 1 ) / matProj._11;
v.y = -( ( ( 2.0f * ptCursor.y ) / 600 ) - 1 ) / matProj._22;
v.z = 1.0f;

// Get the inverse view matrix
D3DXMATRIX matView, m;
g_pD3DDevice->GetTransform( D3DTS_VIEW, &matView );
D3DXMatrixInverse( &m, NULL, &matView );

// Transform the screen space pick ray into 3D space
vPickRayDir.x = v.x*m._11 + v.y*m._21 + v.z*m._31;
vPickRayDir.y = v.x*m._12 + v.y*m._22 + v.z*m._32;
vPickRayDir.z = v.x*m._13 + v.y*m._23 + v.z*m._33;
vPickRayOrig.x = m._41;
vPickRayOrig.y = m._42;
vPickRayOrig.z = m._43;
vOut.y = f3DY;
vOut.x = (f3DY-vPickRayOrig.y)*vPickRayDir.x/vPickRayDir.y + vPickRayOrig.x ;
vOut.z = (f3DY-vPickRayOrig.y)*vPickRayDir.z/vPickRayDir.y + vPickRayOrig.z;
return vOut;

}


以上中,先求得视点以及射线矢量,然后按照直线的空间方程,求得在Y平面上的X,Z坐标,可是实际中我发现这样求得的结果有较大的误差,比如视线沿X轴时X向误差较大,反之沿Z轴时Z向误差较大,恳请赐教!
...全文
253 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
itbest 2004-10-31
  • 打赏
  • 举报
回复
"D3DXVECTOR3 *WINAPI D3DXVec3Unproject(
D3DXVECTOR3 *pOut,
CONST D3DXVECTOR3 *pV,
CONST D3DVIEWPORT9 *pViewport,
CONST D3DXMATRIX *pProjection,
CONST D3DXMATRIX *pView,
CONST D3DXMATRIX *pWorld
);
一个函数搞定"

鼠标在空间中印射的不是一条射线吗? 哪么此时输入的值PV.z设成多少呢? 如果设成0和1然后再按比较取特定的值,仍然有误差,如下:
D3DXVECTOR3 VBegin,VEnd,VOut,VIn;
D3DVIEWPORT8 ViewPort;
D3DXMATRIX World;
D3DXMATRIX View;
D3DXMATRIX Projection;

VIn.x = (double)iScreenX;
VIn.y = (double)iScreenY;
g_pD3DDevice->GetViewport(&ViewPort);
D3DXMatrixIdentity(&World);
g_pD3DDevice->GetTransform(D3DTS_VIEW,&View);
g_pD3DDevice->GetTransform(D3DTS_PROJECTION,&Projection);
VIn.z = 0.0;
D3DXVec3Unproject(&VBegin,&VIn,&ViewPort,&Projection,&View,&World);
VIn.z = 1;
D3DXVec3Unproject(&VEnd,&VIn,&ViewPort,&Projection,&View,&World);
double fParam = (VBegin.y - f3DY) / (VBegin.y - VEnd.y);
VOut.x = VBegin.x - (VBegin.x - VEnd.x) * fParam;
VOut.y = f3DY;
VOut.z = VBegin.z - (VBegin.z - VEnd.z) * fParam;
return VEnd;*//*
D3DXVECTOR3 vPickRayDir;
D3DXVECTOR3 vPickRayOrig;
D3DXVECTOR3 vOut;
D3DXMATRIX matProj;
g_pD3DDevice->GetTransform( D3DTS_PROJECTION, &matProj );

POINT ptCursor;
ptCursor.x = iScreenX;
ptCursor.y = iScreenY;

// Compute the vector of the pick ray in screen space
D3DXVECTOR3 v;
v.x = ( ( ( 2.0f * ptCursor.x ) / 800 ) - 1 ) / matProj._11;
v.y = -( ( ( 2.0f * ptCursor.y ) / 600 ) - 1 ) / matProj._22;
v.z = 1.0f;

// Get the inverse view matrix
D3DXMATRIX matView, m;
g_pD3DDevice->GetTransform( D3DTS_VIEW, &matView );
D3DXMatrixInverse( &m, NULL, &matView );

// Transform the screen space pick ray into 3D space
vPickRayDir.x = v.x*m._11 + v.y*m._21 + v.z*m._31;
vPickRayDir.y = v.x*m._12 + v.y*m._22 + v.z*m._32;
vPickRayDir.z = v.x*m._13 + v.y*m._23 + v.z*m._33;
vPickRayOrig.x = m._41;
vPickRayOrig.y = m._42;
vPickRayOrig.z = m._43;

///vPickRayOrig+=vPickRayDir*1.0;

vOut.y = f3DY;
vOut.x = (f3DY-vPickRayOrig.y)*vPickRayDir.x/vPickRayDir.y + vPickRayOrig.x ;
vOut.z = (f3DY-vPickRayOrig.y)*vPickRayDir.z/vPickRayDir.y + vPickRayOrig.z;
return vOut;



我是不是用错了,你是怎么用的? 谢
itbest 2004-10-31
  • 打赏
  • 举报
回复
先前的贴错了,
第一种算法:
D3DXVECTOR3 VBegin,VEnd,VOut,VIn;
D3DVIEWPORT8 ViewPort;
D3DXMATRIX World;
D3DXMATRIX View;
D3DXMATRIX Projection;

VIn.x = (double)iScreenX;
VIn.y = (double)iScreenY;
g_pD3DDevice->GetViewport(&ViewPort);
D3DXMatrixIdentity(&World);
g_pD3DDevice->GetTransform(D3DTS_VIEW,&View);
g_pD3DDevice->GetTransform(D3DTS_PROJECTION,&Projection);
VIn.z = 0.0;
D3DXVec3Unproject(&VBegin,&VIn,&ViewPort,&Projection,&View,&World);
VIn.z = 1;
D3DXVec3Unproject(&VEnd,&VIn,&ViewPort,&Projection,&View,&World);
double fParam = (VBegin.y - f3DY) / (VBegin.y - VEnd.y);
VOut.x = VBegin.x - (VBegin.x - VEnd.x) * fParam;
VOut.y = f3DY;
VOut.z = VBegin.z - (VBegin.z - VEnd.z) * fParam;
return VEnd;
算出Z=0,Z=1两种情况的空间点,也就是剪切的最近和最远距离,然后根据Y=f3DY来进行一次剪切,按比例得到x,z

第二种:
D3DXVECTOR3 vPickRayDir;
D3DXVECTOR3 vPickRayOrig;
D3DXVECTOR3 vOut;
D3DXMATRIX matProj;
g_pD3DDevice->GetTransform( D3DTS_PROJECTION, &matProj );

POINT ptCursor;
ptCursor.x = iScreenX;
ptCursor.y = iScreenY;

// Compute the vector of the pick ray in screen space
D3DXVECTOR3 v;
v.x = ( ( ( 2.0f * ptCursor.x ) / 800 ) - 1 ) / matProj._11;
v.y = -( ( ( 2.0f * ptCursor.y ) / 600 ) - 1 ) / matProj._22;
v.z = 1.0f;

// Get the inverse view matrix
D3DXMATRIX matView, m;
g_pD3DDevice->GetTransform( D3DTS_VIEW, &matView );
D3DXMatrixInverse( &m, NULL, &matView );

// Transform the screen space pick ray into 3D space
vPickRayDir.x = v.x*m._11 + v.y*m._21 + v.z*m._31;
vPickRayDir.y = v.x*m._12 + v.y*m._22 + v.z*m._32;
vPickRayDir.z = v.x*m._13 + v.y*m._23 + v.z*m._33;
vPickRayOrig.x = m._41;
vPickRayOrig.y = m._42;
vPickRayOrig.z = m._43;

///vPickRayOrig+=vPickRayDir*1.0;

vOut.y = f3DY;
vOut.x = (f3DY-vPickRayOrig.y)*vPickRayDir.x/vPickRayDir.y + vPickRayOrig.x ;
vOut.z = (f3DY-vPickRayOrig.y)*vPickRayDir.z/vPickRayDir.y + vPickRayOrig.z;
return vOut;

利用屏幕位置点在三维空间中的涉线矢量,以及所经过的一个点(也就是视点),通过直线的空间方程,解得世界坐标


以上两种方法都可以得到结果,但是都不是很精确,又 很类似,只是算出来所得到的原点与真正的原点有有点差距。。。。 奇怪!
houdy 2004-10-31
  • 打赏
  • 举报
回复
我还是喜欢OpenGL,虽然没有Direct3D那么方便,但是可以学东西,很多东西都要自己来写,不像Direct3D都给你做好了。
merlinfang 2004-10-31
  • 打赏
  • 举报
回复
D3DXVECTOR3 *WINAPI D3DXVec3Unproject(
D3DXVECTOR3 *pOut,
CONST D3DXVECTOR3 *pV,
CONST D3DVIEWPORT9 *pViewport,
CONST D3DXMATRIX *pProjection,
CONST D3DXMATRIX *pView,
CONST D3DXMATRIX *pWorld
);
一个函数搞定
merlinfang 2004-10-31
  • 打赏
  • 举报
回复
我怎么都没搞明白你!
0,1一样的,输出的一个空间坐标,然后用眼睛点坐标与其相连就是这条射线了
houdy 2004-10-30
  • 打赏
  • 举报
回复
问题不太明白。。。。
其实渲染是以一个窗口(Window)为基础的,若是全屏的,窗口就是整个屏幕区域。
如果是某个窗口的话,你需要首先将屏幕坐标转化的窗口坐标,然后在转化到3D中的坐标中。
实际上这是个设置viewport的问题,在Opengl中只有一个glViewport()可以使用,Direct3D中到底是怎样没有用过,不台清楚。

8,306

社区成员

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

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