diff --git a/README.md b/README.md index faadac41..89b0826c 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,8 @@ 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 ~ Dec 31, 2016) +- [ ] Implement B-Mesh algorithm (Dec 18, 2016 ~ Jan 02, 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. Draw the cylinder which connects two shape balls is more difficult, I need do some math to rotate it. [Here](http://www.thjsmith.com/40/cylinder-between-two-points-opengl-c) described it. @@ -55,10 +56,14 @@ I created the test nodes's geometry information from Blender. Here is the render When I am implementing the B-Mesh algorithm, I am also think in the future, how to create a library of bunch of initial base models. There is a paper [the Skeleton of a Closed 3D Shape](http://www1.idc.ac.il/icgf/GraphicsSeminar2006/DCGskeleton06.pdf) described how to generate skeleton from mesh, this is the reverse progress of what I am doing, I think it can resolve the problem of insufficient initial base models, I can generate from tons of existed models. *Convex Hull* After finish the rotation at the two connected bones, I need implement 3D Convex Hull algorithm at the joint ball, there are so many methods to get the convex hull, I found the [Gift wrapping](http://dccg.upc.edu/people/vera/wp-content/uploads/2014/11/GA2014-ConvexHulls3D-Roger-Hernando.pdf) is the most strait-forward one, though is not the most efficient one. +There is a good implementation of [Gift Wrapping algorithm written in lua](https://github.com/danielhst/3d-Hull-gift-wrap/blob/master/giftWrap.lua) language. When I was implementing, I first translated this version to C language, but maybe there are some bugs on my own translation, there are lots of repeated faces, so changed a little, the code now is not just the translation of the original lua version. *Stitching* 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. - [ ] Export Wavefront .obj - [ ] Render B-Mesh result - [ ] Design UI for monster parts configuration diff --git a/build/dust3d.pro b/build/dust3d.pro index 930d75a2..53e8137f 100644 --- a/build/dust3d.pro +++ b/build/dust3d.pro @@ -17,7 +17,8 @@ SOURCES += main.cpp \ matrix.c \ convexhull.c \ hashtable.c \ - osutil.cpp + osutil.cpp \ + subdivide.c HEADERS += mainwindow.h \ render.h \ @@ -29,4 +30,5 @@ HEADERS += mainwindow.h \ convexhull.h \ hashtable.h \ 3dstruct.h \ - osutil.h \ No newline at end of file + osutil.h \ + subdivide.h \ No newline at end of file diff --git a/src/3dstruct.h b/src/3dstruct.h index 1e0bcb79..8c8362fe 100644 --- a/src/3dstruct.h +++ b/src/3dstruct.h @@ -1,6 +1,7 @@ #ifndef _3DSTRUCT_H #define _3DSTRUCT_H #include "vector3d.h" +#include "array.h" typedef struct { vec3 pt[3]; diff --git a/src/convexhull.c b/src/convexhull.c index 3a47b082..4849901d 100644 --- a/src/convexhull.c +++ b/src/convexhull.c @@ -539,9 +539,8 @@ int convexHullMergeTriangles(convexHull *hull) { e->score = (int)angle; //if (edgeIndex >= 12 && edgeIndex <= 12) { // angle = (int)vec3Angle(&f1normal, &f2normal); - // drawDebugPrintf("edgeIndex:%d angle:%f normal1:<%f,%f,%f> normal2:<%f,%f,%f>", - // edgeIndex, angle, f1normal.x, f1normal.y, f1normal.z, - // f2normal.x, f2normal.y, f2normal.z); + drawDebugPrintf("edgeIndex:%d angle:%f", + edgeIndex, angle); //} } } @@ -564,7 +563,7 @@ int convexHullMergeTriangles(convexHull *hull) { convexHullFace *f2 = (convexHullFace *)arrayGetItem(hull->faceArray, e->face2); if (3 == f1->vertexNum && 3 == f2->vertexNum) { - if (e->score <= 0) { + if (e->score <= 40) { while (e->p1 == f1->u.t.indices[0] || e->p2 == f1->u.t.indices[0]) { rollTriangleIndices((face3 *)f1); } diff --git a/src/hashtable.c b/src/hashtable.c index d6ad7c45..08ee1274 100644 --- a/src/hashtable.c +++ b/src/hashtable.c @@ -31,18 +31,18 @@ hashtable *hashtableCreate(int bucketSize, void *userData) { hashtable *ht = (hashtable *)calloc(1, sizeof(hashtable)); if (!ht) { - fprintf(stderr, "%s:Insufficient memory.", __FUNCTION__); + fprintf(stderr, "%s:Insufficient memory.\n", __FUNCTION__); return 0; } ht->keyArray = arrayCreate(sizeof(hashtableKey)); if (!ht->keyArray) { - fprintf(stderr, "%s:arrayCreate failed.", __FUNCTION__); + fprintf(stderr, "%s:arrayCreate failed.\n", __FUNCTION__); hashtableDestroy(ht); return 0; } ht->entryArray = arrayCreate(sizeof(hashtableEntry)); if (!ht->entryArray) { - fprintf(stderr, "%s:arrayCreate failed.", __FUNCTION__); + fprintf(stderr, "%s:arrayCreate failed.\n", __FUNCTION__); hashtableDestroy(ht); return 0; } @@ -51,7 +51,7 @@ hashtable *hashtableCreate(int bucketSize, ht->compareCallback = compareCallback; ht->userData = userData; if (0 != arraySetLength(ht->keyArray, bucketSize)) { - fprintf(stderr, "%s:arraySetLength failed(bucketSize:%d).", __FUNCTION__, + fprintf(stderr, "%s:arraySetLength failed(bucketSize:%d).\n", __FUNCTION__, bucketSize); hashtableDestroy(ht); return 0; @@ -98,7 +98,7 @@ int hashtableInsert(hashtable *ht, const void *node) { } newEntryIndex = arrayGetLength(ht->entryArray); if (0 != arraySetLength(ht->entryArray, newEntryIndex + 1)) { - fprintf(stderr, "%s:arraySetLength failed(newEntryIndex:%d).", + fprintf(stderr, "%s:arraySetLength failed(newEntryIndex:%d).\n", __FUNCTION__, newEntryIndex); return -1; } diff --git a/src/render.cpp b/src/render.cpp index 095c71d6..8e0dddf7 100644 --- a/src/render.cpp +++ b/src/render.cpp @@ -7,6 +7,7 @@ #include "bmesh.h" #include "matrix.h" #include "vector3d.h" +#include "subdivide.h" static const float bmeshBallColors[][4] { {0.00, 0.78, 1.00, 0.5}, @@ -212,7 +213,7 @@ void Render::initializeGL() { drawInit(); } -#include "../data/bmesh_test_2.h" +#include "../data/bmesh_test_1.h" void Render::paintGL() { bmesh *bm = 0; @@ -235,8 +236,17 @@ void Render::paintGL() { drawGrid(10, 1); glEnable(GL_LIGHTING); + + { + subdivModel *input = subdivCreateModel(); + subdivModel *output; + subdivAddCube(input); + output = subdivCatmullClarkWithLoops(input, 2); + subdivDestroyModel(input); + subdivDestroyModel(output); + } - if (0 == bm) { + if (0 && 0 == bm) { bmeshBall ball; bmeshBone bone; int i; @@ -264,50 +274,53 @@ void Render::paintGL() { bmeshStitch(bm); bmeshGenerateInbetweenMesh(bm); } + + if (bm) { - drawBmeshBallRecursively(bm, bmeshGetRootBall(bm)); + drawBmeshBallRecursively(bm, bmeshGetRootBall(bm)); - //glBegin(GL_QUADS); - drawBmeshBallQuadRecursively(bm, bmeshGetRootBall(bm)); - //glEnd(); + //glBegin(GL_QUADS); + drawBmeshBallQuadRecursively(bm, bmeshGetRootBall(bm)); + //glEnd(); - { - int index; - /* - for (index = 0; index < bmeshGetBallNum(bm); ++index) { - bmeshBall *ball = bmeshGetBall(bm, index); - drawBmeshBall(bm, ball); - }*/ - - for (index = 0; index < bmeshGetBoneNum(bm); ++index) { - bmeshBone *bone = bmeshGetBone(bm, index); - drawBmeshBone(bm, bone); - } - /* - glColor4f(1.0f, 1.0f, 1.0f, 0.5); - glBegin(GL_QUADS); - for (index = 0; index < bmeshGetQuadNum(bm); ++index) { - quad *q = bmeshGetQuad(bm, index); - vec3 normal; - int j; - 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); + { + int index; + /* + for (index = 0; index < bmeshGetBallNum(bm); ++index) { + bmeshBall *ball = bmeshGetBall(bm, index); + drawBmeshBall(bm, ball); + }*/ + + for (index = 0; index < bmeshGetBoneNum(bm); ++index) { + bmeshBone *bone = bmeshGetBone(bm, index); + drawBmeshBone(bm, bone); } - } - glEnd(); - glColor3f(0.0f, 0.0f, 0.0f); - for (index = 0; index < bmeshGetQuadNum(bm); ++index) { - quad *q = bmeshGetQuad(bm, index); - int j; - glBegin(GL_LINE_STRIP); - for (j = 0; j < 4; ++j) { - glVertex3f(q->pt[j].x, q->pt[j].y, q->pt[j].z); + /* + glColor4f(1.0f, 1.0f, 1.0f, 0.5); + glBegin(GL_QUADS); + for (index = 0; index < bmeshGetQuadNum(bm); ++index) { + quad *q = bmeshGetQuad(bm, index); + vec3 normal; + int j; + 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); + } } - glVertex3f(q->pt[0].x, q->pt[0].y, q->pt[0].z); glEnd(); - }*/ + glColor3f(0.0f, 0.0f, 0.0f); + for (index = 0; index < bmeshGetQuadNum(bm); ++index) { + quad *q = bmeshGetQuad(bm, index); + int j; + 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(); + }*/ + } } glPopMatrix(); diff --git a/src/vector3d.c b/src/vector3d.c index 44c0e76b..8fbe3c75 100644 --- a/src/vector3d.c +++ b/src/vector3d.c @@ -137,3 +137,9 @@ float vec3TriangleArea(vec3 *a, vec3 *b, vec3 *c) { vec3CrossProduct(&ab, &ac, &cross); return vec3Length(&cross) * 0.5; } + +void vec3Negative(vec3 *a, vec3 *result) { + result->x = -a->x; + result->y = -a->y; + result->z = -a->z; +} diff --git a/src/vector3d.h b/src/vector3d.h index 0b23356b..0b1c45a8 100644 --- a/src/vector3d.h +++ b/src/vector3d.h @@ -26,6 +26,7 @@ void vec3RotateAlong(vec3 *a, float angle, vec3 *axis, vec3 *result); float vec3Angle(vec3 *a, vec3 *b); void vec3ProjectOver(vec3 *a, vec3 *over, vec3 *result); float vec3TriangleArea(vec3 *a, vec3 *b, vec3 *c); +void vec3Negative(vec3 *a, vec3 *result); #ifdef __cplusplus }