Update progress.
parent
32057f4e4d
commit
68cb7d499f
|
@ -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.
|
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 ~ 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*
|
*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.
|
||||||
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.
|
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.
|
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*
|
*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.
|
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.
|
||||||
<img src="screenshot/dust3d_convex_hull.png" width="124" height="128">
|
<img src="screenshot/dust3d_convex_hull.png" width="124" height="128">
|
||||||
*Stitching*
|
*Stitching*
|
||||||
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*
|
||||||
|
<img src="screenshot/dust3d_subdivide_catmull_clark.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.
|
||||||
- [ ] Export Wavefront .obj
|
- [ ] Export Wavefront .obj
|
||||||
- [ ] Render B-Mesh result
|
- [ ] Render B-Mesh result
|
||||||
- [ ] Design UI for monster parts configuration
|
- [ ] Design UI for monster parts configuration
|
||||||
|
|
|
@ -17,7 +17,8 @@ SOURCES += main.cpp \
|
||||||
matrix.c \
|
matrix.c \
|
||||||
convexhull.c \
|
convexhull.c \
|
||||||
hashtable.c \
|
hashtable.c \
|
||||||
osutil.cpp
|
osutil.cpp \
|
||||||
|
subdivide.c
|
||||||
|
|
||||||
HEADERS += mainwindow.h \
|
HEADERS += mainwindow.h \
|
||||||
render.h \
|
render.h \
|
||||||
|
@ -29,4 +30,5 @@ HEADERS += mainwindow.h \
|
||||||
convexhull.h \
|
convexhull.h \
|
||||||
hashtable.h \
|
hashtable.h \
|
||||||
3dstruct.h \
|
3dstruct.h \
|
||||||
osutil.h
|
osutil.h \
|
||||||
|
subdivide.h
|
|
@ -1,6 +1,7 @@
|
||||||
#ifndef _3DSTRUCT_H
|
#ifndef _3DSTRUCT_H
|
||||||
#define _3DSTRUCT_H
|
#define _3DSTRUCT_H
|
||||||
#include "vector3d.h"
|
#include "vector3d.h"
|
||||||
|
#include "array.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
vec3 pt[3];
|
vec3 pt[3];
|
||||||
|
|
|
@ -539,9 +539,8 @@ int convexHullMergeTriangles(convexHull *hull) {
|
||||||
e->score = (int)angle;
|
e->score = (int)angle;
|
||||||
//if (edgeIndex >= 12 && edgeIndex <= 12) {
|
//if (edgeIndex >= 12 && edgeIndex <= 12) {
|
||||||
// angle = (int)vec3Angle(&f1normal, &f2normal);
|
// angle = (int)vec3Angle(&f1normal, &f2normal);
|
||||||
// drawDebugPrintf("edgeIndex:%d angle:%f normal1:<%f,%f,%f> normal2:<%f,%f,%f>",
|
drawDebugPrintf("edgeIndex:%d angle:%f",
|
||||||
// edgeIndex, angle, f1normal.x, f1normal.y, f1normal.z,
|
edgeIndex, angle);
|
||||||
// f2normal.x, f2normal.y, f2normal.z);
|
|
||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -564,7 +563,7 @@ int convexHullMergeTriangles(convexHull *hull) {
|
||||||
convexHullFace *f2 = (convexHullFace *)arrayGetItem(hull->faceArray,
|
convexHullFace *f2 = (convexHullFace *)arrayGetItem(hull->faceArray,
|
||||||
e->face2);
|
e->face2);
|
||||||
if (3 == f1->vertexNum && 3 == f2->vertexNum) {
|
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]) {
|
while (e->p1 == f1->u.t.indices[0] || e->p2 == f1->u.t.indices[0]) {
|
||||||
rollTriangleIndices((face3 *)f1);
|
rollTriangleIndices((face3 *)f1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,18 +31,18 @@ hashtable *hashtableCreate(int bucketSize,
|
||||||
void *userData) {
|
void *userData) {
|
||||||
hashtable *ht = (hashtable *)calloc(1, sizeof(hashtable));
|
hashtable *ht = (hashtable *)calloc(1, sizeof(hashtable));
|
||||||
if (!ht) {
|
if (!ht) {
|
||||||
fprintf(stderr, "%s:Insufficient memory.", __FUNCTION__);
|
fprintf(stderr, "%s:Insufficient memory.\n", __FUNCTION__);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
ht->keyArray = arrayCreate(sizeof(hashtableKey));
|
ht->keyArray = arrayCreate(sizeof(hashtableKey));
|
||||||
if (!ht->keyArray) {
|
if (!ht->keyArray) {
|
||||||
fprintf(stderr, "%s:arrayCreate failed.", __FUNCTION__);
|
fprintf(stderr, "%s:arrayCreate failed.\n", __FUNCTION__);
|
||||||
hashtableDestroy(ht);
|
hashtableDestroy(ht);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
ht->entryArray = arrayCreate(sizeof(hashtableEntry));
|
ht->entryArray = arrayCreate(sizeof(hashtableEntry));
|
||||||
if (!ht->entryArray) {
|
if (!ht->entryArray) {
|
||||||
fprintf(stderr, "%s:arrayCreate failed.", __FUNCTION__);
|
fprintf(stderr, "%s:arrayCreate failed.\n", __FUNCTION__);
|
||||||
hashtableDestroy(ht);
|
hashtableDestroy(ht);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,7 @@ hashtable *hashtableCreate(int bucketSize,
|
||||||
ht->compareCallback = compareCallback;
|
ht->compareCallback = compareCallback;
|
||||||
ht->userData = userData;
|
ht->userData = userData;
|
||||||
if (0 != arraySetLength(ht->keyArray, bucketSize)) {
|
if (0 != arraySetLength(ht->keyArray, bucketSize)) {
|
||||||
fprintf(stderr, "%s:arraySetLength failed(bucketSize:%d).", __FUNCTION__,
|
fprintf(stderr, "%s:arraySetLength failed(bucketSize:%d).\n", __FUNCTION__,
|
||||||
bucketSize);
|
bucketSize);
|
||||||
hashtableDestroy(ht);
|
hashtableDestroy(ht);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -98,7 +98,7 @@ int hashtableInsert(hashtable *ht, const void *node) {
|
||||||
}
|
}
|
||||||
newEntryIndex = arrayGetLength(ht->entryArray);
|
newEntryIndex = arrayGetLength(ht->entryArray);
|
||||||
if (0 != arraySetLength(ht->entryArray, newEntryIndex + 1)) {
|
if (0 != arraySetLength(ht->entryArray, newEntryIndex + 1)) {
|
||||||
fprintf(stderr, "%s:arraySetLength failed(newEntryIndex:%d).",
|
fprintf(stderr, "%s:arraySetLength failed(newEntryIndex:%d).\n",
|
||||||
__FUNCTION__, newEntryIndex);
|
__FUNCTION__, newEntryIndex);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "bmesh.h"
|
#include "bmesh.h"
|
||||||
#include "matrix.h"
|
#include "matrix.h"
|
||||||
#include "vector3d.h"
|
#include "vector3d.h"
|
||||||
|
#include "subdivide.h"
|
||||||
|
|
||||||
static const float bmeshBallColors[][4] {
|
static const float bmeshBallColors[][4] {
|
||||||
{0.00, 0.78, 1.00, 0.5},
|
{0.00, 0.78, 1.00, 0.5},
|
||||||
|
@ -212,7 +213,7 @@ void Render::initializeGL() {
|
||||||
drawInit();
|
drawInit();
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "../data/bmesh_test_2.h"
|
#include "../data/bmesh_test_1.h"
|
||||||
|
|
||||||
void Render::paintGL() {
|
void Render::paintGL() {
|
||||||
bmesh *bm = 0;
|
bmesh *bm = 0;
|
||||||
|
@ -235,8 +236,17 @@ void Render::paintGL() {
|
||||||
drawGrid(10, 1);
|
drawGrid(10, 1);
|
||||||
|
|
||||||
glEnable(GL_LIGHTING);
|
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;
|
bmeshBall ball;
|
||||||
bmeshBone bone;
|
bmeshBone bone;
|
||||||
int i;
|
int i;
|
||||||
|
@ -264,50 +274,53 @@ void Render::paintGL() {
|
||||||
bmeshStitch(bm);
|
bmeshStitch(bm);
|
||||||
bmeshGenerateInbetweenMesh(bm);
|
bmeshGenerateInbetweenMesh(bm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (bm) {
|
||||||
|
|
||||||
drawBmeshBallRecursively(bm, bmeshGetRootBall(bm));
|
drawBmeshBallRecursively(bm, bmeshGetRootBall(bm));
|
||||||
|
|
||||||
//glBegin(GL_QUADS);
|
//glBegin(GL_QUADS);
|
||||||
drawBmeshBallQuadRecursively(bm, bmeshGetRootBall(bm));
|
drawBmeshBallQuadRecursively(bm, bmeshGetRootBall(bm));
|
||||||
//glEnd();
|
//glEnd();
|
||||||
|
|
||||||
{
|
{
|
||||||
int index;
|
int index;
|
||||||
/*
|
/*
|
||||||
for (index = 0; index < bmeshGetBallNum(bm); ++index) {
|
for (index = 0; index < bmeshGetBallNum(bm); ++index) {
|
||||||
bmeshBall *ball = bmeshGetBall(bm, index);
|
bmeshBall *ball = bmeshGetBall(bm, index);
|
||||||
drawBmeshBall(bm, ball);
|
drawBmeshBall(bm, ball);
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
for (index = 0; index < bmeshGetBoneNum(bm); ++index) {
|
for (index = 0; index < bmeshGetBoneNum(bm); ++index) {
|
||||||
bmeshBone *bone = bmeshGetBone(bm, index);
|
bmeshBone *bone = bmeshGetBone(bm, index);
|
||||||
drawBmeshBone(bm, bone);
|
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);
|
|
||||||
}
|
}
|
||||||
}
|
/*
|
||||||
glEnd();
|
glColor4f(1.0f, 1.0f, 1.0f, 0.5);
|
||||||
glColor3f(0.0f, 0.0f, 0.0f);
|
glBegin(GL_QUADS);
|
||||||
for (index = 0; index < bmeshGetQuadNum(bm); ++index) {
|
for (index = 0; index < bmeshGetQuadNum(bm); ++index) {
|
||||||
quad *q = bmeshGetQuad(bm, index);
|
quad *q = bmeshGetQuad(bm, index);
|
||||||
int j;
|
vec3 normal;
|
||||||
glBegin(GL_LINE_STRIP);
|
int j;
|
||||||
for (j = 0; j < 4; ++j) {
|
vec3Normal(&q->pt[0], &q->pt[1], &q->pt[2], &normal);
|
||||||
glVertex3f(q->pt[j].x, q->pt[j].y, q->pt[j].z);
|
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();
|
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();
|
glPopMatrix();
|
||||||
|
|
|
@ -137,3 +137,9 @@ float vec3TriangleArea(vec3 *a, vec3 *b, vec3 *c) {
|
||||||
vec3CrossProduct(&ab, &ac, &cross);
|
vec3CrossProduct(&ab, &ac, &cross);
|
||||||
return vec3Length(&cross) * 0.5;
|
return vec3Length(&cross) * 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void vec3Negative(vec3 *a, vec3 *result) {
|
||||||
|
result->x = -a->x;
|
||||||
|
result->y = -a->y;
|
||||||
|
result->z = -a->z;
|
||||||
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ void vec3RotateAlong(vec3 *a, float angle, vec3 *axis, vec3 *result);
|
||||||
float vec3Angle(vec3 *a, vec3 *b);
|
float vec3Angle(vec3 *a, vec3 *b);
|
||||||
void vec3ProjectOver(vec3 *a, vec3 *over, vec3 *result);
|
void vec3ProjectOver(vec3 *a, vec3 *over, vec3 *result);
|
||||||
float vec3TriangleArea(vec3 *a, vec3 *b, vec3 *c);
|
float vec3TriangleArea(vec3 *a, vec3 *b, vec3 *c);
|
||||||
|
void vec3Negative(vec3 *a, vec3 *result);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue