History

Tweak to normal computation on dual contour surfaces.

Andrzej Kapolka committed 11 years ago

Commit 82fc75b1 parent b68c8361 file · +91 −109Browse files

Showing the changes to interface/src/MetavoxelSystem.cpp (1 of 1 file). Show all

Unified · Split

interface/src/MetavoxelSystem.cpp+91−109
@@ -1020,16 +1020,37 @@ public: · 1019 unmodified lines
10201020 glm::vec3 normal;
10211021 QRgb color;
10221022 char material;
1023− int axis;
10241023 };
10251024
1026−class AxisIndex {
1025+const int MAX_NORMALS_PER_VERTEX = 4;
1026+
1027+class NormalIndex {
10271028 public:
1028− int x, y, z;
1029+ int indices[MAX_NORMALS_PER_VERTEX];
10291030
1030− AxisIndex(int x = -1, int y = -1, int z = -1) : x(x), y(y), z(z) { }
1031+ int getClosestIndex(const glm::vec3& normal, QVector<VoxelPoint>& vertices) const;
10311032 };
10321033
1034+int NormalIndex::getClosestIndex(const glm::vec3& normal, QVector<VoxelPoint>& vertices) const {
1035+ int firstIndex = indices[0];
1036+ int closestIndex = firstIndex;
1037+ const VoxelPoint& firstVertex = vertices.at(firstIndex);
1038+ float closest = normal.x * firstVertex.normal[0] + normal.y * firstVertex.normal[1] + normal.z * firstVertex.normal[2];
1039+ for (int i = 1; i < MAX_NORMALS_PER_VERTEX; i++) {
1040+ int index = indices[i];
1041+ if (index == firstIndex) {
1042+ break;
1043+ }
1044+ const VoxelPoint& vertex = vertices.at(index);
1045+ float product = normal.x * vertex.normal[0] + normal.y * vertex.normal[1] + normal.z * vertex.normal[2];
1046+ if (product > closest) {
1047+ closest = product;
1048+ closestIndex = index;
1049+ }
1050+ }
1051+ return closestIndex;
1052+}
1053+
10331054 static glm::vec3 safeNormalize(const glm::vec3& vector) {
10341055 float length = glm::length(vector);
10351056 return (length > 0.0f) ? (vector / length) : vector;
@@ -1075,10 +1096,10 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) { · 39 unmodified lines
10751096 // as we scan down the cube generating vertices between grid points, we remember the indices of the last
10761097 // (element, line, section--x, y, z) so that we can connect generated vertices as quads
10771098 int expanded = size + 1;
1078− QVector<AxisIndex> lineIndices(expanded);
1079− QVector<AxisIndex> lastLineIndices(expanded);
1080− QVector<AxisIndex> planeIndices(expanded * expanded);
1081− QVector<AxisIndex> lastPlaneIndices(expanded * expanded);
1099+ QVector<NormalIndex> lineIndices(expanded);
1100+ QVector<NormalIndex> lastLineIndices(expanded);
1101+ QVector<NormalIndex> planeIndices(expanded * expanded);
1102+ QVector<NormalIndex> lastPlaneIndices(expanded * expanded);
10821103
10831104 const int EDGES_PER_CUBE = 12;
10841105 EdgeCrossing crossings[EDGES_PER_CUBE];
@@ -1090,7 +1111,7 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) { · 5 unmodified lines
10901111 for (int z = 0; z < expanded; z++) {
10911112 const QRgb* colorY = colorZ;
10921113 for (int y = 0; y < expanded; y++) {
1093− AxisIndex lastIndex;
1114+ NormalIndex lastIndex;
10941115 const QRgb* colorX = colorY;
10951116 for (int x = 0; x < expanded; x++) {
10961117 int alpha0 = colorX[0] >> ALPHA_OFFSET;
@@ -1165,7 +1186,6 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) { · 68 unmodified lines
11651186 crossing.material = materialBase ? materialBase[0] : 0;
11661187 }
11671188 crossing.point = glm::vec3(qAlpha(hermite) * EIGHT_BIT_MAXIMUM_RECIPROCAL, 0.0f, 0.0f);
1168− crossing.axis = 0;
11691189 }
11701190 if (middleY) {
11711191 if (alpha1 != alpha3) {
@@ -1180,7 +1200,6 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) { · 8 unmodified lines
11801200 crossing.material = materialBase ? materialBase[1] : 0;
11811201 }
11821202 crossing.point = glm::vec3(1.0f, qAlpha(hermite) * EIGHT_BIT_MAXIMUM_RECIPROCAL, 0.0f);
1183− crossing.axis = 1;
11841203 }
11851204 if (alpha2 != alpha3) {
11861205 QRgb hermite = hermiteBase[hermiteStride];
@@ -1194,7 +1213,6 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) { · 7 unmodified lines
11941213 crossing.material = materialBase ? materialBase[size] : 0;
11951214 }
11961215 crossing.point = glm::vec3(qAlpha(hermite) * EIGHT_BIT_MAXIMUM_RECIPROCAL, 1.0f, 0.0f);
1197− crossing.axis = 0;
11981216 }
11991217 if (middleZ) {
12001218 if (alpha3 != alpha7) {
@@ -1209,7 +1227,6 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) { · 8 unmodified lines
12091227 crossing.material = materialBase ? materialBase[offset3] : 0;
12101228 }
12111229 crossing.point = glm::vec3(1.0f, 1.0f, qAlpha(hermite) * EIGHT_BIT_MAXIMUM_RECIPROCAL);
1212− crossing.axis = 2;
12131230 }
12141231 if (alpha5 != alpha7) {
12151232 QRgb hermite = hermiteBase[hermiteArea + VoxelHermiteData::EDGE_COUNT + 1];
@@ -1223,7 +1240,6 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) { · 7 unmodified lines
12231240 crossing.material = materialBase ? materialBase[offset5] : 0;
12241241 }
12251242 crossing.point = glm::vec3(1.0f, qAlpha(hermite) * EIGHT_BIT_MAXIMUM_RECIPROCAL, 1.0f);
1226− crossing.axis = 1;
12271243 }
12281244 if (alpha6 != alpha7) {
12291245 QRgb hermite = hermiteBase[hermiteArea + hermiteStride];
@@ -1237,7 +1253,6 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) { · 7 unmodified lines
12371253 crossing.material = materialBase ? materialBase[offset6] : 0;
12381254 }
12391255 crossing.point = glm::vec3(qAlpha(hermite) * EIGHT_BIT_MAXIMUM_RECIPROCAL, 1.0f, 1.0f);
1240− crossing.axis = 0;
12411256 }
12421257 }
12431258 }
@@ -1254,7 +1269,6 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) { · 10 unmodified lines
12541269 crossing.material = materialBase ? materialBase[1] : 0;
12551270 }
12561271 crossing.point = glm::vec3(1.0f, 0.0f, qAlpha(hermite) * EIGHT_BIT_MAXIMUM_RECIPROCAL);
1257− crossing.axis = 2;
12581272 }
12591273 if (alpha4 != alpha5) {
12601274 QRgb hermite = hermiteBase[hermiteArea];
@@ -1268,7 +1282,6 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) { · 7 unmodified lines
12681282 crossing.material = materialBase ? materialBase[area] : 0;
12691283 }
12701284 crossing.point = glm::vec3(qAlpha(hermite) * EIGHT_BIT_MAXIMUM_RECIPROCAL, 0.0f, 1.0f);
1271− crossing.axis = 0;
12721285 }
12731286 }
12741287 }
@@ -1285,7 +1298,6 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) { · 10 unmodified lines
12851298 crossing.material = materialBase ? materialBase[0] : 0;
12861299 }
12871300 crossing.point = glm::vec3(0.0f, qAlpha(hermite) * EIGHT_BIT_MAXIMUM_RECIPROCAL, 0.0f);
1288− crossing.axis = 1;
12891301 }
12901302 if (middleZ) {
12911303 if (alpha2 != alpha6) {
@@ -1300,7 +1312,6 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) { · 8 unmodified lines
13001312 crossing.material = materialBase ? materialBase[size] : 0;
13011313 }
13021314 crossing.point = glm::vec3(0.0f, 1.0f, qAlpha(hermite) * EIGHT_BIT_MAXIMUM_RECIPROCAL);
1303− crossing.axis = 2;
13041315 }
13051316 if (alpha4 != alpha6) {
13061317 QRgb hermite = hermiteBase[hermiteArea + 1];
@@ -1314,7 +1325,6 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) { · 7 unmodified lines
13141325 crossing.material = materialBase ? materialBase[area] : 0;
13151326 }
13161327 crossing.point = glm::vec3(0.0f, qAlpha(hermite) * EIGHT_BIT_MAXIMUM_RECIPROCAL, 1.0f);
1317− crossing.axis = 1;
13181328 }
13191329 }
13201330 }
@@ -1330,12 +1340,13 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) { · 9 unmodified lines
13301340 crossing.material = materialBase ? materialBase[0] : 0;
13311341 }
13321342 crossing.point = glm::vec3(0.0f, 0.0f, qAlpha(hermite) * EIGHT_BIT_MAXIMUM_RECIPROCAL);
1333− crossing.axis = 2;
13341343 }
13351344 // at present, we simply average the properties of each crossing as opposed to finding the vertex that
13361345 // minimizes the quadratic error function as described in the reference paper
13371346 glm::vec3 center;
1338− glm::vec3 axisNormals[3];
1347+ glm::vec3 normals[MAX_NORMALS_PER_VERTEX];
1348+ int normalCount = 0;
1349+ const float CREASE_COS_NORMAL = glm::cos(glm::radians(40.0f));
13391350 const int MAX_MATERIALS_PER_VERTEX = 4;
13401351 quint8 materials[] = { 0, 0, 0, 0 };
13411352 glm::vec4 materialWeights;
@@ -1344,7 +1355,18 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) { · 2 unmodified lines
13441355 for (int i = 0; i < crossingCount; i++) {
13451356 const EdgeCrossing& crossing = crossings[i];
13461357 center += crossing.point;
1347− axisNormals[crossing.axis] += crossing.normal;
1358+
1359+ int j = 0;
1360+ for (; j < normalCount; j++) {
1361+ if (glm::dot(normals[j], crossing.normal) > CREASE_COS_NORMAL) {
1362+ normals[j] = safeNormalize(normals[j] + crossing.normal);
1363+ break;
1364+ }
1365+ }
1366+ if (j == normalCount) {
1367+ normals[normalCount++] = crossing.normal;
1368+ }
1369+
13481370 red += qRed(crossing.color);
13491371 green += qGreen(crossing.color);
13501372 blue += qBlue(crossing.color);
@@ -1359,7 +1381,7 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) { · 8 unmodified lines
13591381 // when assigning a material, search for its presence and, if not found,
13601382 // place it in the first empty slot
13611383 if (crossing.material != 0) {
1362− for (int j = 0; j < MAX_MATERIALS_PER_VERTEX; j++) {
1384+ for (j = 0; j < MAX_MATERIALS_PER_VERTEX; j++) {
13631385 if (materials[j] == crossing.material) {
13641386 materialWeights[j] += 1.0f;
13651387 totalWeight += 1.0f;
@@ -1374,18 +1396,15 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) { · 8 unmodified lines
13741396 }
13751397 }
13761398 }
1377− glm::vec3 normal = safeNormalize(axisNormals[0] + axisNormals[1] + axisNormals[2]);
13781399 center /= crossingCount;
13791400
13801401 // use a sequence of Givens rotations to perform a QR decomposition
13811402 // see http://www.cs.rice.edu/~jwarren/papers/techreport02408.pdf
13821403 glm::mat4 r(0.0f);
13831404 glm::vec4 bottom;
1384− float smallestCosNormal = 1.0f;
13851405 for (int i = 0; i < crossingCount; i++) {
13861406 const EdgeCrossing& crossing = crossings[i];
13871407 bottom = glm::vec4(crossing.normal, glm::dot(crossing.normal, crossing.point - center));
1388− smallestCosNormal = qMin(smallestCosNormal, glm::dot(crossing.normal, normal));
13891408
13901409 for (int j = 0; j < 4; j++) {
13911410 float angle = glm::atan(-bottom[j], r[j][j]);
@@ -1450,63 +1469,17 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) { · 58 unmodified lines
14501469 }
14511470 VoxelPoint point = { info.minimum + (glm::vec3(clampedX, clampedY, clampedZ) + center) * scale,
14521471 { (quint8)(red / crossingCount), (quint8)(green / crossingCount), (quint8)(blue / crossingCount) },
1453− { (char)(normal.x * 127.0f), (char)(normal.y * 127.0f), (char)(normal.z * 127.0f) },
1472+ { (char)(normals[0].x * 127.0f), (char)(normals[0].y * 127.0f), (char)(normals[0].z * 127.0f) },
14541473 { materials[0], materials[1], materials[2], materials[3] },
14551474 { (quint8)materialWeights[0], (quint8)materialWeights[1], (quint8)materialWeights[2],
14561475 (quint8)materialWeights[3] } };
14571476
1458− // determine whether we must "crease" by generating directional normals
1459− const float CREASE_COS_NORMAL = glm::cos(glm::radians(40.0f));
1460− AxisIndex index(vertices.size(), vertices.size(), vertices.size());
1461− if (smallestCosNormal > CREASE_COS_NORMAL) {
1477+ NormalIndex index = { { vertices.size(), vertices.size(), vertices.size(), vertices.size() } };
1478+ vertices.append(point);
1479+ for (int i = 1; i < normalCount; i++) {
1480+ index.indices[i] = vertices.size();
1481+ point.setNormal(normals[i]);
14621482 vertices.append(point);
1463−
1464− } else {
1465− axisNormals[0] = safeNormalize(axisNormals[0]);
1466− axisNormals[1] = safeNormalize(axisNormals[1]);
1467− axisNormals[2] = safeNormalize(axisNormals[2]);
1468− glm::vec3 normalXY(safeNormalize(axisNormals[0] + axisNormals[1]));
1469− glm::vec3 normalXZ(safeNormalize(axisNormals[0] + axisNormals[2]));
1470− glm::vec3 normalYZ(safeNormalize(axisNormals[1] + axisNormals[2]));
1471− if (glm::dot(axisNormals[0], normalXY) > CREASE_COS_NORMAL &&
1472− glm::dot(axisNormals[1], normalXY) > CREASE_COS_NORMAL) {
1473− point.setNormal(normalXY);
1474− vertices.append(point);
1475−
1476− point.setNormal(axisNormals[2]);
1477− index.z = vertices.size();
1478− vertices.append(point);
1479−
1480− } else if (glm::dot(axisNormals[0], normalXZ) > CREASE_COS_NORMAL &&
1481− glm::dot(axisNormals[2], normalXZ) > CREASE_COS_NORMAL) {
1482− point.setNormal(normalXZ);
1483− vertices.append(point);
1484−
1485− point.setNormal(axisNormals[1]);
1486− index.y = vertices.size();
1487− vertices.append(point);
1488−
1489− } else if (glm::dot(axisNormals[1], normalYZ) > CREASE_COS_NORMAL &&
1490− glm::dot(axisNormals[2], normalYZ) > CREASE_COS_NORMAL) {
1491− point.setNormal(normalYZ);
1492− vertices.append(point);
1493−
1494− point.setNormal(axisNormals[0]);
1495− index.x = vertices.size();
1496− vertices.append(point);
1497−
1498− } else {
1499− point.setNormal(axisNormals[0]);
1500− vertices.append(point);
1501−
1502− point.setNormal(axisNormals[1]);
1503− index.y = vertices.size();
1504− vertices.append(point);
1505−
1506− point.setNormal(axisNormals[2]);
1507− index.z = vertices.size();
1508− vertices.append(point);
1509− }
15101483 }
15111484
15121485 // the first x, y, and z are repeated for the boundary edge; past that, we consider generating
@@ -1517,19 +1490,22 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) { · 4 unmodified lines
15171490 quadIndices.insert(qRgb(x, y - 1, z), indices.size());
15181491 quadIndices.insert(qRgb(x, y - 1, z - 1), indices.size());
15191492 quadIndices.insert(qRgb(x, y, z - 1), indices.size());
1520− indices.append(index.x);
1521− int index1 = lastLineIndices.at(x).x;
1522− int index2 = lastPlaneIndices.at((y - 1) * expanded + x).x;
1523− int index3 = lastPlaneIndices.at(y * expanded + x).x;
1493+
1494+ glm::vec3 normal(1.0f, 0.0f, 0.0f);
1495+
1496+ const NormalIndex& index1 = lastLineIndices.at(x);
1497+ const NormalIndex& index2 = lastPlaneIndices.at((y - 1) * expanded + x);
1498+ const NormalIndex& index3 = lastPlaneIndices.at(y * expanded + x);
15241499 if (alpha0 == 0) { // quad faces negative x
1525− indices.append(index3);
1526− indices.append(index2);
1527− indices.append(index1);
1500+ indices.append(index3.getClosestIndex(normal = -normal, vertices));
1501+ indices.append(index2.getClosestIndex(normal, vertices));
1502+ indices.append(index1.getClosestIndex(normal, vertices));
15281503 } else { // quad faces positive x
1529− indices.append(index1);
1530− indices.append(index2);
1531− indices.append(index3);
1504+ indices.append(index1.getClosestIndex(normal, vertices));
1505+ indices.append(index2.getClosestIndex(normal, vertices));
1506+ indices.append(index3.getClosestIndex(normal, vertices));
15321507 }
1508+ indices.append(index.getClosestIndex(normal, vertices));
15331509 }
15341510
15351511 if (alpha0 != alpha2) {
@@ -1537,19 +1513,22 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) { · 1 unmodified line
15371513 quadIndices.insert(qRgb(x - 1, y, z), indices.size());
15381514 quadIndices.insert(qRgb(x - 1, y, z - 1), indices.size());
15391515 quadIndices.insert(qRgb(x, y, z - 1), indices.size());
1540− indices.append(index.y);
1541− int index1 = lastIndex.y;
1542− int index2 = lastPlaneIndices.at(y * expanded + x - 1).y;
1543− int index3 = lastPlaneIndices.at(y * expanded + x).y;
1516+
1517+ glm::vec3 normal(0.0f, 1.0f, 0.0f);
1518+
1519+ const NormalIndex& index1 = lastIndex;
1520+ const NormalIndex& index2 = lastPlaneIndices.at(y * expanded + x - 1);
1521+ const NormalIndex& index3 = lastPlaneIndices.at(y * expanded + x);
15441522 if (alpha0 == 0) { // quad faces negative y
1545− indices.append(index1);
1546− indices.append(index2);
1547− indices.append(index3);
1523+ indices.append(index1.getClosestIndex(normal = -normal, vertices));
1524+ indices.append(index2.getClosestIndex(normal, vertices));
1525+ indices.append(index3.getClosestIndex(normal, vertices));
15481526 } else { // quad faces positive y
1549− indices.append(index3);
1550− indices.append(index2);
1551− indices.append(index1);
1527+ indices.append(index3.getClosestIndex(normal, vertices));
1528+ indices.append(index2.getClosestIndex(normal, vertices));
1529+ indices.append(index1.getClosestIndex(normal, vertices));
15521530 }
1531+ indices.append(index.getClosestIndex(normal, vertices));
15531532 }
15541533
15551534 if (alpha0 != alpha4) {
@@ -1557,19 +1536,22 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) { · 1 unmodified line
15571536 quadIndices.insert(qRgb(x - 1, y, z), indices.size());
15581537 quadIndices.insert(qRgb(x - 1, y - 1, z), indices.size());
15591538 quadIndices.insert(qRgb(x, y - 1, z), indices.size());
1560− indices.append(index.z);
1561− int index1 = lastIndex.z;
1562− int index2 = lastLineIndices.at(x - 1).z;
1563− int index3 = lastLineIndices.at(x).z;
1539+
1540+ glm::vec3 normal(0.0f, 0.0f, 1.0f);
1541+
1542+ const NormalIndex& index1 = lastIndex;
1543+ const NormalIndex& index2 = lastLineIndices.at(x - 1);
1544+ const NormalIndex& index3 = lastLineIndices.at(x);
15641545 if (alpha0 == 0) { // quad faces negative z
1565− indices.append(index3);
1566− indices.append(index2);
1567− indices.append(index1);
1546+ indices.append(index3.getClosestIndex(normal = -normal, vertices));
1547+ indices.append(index2.getClosestIndex(normal, vertices));
1548+ indices.append(index1.getClosestIndex(normal, vertices));
15681549 } else { // quad faces positive z
1569− indices.append(index1);
1570− indices.append(index2);
1571− indices.append(index3);
1550+ indices.append(index1.getClosestIndex(normal, vertices));
1551+ indices.append(index2.getClosestIndex(normal, vertices));
1552+ indices.append(index3.getClosestIndex(normal, vertices));
15721553 }
1554+ indices.append(index.getClosestIndex(normal, vertices));
15731555 }
15741556 }
15751557 lastIndex = index;