在四叉树高度变形的地形上查找鼠标世界坐标(3D)

时间:2012-12-19 22:43:44

标签: c++ directx logic terrain quadtree

我试图在世界坐标中找到鼠标位置,但却无法找到正确的代码。目前我使用它来确定光线:

float pointX, pointY;
D3DXMATRIX projectionMatrix, viewMatrix, inverseViewMatrix, worldMatrix, translateMatrix, inverseWorldMatrix;
D3DXVECTOR3 direction, origin, rayOrigin, rayDirection;
bool intersect, result;


// Move the mouse cursor coordinates into the -1 to +1 range.
pointX = ((2.0f * (float)mouseX) / (float)m_screenWidth) - 1.0f;
pointY = (((2.0f * (float)mouseY) / (float)m_screenHeight) - 1.0f) * -1.0f;

// Adjust the points using the projection matrix to account for the aspect ratio of the viewport.
m_Direct3D->GetProjectionMatrix(projectionMatrix);
pointX = pointX / projectionMatrix._11;
pointY = pointY / projectionMatrix._22;

// Get the inverse of the view matrix.
m_Camera->GetViewMatrix(viewMatrix);
D3DXMatrixInverse(&inverseViewMatrix, NULL, &viewMatrix);

// Calculate the direction of the picking ray in view space.
direction.x = (pointX * inverseViewMatrix._11) + (pointY * inverseViewMatrix._21) + inverseViewMatrix._31;
direction.y = (pointX * inverseViewMatrix._12) + (pointY * inverseViewMatrix._22) + inverseViewMatrix._32;
direction.z = (pointX * inverseViewMatrix._13) + (pointY * inverseViewMatrix._23) + inverseViewMatrix._33;

// Get the origin of the picking ray which is the position of the camera.
origin = m_Camera->GetPosition();

这给了我射线的起源和方向。

但是...

我使用自定义网格(不是来自directX的网格)和高度图,分成四叉树,我不知道我的逻辑是否正确,我尝试使用视锥体来确定四叉树中的哪些节点是可见的那么只在这些节点上检查三角形的交叉点,这里是这段代码:

注意* m_mousepos是一个向量。

bool QuadTreeClass::getTriangleRay(NodeType* node, FrustumClass* frustum, ID3D10Device* device, D3DXVECTOR3 vPickRayDir, D3DXVECTOR3 vPickRayOrig){


    bool result;
    int count, i, j, indexCount;
    unsigned int stride, offset;
    float fBary1, fBary2;
    float fDist;
    D3DXVECTOR3 v0, v1, v2;
    float p1, p2, p3;


    // Check to see if the node can be viewed.
    result = frustum->CheckCube(node->positionX, 0.0f, node->positionZ, (node->width / 2.0f));

    if(!result)
    {
        return false;
    }




    // If it can be seen then check all four child nodes to see if they can also be seen.
    count = 0;
    for(i=0; i<4; i++)
    {
        if(node->nodes[i] != 0)
        {
            count++;
            getTriangleRay(node->nodes[i], frustum, device, vPickRayOrig, vPickRayDir);
        }
    }

    // If there were any children nodes then dont continue

    if(count != 0)
    {
        return false;
    }

        // Now intersect each triangle in this node

    j = 0;

    for(i=0; i<node->triangleCount; i++){

        j = i * 3;

        v0 = D3DXVECTOR3( node->vertexArray[j].x, node->vertexArray[j].y, node->vertexArray[j].z);
        j++;
        v1 = D3DXVECTOR3( node->vertexArray[j].x, node->vertexArray[j].y, node->vertexArray[j].z);
        j++;
        v2 = D3DXVECTOR3( node->vertexArray[j].x, node->vertexArray[j].y, node->vertexArray[j].z);

        result = IntersectTriangle( vPickRayOrig, vPickRayDir, v0, v1, v2, &fDist, &fBary1, &fBary2);

        if(result == true){

                        // intersection = true, so get a aproximate center of the triangle on the world

            p1 = (v0.x + v0.x + v0.x)/3;
            p2 = (v0.y + v1.y + v2.y)/3;
            p3 = (v0.z + v1.z + v2.z)/3;

            m_mousepos = D3DXVECTOR3(p1, p2, p3);

            return true;

        }

    }




}

bool QuadTreeClass::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;
}

这个代码好吗?如果是,那么我的问题必须与四叉树相关。

谢谢!

1 个答案:

答案 0 :(得分:2)

迭代所有可见的三角形以找到交叉点非常昂贵。如果您的高度图更精细,额外的费用将会增加。

对于我的身高图,我使用了不同的方法:

我一步一步地搜索从原点开始的clickray的高度。在每个步骤中,当前位置沿着光线移动并针对高度图的高度进行测试(因此您需要高度函数)。如果当前位置低于高度图,则通过另外的迭代再次搜索最后一个间隔,以找到更精细的位置。只要你的高度图在高度值上的步长大小不是太高(否则你可以跳过一个峰值),这就行了。