1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
|
// Kollision zwischen Box und Octree berechnen (rekursiv)
TRIBASE_API BOOL tbBoxHitsOctreeRec(const tbVector3& vBoxA,
const tbVector3& vBoxB,
tbMatrix mTransformation,
const tbOctree* pOctree,
const tbOctreeNode* pNode,
int* piClosestTriangle,
float* pfClosestCollision,
tbOctreeNode** ppClosestNode,
BOOL bSimpleMode,
BOOL* pbStop)
{
// Prüfen, ob der Quader den Umgebungsquader des Knotens trifft.
// Falls nicht, können wir sofort abbrechen
if(!tbBoxHitsBox(vBoxA, vBoxB, mTransformation,
pNode->vBoundingBoxMin,
pNode->vBoundingBoxMax,
tbMatrixIdentity(), 3))
{
// Abbruch!
return FALSE;
}
// Ist dieser Knoten ein Endknoten? Falls ja, dann testen wir die
// Kollision jetzt auf Dreiecksebene.
if(pNode->bIsLeaf)
{
// Nun jedes Dreieck dieses Knotens durchgehen und
// nach der nächsten Kollisionen suchen
for(DWORD t = 0; t < pNode->dwNumIndices / 3; t++)
{
/*1. Testen, ob die drei Verbindungslinien im Dreieck die Box treffen
2. Testen, ob die Seitenhalbierenden die Box treffen
Wenn beides zutrifft, schneidet das Dreieck die Box. */
if(COLLISION)
{
// Wenn der Benutzer den Ort der Kollision nicht kennen möchte
// (bSimpleMode = TRUE), dann können wir jetzt schon abbrechen.
if(bSimpleMode)
{
*pbStop = TRUE;
return TRUE;
}
}
}
}
else
{
// Dieser Knoten ist kein Endknoten.
// Wir gehen seine Unterknoten durch und testen diese.
for(DWORD i = 0; i < 8; i++)
{
tbBoxHitsOctreeRec(vBoxA, vBoxB, mTransformation, pOctree, pNode->apChild[i],
piClosestTriangle, pfClosestCollision, ppClosestNode,
bSimpleMode, pbStop);
// Wurde die pbStop-Variable auf TRUE gesetzt?
// Falls ja, dann brechen wir ab und liefern TRUE zurück.
if(*pbStop) return TRUE;
}
// Wenn es eine Kollision gab, wird TRUE geliefert.
if(*piClosestTriangle != -1) return TRUE;
}
// Keine Kollision!
return FALSE;
}
// ******************************************************************
// Kollision zwischen Linie und Octree berechnen
TRIBASE_API BOOL tbBoxHitsOctree(const tbVector3& vBoxA,
const tbVector3& vBoxB,
tbMatrix mTransformation,
const tbOctree* pOctree,
const float fTolerance, // = 0.0f
tbVector3* pvOutPos, // = NULL
tbVector3* pvOutNormal, // = NULL
int* piOutTriangle, // = NULL
tbOctreeNode** ppOutNode) // = NULL
{
// Parameter prüfen
if(pOctree == NULL) TB_ERROR_NULL_POINTER("pOctree", TB_ERROR);
if(!pOctree->m_bExtraData) TB_ERROR("Der Octree hat keine Extradaten!", TB_ERROR);
// Startwerte setzen
int iClosestTriangle = -1;
float fClosestCollision = 100000.0f;
BOOL bStop = FALSE;
tbOctreeNode* pNode;
// Rekursive Funktion aufrufen
tbBoxHitsOctreeRec(vBoxA, vBoxB, mTransformation, pOctree, pOctree->m_pRootNode,
&iClosestTriangle, &fClosestCollision, &pNode,
pvOutPos == NULL, &bStop);
// Gab es eine Kollision?
if(iClosestTriangle != -1)
{
// Falls erwünscht: Ort der Kollision berechnen
//if(pvOutPos != NULL) *pvOutPos = vLineA + fClosestCollision * (vLineB - vLineA);
// Normalvektor des getroffenen Dreiecks eintragen
if(pvOutNormal != NULL)
{
// Wir erhalten den Normalvektor aus der Ebenengleichung des getroffenen Dreiecks.
*pvOutNormal = pNode->pTrianglePlanes[iClosestTriangle * 4].n;
}
// Das getroffene Dreieck und den Knoten selbst eintragen
if(piOutTriangle != NULL) *piOutTriangle = iClosestTriangle;
if(ppOutNode != NULL) *ppOutNode = pNode;
return TRUE;
}
// Keine Kollision!
return FALSE;
}
|