|
|

楼主 |
发表于 2006-10-18 12:54:00
|
显示全部楼层
Re:关于投影和确定光标所在点的问题
fy_pig,主要就是下面这几个函数吧,看得还不是很懂。
///////////////////////////////////////////////
// name: GetCrossObj(
// int x, // 屏幕x坐标
// int y // 屏幕y坐标
// )
// return:
// desc: 相交的物体
///////////////////////////////////////////////
HRESULT GetCrossObj( int x, int y, BOOL clsSelect )
{
D3DVECTOR passPoint;
D3DMATRIX useMat;
D3DMATRIX tmpMat;
float xScale = (float)0;
float yScale = (float)0;
static RELATIVE_OBJECT* crossObj = NULL;
long triangleIndex = 0;
// char tmpStr[255];
strcpy( displayStr, "" );
if( clsSelect )
{
if( NULL != crossObj )
{
crossObj->isSelected = FALSE;
return S_OK;
}
}
if( NULL != crossObj )
{
crossObj->isSelected = FALSE;
crossObj = NULL;
}
/*
strcat( displayStr, "x=" );
_gcvt( (float)x, 3, tmpStr );
strcat( displayStr, tmpStr );
strcat( displayStr, " " );
strcat( displayStr, "y=" );
_gcvt( (float)y, 3, tmpStr );
strcat( displayStr, tmpStr );
strcat( displayStr, " " );
*/
D3DVIEWPORT7 vp;
HRESULT hRet;
if( NULL == pd3dDevice) return E_FAIL;
hRet = pd3dDevice->GetViewport( &vp );
if( FAILED(hRet) )
return MsgboxErr( hRet, "pd3dDevice SetViewport" );
pd3dDevice->GetTransform( D3DTRANSFORMSTATE_PROJECTION, &tmpMat );
float nearFace = -(tmpMat._43/tmpMat._33);
float relHalfWidth = (nearFace/tmpMat._11);
float relHalfHeight = (nearFace/tmpMat._22);
xScale = (float)2*relHalfWidth/(float)vp.dwWidth;
yScale = (float)2*relHalfHeight/(float)vp.dwHeight;
float relX = (float)x * xScale;
relX = relX - relHalfWidth;
float relY = (float)y * yScale;
relY = relHalfHeight - relY;
CalculateTransMatrix( useMat, tmpMat, userCamera.cameraPoint,
userCamera.transCoordinate.vZ, userCamera.eyeUp );
passPoint = D3DVECTOR( relX, relY, nearFace );//0.0f );//
D3DVECTOR startPoint = D3DVECTOR( 0.0f, 0.0f, -0.15f );
passPoint = passPoint * useMat;
startPoint = startPoint * useMat;
/*
_gcvt( (float)startPoint.x, 3, tmpStr );
strcat( displayStr, tmpStr );
strcat( displayStr, " " );
_gcvt( (float)startPoint.y, 3, tmpStr );
strcat( displayStr, tmpStr );
strcat( displayStr, " " );
_gcvt( (float)startPoint.z, 3, tmpStr );
strcat( displayStr, tmpStr );
strcat( displayStr, " " );
//将浮点数的有效位转换为字符串指针
_gcvt( (float)passPoint.x, 3, tmpStr );
strcat( displayStr, tmpStr );
strcat( displayStr, " " );
_gcvt( (float)passPoint.y, 3, tmpStr );
strcat( displayStr, tmpStr );
strcat( displayStr, " " );
_gcvt( (float)passPoint.z, 3, tmpStr );
strcat( displayStr, tmpStr );
*/
// WhichObject( crossObj, triangleIndex,
// startPoint, passPoint );//userCamera.cameraPoint
WhichObject( &crossObj, triangleIndex,
userCamera.cameraPoint, passPoint );
return S_OK;
}
///////////////////////////////////////////////
// name: WhichObject(
// RELATIVE_OBJECT* objPoint, // 相交的物体指针
// long& triangleIndex, // 相交的三角形索引号
// D3DVECTOR startPoint, // 射线起点
// D3DVECTOR passPoint, // 射线经过点
// )
// return: HRESULT 绘制是否成功
// desc: 返回和一条由起点和经过点定义的射线相交的物体,
// 及相交的三角形索引号
///////////////////////////////////////////////
HRESULT WhichObject( RELATIVE_OBJECT** objPoint,
long& triangleIndex, D3DVECTOR startPoint,
D3DVECTOR passPoint )
{
RELATIVE_OBJECT* currentObj = firstObject;
LPDIRECT3DVERTEXBUFFER7 lastVB = NULL;
D3DVECTOR* allPoint = NULL;
D3DVECTOR endPoint;
endPoint = startPoint + 20.0f*Normalize(passPoint - startPoint);
eyeLine[0] = D3DVERTEX(
endPoint,D3DVECTOR(0,1,0),0,0);
eyeLine[1] = D3DVERTEX(
D3DVECTOR(passPoint.x, passPoint.y, passPoint.z),
D3DVECTOR(0,1,0),0,0);
D3DVERTEXBUFFERDESC vbDesc;
int i = 0;
// char tmpStr[256];
D3DVECTOR chaStartPoint;// 将视线变换到物体的坐标内
D3DVECTOR chaPassPoint;// 将视线变换到物体的坐标内
D3DVECTOR chaNormal;
D3DVALUE lastCrossPoint = 65536.0f ;
D3DVALUE crossLong = 65536.0f ;
while( NULL != currentObj )
{
currentObj->isSelected = FALSE;
if( lastVB != (*currentObj->allVertices) )
{
(*currentObj->allVertices)->GetVertexBufferDesc( &vbDesc );
if( NULL != allPoint )
{
delete []allPoint;
allPoint = NULL;
}
allPoint = new D3DVECTOR[vbDesc.dwNumVertices];
GetAllPointPos( (*currentObj->allVertices), allPoint );
lastVB = (*currentObj->allVertices);
}
// 将视线变换到物体的绘制坐标,这样顶点就不用进行转换
chaStartPoint = startPoint *
currentObj->drawCoordinate.matSelfToWorld;
chaPassPoint = passPoint *
currentObj->drawCoordinate.matSelfToWorld;
chaNormal = Normalize( chaPassPoint - chaStartPoint );
/* _DbgOut( currentObj->objName, 0, S_OK, "++++++++++" );
_gcvt( (float)chaNormal.x, 5, tmpStr);
_DbgOut( "chaNormal.x ", 0, S_OK, tmpStr );
_gcvt( (float)chaNormal.y, 5, tmpStr);
_DbgOut( "chaNormal.y ", 0, S_OK, tmpStr );
_gcvt( (float)chaNormal.z, 5, tmpStr);
_DbgOut( "chaNormal.z ", 0, S_OK, tmpStr );
*/
D3DVECTOR triNormal;
for( i=0; i<currentObj->trianglesNum; ++i )
{
int pn0 = (*currentObj->allTriangles).point0;
int pn1 = (*currentObj->allTriangles).point1;
int pn2 = (*currentObj->allTriangles).point2;
TriangleNormal( triNormal, PR_CW,
allPoint[pn0], allPoint[pn1], allPoint[pn2] );
D3DVALUE cosTriEye = DotProduct( triNormal, chaNormal );
if( cosTriEye > 0 )
{
// _gcvt( (float)cosTriEye, 5, tmpStr);
// _DbgOut( currentObj->objName, i, S_OK, tmpStr );
continue;
}
D3DVECTOR t;
D3DVECTOR d = - ( triNormal * allPoint[pn0] );
D3DVECTOR u = ( -d - triNormal*chaStartPoint );
D3DVECTOR dow = ( triNormal * chaNormal );
t = u / dow;// 计算交点
/* char disStr[256];
strcpy( disStr, "三角形 交点距离 " );
_gcvt( (float)t.z, 5, tmpStr);
strcat( disStr, tmpStr );
_DbgOut( currentObj->objName, i, S_OK, disStr );
*/
if( t.x > 0 )
{
crossLong = t.x ;
}
if( t.y > 0 )
{
crossLong = t.y ;
}
if( t.z > 0 )
{
crossLong = t.z ;
}
if( crossLong > 0 )
{
D3DVECTOR crossPoint;
// 根据距离增加一个偏移量,修正误差
crossPoint =
chaStartPoint + crossLong * chaNormal;
/* _DbgOut( currentObj->objName, i, S_OK, "三角形" );
_gcvt( (float)crossPoint.x, 5, tmpStr);
_DbgOut( "交点X ", 0, S_OK, tmpStr );
_gcvt( (float)crossPoint.y, 5, tmpStr);
_DbgOut( "交点Y ", 0, S_OK, tmpStr );
_gcvt( (float)crossPoint.z, 5, tmpStr);
strcat( tmpStr, "++++++" );
_DbgOut( "交点Z ", 0, S_OK, tmpStr );
*/
D3DVALUE isInTri;
D3DVALUE isInTri1;
D3DVALUE isInTri2;
D3DVALUE isInTri3;
D3DVECTOR norLine0 = Normalize( allPoint[pn0] - crossPoint );
D3DVECTOR norLine1 = Normalize( allPoint[pn1] - crossPoint );
D3DVECTOR norLine2 = Normalize( allPoint[pn2] - crossPoint );
// 判断是否在三角形内部
isInTri1 = DotProduct( norLine0, norLine1 );
isInTri2 = DotProduct( norLine0, norLine2 );
isInTri3 = DotProduct( norLine1, norLine2 );
isInTri = isInTri1 + isInTri2 + isInTri3;
/* _gcvt( (float)isInTri, 5, tmpStr);
_DbgOut( "交点X ", i, S_OK, tmpStr );
_gcvt( (float)isInTri.y, 5, tmpStr);
_DbgOut( "交点Y ", 0, S_OK, tmpStr );
_gcvt( (float)isInTri.z, 5, tmpStr);
strcat( tmpStr, "++++++" );
_DbgOut( "交点Z ", 0, S_OK, tmpStr );
*/
if( isInTri < -1 )
{
// _DbgOut( currentObj->objName, i, S_OK, "三角形" );
// 将交点变换到世界坐标
crossPoint =
crossPoint * currentObj->drawCoordinate.matWorldToSelf;
if( lastCrossPoint > crossLong )
{
lastCrossPoint = crossLong;
*objPoint = currentObj;
triangleIndex = i;
}
}
}
}
currentObj = currentObj->nextObject;
}
if( NULL != (*objPoint) )
{
(*objPoint)->isSelected = TRUE;
// _DbgOut( objPoint->objName, i, S_OK, "被选中" );
}
if( NULL != allPoint )
{
delete []allPoint;
allPoint = NULL;
}
return S_OK;
}
|
|