游戏开发论坛

 找回密码
 立即注册
搜索
查看: 5486|回复: 21

关于投影和确定光标所在点的问题

[复制链接]

20

主题

465

帖子

472

积分

中级会员

Rank: 3Rank: 3

积分
472
QQ
发表于 2006-10-17 20:48:00 | 显示全部楼层 |阅读模式
是这样的,我在写一个3D战棋类的游戏,使用DX9,我已经做好地图部份。地图是一个有起伏的N X M平面块的组合,反正一般的战棋类游戏都是这样。类似的游戏有《天使之谷》、《出云战记》之类的。
我有一个问题没有解决:我怎么知道我现在鼠标指向的是哪个地形块呢?我使用的镜头是45度的俯视角,当然,这个角度和方向都是可以改变的(就像魔兽一样),我怎么才能计算出现在鼠标在屏幕上的位置指向的是哪个地形块?
这个问题应该是个很普遍的问题,我相信也应该有很多现成的解决手段,小弟才疏学浅,希望哪位懂的人可以告知一下解决方法,或者是在哪能找到这个问题的答案,谢谢。

附件中是一个演示程序,WSAD或方向键控制镜头方向,Q和E可以旋转镜头。

sf_20061017204740.rar

333.35 KB, 下载次数:

20

主题

465

帖子

472

积分

中级会员

Rank: 3Rank: 3

积分
472
QQ
 楼主| 发表于 2006-10-17 21:02:00 | 显示全部楼层

Re:关于投影和确定光标所在点的问题

不好意思,情急之下说错了一点,演示程序里面WSAD或方向键是控制镜头位置的,鼠标控制方向。

3

主题

121

帖子

121

积分

注册会员

Rank: 2

积分
121
QQ
发表于 2006-10-17 21:41:00 | 显示全部楼层

Re:关于投影和确定光标所在点的问题

这个函数我还没有验证过.

DWORD CheckMouseHitFace()
{
D3DXVECTOR3 VecPos, VecDir;
D3DXVECTOR3 v;
D3DXMATRIX matProj, matView;
D3DXMATRIX matTemp;

g_pd3dDevice->GetTransform( D3DTS_PROJECTION, &matProj );
g_pd3dDevice->GetTransform( D3DTS_VIEW, &matView );

D3DXMatrixInverse( &matTemp, NULL, &matView );

// 为得到你的鼠标的输入.
Mouse.Input();

v.x = (((2.0f *Mouse.GetXPos()) / Graphics.GetWidth()) - 1) / matProj._11;
v.y = -(((2.0f *Mouse.GetYPos()) / Graphics.GetHeight()) - 1) / matProj._22;
v.z = 1.0f;

VecPos.x = matTemp._41;
VecPos.y = matTemp._42;
VecPos.z = matTemp._43;
VecDir.x = v.x * matTemp._11 + v.y * matTemp._21 + v.z * matTemp._31;
VecDir.y = v.x * matTemp._12 + v.y * matTemp._22 + v.z * matTemp._32;
VecDir.z = v.x * matTemp._13 + v.y * matTemp._23 + v.z * matTemp._33;

ID3DXMesh *pMesh;
BOOL Hit;
DWORD FaceIndex;
float u,v,Dist;

// m_pMesh你所加载的地形
pMesh = m_pMesh;
ID3DXIntersect( pMesh, &VecPos, &VecDir, &Hit, &FaceIndex, &u, &v, &Dist, NULL, NULL );

if( Hit )
return FaceIndex;
return 0L;
}

20

主题

465

帖子

472

积分

中级会员

Rank: 3Rank: 3

积分
472
QQ
 楼主| 发表于 2006-10-17 23:58:00 | 显示全部楼层

Re:关于投影和确定光标所在点的问题

谢谢,大体明白一点了。
ID3DXIntersect 应该是用来确定点击到了整个渲染序列的哪个表面吧?
我没有用Mesh对象,是自己根据地形制作一个vertex buffer,使用(LPDIRECT3DVERTEXBUFFER9和顶点索引LPDIRECT3DINDEXBUFFER9结构来渲染的),这两者之间有法转换吗?
有没有不依靠DX,用自己的算法来确定的方法呢?

29

主题

224

帖子

224

积分

中级会员

Rank: 3Rank: 3

积分
224
QQ
发表于 2006-10-18 02:43:00 | 显示全部楼层

Re:关于投影和确定光标所在点的问题

如果可以仔细学习一下投影变换的过程,应该就可以做出来了。
我这个比较乱,希望你能看懂,不过好象不是太精确,不知道问题在哪。
http://bbs.gameres.com/upload/sf_200697152953.rar

3

主题

121

帖子

121

积分

注册会员

Rank: 2

积分
121
QQ
发表于 2006-10-18 10:07:00 | 显示全部楼层

Re:关于投影和确定光标所在点的问题

如果不用DX,用vertex buffer也就是多边形与向量的相交问题.

3

主题

121

帖子

121

积分

注册会员

Rank: 2

积分
121
QQ
发表于 2006-10-18 10:10:00 | 显示全部楼层

Re:关于投影和确定光标所在点的问题

ID3DXIntersect也是处理这个问题,只不过它是以Mesh为对象.

20

主题

465

帖子

472

积分

中级会员

Rank: 3Rank: 3

积分
472
QQ
 楼主| 发表于 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;
}

20

主题

465

帖子

472

积分

中级会员

Rank: 3Rank: 3

积分
472
QQ
 楼主| 发表于 2006-10-18 12:58:00 | 显示全部楼层

Re: Re:关于投影和确定光标所在点的问题

踏魔狼: Re:关于投影和确定光标所在点的问题

如果不用DX,用vertex buffer也就是多边形与向量的相交问题.


也就是历遍所有的多边形了,性能上会有什么问题吗?
知道了镜头变换矩阵和屏幕坐标,能反向得到什么信息啊?

关于多边形和向量相交有固定的方法,但是我用什么方法知道x, y坐标表示的向量呢?

20

主题

465

帖子

472

积分

中级会员

Rank: 3Rank: 3

积分
472
QQ
 楼主| 发表于 2006-10-18 14:15:00 | 显示全部楼层

Re:关于投影和确定光标所在点的问题

ID3DXIntersect 这个函数我怎么在帮助文档中找不到?
我用的是DX9,在DX9里面还没有这个函数吗?
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2026-1-25 15:28

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表