3D重心点交点

时间:2014-03-10 01:01:35

标签: c++ 3d geometry directx collision

我首先要说的是,是的,我已经找了几天甚至几个小时,但几个月才解决这个问题。我喜欢直接解决我的问题,但今天我完全陷入困境。

我正在尝试确定一个点是否在3D空间的三角形内,并且我有以下代码来尝试检测它。

测试:

bool D3DHandler::IsCollidingWithTerrain(D3DXVECTOR3 pos){
    for (unsigned int i = 1; i < chunk.at(0).GetWidth()-1; i++){
        for (unsigned int ii = 1; ii < chunk.at(0).GetWidth()-1; ii++){
            if (Physics::PolyPointCollision(
                NORMALVERTEX{ chunk.at(0).GetVertex(i, ii).X, chunk.at(0).GetVertex(i, ii).Y, chunk.at(0).GetVertex(i, ii).Z, { 0, 0, 0 } },
                NORMALVERTEX{ chunk.at(0).GetVertex(i + 1, ii).X, chunk.at(0).GetVertex(i + 1, ii).Y, chunk.at(0).GetVertex(i + 1, ii).Z, { 0, 0, 0 } },
                NORMALVERTEX{ chunk.at(0).GetVertex(i, ii + 1).X, chunk.at(0).GetVertex(i, ii + 1).Y, chunk.at(0).GetVertex(i, ii + 1).Z, { 0, 0, 0 } },
                NORMALVERTEX{ pos.x, pos.y, pos.z, { 0, 0, 0 } })
                ||
                Physics::PolyPointCollision(
                NORMALVERTEX{ chunk.at(0).GetVertex(i, ii).X, chunk.at(0).GetVertex(i, ii).Y, chunk.at(0).GetVertex(i, ii).Z, { 0, 0, 0 } },
                NORMALVERTEX{ chunk.at(0).GetVertex(i - 1, ii).X, chunk.at(0).GetVertex(i - 1, ii).Y, chunk.at(0).GetVertex(i - 1, ii).Z, { 0, 0, 0 } },
                NORMALVERTEX{ chunk.at(0).GetVertex(i, ii - 1).X, chunk.at(0).GetVertex(i, ii - 1).Y, chunk.at(0).GetVertex(i, ii - 1).Z, { 0, 0, 0 } },
                NORMALVERTEX{ pos.x, pos.y, pos.z, { 0, 0, 0 } })){
                return true;
            }
        }
    }
    return false;
}

有问题的功能:

bool Physics::PolyPointCollision(NORMALVERTEX a, NORMALVERTEX b, NORMALVERTEX c, NORMALVERTEX p){
    NORMALVERTEX v0 =  { c.X - a.X, c.Y - a.Y, c.Z - a.Z, { 0, 0, 0 } };
    NORMALVERTEX v1 =  { b.X - a.X, b.Y - a.Y, b.Z - a.Z, { 0, 0, 0 } };
    NORMALVERTEX v2 =  { p.X - a.X, p.Y - a.Y, p.Z - a.Z, { 0, 0, 0 } };
    float dot00 = (v0.X*v0.X) + (v0.Y*v0.Y) + (v0.Z * v0.Z);
    float dot01 = (v0.X*v1.X) + (v0.Y*v1.Y) + (v0.Z * v1.Z);
    float dot02 = (v0.X*v2.X) + (v0.Y*v2.Y) + (v0.Z * v2.Z);
    float dot11 = (v1.X*v1.X) + (v1.Y*v1.Y) + (v1.Z * v1.Z);
    float dot12 = (v1.X*v2.X) + (v1.Y*v2.Y) + (v1.Z * v2.Z);
    float invDenom = 1 / ((dot00*dot11) - (dot01*dot01));
    float u = ((dot11*dot02) - (dot01*dot12))*invDenom;
    float v = ((dot00*dot12) - (dot01*dot02))*invDenom;
    if (u >= 0 && v >= 0 && (v + u)<1){
        return true;
    }
    return false;
}

我在这里做的是转换网格中的3个点以将地形转换为三角形,然后将其发送到函数以将其转换为测试以确定点是否在使用重心的三角形内坐标。但是,它在某种程度上起作用,就好像我进入三角形的X-Z平面一样,测试将返回true,但是它不会沿Y轴检测到任何东西。我的问题是如何让我的函数检测Z轴,所以我确定该点在所有轴的三角形范围内。

以下是我正在尝试解释的确切情况的引擎截图。

http://i.stack.imgur.com/kfqnL.png

编辑:

D3DHandler.h课程:

class D3DHandler{
public:
    D3DHandler(HWND hWnd,int WINX,int WINY,HINSTANCE hInstance,
                   HINSTANCE hPrevInstance,
                   LPSTR lpCmdLine,
                   int nCmdShow);
    ~D3DHandler();
    bool IsCollidingWithTerrain(D3DXVECTOR3 pos);
    bool DeviceCheck();
    void UnlockBuffer();
    void LockBuffer();
    void print2DPixel(int x,int y,int r,int g,int b);
    void print2DPixel(int x,int y,D3DCOLOR c);
    void printVertexArray(NORMALVERTEX *vertex,int length);
    void printIndexArray(NORMALVERTEX *vertex,short *indicies,int vLength,int iLength);
    void printVertexArrayWireframe(NORMALVERTEX *vertex,int length);
    void printIndexArrayWireframe(NORMALVERTEX *vertex,short *indicies,int vLength,int iLength);
    void PrepareFrame(Player p);
    void SetupLight();
    void AddObjectToRoom(NORMALVERTEX* model,int mLength,short *modelIndices,int iLength,D3DXCOLOR dCol,D3DXCOLOR aCol);
    void AddObjectToRoom(TEXVERTEX* model,int mLength,short *modelIndices,int iLength,D3DXCOLOR dCol,D3DXCOLOR aCol,int texId);
    void AddObjectToRoom(float xPos,float yPos,float zPos,wchar_t meshName);
    boolean CheckRoom();
    void RenderRoom();
    void RenderTerrain();
    void ClearBuffer();
    void SetRenders();
    void LoadRoom();
    void PresentParams();
    void NewFont(LPCTSTR faceName,int size,int thickness, bool italic);
    IDirect3DDevice9* GetDevice();
    LPDIRECT3DTEXTURE9 grabTexture(int index);
    void PresentFrame();
    D3DMesh* GrabMesh(wchar_t meshName);
    void RenderFont(int fontId,char* text,int x,int y,D3DCOLOR colour,LPD3DXSPRITE sprite,DWORD alignment);
    void ResetDevice(HWND hWnd);
    void RebootDevice(HWND hWnd);
    bool isActive;
private:
    D3DVIEWPORT9        viewPort;
    D3DPRESENT_PARAMETERS d3dpp;
    D3DRoom *room;
    D3DXMATRIX matRotateX,matRotateY,matRotateZ,matTranslate,matScale,matView,matProjection;
    D3DLIGHT9 light;
    D3DMATERIAL9 material;
    IDirect3D9*         pDirect3D;
    IDirect3DDevice9*   pDevice;
    IDirect3DSurface9*  pBackBuffer;
    D3DLOCKED_RECT      backRect;
    LPDIRECT3DVERTEXBUFFER9 vBuffer;
    LPDIRECT3DINDEXBUFFER9 iBuffer;
    HWND                            hWind;
    std::vector<D3DTerrain>         chunk;
    std::vector<D3DFont>            font;
    std::vector<LPDIRECT3DTEXTURE9> texture;
    std::vector<D3DMesh>            mesh;
    int WINX,WINY;

    HINSTANCE hInst;
    HINSTANCE hPrev;
    LPSTR lpCmdLne;
    int nCmdShw;
};

D3DTerrain类(它是“块”):

class D3DTerrain{
public:
    D3DTerrain(float xPos,float yPos,float zPos);
    ~D3DTerrain();
    void Render(LPDIRECT3DDEVICE9 pDevice);
    void Load(LPDIRECT3DDEVICE9 pDevice);
    void Load(LPDIRECT3DDEVICE9 PDevice,char* fName,wchar_t* tName);
    void Release(){vBuffer->Release();iBuffer->Release();m_texture->Release();m_textureDetail->Release();m_vertecies=NULL;m_indices=NULL;m_height=NULL;}
    TEX2VERTEX GetVertex(unsigned int x,unsigned int y){return m_vertex[x*(int)m_width+y];}
    UINT GetWidth(){return m_width;}
private:
    IDirect3DVertexBuffer9  *vBuffer;
    IDirect3DIndexBuffer9   *iBuffer;
    TEX2VERTEX              *m_vertex;
    UCHAR*                  m_height;
    UINT                    m_vertecies;
    UINT                    m_indices;
    UINT                    m_width;
    char                    m_fileLoc[128];
    wchar_t                 m_textureName[128];
    LPDIRECT3DTEXTURE9      m_texture,m_textureDetail;
    D3DXMATRIX m_rotX,m_rotY,m_rotZ,m_translate,m_scale,m_textureCords; 
};

顶点类型:

struct NORMALVERTEX{
    FLOAT X, Y, Z;
    D3DVECTOR NORMAL;
};
struct T_NORMALVERTEX{
    FLOAT X, Y, Z;
    D3DVECTOR NORMAL;
    FLOAT U, V;
};
struct TEXVERTEX{
    FLOAT X, Y, Z;
    FLOAT U, V;
};
struct TEX2VERTEX{
    FLOAT X, Y, Z;
    FLOAT U1, U2, V1, V2;
};

我不是在这里批评我的编程,它很乱,因为我只是试图让一个主要的功能工作,然后我将优化和重新组织我的代码,这是一个个人项目,我知道它是粗糙的

1 个答案:

答案 0 :(得分:1)

好吧,所以无论我接触的前一种方式是不正确的,所以我寻找了如何找到重心坐标的数学定义,其中涉及矢量长度和交叉积。虽然平方生根很慢,但是它有效,我将调整此函数在未来的工作方式并尝试清理和优化它以达到我的最佳能力,但这就是我解决这个问题的方法。

UtilityFunctions.h

#include "DataTypes.h"
namespace Util{
    float map(float in, float minA, float maxA, float minB, float maxB);
    float dot(float ax, float ay, float az, float bx, float by, float bz);
    float dot(Point3D a, Point3D b);
    float length(Point3D p);
    Point3D sub(Point3D a, Point3D b);
    Point3D toBarycentric(Point3D a, Point3D b, Point3D c, Point3D p);
    Point3D cross(Point3D a, Point3D b);
};

UtilityFunctions.cpp

#include <vector>
#include <stdio.h>
#include <math.h>
#include "UtilityFunctions.h"

float Util::map(float in, float minA, float maxA, float minB, float maxB){
    float ratio = 0.0f;
    if (abs(maxA - minA)>0){
        ratio = (maxB - minB) / (maxA - minA);
    }
    return (in - minA)*ratio + minB;
}

float Util::dot(float ax, float ay, float az, float bx, float by, float bz){ return (ax*bx) + (ay*by) + (az*bz); }
float Util::dot(Point3D a, Point3D b){ return (a.X*b.X) + (a.Y*b.Y) + (a.Z*b.Z); }
float Util::length(Point3D p){
    return ((p.X*p.X) + (p.Y*p.Y) + (p.Z*p.Z));
}
Point3D Util::cross(Point3D a, Point3D b){
    return{ ((a.Y*b.Z) - (a.Z*b.Y)), ((a.X*b.Z) - (a.Z*b.X)), ((a.X*b.Y) - (a.Y*b.X)) };
}
Point3D Util::sub(Point3D a, Point3D b){
    return{ a.X - b.X, a.Y - b.Y, a.Z - b.Z };
}
Point3D Util::toBarycentric(Point3D a, Point3D b, Point3D c, Point3D p){
    Point3D v0 = sub(c, a);
    Point3D v1 = sub(b, a);
    Point3D v2 = sub(p, a);

    Point3D v12 = cross(v1, v2);
    Point3D v10 = cross(v1, v0);

    if (dot(v12, v10) < 0){ return{ 0, 0, -1 }; }

    Point3D v02 = cross(v0, v2);
    Point3D v01 = cross(v0, v1);

    if (dot(v02, v01) < 0){ return{ 0, 0, -1 }; }

    float denom = length(v01);
    return{ length(v12) / denom, length(v02) / denom, 0 };
}

PhysicsFunctions.cpp

#include "PhysicsHandler.h"
bool Physics::PolyPointCollision(Point3D a,Point3D b,Point3D c,Point3D p){
    Point3D w = Util::toBarycentric(a, b, c, p);
    if (w.X+w.Y<=1&&w.Z>=0){
        return true;
    }
    return false;
}

最顶层的功能:

bool D3DHandler::IsCollidingWithTerrain(D3DXVECTOR3 pos){
    Point3D pointPos = { pos.x, pos.y, pos.z };
    for (unsigned int i = 1; i < chunk.at(0).GetWidth() - 1; i++){
        for (unsigned int ii = 1; ii < chunk.at(0).GetWidth() - 1; ii++){
            Point3D originVertex = chunk.at(0).GetVertex(i, ii);
            if (Physics::PolyPointCollision(originVertex,chunk.at(0).GetVertex(i + 1, ii),
                chunk.at(0).GetVertex(i, ii + 1),pointPos)){
                return true;
            }
            if (Physics::PolyPointCollision(originVertex,chunk.at(0).GetVertex(i - 1, ii),
                chunk.at(0).GetVertex(i, ii - 1),pointPos)){
                return true;
            }
        }
    }
    return false;
}

证明/测试结果: http://imgur.com/a/HH2pp