|
@@ -1,5 +1,9 @@
|
|
|
-var BABYLON;
|
|
|
+var BABYLON;
|
|
|
(function (BABYLON) {
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
var SimplificationSettings = (function () {
|
|
|
function SimplificationSettings(quality, distance) {
|
|
|
this.quality = quality;
|
|
@@ -8,14 +12,16 @@ var BABYLON;
|
|
|
return SimplificationSettings;
|
|
|
})();
|
|
|
BABYLON.SimplificationSettings = SimplificationSettings;
|
|
|
+
|
|
|
/**
|
|
|
- * The implemented types of simplification.
|
|
|
- * At the moment only Quadratic Error Decimation is implemented.
|
|
|
- */
|
|
|
+ * The implemented types of simplification.
|
|
|
+ * At the moment only Quadratic Error Decimation is implemented.
|
|
|
+ */
|
|
|
(function (SimplificationType) {
|
|
|
SimplificationType[SimplificationType["QUADRATIC"] = 0] = "QUADRATIC";
|
|
|
})(BABYLON.SimplificationType || (BABYLON.SimplificationType = {}));
|
|
|
var SimplificationType = BABYLON.SimplificationType;
|
|
|
+
|
|
|
var DecimationTriangle = (function () {
|
|
|
function DecimationTriangle(vertices) {
|
|
|
this.vertices = vertices;
|
|
@@ -27,6 +33,7 @@ var BABYLON;
|
|
|
return DecimationTriangle;
|
|
|
})();
|
|
|
BABYLON.DecimationTriangle = DecimationTriangle;
|
|
|
+
|
|
|
var DecimationVertex = (function () {
|
|
|
function DecimationVertex(position, normal, uv, id) {
|
|
|
this.position = position;
|
|
@@ -41,14 +48,14 @@ var BABYLON;
|
|
|
return DecimationVertex;
|
|
|
})();
|
|
|
BABYLON.DecimationVertex = DecimationVertex;
|
|
|
+
|
|
|
var QuadraticMatrix = (function () {
|
|
|
function QuadraticMatrix(data) {
|
|
|
this.data = new Array(10);
|
|
|
for (var i = 0; i < 10; ++i) {
|
|
|
if (data && data[i]) {
|
|
|
this.data[i] = data[i];
|
|
|
- }
|
|
|
- else {
|
|
|
+ } else {
|
|
|
this.data[i] = 0;
|
|
|
}
|
|
|
}
|
|
@@ -57,16 +64,19 @@ var BABYLON;
|
|
|
var det = this.data[a11] * this.data[a22] * this.data[a33] + this.data[a13] * this.data[a21] * this.data[a32] + this.data[a12] * this.data[a23] * this.data[a31] - this.data[a13] * this.data[a22] * this.data[a31] - this.data[a11] * this.data[a23] * this.data[a32] - this.data[a12] * this.data[a21] * this.data[a33];
|
|
|
return det;
|
|
|
};
|
|
|
+
|
|
|
QuadraticMatrix.prototype.addInPlace = function (matrix) {
|
|
|
for (var i = 0; i < 10; ++i) {
|
|
|
this.data[i] += matrix.data[i];
|
|
|
}
|
|
|
};
|
|
|
+
|
|
|
QuadraticMatrix.prototype.addArrayInPlace = function (data) {
|
|
|
for (var i = 0; i < 10; ++i) {
|
|
|
this.data[i] += data[i];
|
|
|
}
|
|
|
};
|
|
|
+
|
|
|
QuadraticMatrix.prototype.add = function (matrix) {
|
|
|
var m = new QuadraticMatrix();
|
|
|
for (var i = 0; i < 10; ++i) {
|
|
@@ -74,9 +84,11 @@ var BABYLON;
|
|
|
}
|
|
|
return m;
|
|
|
};
|
|
|
+
|
|
|
QuadraticMatrix.FromData = function (a, b, c, d) {
|
|
|
return new QuadraticMatrix(QuadraticMatrix.DataFromNumbers(a, b, c, d));
|
|
|
};
|
|
|
+
|
|
|
//returning an array to avoid garbage collection
|
|
|
QuadraticMatrix.DataFromNumbers = function (a, b, c, d) {
|
|
|
return [a * a, a * b, a * c, a * d, b * b, b * c, b * d, c * c, c * d, d * d];
|
|
@@ -84,6 +96,7 @@ var BABYLON;
|
|
|
return QuadraticMatrix;
|
|
|
})();
|
|
|
BABYLON.QuadraticMatrix = QuadraticMatrix;
|
|
|
+
|
|
|
var Reference = (function () {
|
|
|
function Reference(vertexId, triangleId) {
|
|
|
this.vertexId = vertexId;
|
|
@@ -92,12 +105,13 @@ var BABYLON;
|
|
|
return Reference;
|
|
|
})();
|
|
|
BABYLON.Reference = Reference;
|
|
|
+
|
|
|
/**
|
|
|
- * An implementation of the Quadratic Error simplification algorithm.
|
|
|
- * Original paper : http://www1.cs.columbia.edu/~cs4162/html05s/garland97.pdf
|
|
|
- * Ported mostly from QSlim and http://voxels.blogspot.de/2014/05/quadric-mesh-simplification-with-source.html to babylon JS
|
|
|
- * @author RaananW
|
|
|
- */
|
|
|
+ * An implementation of the Quadratic Error simplification algorithm.
|
|
|
+ * Original paper : http://www1.cs.columbia.edu/~cs4162/html05s/garland97.pdf
|
|
|
+ * Ported mostly from QSlim and http://voxels.blogspot.de/2014/05/quadric-mesh-simplification-with-source.html to babylon JS
|
|
|
+ * @author RaananW
|
|
|
+ */
|
|
|
var QuadraticErrorSimplification = (function () {
|
|
|
function QuadraticErrorSimplification(_mesh) {
|
|
|
this._mesh = _mesh;
|
|
@@ -112,20 +126,26 @@ var BABYLON;
|
|
|
_this.runDecimation(settings, successCallback);
|
|
|
});
|
|
|
};
|
|
|
+
|
|
|
QuadraticErrorSimplification.prototype.runDecimation = function (settings, successCallback) {
|
|
|
var _this = this;
|
|
|
var targetCount = ~~(this.triangles.length * settings.quality);
|
|
|
var deletedTriangles = 0;
|
|
|
+
|
|
|
var triangleCount = this.triangles.length;
|
|
|
+
|
|
|
var iterationFunction = function (iteration, callback) {
|
|
|
setTimeout(function () {
|
|
|
if (iteration % 5 === 0) {
|
|
|
_this.updateMesh(iteration === 0);
|
|
|
}
|
|
|
+
|
|
|
for (var i = 0; i < _this.triangles.length; ++i) {
|
|
|
_this.triangles[i].isDirty = false;
|
|
|
}
|
|
|
+
|
|
|
var threshold = 0.000000001 * Math.pow((iteration + 3), _this.aggressiveness);
|
|
|
+
|
|
|
var trianglesIterator = function (i) {
|
|
|
var tIdx = ((_this.triangles.length / 2) + i) % _this.triangles.length;
|
|
|
var t = _this.triangles[tIdx];
|
|
@@ -138,38 +158,47 @@ var BABYLON;
|
|
|
if (t.error[j] < threshold) {
|
|
|
var deleted0 = [];
|
|
|
var deleted1 = [];
|
|
|
+
|
|
|
var i0 = t.vertices[j];
|
|
|
var i1 = t.vertices[(j + 1) % 3];
|
|
|
var v0 = _this.vertices[i0];
|
|
|
var v1 = _this.vertices[i1];
|
|
|
+
|
|
|
if (v0.isBorder !== v1.isBorder)
|
|
|
continue;
|
|
|
+
|
|
|
var p = BABYLON.Vector3.Zero();
|
|
|
var n = BABYLON.Vector3.Zero();
|
|
|
var uv = BABYLON.Vector2.Zero();
|
|
|
+
|
|
|
_this.calculateError(v0, v1, p, n, uv);
|
|
|
+
|
|
|
if (_this.isFlipped(v0, i1, p, deleted0, t.borderFactor))
|
|
|
continue;
|
|
|
if (_this.isFlipped(v1, i0, p, deleted1, t.borderFactor))
|
|
|
continue;
|
|
|
+
|
|
|
v0.position = p;
|
|
|
v0.normal = n;
|
|
|
v0.uv = uv;
|
|
|
v0.q = v1.q.add(v0.q);
|
|
|
var tStart = _this.references.length;
|
|
|
+
|
|
|
deletedTriangles = _this.updateTriangles(v0.id, v0, deleted0, deletedTriangles);
|
|
|
deletedTriangles = _this.updateTriangles(v0.id, v1, deleted1, deletedTriangles);
|
|
|
+
|
|
|
var tCount = _this.references.length - tStart;
|
|
|
+
|
|
|
if (tCount <= v0.triangleCount) {
|
|
|
if (tCount) {
|
|
|
for (var c = 0; c < tCount; c++) {
|
|
|
_this.references[v0.triangleStart + c] = _this.references[tStart + c];
|
|
|
}
|
|
|
}
|
|
|
- }
|
|
|
- else {
|
|
|
+ } else {
|
|
|
v0.triangleStart = tStart;
|
|
|
}
|
|
|
+
|
|
|
v0.triangleCount = tCount;
|
|
|
break;
|
|
|
}
|
|
@@ -180,6 +209,7 @@ var BABYLON;
|
|
|
});
|
|
|
}, 0);
|
|
|
};
|
|
|
+
|
|
|
BABYLON.AsyncLoop.Run(this.decimationIterations, function (loop) {
|
|
|
if (triangleCount - deletedTriangles <= targetCount)
|
|
|
loop.breakLoop();
|
|
@@ -194,27 +224,30 @@ var BABYLON;
|
|
|
}, 0);
|
|
|
});
|
|
|
};
|
|
|
+
|
|
|
QuadraticErrorSimplification.prototype.initWithMesh = function (mesh, callback) {
|
|
|
var _this = this;
|
|
|
if (!mesh)
|
|
|
return;
|
|
|
+
|
|
|
this.vertices = [];
|
|
|
this.triangles = [];
|
|
|
+
|
|
|
this._mesh = mesh;
|
|
|
+
|
|
|
//It is assumed that a mesh has positions, normals and either uvs or colors.
|
|
|
var positionData = this._mesh.getVerticesData(BABYLON.VertexBuffer.PositionKind);
|
|
|
var normalData = this._mesh.getVerticesData(BABYLON.VertexBuffer.NormalKind);
|
|
|
var uvs = this._mesh.getVerticesData(BABYLON.VertexBuffer.UVKind);
|
|
|
var colorsData = this._mesh.getVerticesData(BABYLON.VertexBuffer.ColorKind);
|
|
|
var indices = mesh.getIndices();
|
|
|
+
|
|
|
var vertexInit = function (i) {
|
|
|
- var uv;
|
|
|
- if (uvs[i * 2]) {
|
|
|
- uv = BABYLON.Vector2.FromArray(uvs, i * 2);
|
|
|
- }
|
|
|
- var vertex = new DecimationVertex(BABYLON.Vector3.FromArray(positionData, i * 3), BABYLON.Vector3.FromArray(normalData, i * 3), uv, i);
|
|
|
- if (!uv && colorsData[i * 3]) {
|
|
|
- vertex.color = BABYLON.Color3.FromArray(colorsData, i * 3);
|
|
|
+ var vertex = new DecimationVertex(BABYLON.Vector3.FromArray(positionData, i * 3), BABYLON.Vector3.FromArray(normalData, i * 3), null, i);
|
|
|
+ if (_this._mesh.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) {
|
|
|
+ vertex.uv = BABYLON.Vector2.FromArray(uvs, i * 2);
|
|
|
+ } else if (_this._mesh.isVerticesDataPresent(BABYLON.VertexBuffer.ColorKind)) {
|
|
|
+ vertex.color = BABYLON.Color4.FromArray(colorsData, i * 4);
|
|
|
}
|
|
|
_this.vertices.push(vertex);
|
|
|
};
|
|
@@ -233,6 +266,7 @@ var BABYLON;
|
|
|
});
|
|
|
});
|
|
|
};
|
|
|
+
|
|
|
QuadraticErrorSimplification.prototype.init = function (callback) {
|
|
|
var _this = this;
|
|
|
var triangleInit1 = function (i) {
|
|
@@ -256,6 +290,7 @@ var BABYLON;
|
|
|
});
|
|
|
});
|
|
|
};
|
|
|
+
|
|
|
QuadraticErrorSimplification.prototype.reconstructMesh = function () {
|
|
|
var newTriangles = [];
|
|
|
var i;
|
|
@@ -273,7 +308,9 @@ var BABYLON;
|
|
|
newTriangles.push(t);
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
var newVerticesOrder = [];
|
|
|
+
|
|
|
//compact vertices, get the IDs of the vertices used.
|
|
|
var dst = 0;
|
|
|
for (i = 0; i < this.vertices.length; ++i) {
|
|
@@ -286,6 +323,7 @@ var BABYLON;
|
|
|
dst++;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
for (i = 0; i < newTriangles.length; ++i) {
|
|
|
t = newTriangles[i];
|
|
|
for (j = 0; j < 3; ++j) {
|
|
@@ -293,10 +331,12 @@ var BABYLON;
|
|
|
}
|
|
|
}
|
|
|
this.vertices = this.vertices.slice(0, dst);
|
|
|
+
|
|
|
var newPositionData = [];
|
|
|
var newNormalData = [];
|
|
|
var newUVsData = [];
|
|
|
var newColorsData = [];
|
|
|
+
|
|
|
for (i = 0; i < newVerticesOrder.length; ++i) {
|
|
|
newPositionData.push(this.vertices[i].position.x);
|
|
|
newPositionData.push(this.vertices[i].position.y);
|
|
@@ -307,19 +347,21 @@ var BABYLON;
|
|
|
if (this.vertices[i].uv) {
|
|
|
newUVsData.push(this.vertices[i].uv.x);
|
|
|
newUVsData.push(this.vertices[i].uv.y);
|
|
|
- }
|
|
|
- else if (this.vertices[i].color) {
|
|
|
+ } else if (this.vertices[i].color) {
|
|
|
newColorsData.push(this.vertices[i].color.r);
|
|
|
newColorsData.push(this.vertices[i].color.g);
|
|
|
newColorsData.push(this.vertices[i].color.b);
|
|
|
+ newColorsData.push(this.vertices[i].color.a);
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
var newIndicesArray = [];
|
|
|
for (i = 0; i < newTriangles.length; ++i) {
|
|
|
newIndicesArray.push(newTriangles[i].vertices[0]);
|
|
|
newIndicesArray.push(newTriangles[i].vertices[1]);
|
|
|
newIndicesArray.push(newTriangles[i].vertices[2]);
|
|
|
}
|
|
|
+
|
|
|
//not cloning, to avoid geometry problems. Creating a whole new mesh.
|
|
|
var newMesh = new BABYLON.Mesh(this._mesh + "Decimated", this._mesh.getScene());
|
|
|
newMesh.material = this._mesh.material;
|
|
@@ -331,23 +373,32 @@ var BABYLON;
|
|
|
newMesh.setVerticesData(BABYLON.VertexBuffer.UVKind, newUVsData);
|
|
|
if (newColorsData.length > 0)
|
|
|
newMesh.setVerticesData(BABYLON.VertexBuffer.ColorKind, newColorsData);
|
|
|
+
|
|
|
//preparing the skeleton support
|
|
|
if (this._mesh.skeleton) {
|
|
|
+ //newMesh.skeleton = this._mesh.skeleton.clone("", "");
|
|
|
+ //newMesh.getScene().beginAnimation(newMesh.skeleton, 0, 100, true, 1.0);
|
|
|
}
|
|
|
+
|
|
|
return newMesh;
|
|
|
};
|
|
|
+
|
|
|
QuadraticErrorSimplification.prototype.isFlipped = function (vertex1, index2, point, deletedArray, borderFactor) {
|
|
|
for (var i = 0; i < vertex1.triangleCount; ++i) {
|
|
|
var t = this.triangles[this.references[vertex1.triangleStart + i].triangleId];
|
|
|
if (t.deleted)
|
|
|
continue;
|
|
|
+
|
|
|
var s = this.references[vertex1.triangleStart + i].vertexId;
|
|
|
+
|
|
|
var id1 = t.vertices[(s + 1) % 3];
|
|
|
var id2 = t.vertices[(s + 2) % 3];
|
|
|
+
|
|
|
if ((id1 === index2 || id2 === index2) && borderFactor < 2) {
|
|
|
deletedArray[i] = true;
|
|
|
continue;
|
|
|
}
|
|
|
+
|
|
|
var d1 = this.vertices[id1].position.subtract(point);
|
|
|
d1 = d1.normalize();
|
|
|
var d2 = this.vertices[id2].position.subtract(point);
|
|
@@ -359,8 +410,10 @@ var BABYLON;
|
|
|
if (BABYLON.Vector3.Dot(normal, t.normal) < 0.2)
|
|
|
return true;
|
|
|
}
|
|
|
+
|
|
|
return false;
|
|
|
};
|
|
|
+
|
|
|
QuadraticErrorSimplification.prototype.updateTriangles = function (vertexId, vertex, deletedArray, deletedTriangles) {
|
|
|
var newDeleted = deletedTriangles;
|
|
|
for (var i = 0; i < vertex.triangleCount; ++i) {
|
|
@@ -383,6 +436,7 @@ var BABYLON;
|
|
|
}
|
|
|
return newDeleted;
|
|
|
};
|
|
|
+
|
|
|
QuadraticErrorSimplification.prototype.identifyBorder = function () {
|
|
|
for (var i = 0; i < this.vertices.length; ++i) {
|
|
|
var vCount = [];
|
|
@@ -402,24 +456,24 @@ var BABYLON;
|
|
|
if (ofs === vCount.length) {
|
|
|
vCount.push(1);
|
|
|
vId.push(id);
|
|
|
- }
|
|
|
- else {
|
|
|
+ } else {
|
|
|
vCount[ofs]++;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
for (j = 0; j < vCount.length; ++j) {
|
|
|
if (vCount[j] === 1) {
|
|
|
this.vertices[vId[j]].isBorder = true;
|
|
|
- }
|
|
|
- else {
|
|
|
+ } else {
|
|
|
this.vertices[vId[j]].isBorder = false;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
+
|
|
|
QuadraticErrorSimplification.prototype.updateMesh = function (identifyBorders) {
|
|
|
- if (identifyBorders === void 0) { identifyBorders = false; }
|
|
|
+ if (typeof identifyBorders === "undefined") { identifyBorders = false; }
|
|
|
var i;
|
|
|
if (!identifyBorders) {
|
|
|
var newTrianglesVector = [];
|
|
@@ -430,6 +484,7 @@ var BABYLON;
|
|
|
}
|
|
|
this.triangles = newTrianglesVector;
|
|
|
}
|
|
|
+
|
|
|
for (i = 0; i < this.vertices.length; ++i) {
|
|
|
this.vertices[i].triangleCount = 0;
|
|
|
this.vertices[i].triangleStart = 0;
|
|
@@ -444,12 +499,15 @@ var BABYLON;
|
|
|
v.triangleCount++;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
var tStart = 0;
|
|
|
+
|
|
|
for (i = 0; i < this.vertices.length; ++i) {
|
|
|
this.vertices[i].triangleStart = tStart;
|
|
|
tStart += this.vertices[i].triangleCount;
|
|
|
this.vertices[i].triangleCount = 0;
|
|
|
}
|
|
|
+
|
|
|
var newReferences = new Array(this.triangles.length * 3);
|
|
|
for (i = 0; i < this.triangles.length; ++i) {
|
|
|
t = this.triangles[i];
|
|
@@ -460,21 +518,25 @@ var BABYLON;
|
|
|
}
|
|
|
}
|
|
|
this.references = newReferences;
|
|
|
+
|
|
|
if (identifyBorders) {
|
|
|
this.identifyBorder();
|
|
|
}
|
|
|
};
|
|
|
+
|
|
|
QuadraticErrorSimplification.prototype.vertexError = function (q, point) {
|
|
|
var x = point.x;
|
|
|
var y = point.y;
|
|
|
var z = point.z;
|
|
|
return q.data[0] * x * x + 2 * q.data[1] * x * y + 2 * q.data[2] * x * z + 2 * q.data[3] * x + q.data[4] * y * y + 2 * q.data[5] * y * z + 2 * q.data[6] * y + q.data[7] * z * z + 2 * q.data[8] * z + q.data[9];
|
|
|
};
|
|
|
+
|
|
|
QuadraticErrorSimplification.prototype.calculateError = function (vertex1, vertex2, pointResult, normalResult, uvResult) {
|
|
|
var q = vertex1.q.add(vertex2.q);
|
|
|
var border = vertex1.isBorder && vertex2.isBorder;
|
|
|
var error = 0;
|
|
|
var qDet = q.det(0, 1, 2, 1, 4, 5, 2, 5, 7);
|
|
|
+
|
|
|
if (qDet !== 0 && !border) {
|
|
|
if (!pointResult) {
|
|
|
pointResult = BABYLON.Vector3.Zero();
|
|
@@ -483,13 +545,13 @@ var BABYLON;
|
|
|
pointResult.y = 1 / qDet * (q.det(0, 2, 3, 1, 5, 6, 2, 7, 8));
|
|
|
pointResult.z = -1 / qDet * (q.det(0, 1, 3, 1, 4, 6, 2, 5, 8));
|
|
|
error = this.vertexError(q, pointResult);
|
|
|
+
|
|
|
//TODO this should be correctly calculated
|
|
|
if (normalResult) {
|
|
|
normalResult.copyFrom(vertex1.normal);
|
|
|
uvResult.copyFrom(vertex1.uv);
|
|
|
}
|
|
|
- }
|
|
|
- else {
|
|
|
+ } else {
|
|
|
var p3 = (vertex1.position.add(vertex2.position)).divide(new BABYLON.Vector3(2, 2, 2));
|
|
|
var norm3 = (vertex1.normal.add(vertex2.normal)).divide(new BABYLON.Vector3(2, 2, 2)).normalize();
|
|
|
var error1 = this.vertexError(q, vertex1.position);
|
|
@@ -502,15 +564,13 @@ var BABYLON;
|
|
|
normalResult.copyFrom(vertex1.normal);
|
|
|
uvResult.copyFrom(vertex1.uv);
|
|
|
}
|
|
|
- }
|
|
|
- else if (error === error2) {
|
|
|
+ } else if (error === error2) {
|
|
|
if (pointResult) {
|
|
|
pointResult.copyFrom(vertex2.position);
|
|
|
normalResult.copyFrom(vertex2.normal);
|
|
|
uvResult.copyFrom(vertex2.uv);
|
|
|
}
|
|
|
- }
|
|
|
- else {
|
|
|
+ } else {
|
|
|
if (pointResult) {
|
|
|
pointResult.copyFrom(p3);
|
|
|
normalResult.copyFrom(norm3);
|
|
@@ -524,4 +584,4 @@ var BABYLON;
|
|
|
})();
|
|
|
BABYLON.QuadraticErrorSimplification = QuadraticErrorSimplification;
|
|
|
})(BABYLON || (BABYLON = {}));
|
|
|
-//# sourceMappingURL=babylon.meshSimplification.js.map
|
|
|
+//# sourceMappingURL=babylon.meshSimplification.js.map
|