【发布时间】:2015-02-16 11:49:39
【问题描述】:
我首先要说的是,是的,我甚至没有寻找几天或几个小时,而是几个月来解决这个问题。我喜欢直面问题,但今天我完全陷入困境。
我正在尝试确定一个点是否在 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;
};
我不是来批评我的编程的,这很混乱,因为我只是想让一个主要功能正常工作,然后我会优化和重组我的代码,这是一个个人项目,我知道这很粗糙.
【问题讨论】:
-
哦,你的代码太混乱了!这是一种面向复制粘贴的编程。这两个功能都是一团糟!切换到面向对象:引入某种数学对象和函数,例如
Vector3f、dot()和toBarycentric(),以提高可读性并使其不易出错。我敢肯定,您会立即在调试器中发现错误。检查DRY原理。 -
在 3D 三角形测试中或上的 3D 点的纯算法适应将容易受到精度限制。您需要使用公差/epsilon 值伪造点或平面的“厚度”。 Dan Sunday 有一个带有 algorithms 的站点,用于确定重心坐标中的点。
-
如果该点在三角形的平面内(或至少几乎在平面内),您需要添加一个测试。否则,您将无法获得有效的重心坐标。这可以通过计算点到平面的距离来完成。
-
Drop:我是 100% 从头开始写的,没有语法或语义错误,这是我算法的问题。我不知道 toBarycentric() 和 dot() 函数,谢谢你给我看。 :)。 BrettHale:我想我不明白你的意思,而且我以前访问过那个网站,它让我很困惑,就像现在一样,你能扩展一下,我会喜欢它,谢谢。 @NicoSchertler 我该如何计算点的距离?我之前已经看到过这个,但是在查找数学时它变得非常混乱。全部:我将添加更多代码以减少您看到的任何混淆。
-
@Drop 抱歉,我浏览了您的评论,重新阅读后我明白您的意思。我还没有实现任何东西来清理诸如数学函数之类的代码,因为我只是想在清理它之前让功能正常工作。调试器显然不会显示任何内容,因为返回输出到我的屏幕上。我之前也调试过它,无论我是否与空间发生碰撞,它都会返回 true,但是如果在 X-Z 平面上我没有发生碰撞,它会发出通知。另外,我不会在第一个函数上重复自己,因为一个检查 + 点,另一个检查 - 点。
标签: c++ 3d geometry directx collision