diff --git a/README.md b/README.md index 89b0826c..f322f5ba 100644 --- a/README.md +++ b/README.md @@ -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. Now, for just beginning, I think it's a not bad start. -- [ ] 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. *Drawing Skeletal Shape Balls* 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. *Catmull-Clark Subdivision* - + 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 -- [ ] 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 - [ ] Test B-Mesh realtime generation with UI - [ ] Render rigid animation diff --git a/screenshot/dust3d_bmesh_subdivide_2.png b/screenshot/dust3d_bmesh_subdivide_2.png new file mode 100644 index 00000000..609403cb Binary files /dev/null and b/screenshot/dust3d_bmesh_subdivide_2.png differ diff --git a/src/bmesh.c b/src/bmesh.c index fb2c9d62..cf6afe67 100644 --- a/src/bmesh.c +++ b/src/bmesh.c @@ -41,10 +41,6 @@ struct bmesh { bmeshModelVertex findModelVertex; }; -static int cantorPair(int k1, int k2) { - return (k1 + k2) * (k1 + k2 + 1) / 2 + k2; -} - static bmeshModelVertex *bmeshFindModelVertex(bmesh *bm, vec3 *vertex) { int index; bm->findModelVertex.vertex = *vertex; @@ -66,6 +62,11 @@ static int bmeshAddModelVertex(bmesh *bm, vec3 *vertex) { memset(v, 0, sizeof(bmeshModelVertex)); v->vertex = *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; } @@ -118,8 +119,7 @@ bmeshModelVertex *bmeshGetModelVertexByHashtableParam(void *userData, static int modelVertexHash(void *userData, const void *node) { bmeshModelVertex *v = bmeshGetModelVertexByHashtableParam(userData, node); - return cantorPair(cantorPair(v->vertex.x, v->vertex.y), - v->vertex.z); + return abs(*((int *)v)); } static int modelVertexCompare(void *userData, const void *firstNode, @@ -128,7 +128,12 @@ static int modelVertexCompare(void *userData, const void *firstNode, firstNode); bmeshModelVertex *v2 = bmeshGetModelVertexByHashtableParam(userData, 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) { @@ -1027,19 +1032,17 @@ int bmeshGenerate(bmesh *bm) { bmeshStitch(bm); bmeshGenerateInbetweenMesh(bm); subdivCalculteNorms(bm->model); - bm->subdivModel = subdivCatmullClarkWithLoops(bm->model, 1); + //bm->subdivModel = subdivCatmullClark(bm->model); + bm->subdivModel = subdivCatmullClarkWithLoops(bm->model, 2); return 0; } int bmeshDraw(bmesh *bm) { glPushMatrix(); - glTranslatef(-5, 0, 0); + glTranslatef(-7, 0, 0); subdivDrawModel(bm->model); glPopMatrix(); subdivDrawModel(bm->subdivModel); - //subdivModel *model = subdivCreateModel(); - //subdivAddCube(model); - //subdivDrawModel(subdivCatmullClarkWithLoops(model, 2)); return 0; } diff --git a/src/subdivide.c b/src/subdivide.c index f0d755f3..f0fd6ea0 100644 --- a/src/subdivide.c +++ b/src/subdivide.c @@ -291,6 +291,7 @@ static int facePoint(subdivModel *model, int f) { int nv = getFace(model, f)->avg; if (-1 == nv) { int iterator; + int i; subdivVertex *newVertex = allocVertex(model); if (!newVertex) { fprintf(stderr, "%s:allocVertex failed.\n", __FUNCTION__); @@ -299,18 +300,20 @@ static int facePoint(subdivModel *model, int f) { nv = newVertex->index; getFace(model, f)->avg = nv; iterator = getFace(model, f)->vertexLink; + i = 0; while (-1 != iterator) { int p; subdivLink *linkItem = (subdivLink *)arrayGetItem(model->indexArray, iterator); p = linkItem->index; iterator = linkItem->nextLink; - if (getFace(model, f)->vertexLink == iterator) { + if (!i) { getVertex(model, nv)->v = getVertex(model, p)->v; } else { vec3Add(&getVertex(model, nv)->v, &getVertex(model, p)->v, &getVertex(model, nv)->v); } + ++i; } vec3Scale(&getVertex(model, nv)->v, 1.0 / (getFace(model, f)->vertexNum), &getVertex(model, nv)->v); @@ -625,7 +628,8 @@ static int subdivAddEdge(subdivModel *model, int p1, int p2) { fprintf(stderr, "%s:pushLink failed.\n", __FUNCTION__); 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__); return -1; }