diff --git a/README.md b/README.md index 6de8f926..50fd1ccd 100644 --- a/README.md +++ b/README.md @@ -21,18 +21,20 @@ 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 19, 2016) +- [ ] Implement B-Mesh algorithm (Dec 18, 2016 ~ Dec 20, 2016) *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. *Camera Control* Camera rotate/zoom implemented, [here](http://www.songho.ca/opengl/gl_transform.html) is a good article which explained the theory of OpenGL Transformation. Most important is that the demo app is very beautiful. Added x,z axis, looks better than last screenshot. -I have to use the GLU library, the previous implementation of drawSphere and drawCylinder looks not good, and take too much time to debug. - +I have to use the GLU library, the previous implementation of drawSphere and drawCylinder looks not good, and take too much time to debug. + *B-Mesh data struct* -I created the test nodes's geometry information from Blender. Here is the render result of `data/bmesh_test_1.h` - +I created the test nodes's geometry information from Blender. Here is the render result of `data/bmesh_test_1.h` + +*Generate Inbetween Nodes* + - [ ] Export Wavefront .obj - [ ] Render B-Mesh result - [ ] Design UI for monster parts configuration diff --git a/data/bmesh_test_1.h b/data/bmesh_test_1.h index 32df44ff..937b74fd 100644 --- a/data/bmesh_test_1.h +++ b/data/bmesh_test_1.h @@ -1,9 +1,9 @@ -const float bmeshTest1Nodes[][4] = { - {0, -2.07575, 1.53902, 0.04122}, {1, 2.40837, 2.34882, 0.48585}, - {2, -0.91403, 0.77069, 0.62299}, {3, 2.25224, 0.74973, 0.85115}, - {4, 0, 0, 0}, - {5, 0.00920, -0.66115, -2.04601}, - {6, 0.01726, -0.88224, -2.87471} +const float bmeshTest1Nodes[][6] = { + {0, -2.07575, 1.53902, 0.04122, 0.25}, {1, 2.40837, 2.34882, 0.48585, 0.3}, + {2, -0.91403, 0.77069, 0.62299, 0.5}, {3, 2.25224, 0.74973, 0.85115, 0.5}, + {4, 0, 0, 0, 0.8, 1}, + {5, 0.00920, -0.66115, -2.04601, 0.5}, + {6, 0.01726, -0.88224, -2.87471, 0.2} }; const int bmeshTest1Edges[][2] = { diff --git a/screenshot/dust3d_bmesh_inbetween.png b/screenshot/dust3d_bmesh_inbetween.png new file mode 100644 index 00000000..af9b9885 Binary files /dev/null and b/screenshot/dust3d_bmesh_inbetween.png differ diff --git a/screenshot/dust3d_bmesh_skeleton.png b/screenshot/dust3d_bmesh_skeleton.png new file mode 100644 index 00000000..ab281741 Binary files /dev/null and b/screenshot/dust3d_bmesh_skeleton.png differ diff --git a/src/bmesh.c b/src/bmesh.c index e90de4cc..f136b9b4 100644 --- a/src/bmesh.c +++ b/src/bmesh.c @@ -73,3 +73,39 @@ int bmeshAddEdge(bmesh *bm, bmeshEdge *edge) { memcpy(arrayGetItem(bm->edgeArray, index), edge, sizeof(bmeshEdge)); return index; } + +static int bmeshAddInbetweenNodeBetween(bmesh *bm, + bmeshNode *firstNode, bmeshNode *secondNode, float frac) { + bmeshNode newNode; + memset(&newNode, 0, sizeof(newNode)); + newNode.type = BMESH_NODE_TYPE_INBETWEEN; + newNode.radius = firstNode->radius * (1 - frac) + + secondNode->radius * frac; + vec3Lerp(&firstNode->position, &secondNode->position, frac, + &newNode.position); + return bmeshAddNode(bm, &newNode); +} + +int bmeshGenerateInbetweenNodes(bmesh *bm) { + int edgeIdx; + for (edgeIdx = 0; edgeIdx < bmeshGetEdgeNum(bm); ++edgeIdx) { + bmeshEdge *edge = bmeshGetEdge(bm, edgeIdx); + bmeshNode *firstNode = bmeshGetNode(bm, edge->firstNode); + bmeshNode *secondNode = bmeshGetNode(bm, edge->secondNode); + float step = 0.5; + float distance = vec3Distance(&firstNode->position, &secondNode->position); + if (distance > 0) { + float offset = step; + if (offset + step <= distance) { + while (offset + step <= distance) { + float frac = offset / distance; + bmeshAddInbetweenNodeBetween(bm, firstNode, secondNode, frac); + offset += step; + } + } else if (distance > step) { + bmeshAddInbetweenNodeBetween(bm, firstNode, secondNode, 0.5); + } + } + } + return 0; +} diff --git a/src/bmesh.h b/src/bmesh.h index c7c22b32..83b8de8b 100644 --- a/src/bmesh.h +++ b/src/bmesh.h @@ -7,10 +7,10 @@ extern "C" { #endif typedef enum { - BMESH_NODE_FLAG_KEY = 0x00000001, - BMESH_NODE_FLAG_INBETWEEN = 0x00000002, - BMESH_NODE_FLAG_ROOT = 0x00000010, -} bmeshNodeFlag; + BMESH_NODE_TYPE_KEY = 0, + BMESH_NODE_TYPE_ROOT = 1, + BMESH_NODE_TYPE_INBETWEEN = 2, +} bmeshNodeType; typedef struct bmesh bmesh; @@ -18,7 +18,7 @@ typedef struct { int index; vec3 position; float radius; - unsigned int flag; + int type; } bmeshNode; typedef struct { @@ -35,6 +35,7 @@ bmeshNode *bmeshGetNode(bmesh *bm, int index); bmeshEdge *bmeshGetEdge(bmesh *bm, int index); int bmeshAddNode(bmesh *bm, bmeshNode *node); int bmeshAddEdge(bmesh *bm, bmeshEdge *edge); +int bmeshGenerateInbetweenNodes(bmesh *bm); #ifdef __cplusplus } diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 163a14f4..ce4872ae 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -6,7 +6,8 @@ MainWindow::MainWindow(void) { render = new Render; - resize(QDesktopWidget().availableGeometry(this).size() * 0.7); + int size = QDesktopWidget().availableGeometry(this).size().height() * 0.7; + resize(QSize(size, size)); QHBoxLayout *mainLayout = new QHBoxLayout; mainLayout->addWidget(render); setLayout(mainLayout); diff --git a/src/render.cpp b/src/render.cpp index 9fd51405..4c7a6cda 100644 --- a/src/render.cpp +++ b/src/render.cpp @@ -7,18 +7,24 @@ #include "bmesh.h" #include "matrix.h" +static const float bmeshNodeColors[][3] { + {0, 0.78, 1}, + {1, 0, 0}, + {1, 1, 1} +}; + +static const float bmeshEdgeColor[3] = {1, 1, 0}; + static QGLWidget *_this = 0; static int drawBmeshNode(bmesh *bm, bmeshNode *node) { - float color1[3] = {1, 0, 0}; - glColor3fv(color1); + glColor3fv(bmeshNodeColors[node->type]); drawSphere(&node->position, node->radius, 36, 24); return 0; } static int drawBmeshEdge(bmesh *bm, bmeshEdge *edge) { - float color2[3] = {1, 1, 0}; - glColor3fv(color2); + glColor3fv(bmeshEdgeColor); bmeshNode *firstNode = bmeshGetNode(bm, edge->firstNode); bmeshNode *secondNode = bmeshGetNode(bm, edge->secondNode); drawCylinder(&firstNode->position, &secondNode->position, 0.1, 36, 24); @@ -26,7 +32,10 @@ static int drawBmeshEdge(bmesh *bm, bmeshEdge *edge) { } int drawText(int x, int y, char *text) { - _this->renderText(x, y, QString(text)); + QFont font = QFont("Arial"); + font.setPointSize(9); + font.setBold(false); + _this->renderText(x, y, QString(text), font); return 0; } @@ -40,7 +49,7 @@ Render::Render(QWidget *parent) mouseY = 0; cameraAngleX = 20; cameraAngleY = -225; - cameraDistance = 3; + cameraDistance = 7; } Render::~Render(void) { @@ -99,8 +108,8 @@ void Render::paintGL() { glRotatef(cameraAngleY, 0, 1, 0); glColor3f(0, 0, 0); - drawPrintf(0, 10, "cameraAngleX:%f cameraAngleY:%f", cameraAngleX, - cameraAngleY); + drawPrintf(0, 10, "cameraAngleX:%f cameraAngleY:%f cameraDistance:%f", + cameraAngleX, cameraAngleY, cameraDistance); drawGrid(10, 1); @@ -117,7 +126,8 @@ void Render::paintGL() { node.position.x = bmeshTest1Nodes[i][1]; node.position.y = bmeshTest1Nodes[i][2]; node.position.z = bmeshTest1Nodes[i][3]; - node.radius = 0.35; + node.radius = bmeshTest1Nodes[i][4]; + node.type = bmeshTest1Nodes[i][5]; bmeshAddNode(bm, &node); } @@ -127,6 +137,8 @@ void Render::paintGL() { edge.secondNode = bmeshTest1Edges[i][1]; bmeshAddEdge(bm, &edge); } + + bmeshGenerateInbetweenNodes(bm); } { @@ -149,7 +161,7 @@ void Render::resizeGL(int w, int h) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); - gluPerspective(60.0f, w/(h/2.0f), 1, 100); + gluPerspective(60.0f, w/h, 1, 100); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); diff --git a/src/vector3d.c b/src/vector3d.c index 1be5570f..c8cb9845 100644 --- a/src/vector3d.c +++ b/src/vector3d.c @@ -1,3 +1,4 @@ +#include #include "vector3d.h" float vec3Length(vec3 *p) { @@ -18,9 +19,13 @@ void vec3Normalize(vec3 *p) { } void vec3Midpoint(vec3 *a, vec3 *b, vec3 *mid) { - mid->x = (a->x + b->x) * 0.5; - mid->y = (a->y + b->y) * 0.5; - mid->z = (a->z + b->z) * 0.5; + vec3Lerp(a, b, 0.5, mid); +} + +void vec3Lerp(vec3 *a, vec3 *b, float frac, vec3 *result) { + result->x = a->x + (b->x - a->x) * frac; + result->y = a->y + (b->y - a->y) * frac; + result->z = a->z + (b->z - a->z) * frac; } void vec3Sub(vec3 *a, vec3 *b, vec3 *result) { @@ -38,3 +43,9 @@ void vec3CrossProduct(vec3 *a, vec3 *b, vec3 *result) { float vec3DotProduct(vec3 *a, vec3 *b) { return a->x * b->x + a->y * b->y + a->z * b->z; } + +float vec3Distance(vec3 *a, vec3 *b) { + vec3 p; + vec3Sub(a, b, &p); + return vec3Length(&p); +} diff --git a/src/vector3d.h b/src/vector3d.h index 67f8d5c3..eea3d7fe 100644 --- a/src/vector3d.h +++ b/src/vector3d.h @@ -13,10 +13,12 @@ typedef struct { void vec3Normalize(vec3 *p); void vec3Midpoint(vec3 *a, vec3 *b, vec3 *mid); +void vec3Lerp(vec3 *a, vec3 *b, float frac, vec3 *result); void vec3CrossProduct(vec3 *a, vec3 *b, vec3 *result); void vec3Sub(vec3 *a, vec3 *b, vec3 *result); float vec3DotProduct(vec3 *a, vec3 *b); float vec3Length(vec3 *p); +float vec3Distance(vec3 *a, vec3 *b); #ifdef __cplusplus }