Add merge triangles inside implementation of convex hull.

master
Jeremy Hu 2016-12-31 00:29:54 +09:30
parent 1c305d5ef9
commit 06e584ac1c
3 changed files with 214 additions and 60 deletions

View File

@ -596,6 +596,7 @@ static int bmeshStichFrom(bmesh *bm, bmeshBall *parent, bmeshBall *ball) {
} }
convexHullGenerate(hull); convexHullGenerate(hull);
convexHullUnifyNormals(hull, &ball->position); convexHullUnifyNormals(hull, &ball->position);
convexHullMergeTriangles(hull);
glPushMatrix(); glPushMatrix();
/* /*
@ -619,41 +620,84 @@ static int bmeshStichFrom(bmesh *bm, bmeshBall *parent, bmeshBall *ball) {
} }
}*/ }*/
glColor3f(1.0f, 1.0f, 1.0f);
{ {
int triIndex; int triIndex;
for (triIndex = 0; triIndex < convexHullGetFace3Num(hull); for (triIndex = 0; triIndex < convexHullGetFaceNum(hull);
++triIndex) { ++triIndex) {
convexHullFace *face = (convexHullFace *)convexHullGetFace(hull,
triIndex);
if (3 == face->vertexNum) {
triangle tri; triangle tri;
face3 *face = (face3 *)convexHullGetFace3(hull, triIndex); int j;
tri.pt[0] = *convexHullGetVertex(hull, face->indices[0]); tri.pt[0] = *convexHullGetVertex(hull, face->u.t.indices[0]);
tri.pt[1] = *convexHullGetVertex(hull, face->indices[1]); tri.pt[1] = *convexHullGetVertex(hull, face->u.t.indices[1]);
tri.pt[2] = *convexHullGetVertex(hull, face->indices[2]); tri.pt[2] = *convexHullGetVertex(hull, face->u.t.indices[2]);
if (triIndex >= showFaceIndex) { if (triIndex >= showFaceIndex) {
break; break;
} }
glColor3f(1.0f, 1.0f, 1.0f);
drawTriangle(&tri); drawTriangle(&tri);
}
}
glColor3f(0.0f, 0.0f, 0.0f);
{
int triIndex;
int j;
for (triIndex = 0; triIndex < convexHullGetFace3Num(hull);
++triIndex) {
triangle tri;
face3 *face = (face3 *)convexHullGetFace3(hull, triIndex);
tri.pt[0] = *convexHullGetVertex(hull, face->indices[0]);
tri.pt[1] = *convexHullGetVertex(hull, face->indices[1]);
tri.pt[2] = *convexHullGetVertex(hull, face->indices[2]);
glBegin(GL_LINE_STRIP); glBegin(GL_LINE_STRIP);
for (j = 0; j < 3; ++j) { for (j = 0; j < 3; ++j) {
glVertex3f(tri.pt[j].x, tri.pt[j].y, tri.pt[j].z); glVertex3f(tri.pt[j].x, tri.pt[j].y, tri.pt[j].z);
} }
glVertex3f(tri.pt[0].x, tri.pt[0].y, tri.pt[0].z); glVertex3f(tri.pt[0].x, tri.pt[0].y, tri.pt[0].z);
glEnd(); glEnd();
} else if (4 == face->vertexNum) {
quad q;
vec3 normal;
int j;
q.pt[0] = *convexHullGetVertex(hull, face->u.q.indices[0]);
q.pt[1] = *convexHullGetVertex(hull, face->u.q.indices[1]);
q.pt[2] = *convexHullGetVertex(hull, face->u.q.indices[2]);
q.pt[3] = *convexHullGetVertex(hull, face->u.q.indices[3]);
glColor3f(1.0f, 1.0f, 1.0f);
glBegin(GL_QUADS);
vec3Normal(&q.pt[0], &q.pt[1], &q.pt[2], &normal);
for (j = 0; j < 4; ++j) {
glNormal3f(normal.x, normal.y, normal.z);
glVertex3f(q.pt[j].x, q.pt[j].y, q.pt[j].z);
}
glEnd();
glBegin(GL_LINE_STRIP);
for (j = 0; j < 4; ++j) {
glVertex3f(q.pt[j].x, q.pt[j].y, q.pt[j].z);
}
glVertex3f(q.pt[0].x, q.pt[0].y, q.pt[0].z);
glEnd();
} }
} }
}
/*
glColor3f(0.0f, 0.0f, 0.0f);
{
int triIndex;
int j;
for (triIndex = 0; triIndex < convexHullGetFaceNum(hull);
++triIndex) {
convexHullFace *face = (convexHullFace *)convexHullGetFace(hull,
triIndex);
if (3 == face->vertexNum) {
triangle tri;
tri.pt[0] = *convexHullGetVertex(hull, face->u.t.indices[0]);
tri.pt[1] = *convexHullGetVertex(hull, face->u.t.indices[1]);
tri.pt[2] = *convexHullGetVertex(hull, face->u.t.indices[2]);
glBegin(GL_LINE_STRIP);
for (j = 0; j < 3; ++j) {
glVertex3f(tri.pt[j].x, tri.pt[j].y, tri.pt[j].z);
}
glVertex3f(tri.pt[0].x, tri.pt[0].y, tri.pt[0].z);
glEnd();
} else if ()
}
}*/
/* /*
glColor3f(1.0f, 1.0f, 1.0f); glColor3f(1.0f, 1.0f, 1.0f);

View File

@ -18,7 +18,7 @@ typedef struct {
vec3 pt; vec3 pt;
int plane; int plane;
int orderOnPlane; int orderOnPlane;
} converHullVertex; } convexHullVertex;
typedef struct { typedef struct {
int p1; int p1;
@ -26,12 +26,15 @@ typedef struct {
int hill1; int hill1;
int hill2; int hill2;
vec3 hill1Normal; vec3 hill1Normal;
int score;
int face1;
int face2;
} edge; } edge;
struct convexHull { struct convexHull {
array *vertexArray; array *vertexArray;
array *todoArray; array *todoArray;
array *face3Array; array *faceArray;
int nextTodoIndex; int nextTodoIndex;
unsigned int *openEdgeProcessedMap; unsigned int *openEdgeProcessedMap;
hashtable *face3Hashtable; hashtable *face3Hashtable;
@ -57,7 +60,7 @@ face3 *convexHullGetFaceByHashtableParam(void *userData, const void *node) {
if (0 == index) { if (0 == index) {
return &hull->findFace3; return &hull->findFace3;
} }
return (face3 *)arrayGetItem(hull->face3Array, index - 1); return (face3 *)arrayGetItem(hull->faceArray, index - 1);
} }
static int face3Hash(void *userData, const void *node) { static int face3Hash(void *userData, const void *node) {
@ -104,7 +107,7 @@ convexHull *convexHullCreate(void) {
fprintf(stderr, "%s:Insufficient memory.\n", __FUNCTION__); fprintf(stderr, "%s:Insufficient memory.\n", __FUNCTION__);
return 0; return 0;
} }
hull->vertexArray = arrayCreate(sizeof(converHullVertex)); hull->vertexArray = arrayCreate(sizeof(convexHullVertex));
if (!hull->vertexArray) { if (!hull->vertexArray) {
fprintf(stderr, "%s:arrayCreate failed.\n", __FUNCTION__); fprintf(stderr, "%s:arrayCreate failed.\n", __FUNCTION__);
convexHullDestroy(hull); convexHullDestroy(hull);
@ -116,8 +119,8 @@ convexHull *convexHullCreate(void) {
convexHullDestroy(hull); convexHullDestroy(hull);
return 0; return 0;
} }
hull->face3Array = arrayCreate(sizeof(face3)); hull->faceArray = arrayCreate(sizeof(convexHullFace));
if (!hull->face3Array) { if (!hull->faceArray) {
fprintf(stderr, "%s:arrayCreate failed.\n", __FUNCTION__); fprintf(stderr, "%s:arrayCreate failed.\n", __FUNCTION__);
convexHullDestroy(hull); convexHullDestroy(hull);
return 0; return 0;
@ -156,7 +159,8 @@ edge *convexHullFindEdge(convexHull *hull, int p1, int p2) {
return arrayGetItem(hull->edgeArray, index - 1); return arrayGetItem(hull->edgeArray, index - 1);
} }
int convexHullAddEdge(convexHull *hull, int p1, int p2, int hill) { int convexHullAddEdge(convexHull *hull, int p1, int p2, int hill,
int face) {
edge *e = convexHullFindEdge(hull, p1, p2); edge *e = convexHullFindEdge(hull, p1, p2);
if (!e) { if (!e) {
int newIndex = arrayGetLength(hull->edgeArray); int newIndex = arrayGetLength(hull->edgeArray);
@ -165,10 +169,13 @@ int convexHullAddEdge(convexHull *hull, int p1, int p2, int hill) {
return -1; return -1;
} }
e = (edge *)arrayGetItem(hull->edgeArray, newIndex); e = (edge *)arrayGetItem(hull->edgeArray, newIndex);
memset(e, 0, sizeof(edge));
e->p1 = p1; e->p1 = p1;
e->p2 = p2; e->p2 = p2;
e->hill1 = hill; e->hill1 = hill;
e->hill2 = -1; e->hill2 = -1;
e->face1 = face;
e->face2 = -1;
vec3Normal((vec3 *)arrayGetItem(hull->vertexArray, e->p1), vec3Normal((vec3 *)arrayGetItem(hull->vertexArray, e->p1),
(vec3 *)arrayGetItem(hull->vertexArray, e->p2), (vec3 *)arrayGetItem(hull->vertexArray, e->p2),
(vec3 *)arrayGetItem(hull->vertexArray, e->hill1), &e->hill1Normal); (vec3 *)arrayGetItem(hull->vertexArray, e->hill1), &e->hill1Normal);
@ -179,7 +186,9 @@ int convexHullAddEdge(convexHull *hull, int p1, int p2, int hill) {
return 0; return 0;
} }
assert(-1 == e->hill2); assert(-1 == e->hill2);
assert(-1 == e->face2);
e->hill2 = hill; e->hill2 = hill;
e->face2 = face;
return 0; return 0;
} }
@ -204,13 +213,13 @@ int convexHullOpenEdgeProcessed(convexHull *hull, int firstVertex,
int convexHullAddVertex(convexHull *hull, vec3 *vertex, int plane, int convexHullAddVertex(convexHull *hull, vec3 *vertex, int plane,
int orderOnPlane) { int orderOnPlane) {
converHullVertex *vtx; convexHullVertex *vtx;
int newVertex = arrayGetLength(hull->vertexArray); int newVertex = arrayGetLength(hull->vertexArray);
if (0 != arraySetLength(hull->vertexArray, newVertex + 1)) { if (0 != arraySetLength(hull->vertexArray, newVertex + 1)) {
fprintf(stderr, "%s:arraySetLength failed.\n", __FUNCTION__); fprintf(stderr, "%s:arraySetLength failed.\n", __FUNCTION__);
return -1; return -1;
} }
vtx = (converHullVertex *)arrayGetItem(hull->vertexArray, newVertex); vtx = (convexHullVertex *)arrayGetItem(hull->vertexArray, newVertex);
vtx->plane = plane; vtx->plane = plane;
vtx->orderOnPlane = orderOnPlane; vtx->orderOnPlane = orderOnPlane;
vtx->pt = *vertex; vtx->pt = *vertex;
@ -252,13 +261,13 @@ static int sortface(const void *first, const void *second) {
int convexHullAddFace3(convexHull *hull, int firstVertex, int secondVertex, int convexHullAddFace3(convexHull *hull, int firstVertex, int secondVertex,
int thirdVertex) { int thirdVertex) {
face3 *tri; face3 *tri;
converHullVertex *vtx1; convexHullVertex *vtx1;
converHullVertex *vtx2; convexHullVertex *vtx2;
converHullVertex *vtx3; convexHullVertex *vtx3;
int newTri; int newTri;
vtx1 = (converHullVertex *)arrayGetItem(hull->vertexArray, firstVertex); vtx1 = (convexHullVertex *)arrayGetItem(hull->vertexArray, firstVertex);
vtx2 = (converHullVertex *)arrayGetItem(hull->vertexArray, secondVertex); vtx2 = (convexHullVertex *)arrayGetItem(hull->vertexArray, secondVertex);
vtx3 = (converHullVertex *)arrayGetItem(hull->vertexArray, thirdVertex); vtx3 = (convexHullVertex *)arrayGetItem(hull->vertexArray, thirdVertex);
if (vtx1->plane == vtx2->plane && vtx1->plane == vtx3->plane) { if (vtx1->plane == vtx2->plane && vtx1->plane == vtx3->plane) {
return 0; return 0;
} }
@ -284,18 +293,22 @@ int convexHullAddFace3(convexHull *hull, int firstVertex, int secondVertex,
qsort(hull->findFace3.indices, 3, qsort(hull->findFace3.indices, 3,
sizeof(hull->findFace3.indices[0]), sortface); sizeof(hull->findFace3.indices[0]), sortface);
if (0 == hashtableGet(hull->face3Hashtable, 0)) { if (0 == hashtableGet(hull->face3Hashtable, 0)) {
newTri = arrayGetLength(hull->face3Array); newTri = arrayGetLength(hull->faceArray);
if (0 != arraySetLength(hull->face3Array, newTri + 1)) { if (0 != arraySetLength(hull->faceArray, newTri + 1)) {
fprintf(stderr, "%s:arraySetLength failed.\n", __FUNCTION__); fprintf(stderr, "%s:arraySetLength failed.\n", __FUNCTION__);
return -1; return -1;
} }
tri = (face3 *)arrayGetItem(hull->face3Array, newTri); tri = (face3 *)arrayGetItem(hull->faceArray, newTri);
((convexHullFace *)tri)->vertexNum = 3;
*tri = hull->findFace3; *tri = hull->findFace3;
if (0 != hashtableInsert(hull->face3Hashtable, if (0 != hashtableInsert(hull->face3Hashtable,
(char *)0 + newTri + 1)) { (char *)0 + newTri + 1)) {
fprintf(stderr, "%s:hashtableInsert failed.\n", __FUNCTION__); fprintf(stderr, "%s:hashtableInsert failed.\n", __FUNCTION__);
return -1; return -1;
} }
convexHullAddEdge(hull, firstVertex, secondVertex, thirdVertex, newTri);
convexHullAddEdge(hull, secondVertex, thirdVertex, firstVertex, newTri);
convexHullAddEdge(hull, thirdVertex, firstVertex, secondVertex, newTri);
} }
return 0; return 0;
} }
@ -308,7 +321,7 @@ static void convexHullReleaseForGenerate(convexHull *hull) {
void convexHullDestroy(convexHull *hull) { void convexHullDestroy(convexHull *hull) {
arrayDestroy(hull->vertexArray); arrayDestroy(hull->vertexArray);
arrayDestroy(hull->todoArray); arrayDestroy(hull->todoArray);
arrayDestroy(hull->face3Array); arrayDestroy(hull->faceArray);
arrayDestroy(hull->edgeArray); arrayDestroy(hull->edgeArray);
hashtableDestroy(hull->edgeHashtable); hashtableDestroy(hull->edgeHashtable);
hashtableDestroy(hull->face3Hashtable); hashtableDestroy(hull->face3Hashtable);
@ -374,7 +387,7 @@ static int convexHullCanAddFace3(convexHull *hull, int index1, int index2,
int i; int i;
int indices[] = {index1, index2, index3}; int indices[] = {index1, index2, index3};
if (showFaceIndex == arrayGetLength(hull->face3Array)) { if (showFaceIndex == arrayGetLength(hull->faceArray)) {
drawDebugPrintf("showFaceIndex:%d can add (%d,%d,%d)", showFaceIndex, drawDebugPrintf("showFaceIndex:%d can add (%d,%d,%d)", showFaceIndex,
index1, index2, index3); index1, index2, index3);
} }
@ -395,7 +408,7 @@ static int convexHullCanAddFace3(convexHull *hull, int index1, int index2,
(vec3 *)arrayGetItem(hull->vertexArray, hill), &normal); (vec3 *)arrayGetItem(hull->vertexArray, hill), &normal);
angle = vec3Angle(&e->hill1Normal, &normal); angle = vec3Angle(&e->hill1Normal, &normal);
if (showFaceIndex == arrayGetLength(hull->face3Array)) { if (showFaceIndex == arrayGetLength(hull->faceArray)) {
drawDebugPrintf("showFaceIndex:%d angle:%f (%d,%d,%d)", drawDebugPrintf("showFaceIndex:%d angle:%f (%d,%d,%d)",
showFaceIndex, angle, e->p1, e->p2, e->hill1); showFaceIndex, angle, e->p1, e->p2, e->hill1);
drawSphere((vec3 *)arrayGetItem(hull->vertexArray, 9), drawSphere((vec3 *)arrayGetItem(hull->vertexArray, 9),
@ -435,13 +448,10 @@ int convexHullGenerate(convexHull *hull) {
if (!convexHullCanAddFace3(hull, index1, index2, index3)) { if (!convexHullCanAddFace3(hull, index1, index2, index3)) {
continue; continue;
} }
if (showFaceIndex == arrayGetLength(hull->face3Array)) { if (showFaceIndex == arrayGetLength(hull->faceArray)) {
drawDebugPrintf("showFaceIndex:%d added face3 (%d,%d,%d)", drawDebugPrintf("showFaceIndex:%d added face3 (%d,%d,%d)",
showFaceIndex, index1, index2, index3); showFaceIndex, index1, index2, index3);
} }
convexHullAddEdge(hull, index1, index2, index3);
convexHullAddEdge(hull, index2, index3, index1);
convexHullAddEdge(hull, index3, index1, index2);
convexHullAddFace3(hull, index1, index2, index3); convexHullAddFace3(hull, index1, index2, index3);
convexHullAddTodo(hull, index2, index3, index1); convexHullAddTodo(hull, index2, index3, index1);
convexHullAddTodo(hull, index3, index1, index2); convexHullAddTodo(hull, index3, index1, index2);
@ -451,14 +461,14 @@ int convexHullGenerate(convexHull *hull) {
int convexHullUnifyNormals(convexHull *hull, vec3 *origin) { int convexHullUnifyNormals(convexHull *hull, vec3 *origin) {
int i; int i;
for (i = 0; i < arrayGetLength(hull->face3Array); ++i) { for (i = 0; i < arrayGetLength(hull->faceArray); ++i) {
face3 *triIdx = (face3 *)arrayGetItem( face3 *triIdx = (face3 *)arrayGetItem(
hull->face3Array, i); hull->faceArray, i);
converHullVertex *p1 = (converHullVertex *)arrayGetItem( convexHullVertex *p1 = (convexHullVertex *)arrayGetItem(
hull->vertexArray, triIdx->indices[0]); hull->vertexArray, triIdx->indices[0]);
converHullVertex *p2 = (converHullVertex *)arrayGetItem( convexHullVertex *p2 = (convexHullVertex *)arrayGetItem(
hull->vertexArray, triIdx->indices[1]); hull->vertexArray, triIdx->indices[1]);
converHullVertex *p3 = (converHullVertex *)arrayGetItem( convexHullVertex *p3 = (convexHullVertex *)arrayGetItem(
hull->vertexArray, triIdx->indices[2]); hull->vertexArray, triIdx->indices[2]);
vec3 normal; vec3 normal;
vec3 o2v; vec3 o2v;
@ -473,16 +483,107 @@ int convexHullUnifyNormals(convexHull *hull, vec3 *origin) {
return 0; return 0;
} }
face3 *convexHullGetFace3(convexHull *hull, int faceIndex) { static int sortEdgeByScore(const void *first, const void *second) {
return (face3 *)arrayGetItem(hull->face3Array, faceIndex); edge *e1 = (edge *)first;
edge *e2 = (edge *)second;
return e2->score - e1->score;
}
static int findFace3FirstEdgeVertex(face3 *face, edge *e) {
int i;
for (i = 0; i < 3; ++i) {
if (face->indices[i] == e->p1 || face->indices[i] == e->p2) {
return i;
}
}
return 0;
}
int convexHullMergeTriangles(convexHull *hull) {
int edgeIndex;
for (edgeIndex = 0; edgeIndex < arrayGetLength(hull->edgeArray);
++edgeIndex) {
edge *e = (edge *)arrayGetItem(hull->edgeArray, edgeIndex);
if (-1 != e->face1 && -1 != e->face2) {
face3 *f1 = (face3 *)arrayGetItem(hull->faceArray, e->face1);
face3 *f2 = (face3 *)arrayGetItem(hull->faceArray, e->face2);
float sumArea;
vec3 f1normal;
vec3 f2normal;
convexHullVertex *f1p1 = (convexHullVertex *)arrayGetItem(
hull->vertexArray, f1->indices[0]);
convexHullVertex *f1p2 = (convexHullVertex *)arrayGetItem(
hull->vertexArray, f1->indices[1]);
convexHullVertex *f1p3 = (convexHullVertex *)arrayGetItem(
hull->vertexArray, f1->indices[2]);
convexHullVertex *f2p1 = (convexHullVertex *)arrayGetItem(
hull->vertexArray, f2->indices[0]);
convexHullVertex *f2p2 = (convexHullVertex *)arrayGetItem(
hull->vertexArray, f2->indices[1]);
convexHullVertex *f2p3 = (convexHullVertex *)arrayGetItem(
hull->vertexArray, f2->indices[2]);
sumArea = vec3TriangleArea(&f1p1->pt, &f1p2->pt, &f1p3->pt) +
vec3TriangleArea(&f2p1->pt, &f2p2->pt, &f2p3->pt);
vec3Normal(&f1p1->pt, &f1p2->pt, &f1p3->pt, &f1normal);
vec3Normal(&f2p1->pt, &f2p2->pt, &f2p3->pt, &f2normal);
e->score = sumArea * vec3DotProduct(&f1normal, &f2normal) * 100;
}
}
qsort(arrayGetItem(hull->edgeArray, 0), arrayGetLength(hull->edgeArray),
sizeof(edge), sortEdgeByScore);
//
// After sort by score, the edge hashmap can not be used anymore.
//
hashtableDestroy(hull->edgeHashtable);
hull->edgeHashtable = 0;
for (edgeIndex = 0; edgeIndex < arrayGetLength(hull->edgeArray);
++edgeIndex) {
edge *e = (edge *)arrayGetItem(hull->edgeArray, edgeIndex);
if (-1 != e->face1 && -1 != e->face2) {
convexHullFace *f1 = (convexHullFace *)arrayGetItem(hull->faceArray,
e->face1);
convexHullFace *f2 = (convexHullFace *)arrayGetItem(hull->faceArray,
e->face2);
if (3 == f1->vertexNum && 3 == f2->vertexNum) {
if (e->score > 0) {
int firstEdgeVertex = findFace3FirstEdgeVertex((face3 *)f1, e);
int insertPos = firstEdgeVertex + 1;
drawDebugPrintf("score:%d", e->score);
memmove(&f1->u.q.indices[insertPos + 1],
&f1->u.q.indices[insertPos], (3 - insertPos) * sizeof(int));
f1->u.q.indices[insertPos] = e->hill2;
f1->vertexNum = 4;
f2->vertexNum = 0;
}
}
}
}
// After merge, face3 hashtable can not be used anymore.
hashtableDestroy(hull->face3Hashtable);
hull->face3Hashtable = 0;
return 0;
}
convexHullFace *convexHullGetFace(convexHull *hull, int faceIndex) {
convexHullFace *face = (convexHullFace *)arrayGetItem(hull->faceArray,
faceIndex);
return face;
} }
vec3 *convexHullGetVertex(convexHull *hull, int vertexIndex) { vec3 *convexHullGetVertex(convexHull *hull, int vertexIndex) {
converHullVertex *vertex = (converHullVertex *)arrayGetItem( convexHullVertex *vertex = (convexHullVertex *)arrayGetItem(
hull->vertexArray, vertexIndex); hull->vertexArray, vertexIndex);
return &vertex->pt; return &vertex->pt;
} }
int convexHullGetFace3Num(convexHull *hull) { int convexHullGetFaceNum(convexHull *hull) {
return arrayGetLength(hull->face3Array); return arrayGetLength(hull->faceArray);
} }

View File

@ -3,14 +3,23 @@
#include "3dstruct.h" #include "3dstruct.h"
typedef struct convexHull convexHull; typedef struct convexHull convexHull;
typedef struct {
union {
face4 q;
face3 t;
} u;
int vertexNum;
} convexHullFace;
convexHull *convexHullCreate(void); convexHull *convexHullCreate(void);
int convexHullAddVertex(convexHull *hull, vec3 *vertex, int plane, int convexHullAddVertex(convexHull *hull, vec3 *vertex, int plane,
int orderOnPlane); int orderOnPlane);
void convexHullDestroy(convexHull *hull); void convexHullDestroy(convexHull *hull);
int convexHullGenerate(convexHull *hull); int convexHullGenerate(convexHull *hull);
int convexHullUnifyNormals(convexHull *hull, vec3 *origin); int convexHullUnifyNormals(convexHull *hull, vec3 *origin);
int convexHullGetFace3Num(convexHull *hull); int convexHullMergeTriangles(convexHull *hull);
face3 *convexHullGetFace3(convexHull *hull, int faceIndex); int convexHullGetFaceNum(convexHull *hull);
convexHullFace *convexHullGetFace(convexHull *hull, int faceIndex);
vec3 *convexHullGetVertex(convexHull *hull, int vertexIndex); vec3 *convexHullGetVertex(convexHull *hull, int vertexIndex);
int convexHullAddTodo(convexHull *hull, int vertex1, int vertex2, int vertex3); int convexHullAddTodo(convexHull *hull, int vertex1, int vertex2, int vertex3);