3D质心点相交

3D Barycentric point Intersection

本文关键字:3D      更新时间:2023-10-16

我首先要说,是的,我在这个问题上已经找了几个月了,甚至不是几天或几个小时。我喜欢正面解决问题,但是今天我完全被卡住了。

我正在尝试确定一个点是否在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轴,这样我就可以肯定地知道这个点在三角形的所有轴的边界内。

这是我正在制作的引擎的截图,我试图解释的确切情况。

https://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类(也就是"chunk"):

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;
};

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

好了,不管是什么原因,我之前的方法是不正确的,所以我寻找如何找到质心坐标的数学定义,这涉及到向量长度和叉乘。虽然平方根很慢,但它有效,我将在未来调整这个函数的工作方式,并尝试以我最好的能力清理和优化它,但这就是我如何解决这个问题。

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;
}

证明/测试结果:https://i.stack.imgur.com/42pcJ.jpg

相关文章:
  • 没有找到相关文章