|
@@ -221,6 +221,13 @@ var __extends = this.__extends || function (d, b) {
|
|
return new Color4(this.r, this.g, this.b, this.a);
|
|
return new Color4(this.r, this.g, this.b, this.a);
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+ Color4.prototype.copyFrom = function (source) {
|
|
|
|
+ this.r = source.r;
|
|
|
|
+ this.g = source.g;
|
|
|
|
+ this.b = source.b;
|
|
|
|
+ this.a = source.a;
|
|
|
|
+ };
|
|
|
|
+
|
|
// Statics
|
|
// Statics
|
|
Color4.Lerp = function (left, right, amount) {
|
|
Color4.Lerp = function (left, right, amount) {
|
|
var result = new Color4(0, 0, 0, 0);
|
|
var result = new Color4(0, 0, 0, 0);
|
|
@@ -3596,6 +3603,95 @@ var BABYLON;
|
|
return Tools;
|
|
return Tools;
|
|
})();
|
|
})();
|
|
BABYLON.Tools = Tools;
|
|
BABYLON.Tools = Tools;
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * An implementation of a loop for asynchronous functions.
|
|
|
|
+ */
|
|
|
|
+ var AsyncLoop = (function () {
|
|
|
|
+ /**
|
|
|
|
+ * Constroctor.
|
|
|
|
+ * @param iterations the number of iterations.
|
|
|
|
+ * @param _fn the function to run each iteration
|
|
|
|
+ * @param _successCallback the callback that will be called upon succesful execution
|
|
|
|
+ * @param offset starting offset.
|
|
|
|
+ */
|
|
|
|
+ function AsyncLoop(iterations, _fn, _successCallback, offset) {
|
|
|
|
+ if (typeof offset === "undefined") { offset = 0; }
|
|
|
|
+ this.iterations = iterations;
|
|
|
|
+ this._fn = _fn;
|
|
|
|
+ this._successCallback = _successCallback;
|
|
|
|
+ this.index = offset - 1;
|
|
|
|
+ this._done = false;
|
|
|
|
+ }
|
|
|
|
+ /**
|
|
|
|
+ * Execute the next iteration. Must be called after the last iteration was finished.
|
|
|
|
+ */
|
|
|
|
+ AsyncLoop.prototype.executeNext = function () {
|
|
|
|
+ if (!this._done) {
|
|
|
|
+ if (this.index < this.iterations) {
|
|
|
|
+ ++this.index;
|
|
|
|
+ this._fn(this);
|
|
|
|
+ } else {
|
|
|
|
+ this.breakLoop();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Break the loop and run the success callback.
|
|
|
|
+ */
|
|
|
|
+ AsyncLoop.prototype.breakLoop = function () {
|
|
|
|
+ this._done = true;
|
|
|
|
+ this._successCallback();
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Helper function
|
|
|
|
+ */
|
|
|
|
+ AsyncLoop.Run = function (iterations, _fn, _successCallback, offset) {
|
|
|
|
+ if (typeof offset === "undefined") { offset = 0; }
|
|
|
|
+ var loop = new AsyncLoop(iterations, _fn, _successCallback, offset);
|
|
|
|
+
|
|
|
|
+ loop.executeNext();
|
|
|
|
+
|
|
|
|
+ return loop;
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * A for-loop that will run a given number of iterations synchronous and the rest async.
|
|
|
|
+ * @param iterations total number of iterations
|
|
|
|
+ * @param syncedIterations number of synchronous iterations in each async iteration.
|
|
|
|
+ * @param fn the function to call each iteration.
|
|
|
|
+ * @param callback a success call back that will be called when iterating stops.
|
|
|
|
+ * @param breakFunction a break condition (optional)
|
|
|
|
+ * @param timeout timeout settings for the setTimeout function. default - 0.
|
|
|
|
+ * @constructor
|
|
|
|
+ */
|
|
|
|
+ AsyncLoop.SyncAsyncForLoop = function (iterations, syncedIterations, fn, callback, breakFunction, timeout) {
|
|
|
|
+ if (typeof timeout === "undefined") { timeout = 0; }
|
|
|
|
+ var asyncLoop = new AsyncLoop(Math.ceil(iterations / syncedIterations), function (loop) {
|
|
|
|
+ if (breakFunction && breakFunction())
|
|
|
|
+ loop.breakLoop();
|
|
|
|
+ else {
|
|
|
|
+ setTimeout(function () {
|
|
|
|
+ for (var i = 0; i < syncedIterations; ++i) {
|
|
|
|
+ var iteration = (loop.index * syncedIterations) + i;
|
|
|
|
+ if (iteration >= iterations)
|
|
|
|
+ break;
|
|
|
|
+ fn(iteration);
|
|
|
|
+ if (breakFunction && breakFunction()) {
|
|
|
|
+ loop.breakLoop();
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ loop.executeNext();
|
|
|
|
+ }, timeout);
|
|
|
|
+ }
|
|
|
|
+ }, callback);
|
|
|
|
+ };
|
|
|
|
+ return AsyncLoop;
|
|
|
|
+ })();
|
|
|
|
+ BABYLON.AsyncLoop = AsyncLoop;
|
|
})(BABYLON || (BABYLON = {}));
|
|
})(BABYLON || (BABYLON = {}));
|
|
//# sourceMappingURL=babylon.tools.js.map
|
|
//# sourceMappingURL=babylon.tools.js.map
|
|
var BABYLON;
|
|
var BABYLON;
|
|
@@ -12317,6 +12413,64 @@ var BABYLON;
|
|
}
|
|
}
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
+ * Simplify the mesh according to the given array of settings.
|
|
|
|
+ * Function will return immediately and will simplify asnyc.
|
|
|
|
+ * @param settings a collection of simplification settings.
|
|
|
|
+ * @param parallelProcessing should all levels calculate parallel or one after the other.
|
|
|
|
+ * @param type the type of simplification to run.
|
|
|
|
+ * successCallback optional success callback to be called after the simplification finished processing all settings.
|
|
|
|
+ */
|
|
|
|
+ Mesh.prototype.simplify = function (settings, parallelProcessing, type, successCallback) {
|
|
|
|
+ var _this = this;
|
|
|
|
+ if (typeof parallelProcessing === "undefined") { parallelProcessing = true; }
|
|
|
|
+ if (typeof type === "undefined") { type = 0 /* QUADRATIC */; }
|
|
|
|
+ var getSimplifier = function () {
|
|
|
|
+ switch (type) {
|
|
|
|
+ case 0 /* QUADRATIC */:
|
|
|
|
+ default:
|
|
|
|
+ return new BABYLON.QuadraticErrorSimplification(_this);
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ if (parallelProcessing) {
|
|
|
|
+ //parallel simplifier
|
|
|
|
+ settings.forEach(function (setting) {
|
|
|
|
+ var simplifier = getSimplifier();
|
|
|
|
+ simplifier.simplify(setting, function (newMesh) {
|
|
|
|
+ _this.addLODLevel(setting.distance, newMesh);
|
|
|
|
+
|
|
|
|
+ //check if it is the last
|
|
|
|
+ if (setting.quality == settings[settings.length - 1].quality && successCallback) {
|
|
|
|
+ //all done, run the success callback.
|
|
|
|
+ successCallback();
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ });
|
|
|
|
+ } else {
|
|
|
|
+ //single simplifier.
|
|
|
|
+ var simplifier = getSimplifier();
|
|
|
|
+
|
|
|
|
+ var runDecimation = function (setting, callback) {
|
|
|
|
+ simplifier.simplify(setting, function (newMesh) {
|
|
|
|
+ _this.addLODLevel(setting.distance, newMesh);
|
|
|
|
+
|
|
|
|
+ //run the next quality level
|
|
|
|
+ callback();
|
|
|
|
+ });
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ var asyncLoop = new BABYLON.AsyncLoop(settings.length, function (loop) {
|
|
|
|
+ runDecimation(settings[loop.index], function () {
|
|
|
|
+ loop.executeNext();
|
|
|
|
+ });
|
|
|
|
+ }, function () {
|
|
|
|
+ //execution ended, run the success callback.
|
|
|
|
+ successCallback();
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
+
|
|
// Statics
|
|
// Statics
|
|
Mesh.CreateBox = function (name, size, scene, updatable) {
|
|
Mesh.CreateBox = function (name, size, scene, updatable) {
|
|
var box = new BABYLON.Mesh(name, scene);
|
|
var box = new BABYLON.Mesh(name, scene);
|
|
@@ -17142,6 +17296,17 @@ var BABYLON;
|
|
this.angle = 0;
|
|
this.angle = 0;
|
|
this.angularSpeed = 0;
|
|
this.angularSpeed = 0;
|
|
}
|
|
}
|
|
|
|
+ Particle.prototype.copyTo = function (other) {
|
|
|
|
+ other.position.copyFrom(this.position);
|
|
|
|
+ other.direction.copyFrom(this.direction);
|
|
|
|
+ other.color.copyFrom(this.color);
|
|
|
|
+ other.colorStep.copyFrom(this.colorStep);
|
|
|
|
+ other.lifeTime = this.lifeTime;
|
|
|
|
+ other.age = this.age;
|
|
|
|
+ other.size = this.size;
|
|
|
|
+ other.angle = this.angle;
|
|
|
|
+ other.angularSpeed = this.angularSpeed;
|
|
|
|
+ };
|
|
return Particle;
|
|
return Particle;
|
|
})();
|
|
})();
|
|
BABYLON.Particle = Particle;
|
|
BABYLON.Particle = Particle;
|
|
@@ -17253,8 +17418,7 @@ var BABYLON;
|
|
particle.age += _this._scaledUpdateSpeed;
|
|
particle.age += _this._scaledUpdateSpeed;
|
|
|
|
|
|
if (particle.age >= particle.lifeTime) {
|
|
if (particle.age >= particle.lifeTime) {
|
|
- particles.splice(index, 1);
|
|
|
|
- _this._stockParticles.push(particle);
|
|
|
|
|
|
+ _this.recycleParticle(particle);
|
|
index--;
|
|
index--;
|
|
continue;
|
|
continue;
|
|
} else {
|
|
} else {
|
|
@@ -17275,6 +17439,15 @@ var BABYLON;
|
|
}
|
|
}
|
|
};
|
|
};
|
|
}
|
|
}
|
|
|
|
+ ParticleSystem.prototype.recycleParticle = function (particle) {
|
|
|
|
+ var lastParticle = this.particles.pop();
|
|
|
|
+
|
|
|
|
+ if (lastParticle !== particle) {
|
|
|
|
+ lastParticle.copyTo(particle);
|
|
|
|
+ this._stockParticles.push(lastParticle);
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
+
|
|
ParticleSystem.prototype.getCapacity = function () {
|
|
ParticleSystem.prototype.getCapacity = function () {
|
|
return this._capacity;
|
|
return this._capacity;
|
|
};
|
|
};
|
|
@@ -30774,3 +30947,575 @@ var BABYLON;
|
|
BABYLON.PolygonMeshBuilder = PolygonMeshBuilder;
|
|
BABYLON.PolygonMeshBuilder = PolygonMeshBuilder;
|
|
})(BABYLON || (BABYLON = {}));
|
|
})(BABYLON || (BABYLON = {}));
|
|
//# sourceMappingURL=babylon.polygonMesh.js.map
|
|
//# sourceMappingURL=babylon.polygonMesh.js.map
|
|
|
|
+var BABYLON;
|
|
|
|
+(function (BABYLON) {
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ var SimplificationSettings = (function () {
|
|
|
|
+ function SimplificationSettings(quality, distance) {
|
|
|
|
+ this.quality = quality;
|
|
|
|
+ this.distance = distance;
|
|
|
|
+ }
|
|
|
|
+ return SimplificationSettings;
|
|
|
|
+ })();
|
|
|
|
+ BABYLON.SimplificationSettings = SimplificationSettings;
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 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;
|
|
|
|
+ this.error = new Array(4);
|
|
|
|
+ this.deleted = false;
|
|
|
|
+ this.isDirty = false;
|
|
|
|
+ this.borderFactor = 0;
|
|
|
|
+ }
|
|
|
|
+ return DecimationTriangle;
|
|
|
|
+ })();
|
|
|
|
+ BABYLON.DecimationTriangle = DecimationTriangle;
|
|
|
|
+
|
|
|
|
+ var DecimationVertex = (function () {
|
|
|
|
+ function DecimationVertex(position, normal, uv, id) {
|
|
|
|
+ this.position = position;
|
|
|
|
+ this.normal = normal;
|
|
|
|
+ this.uv = uv;
|
|
|
|
+ this.id = id;
|
|
|
|
+ this.isBorder = true;
|
|
|
|
+ this.q = new QuadraticMatrix();
|
|
|
|
+ this.triangleCount = 0;
|
|
|
|
+ this.triangleStart = 0;
|
|
|
|
+ }
|
|
|
|
+ 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 {
|
|
|
|
+ this.data[i] = 0;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ QuadraticMatrix.prototype.det = function (a11, a12, a13, a21, a22, a23, a31, a32, a33) {
|
|
|
|
+ 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) {
|
|
|
|
+ m.data[i] = this.data[i] + matrix.data[i];
|
|
|
|
+ }
|
|
|
|
+ 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];
|
|
|
|
+ };
|
|
|
|
+ return QuadraticMatrix;
|
|
|
|
+ })();
|
|
|
|
+ BABYLON.QuadraticMatrix = QuadraticMatrix;
|
|
|
|
+
|
|
|
|
+ var Reference = (function () {
|
|
|
|
+ function Reference(vertexId, triangleId) {
|
|
|
|
+ this.vertexId = vertexId;
|
|
|
|
+ this.triangleId = triangleId;
|
|
|
|
+ }
|
|
|
|
+ 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
|
|
|
|
+ */
|
|
|
|
+ var QuadraticErrorSimplification = (function () {
|
|
|
|
+ function QuadraticErrorSimplification(_mesh) {
|
|
|
|
+ this._mesh = _mesh;
|
|
|
|
+ this.initialised = false;
|
|
|
|
+ this.syncIterations = 5000;
|
|
|
|
+ this.agressiveness = 7;
|
|
|
|
+ this.decimationIterations = 100;
|
|
|
|
+ }
|
|
|
|
+ QuadraticErrorSimplification.prototype.simplify = function (settings, successCallback) {
|
|
|
|
+ var _this = this;
|
|
|
|
+ this.initWithMesh(this._mesh, function () {
|
|
|
|
+ _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.agressiveness);
|
|
|
|
+
|
|
|
|
+ var trianglesIterator = function (i) {
|
|
|
|
+ var t = _this.triangles[i];
|
|
|
|
+ if (!t)
|
|
|
|
+ return;
|
|
|
|
+ if (t.error[3] > threshold) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ if (t.deleted) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ if (t.isDirty) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ for (var j = 0; j < 3; ++j) {
|
|
|
|
+ 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 {
|
|
|
|
+ v0.triangleStart = tStart;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ v0.triangleCount = tCount;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
+ BABYLON.AsyncLoop.SyncAsyncForLoop(_this.triangles.length, _this.syncIterations, trianglesIterator, callback, function () {
|
|
|
|
+ return (triangleCount - deletedTriangles <= targetCount);
|
|
|
|
+ });
|
|
|
|
+ }, 0);
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ BABYLON.AsyncLoop.Run(this.decimationIterations, function (loop) {
|
|
|
|
+ if (triangleCount - deletedTriangles <= targetCount)
|
|
|
|
+ loop.breakLoop();
|
|
|
|
+ else {
|
|
|
|
+ iterationFunction(loop.index, function () {
|
|
|
|
+ loop.executeNext();
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+ }, function () {
|
|
|
|
+ setTimeout(function () {
|
|
|
|
+ successCallback(_this.reconstructMesh());
|
|
|
|
+ }, 0);
|
|
|
|
+ });
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ QuadraticErrorSimplification.prototype.initWithMesh = function (mesh, callback) {
|
|
|
|
+ var _this = this;
|
|
|
|
+ if (!mesh)
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ this.vertices = [];
|
|
|
|
+ this.triangles = [];
|
|
|
|
+
|
|
|
|
+ this._mesh = mesh;
|
|
|
|
+ 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 indices = mesh.getIndices();
|
|
|
|
+
|
|
|
|
+ var vertexInit = function (i) {
|
|
|
|
+ var vertex = new DecimationVertex(BABYLON.Vector3.FromArray(positionData, i * 3), BABYLON.Vector3.FromArray(normalData, i * 3), BABYLON.Vector2.FromArray(uvs, i * 2), i);
|
|
|
|
+ _this.vertices.push(vertex);
|
|
|
|
+ };
|
|
|
|
+ var totalVertices = mesh.getTotalVertices();
|
|
|
|
+ BABYLON.AsyncLoop.SyncAsyncForLoop(totalVertices, this.syncIterations, vertexInit, function () {
|
|
|
|
+ var indicesInit = function (i) {
|
|
|
|
+ var pos = i * 3;
|
|
|
|
+ var i0 = indices[pos + 0];
|
|
|
|
+ var i1 = indices[pos + 1];
|
|
|
|
+ var i2 = indices[pos + 2];
|
|
|
|
+ var triangle = new DecimationTriangle([_this.vertices[i0].id, _this.vertices[i1].id, _this.vertices[i2].id]);
|
|
|
|
+ _this.triangles.push(triangle);
|
|
|
|
+ };
|
|
|
|
+ BABYLON.AsyncLoop.SyncAsyncForLoop(indices.length / 3, _this.syncIterations, indicesInit, function () {
|
|
|
|
+ _this.init(callback);
|
|
|
|
+ });
|
|
|
|
+ });
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ QuadraticErrorSimplification.prototype.init = function (callback) {
|
|
|
|
+ var _this = this;
|
|
|
|
+ var triangleInit1 = function (i) {
|
|
|
|
+ var t = _this.triangles[i];
|
|
|
|
+ t.normal = BABYLON.Vector3.Cross(_this.vertices[t.vertices[1]].position.subtract(_this.vertices[t.vertices[0]].position), _this.vertices[t.vertices[2]].position.subtract(_this.vertices[t.vertices[0]].position)).normalize();
|
|
|
|
+ for (var j = 0; j < 3; j++) {
|
|
|
|
+ _this.vertices[t.vertices[j]].q.addArrayInPlace(QuadraticMatrix.DataFromNumbers(t.normal.x, t.normal.y, t.normal.z, -(BABYLON.Vector3.Dot(t.normal, _this.vertices[t.vertices[0]].position))));
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
+ BABYLON.AsyncLoop.SyncAsyncForLoop(this.triangles.length, this.syncIterations, triangleInit1, function () {
|
|
|
|
+ var triangleInit2 = function (i) {
|
|
|
|
+ var t = _this.triangles[i];
|
|
|
|
+ for (var j = 0; j < 3; ++j) {
|
|
|
|
+ t.error[j] = _this.calculateError(_this.vertices[t.vertices[j]], _this.vertices[t.vertices[(j + 1) % 3]]);
|
|
|
|
+ }
|
|
|
|
+ t.error[3] = Math.min(t.error[0], t.error[1], t.error[2]);
|
|
|
|
+ };
|
|
|
|
+ BABYLON.AsyncLoop.SyncAsyncForLoop(_this.triangles.length, _this.syncIterations, triangleInit2, function () {
|
|
|
|
+ _this.initialised = true;
|
|
|
|
+ callback();
|
|
|
|
+ });
|
|
|
|
+ });
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ QuadraticErrorSimplification.prototype.reconstructMesh = function () {
|
|
|
|
+ var newTriangles = [];
|
|
|
|
+ var i;
|
|
|
|
+ for (i = 0; i < this.vertices.length; ++i) {
|
|
|
|
+ this.vertices[i].triangleCount = 0;
|
|
|
|
+ }
|
|
|
|
+ var t;
|
|
|
|
+ var j;
|
|
|
|
+ for (i = 0; i < this.triangles.length; ++i) {
|
|
|
|
+ if (!this.triangles[i].deleted) {
|
|
|
|
+ t = this.triangles[i];
|
|
|
|
+ for (j = 0; j < 3; ++j) {
|
|
|
|
+ this.vertices[t.vertices[j]].triangleCount = 1;
|
|
|
|
+ }
|
|
|
|
+ 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) {
|
|
|
|
+ if (this.vertices[i].triangleCount) {
|
|
|
|
+ this.vertices[i].triangleStart = dst;
|
|
|
|
+ this.vertices[dst].position = this.vertices[i].position;
|
|
|
|
+ this.vertices[dst].normal = this.vertices[i].normal;
|
|
|
|
+ this.vertices[dst].uv = this.vertices[i].uv;
|
|
|
|
+ newVerticesOrder.push(i);
|
|
|
|
+ dst++;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ for (i = 0; i < newTriangles.length; ++i) {
|
|
|
|
+ t = newTriangles[i];
|
|
|
|
+ for (j = 0; j < 3; ++j) {
|
|
|
|
+ t.vertices[j] = this.vertices[t.vertices[j]].triangleStart;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ this.vertices = this.vertices.slice(0, dst);
|
|
|
|
+
|
|
|
|
+ var newPositionData = [];
|
|
|
|
+ var newNormalData = [];
|
|
|
|
+ var newUVsData = [];
|
|
|
|
+
|
|
|
|
+ for (i = 0; i < newVerticesOrder.length; ++i) {
|
|
|
|
+ newPositionData.push(this.vertices[i].position.x);
|
|
|
|
+ newPositionData.push(this.vertices[i].position.y);
|
|
|
|
+ newPositionData.push(this.vertices[i].position.z);
|
|
|
|
+ newNormalData.push(this.vertices[i].normal.x);
|
|
|
|
+ newNormalData.push(this.vertices[i].normal.y);
|
|
|
|
+ newNormalData.push(this.vertices[i].normal.z);
|
|
|
|
+ newUVsData.push(this.vertices[i].uv.x);
|
|
|
|
+ newUVsData.push(this.vertices[i].uv.y);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ 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]);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ var newMesh = new BABYLON.Mesh(this._mesh + "Decimated", this._mesh.getScene());
|
|
|
|
+ newMesh.material = this._mesh.material;
|
|
|
|
+ newMesh.parent = this._mesh.parent;
|
|
|
|
+ newMesh.setIndices(newIndicesArray);
|
|
|
|
+ newMesh.setVerticesData(BABYLON.VertexBuffer.PositionKind, newPositionData);
|
|
|
|
+ newMesh.setVerticesData(BABYLON.VertexBuffer.NormalKind, newNormalData);
|
|
|
|
+ newMesh.setVerticesData(BABYLON.VertexBuffer.UVKind, newUVsData);
|
|
|
|
+
|
|
|
|
+ //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);
|
|
|
|
+ d2 = d2.normalize();
|
|
|
|
+ if (Math.abs(BABYLON.Vector3.Dot(d1, d2)) > 0.999)
|
|
|
|
+ return true;
|
|
|
|
+ var normal = BABYLON.Vector3.Cross(d1, d2).normalize();
|
|
|
|
+ deletedArray[i] = false;
|
|
|
|
+ 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) {
|
|
|
|
+ var ref = this.references[vertex.triangleStart + i];
|
|
|
|
+ var t = this.triangles[ref.triangleId];
|
|
|
|
+ if (t.deleted)
|
|
|
|
+ continue;
|
|
|
|
+ if (deletedArray[i]) {
|
|
|
|
+ t.deleted = true;
|
|
|
|
+ newDeleted++;
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ t.vertices[ref.vertexId] = vertexId;
|
|
|
|
+ t.isDirty = true;
|
|
|
|
+ t.error[0] = this.calculateError(this.vertices[t.vertices[0]], this.vertices[t.vertices[1]]) + (t.borderFactor / 2);
|
|
|
|
+ t.error[1] = this.calculateError(this.vertices[t.vertices[1]], this.vertices[t.vertices[2]]) + (t.borderFactor / 2);
|
|
|
|
+ t.error[2] = this.calculateError(this.vertices[t.vertices[2]], this.vertices[t.vertices[0]]) + (t.borderFactor / 2);
|
|
|
|
+ t.error[3] = Math.min(t.error[0], t.error[1], t.error[2]);
|
|
|
|
+ this.references.push(ref);
|
|
|
|
+ }
|
|
|
|
+ return newDeleted;
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ QuadraticErrorSimplification.prototype.identifyBorder = function () {
|
|
|
|
+ for (var i = 0; i < this.vertices.length; ++i) {
|
|
|
|
+ var vCount = [];
|
|
|
|
+ var vId = [];
|
|
|
|
+ var v = this.vertices[i];
|
|
|
|
+ var j;
|
|
|
|
+ for (j = 0; j < v.triangleCount; ++j) {
|
|
|
|
+ var triangle = this.triangles[this.references[v.triangleStart + j].triangleId];
|
|
|
|
+ for (var ii = 0; ii < 3; ii++) {
|
|
|
|
+ var ofs = 0;
|
|
|
|
+ var id = triangle.vertices[ii];
|
|
|
|
+ while (ofs < vCount.length) {
|
|
|
|
+ if (vId[ofs] === id)
|
|
|
|
+ break;
|
|
|
|
+ ++ofs;
|
|
|
|
+ }
|
|
|
|
+ if (ofs === vCount.length) {
|
|
|
|
+ vCount.push(1);
|
|
|
|
+ vId.push(id);
|
|
|
|
+ } else {
|
|
|
|
+ vCount[ofs]++;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ for (j = 0; j < vCount.length; ++j) {
|
|
|
|
+ if (vCount[j] === 1) {
|
|
|
|
+ this.vertices[vId[j]].isBorder = true;
|
|
|
|
+ } else {
|
|
|
|
+ this.vertices[vId[j]].isBorder = false;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ QuadraticErrorSimplification.prototype.updateMesh = function (identifyBorders) {
|
|
|
|
+ if (typeof identifyBorders === "undefined") { identifyBorders = false; }
|
|
|
|
+ var i;
|
|
|
|
+ if (!identifyBorders) {
|
|
|
|
+ var newTrianglesVector = [];
|
|
|
|
+ for (i = 0; i < this.triangles.length; ++i) {
|
|
|
|
+ if (!this.triangles[i].deleted) {
|
|
|
|
+ newTrianglesVector.push(this.triangles[i]);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ this.triangles = newTrianglesVector;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ for (i = 0; i < this.vertices.length; ++i) {
|
|
|
|
+ this.vertices[i].triangleCount = 0;
|
|
|
|
+ this.vertices[i].triangleStart = 0;
|
|
|
|
+ }
|
|
|
|
+ var t;
|
|
|
|
+ var j;
|
|
|
|
+ var v;
|
|
|
|
+ for (i = 0; i < this.triangles.length; ++i) {
|
|
|
|
+ t = this.triangles[i];
|
|
|
|
+ for (j = 0; j < 3; ++j) {
|
|
|
|
+ v = this.vertices[t.vertices[j]];
|
|
|
|
+ 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];
|
|
|
|
+ for (j = 0; j < 3; ++j) {
|
|
|
|
+ v = this.vertices[t.vertices[j]];
|
|
|
|
+ newReferences[v.triangleStart + v.triangleCount] = new Reference(j, i);
|
|
|
|
+ v.triangleCount++;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ 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();
|
|
|
|
+ }
|
|
|
|
+ pointResult.x = -1 / qDet * (q.det(1, 2, 3, 4, 5, 6, 5, 7, 8));
|
|
|
|
+ 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 {
|
|
|
|
+ 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);
|
|
|
|
+ var error2 = this.vertexError(q, vertex2.position);
|
|
|
|
+ var error3 = this.vertexError(q, p3);
|
|
|
|
+ error = Math.min(error1, error2, error3);
|
|
|
|
+ if (error === error1) {
|
|
|
|
+ if (pointResult) {
|
|
|
|
+ pointResult.copyFrom(vertex1.position);
|
|
|
|
+ normalResult.copyFrom(vertex1.normal);
|
|
|
|
+ uvResult.copyFrom(vertex1.uv);
|
|
|
|
+ }
|
|
|
|
+ } else if (error === error2) {
|
|
|
|
+ if (pointResult) {
|
|
|
|
+ pointResult.copyFrom(vertex2.position);
|
|
|
|
+ normalResult.copyFrom(vertex2.normal);
|
|
|
|
+ uvResult.copyFrom(vertex2.uv);
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ if (pointResult) {
|
|
|
|
+ pointResult.copyFrom(p3);
|
|
|
|
+ normalResult.copyFrom(norm3);
|
|
|
|
+ uvResult.copyFrom(vertex1.uv);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return error;
|
|
|
|
+ };
|
|
|
|
+ return QuadraticErrorSimplification;
|
|
|
|
+ })();
|
|
|
|
+ BABYLON.QuadraticErrorSimplification = QuadraticErrorSimplification;
|
|
|
|
+})(BABYLON || (BABYLON = {}));
|
|
|
|
+//# sourceMappingURL=babylon.meshSimplification.js.map
|