Я пытался реализовать алгоритм марширующих кубов с помощью C ++ и Qt. В любом случае, все шаги уже написаны, но я получаю действительно плохой результат. Я ищу ориентацию или советы о том, что может пойти не так. Я подозреваю, что одна из проблем может быть с воксельная концепция, конкретно о том, какая вершина идет в какой угол (0, 1, …, 7). Кроме того, я не уверен на 100% в том, как интерпретировать входные данные для алгоритма (я использую наборы данных). Должен ли я прочитать это в ZYX заказать и переместить движущийся куб таким же образом или это не имеет значения вообще? (Оставляя в стороне тот факт, что ни одно измерение не должно иметь одинаковый размер).
Вот что я получаю против того, как это должно выглядеть …
http://en.wikipedia.org/wiki/Marching_cubes
http://en.wikipedia.org/wiki/Marching_cubes#External_links
Пол Бурк «Обзор и исходный код».
http://paulbourke.net/geometry/polygonise/
Qt_MARCHING_CUBES.zip: пример Qt / OpenGL любезно предоставлен доктором Клаусом Мильтенбергером.
http://paulbourke.net/geometry/polygonise/Qt_MARCHING_CUBES.zip
Пример требует повышения, но похоже, что он, вероятно, должен работать.
В его примере это имеет в marchingcubes.cpp
Несколько разных методов расчета марширующих кубов: vMarchCube1
а также vMarchCube2
,
В комментариях говорится vMarchCube2
выполняет алгоритм Марширующих тетраэдров для одного куба, выполнив шесть вызовов vMarchTetrahedron.
Ниже приведен источник для первого vMarchCube1
:
//vMarchCube1 performs the Marching Cubes algorithm on a single cube
GLvoid GL_Widget::vMarchCube1(const GLfloat &fX, const GLfloat &fY, const GLfloat &fZ, const GLfloat &fScale, const GLfloat &fTv)
{
GLint iCorner, iVertex, iVertexTest, iEdge, iTriangle, iFlagIndex, iEdgeFlags;
GLfloat fOffset;
GLvector sColor;
GLfloat afCubeValue[8];
GLvector asEdgeVertex[12];
GLvector asEdgeNorm[12];
//Make a local copy of the values at the cube's corners
for(iVertex = 0; iVertex < 8; iVertex++)
{
afCubeValue[iVertex] = (this->*fSample)(fX + a2fVertexOffset[iVertex][0]*fScale,fY + a2fVertexOffset[iVertex][1]*fScale,fZ + a2fVertexOffset[iVertex][2]*fScale);
}
//Find which vertices are inside of the surface and which are outside
iFlagIndex = 0;
for(iVertexTest = 0; iVertexTest < 8; iVertexTest++)
{
if(afCubeValue[iVertexTest] <= fTv) iFlagIndex |= 1<<iVertexTest;
}
//Find which edges are intersected by the surface
iEdgeFlags = aiCubeEdgeFlags[iFlagIndex];
//If the cube is entirely inside or outside of the surface, then there will be no intersections
if(iEdgeFlags == 0)
{
return;
}
//Find the point of intersection of the surface with each edge
//Then find the normal to the surface at those points
for(iEdge = 0; iEdge < 12; iEdge++)
{
//if there is an intersection on this edge
if(iEdgeFlags & (1<<iEdge))
{
fOffset = fGetOffset(afCubeValue[ a2iEdgeConnection[iEdge][0] ],afCubeValue[ a2iEdgeConnection[iEdge][1] ], fTv);
asEdgeVertex[iEdge].fX = fX + (a2fVertexOffset[ a2iEdgeConnection[iEdge][0] ][0] + fOffset * a2fEdgeDirection[iEdge][0]) * fScale;
asEdgeVertex[iEdge].fY = fY + (a2fVertexOffset[ a2iEdgeConnection[iEdge][0] ][1] + fOffset * a2fEdgeDirection[iEdge][1]) * fScale;
asEdgeVertex[iEdge].fZ = fZ + (a2fVertexOffset[ a2iEdgeConnection[iEdge][0] ][2] + fOffset * a2fEdgeDirection[iEdge][2]) * fScale;
vGetNormal(asEdgeNorm[iEdge], asEdgeVertex[iEdge].fX, asEdgeVertex[iEdge].fY, asEdgeVertex[iEdge].fZ);
}
}//Draw the triangles that were found. There can be up to five per cube
for(iTriangle = 0; iTriangle < 5; iTriangle++)
{
if(a2iTriangleConnectionTable[iFlagIndex][3*iTriangle] < 0) break;
for(iCorner = 0; iCorner < 3; iCorner++)
{
iVertex = a2iTriangleConnectionTable[iFlagIndex][3*iTriangle+iCorner];
vGetColor(sColor, asEdgeVertex[iVertex], asEdgeNorm[iVertex]);
glColor4f(sColor.fX, sColor.fY, sColor.fZ, 0.6);
glNormal3f(asEdgeNorm[iVertex].fX, asEdgeNorm[iVertex].fY, asEdgeNorm[iVertex].fZ);
glVertex3f(asEdgeVertex[iVertex].fX, asEdgeVertex[iVertex].fY, asEdgeVertex[iVertex].fZ);
}
}
}
ОБНОВЛЕНИЕ: Github рабочий пример, проверено
https://github.com/peteristhegreat/qt-marching-cubes
Надеюсь, это поможет.
Наконец-то я обнаружил, что было не так.
Я использую класс индексатора VBO, чтобы уменьшить количество дублированных вершин и ускорить рендеринг. Этот класс реализован с помощью std :: map для поиска и удаления уже существующих вершин с использованием кортежа < vec3, неподписанный короткий >. Как вы можете себе представить, алгоритм движущихся кубов генерирует структуры с тысячами, если не миллионами вершин. Наибольшее число общего неподписанный короткий может держать это 65536, или 2 ^ 16. Таким образом, когда выходная геометрия имела больше, индекс карты начал переполняться, и в результате получился беспорядок, так как он начал перезаписывать вершины новыми. Я просто изменил свою реализацию, чтобы рисовать с обычным VBO и не индексировать, пока я исправляю свой класс для поддержки миллионов вершин.
Результат с некоторыми незначительными проблемами с вершинами говорит сам за себя:
http://i61.tinypic.com/fep2t3.jpg