Fix bmesh vertex hash of subdivision.
parent
c271354ab1
commit
37e1cf2ca7
|
@ -36,7 +36,7 @@ Two caps and many strips composites a cylinder.
|
||||||
Almost all 3D editor have a infinite grid ground, I just made a finite one, in the future, I should expand the grid outside of the screen to make it infinite.
|
Almost all 3D editor have a infinite grid ground, I just made a finite one, in the future, I should expand the grid outside of the screen to make it infinite.
|
||||||
Now, for just beginning, I think it's a not bad start.
|
Now, for just beginning, I think it's a not bad start.
|
||||||
<img src="screenshot/dust3d_sphere_cylinder.png">
|
<img src="screenshot/dust3d_sphere_cylinder.png">
|
||||||
- [ ] Implement B-Mesh algorithm (Dec 18, 2016 ~ Jan 02, 2017)
|
- [x] Implement B-Mesh algorithm (Dec 18, 2016 ~ Jan 04, 2017)
|
||||||
There is a implementation of [B-Mesh algorithm in C++](https://github.com/evanw/cs224final) language, but I want the pure C version, so I start to implement my own version. I read both paper and this implementation, it gave me very helpful understanding of this algorithm.
|
There is a implementation of [B-Mesh algorithm in C++](https://github.com/evanw/cs224final) language, but I want the pure C version, so I start to implement my own version. I read both paper and this implementation, it gave me very helpful understanding of this algorithm.
|
||||||
*Drawing Skeletal Shape Balls*
|
*Drawing Skeletal Shape Balls*
|
||||||
Draw shape ball is easy, no need to rotate, I just need scale it along the ball's radius.
|
Draw shape ball is easy, no need to rotate, I just need scale it along the ball's radius.
|
||||||
|
@ -62,10 +62,12 @@ There is a good implementation of [Gift Wrapping algorithm written in lua](https
|
||||||
I follow the B-Mesh paper, made another test module inside Blender, and created a correspond `data/bmesh_test_2.h` manually.
|
I follow the B-Mesh paper, made another test module inside Blender, and created a correspond `data/bmesh_test_2.h` manually.
|
||||||
<img src="screenshot/dust3d_bmesh_test_2.png" width="124" height="128"> <img src="screenshot/dust3d_bmesh_joint_1.png" width="124" height="128"> <img src="screenshot/dust3d_bmesh_joint_2.png" width="124" height="128">
|
<img src="screenshot/dust3d_bmesh_test_2.png" width="124" height="128"> <img src="screenshot/dust3d_bmesh_joint_1.png" width="124" height="128"> <img src="screenshot/dust3d_bmesh_joint_2.png" width="124" height="128">
|
||||||
*Catmull-Clark Subdivision*
|
*Catmull-Clark Subdivision*
|
||||||
<img src="screenshot/dust3d_subdivide_catmull_clark.png" width="124" height="128">
|
<img src="screenshot/dust3d_subdivide_catmull_clark.png" width="124" height="128"> <img src="screenshot/dust3d_bmesh_subdivide_2.png" width="124" height="128">
|
||||||
There is a implementation of Catmull-Clark Subdivision algorithm on [rosettacode](https://rosettacode.org/wiki/Catmull%E2%80%93Clark_subdivision_surface/C), the code is very simple and beautiful, just lack of some memory alloc fail check. I translated the algorithm to use my own array implementation.
|
There is a implementation of Catmull-Clark Subdivision algorithm on [rosettacode](https://rosettacode.org/wiki/Catmull%E2%80%93Clark_subdivision_surface/C), the code is very simple and beautiful, just lack of some memory alloc fail check. I translated the algorithm to use my own array implementation.
|
||||||
|
Now, the render result looks not bad after 2 times of subdivisions. I would like to mark this todo as done, though there are more polish steps on the original paper, I just leave it as to be done in the future.
|
||||||
- [ ] Export Wavefront .obj
|
- [ ] Export Wavefront .obj
|
||||||
- [ ] Render B-Mesh result
|
- [x] Render B-Mesh result
|
||||||
|
This todo already done in the B-Mesh algorithm implementation.
|
||||||
- [ ] Design UI for monster parts configuration
|
- [ ] Design UI for monster parts configuration
|
||||||
- [ ] Test B-Mesh realtime generation with UI
|
- [ ] Test B-Mesh realtime generation with UI
|
||||||
- [ ] Render rigid animation
|
- [ ] Render rigid animation
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 267 KiB |
27
src/bmesh.c
27
src/bmesh.c
|
@ -41,10 +41,6 @@ struct bmesh {
|
||||||
bmeshModelVertex findModelVertex;
|
bmeshModelVertex findModelVertex;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int cantorPair(int k1, int k2) {
|
|
||||||
return (k1 + k2) * (k1 + k2 + 1) / 2 + k2;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bmeshModelVertex *bmeshFindModelVertex(bmesh *bm, vec3 *vertex) {
|
static bmeshModelVertex *bmeshFindModelVertex(bmesh *bm, vec3 *vertex) {
|
||||||
int index;
|
int index;
|
||||||
bm->findModelVertex.vertex = *vertex;
|
bm->findModelVertex.vertex = *vertex;
|
||||||
|
@ -66,6 +62,11 @@ static int bmeshAddModelVertex(bmesh *bm, vec3 *vertex) {
|
||||||
memset(v, 0, sizeof(bmeshModelVertex));
|
memset(v, 0, sizeof(bmeshModelVertex));
|
||||||
v->vertex = *vertex;
|
v->vertex = *vertex;
|
||||||
v->indexOnModel = subdivAddVertex(bm->model, &v->vertex);
|
v->indexOnModel = subdivAddVertex(bm->model, &v->vertex);
|
||||||
|
if (-1 == hashtableInsert(bm->modelVertexHashtable,
|
||||||
|
(char *)0 + arrayGetLength(bm->modelVertexArray))) {
|
||||||
|
fprintf(stderr, "%s:hashtableInsert failed.\n", __FUNCTION__);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return v->indexOnModel;
|
return v->indexOnModel;
|
||||||
}
|
}
|
||||||
|
@ -118,8 +119,7 @@ bmeshModelVertex *bmeshGetModelVertexByHashtableParam(void *userData,
|
||||||
|
|
||||||
static int modelVertexHash(void *userData, const void *node) {
|
static int modelVertexHash(void *userData, const void *node) {
|
||||||
bmeshModelVertex *v = bmeshGetModelVertexByHashtableParam(userData, node);
|
bmeshModelVertex *v = bmeshGetModelVertexByHashtableParam(userData, node);
|
||||||
return cantorPair(cantorPair(v->vertex.x, v->vertex.y),
|
return abs(*((int *)v));
|
||||||
v->vertex.z);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int modelVertexCompare(void *userData, const void *firstNode,
|
static int modelVertexCompare(void *userData, const void *firstNode,
|
||||||
|
@ -128,7 +128,12 @@ static int modelVertexCompare(void *userData, const void *firstNode,
|
||||||
firstNode);
|
firstNode);
|
||||||
bmeshModelVertex *v2 = bmeshGetModelVertexByHashtableParam(userData,
|
bmeshModelVertex *v2 = bmeshGetModelVertexByHashtableParam(userData,
|
||||||
secondNode);
|
secondNode);
|
||||||
return 0 == memcmp(&v1->vertex, &v2->vertex, sizeof(v1->vertex));
|
if (0 == v1->vertex.x - v2->vertex.x &&
|
||||||
|
0 == v1->vertex.y - v2->vertex.y &&
|
||||||
|
0 == v1->vertex.z - v2->vertex.z) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bmesh *bmeshCreate(void) {
|
bmesh *bmeshCreate(void) {
|
||||||
|
@ -1027,19 +1032,17 @@ int bmeshGenerate(bmesh *bm) {
|
||||||
bmeshStitch(bm);
|
bmeshStitch(bm);
|
||||||
bmeshGenerateInbetweenMesh(bm);
|
bmeshGenerateInbetweenMesh(bm);
|
||||||
subdivCalculteNorms(bm->model);
|
subdivCalculteNorms(bm->model);
|
||||||
bm->subdivModel = subdivCatmullClarkWithLoops(bm->model, 1);
|
//bm->subdivModel = subdivCatmullClark(bm->model);
|
||||||
|
bm->subdivModel = subdivCatmullClarkWithLoops(bm->model, 2);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bmeshDraw(bmesh *bm) {
|
int bmeshDraw(bmesh *bm) {
|
||||||
glPushMatrix();
|
glPushMatrix();
|
||||||
glTranslatef(-5, 0, 0);
|
glTranslatef(-7, 0, 0);
|
||||||
subdivDrawModel(bm->model);
|
subdivDrawModel(bm->model);
|
||||||
glPopMatrix();
|
glPopMatrix();
|
||||||
subdivDrawModel(bm->subdivModel);
|
subdivDrawModel(bm->subdivModel);
|
||||||
//subdivModel *model = subdivCreateModel();
|
|
||||||
//subdivAddCube(model);
|
|
||||||
//subdivDrawModel(subdivCatmullClarkWithLoops(model, 2));
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -291,6 +291,7 @@ static int facePoint(subdivModel *model, int f) {
|
||||||
int nv = getFace(model, f)->avg;
|
int nv = getFace(model, f)->avg;
|
||||||
if (-1 == nv) {
|
if (-1 == nv) {
|
||||||
int iterator;
|
int iterator;
|
||||||
|
int i;
|
||||||
subdivVertex *newVertex = allocVertex(model);
|
subdivVertex *newVertex = allocVertex(model);
|
||||||
if (!newVertex) {
|
if (!newVertex) {
|
||||||
fprintf(stderr, "%s:allocVertex failed.\n", __FUNCTION__);
|
fprintf(stderr, "%s:allocVertex failed.\n", __FUNCTION__);
|
||||||
|
@ -299,18 +300,20 @@ static int facePoint(subdivModel *model, int f) {
|
||||||
nv = newVertex->index;
|
nv = newVertex->index;
|
||||||
getFace(model, f)->avg = nv;
|
getFace(model, f)->avg = nv;
|
||||||
iterator = getFace(model, f)->vertexLink;
|
iterator = getFace(model, f)->vertexLink;
|
||||||
|
i = 0;
|
||||||
while (-1 != iterator) {
|
while (-1 != iterator) {
|
||||||
int p;
|
int p;
|
||||||
subdivLink *linkItem = (subdivLink *)arrayGetItem(model->indexArray,
|
subdivLink *linkItem = (subdivLink *)arrayGetItem(model->indexArray,
|
||||||
iterator);
|
iterator);
|
||||||
p = linkItem->index;
|
p = linkItem->index;
|
||||||
iterator = linkItem->nextLink;
|
iterator = linkItem->nextLink;
|
||||||
if (getFace(model, f)->vertexLink == iterator) {
|
if (!i) {
|
||||||
getVertex(model, nv)->v = getVertex(model, p)->v;
|
getVertex(model, nv)->v = getVertex(model, p)->v;
|
||||||
} else {
|
} else {
|
||||||
vec3Add(&getVertex(model, nv)->v, &getVertex(model, p)->v,
|
vec3Add(&getVertex(model, nv)->v, &getVertex(model, p)->v,
|
||||||
&getVertex(model, nv)->v);
|
&getVertex(model, nv)->v);
|
||||||
}
|
}
|
||||||
|
++i;
|
||||||
}
|
}
|
||||||
vec3Scale(&getVertex(model, nv)->v, 1.0 / (getFace(model, f)->vertexNum),
|
vec3Scale(&getVertex(model, nv)->v, 1.0 / (getFace(model, f)->vertexNum),
|
||||||
&getVertex(model, nv)->v);
|
&getVertex(model, nv)->v);
|
||||||
|
@ -625,7 +628,8 @@ static int subdivAddEdge(subdivModel *model, int p1, int p2) {
|
||||||
fprintf(stderr, "%s:pushLink failed.\n", __FUNCTION__);
|
fprintf(stderr, "%s:pushLink failed.\n", __FUNCTION__);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (-1 == pushLink(model, &model->edgeLink, &model->edgeNum, newEdge->index)) {
|
if (-1 == pushLink(model, &model->edgeLink, &model->edgeNum,
|
||||||
|
newEdge->index)) {
|
||||||
fprintf(stderr, "%s:pushLink failed.\n", __FUNCTION__);
|
fprintf(stderr, "%s:pushLink failed.\n", __FUNCTION__);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue