|
@@ -7478,6 +7478,9 @@ var BABYLON;
|
|
|
this._drawCalls = new BABYLON.PerfCounter();
|
|
|
this._renderingQueueLaunched = false;
|
|
|
this._activeRenderLoops = [];
|
|
|
+ // Deterministic lockstepMaxSteps
|
|
|
+ this._deterministicLockstep = false;
|
|
|
+ this._lockstepMaxSteps = 4;
|
|
|
// FPS
|
|
|
this._performanceMonitor = new BABYLON.PerformanceMonitor();
|
|
|
this._fps = 60;
|
|
@@ -7530,6 +7533,12 @@ var BABYLON;
|
|
|
if (antialias != null) {
|
|
|
options.antialias = antialias;
|
|
|
}
|
|
|
+ if (options.deterministicLockstep === undefined) {
|
|
|
+ options.deterministicLockstep = false;
|
|
|
+ }
|
|
|
+ if (options.lockstepMaxSteps === undefined) {
|
|
|
+ options.lockstepMaxSteps = 4;
|
|
|
+ }
|
|
|
if (options.preserveDrawingBuffer === undefined) {
|
|
|
options.preserveDrawingBuffer = false;
|
|
|
}
|
|
@@ -7539,6 +7548,8 @@ var BABYLON;
|
|
|
if (options.stencil === undefined) {
|
|
|
options.stencil = true;
|
|
|
}
|
|
|
+ this._deterministicLockstep = options.deterministicLockstep;
|
|
|
+ this._lockstepMaxSteps = options.lockstepMaxSteps;
|
|
|
// GL
|
|
|
if (!options.disableWebGL2Support) {
|
|
|
try {
|
|
@@ -7620,7 +7631,7 @@ var BABYLON;
|
|
|
// Constants
|
|
|
this._gl.HALF_FLOAT_OES = 0x8D61; // Half floating-point type (16-bit).
|
|
|
this._gl.RGBA16F = 0x881A; // RGBA 16-bit floating-point color-renderable internal sized format.
|
|
|
- this._gl.RGBA32F = 0x8814; // RGBA 32-bit floating-point color-renderable internal sized format.
|
|
|
+ this._gl.RGBA32F = 0x8814; // RGBA 32-bit floating-point color-renderable internal sized format.
|
|
|
this._gl.DEPTH24_STENCIL8 = 35056;
|
|
|
// Extensions
|
|
|
this._caps.standardDerivatives = this._webGLVersion > 1 || (this._gl.getExtension('OES_standard_derivatives') !== null);
|
|
@@ -7648,7 +7659,7 @@ var BABYLON;
|
|
|
}
|
|
|
this._caps.textureHalfFloatRender = this._caps.textureHalfFloat && this._canRenderToHalfFloatFramebuffer();
|
|
|
this._caps.textureLOD = this._webGLVersion > 1 || this._gl.getExtension('EXT_shader_texture_lod');
|
|
|
- // Vertex array object
|
|
|
+ // Vertex array object
|
|
|
if (this._webGLVersion > 1) {
|
|
|
this._caps.vertexArrayObject = true;
|
|
|
}
|
|
@@ -7664,7 +7675,7 @@ var BABYLON;
|
|
|
this._caps.vertexArrayObject = false;
|
|
|
}
|
|
|
}
|
|
|
- // Instances count
|
|
|
+ // Instances count
|
|
|
if (this._webGLVersion > 1) {
|
|
|
this._caps.instancedArrays = true;
|
|
|
}
|
|
@@ -7682,7 +7693,7 @@ var BABYLON;
|
|
|
}
|
|
|
// Intelligently add supported compressed formats in order to check for.
|
|
|
// Check for ASTC support first as it is most powerful and to be very cross platform.
|
|
|
- // Next PVRTC & DXT, which are probably superior to ETC1/2.
|
|
|
+ // Next PVRTC & DXT, which are probably superior to ETC1/2.
|
|
|
// Likely no hardware which supports both PVR & DXT, so order matters little.
|
|
|
// ETC2 is newer and handles ETC1 (no alpha capability), so check for first.
|
|
|
if (this._caps.astc)
|
|
@@ -8186,6 +8197,12 @@ var BABYLON;
|
|
|
this._activeTexturesCache[index] = null;
|
|
|
}
|
|
|
};
|
|
|
+ Engine.prototype.isDeterministicLockStep = function () {
|
|
|
+ return this._deterministicLockstep;
|
|
|
+ };
|
|
|
+ Engine.prototype.getLockstepMaxSteps = function () {
|
|
|
+ return this._lockstepMaxSteps;
|
|
|
+ };
|
|
|
Engine.prototype.getGlInfo = function () {
|
|
|
return {
|
|
|
vendor: this._glVendor,
|
|
@@ -9277,7 +9294,7 @@ var BABYLON;
|
|
|
Engine.prototype.setState = function (culling, zOffset, force, reverseSide) {
|
|
|
if (zOffset === void 0) { zOffset = 0; }
|
|
|
if (reverseSide === void 0) { reverseSide = false; }
|
|
|
- // Culling
|
|
|
+ // Culling
|
|
|
var showSide = reverseSide ? this._gl.FRONT : this._gl.BACK;
|
|
|
var hideSide = reverseSide ? this._gl.BACK : this._gl.FRONT;
|
|
|
var cullFace = this.cullBackFaces ? showSide : hideSide;
|
|
@@ -9385,7 +9402,7 @@ var BABYLON;
|
|
|
}
|
|
|
this.resetTextureCache();
|
|
|
this._currentEffect = null;
|
|
|
- // 6/8/2017: deltakosh: Should not be required anymore.
|
|
|
+ // 6/8/2017: deltakosh: Should not be required anymore.
|
|
|
// This message is then mostly for the future myself which will scream out loud when seeing that actually it was required :)
|
|
|
if (bruteForce) {
|
|
|
this._currentProgram = null;
|
|
@@ -15958,6 +15975,16 @@ var BABYLON;
|
|
|
*/
|
|
|
this.onMeshRemovedObservable = new BABYLON.Observable();
|
|
|
/**
|
|
|
+ * An event triggered before calculating deterministic simulation step
|
|
|
+ * @type {BABYLON.Observable}
|
|
|
+ */
|
|
|
+ this.onBeforeStepObservable = new BABYLON.Observable();
|
|
|
+ /**
|
|
|
+ * An event triggered after calculating deterministic simulation step
|
|
|
+ * @type {BABYLON.Observable}
|
|
|
+ */
|
|
|
+ this.onAfterStepObservable = new BABYLON.Observable();
|
|
|
+ /**
|
|
|
* This Observable will be triggered for each stage of each renderingGroup of each rendered camera.
|
|
|
* The RenderinGroupInfo class contains all the information about the context in which the observable is called
|
|
|
* If you wish to register an Observer only for a given set of renderingGroup, use the mask with a combination of the renderingGroup index elevated to the power of two (1 for renderingGroup 0, 2 for renderingrOup1, 4 for 2 and 8 for 3)
|
|
@@ -15986,6 +16013,10 @@ var BABYLON;
|
|
|
this._previousStartingPointerPosition = new BABYLON.Vector2(0, 0);
|
|
|
this._startingPointerTime = 0;
|
|
|
this._previousStartingPointerTime = 0;
|
|
|
+ // Deterministic lockstep
|
|
|
+ this._timeAccumulator = 0;
|
|
|
+ this._currentStepId = 0;
|
|
|
+ this._currentInternalStep = 0;
|
|
|
// Coordinate system
|
|
|
/**
|
|
|
* use right-handed coordinate system on this scene.
|
|
@@ -16267,6 +16298,26 @@ var BABYLON;
|
|
|
enumerable: true,
|
|
|
configurable: true
|
|
|
});
|
|
|
+ Object.defineProperty(Scene.prototype, "beforeStep", {
|
|
|
+ set: function (callback) {
|
|
|
+ if (this.onBeforeStepObservable) {
|
|
|
+ this.onBeforeStepObservable.remove(this._onBeforeStepObserver);
|
|
|
+ }
|
|
|
+ this._onBeforeStepObserver = this.onBeforeStepObservable.add(callback);
|
|
|
+ },
|
|
|
+ enumerable: true,
|
|
|
+ configurable: true
|
|
|
+ });
|
|
|
+ Object.defineProperty(Scene.prototype, "afterStep", {
|
|
|
+ set: function (callback) {
|
|
|
+ if (this.onAfterStepObservable) {
|
|
|
+ this.onAfterStepObservable.remove(this._onAfterStepObserver);
|
|
|
+ }
|
|
|
+ this._onAfterStepObserver = this.onAfterStepObservable.add(callback);
|
|
|
+ },
|
|
|
+ enumerable: true,
|
|
|
+ configurable: true
|
|
|
+ });
|
|
|
Object.defineProperty(Scene.prototype, "unTranslatedPointer", {
|
|
|
get: function () {
|
|
|
return new BABYLON.Vector2(this._unTranslatedPointerX, this._unTranslatedPointerY);
|
|
@@ -16288,6 +16339,14 @@ var BABYLON;
|
|
|
enumerable: true,
|
|
|
configurable: true
|
|
|
});
|
|
|
+ Scene.prototype.getStepId = function () {
|
|
|
+ return this._currentStepId;
|
|
|
+ };
|
|
|
+ ;
|
|
|
+ Scene.prototype.getInternalStep = function () {
|
|
|
+ return this._currentInternalStep;
|
|
|
+ };
|
|
|
+ ;
|
|
|
Object.defineProperty(Scene.prototype, "fogEnabled", {
|
|
|
get: function () {
|
|
|
return this._fogEnabled;
|
|
@@ -17134,6 +17193,18 @@ var BABYLON;
|
|
|
Scene.prototype.unregisterAfterRender = function (func) {
|
|
|
this.onAfterRenderObservable.removeCallback(func);
|
|
|
};
|
|
|
+ Scene.prototype.registerBeforeStep = function (func) {
|
|
|
+ this.onBeforeStepObservable.add(func);
|
|
|
+ };
|
|
|
+ Scene.prototype.unregisterBeforeStep = function (func) {
|
|
|
+ this.onBeforeStepObservable.removeCallback(func);
|
|
|
+ };
|
|
|
+ Scene.prototype.registerAfterStep = function (func) {
|
|
|
+ this.onAfterStepObservable.add(func);
|
|
|
+ };
|
|
|
+ Scene.prototype.unregisterAfterStep = function (func) {
|
|
|
+ this.onAfterStepObservable.removeCallback(func);
|
|
|
+ };
|
|
|
Scene.prototype._addPendingData = function (data) {
|
|
|
this._pendingData.push(data);
|
|
|
};
|
|
@@ -17314,7 +17385,7 @@ var BABYLON;
|
|
|
Scene.prototype.removeMesh = function (toRemove) {
|
|
|
var index = this.meshes.indexOf(toRemove);
|
|
|
if (index !== -1) {
|
|
|
- // Remove from the scene if mesh found
|
|
|
+ // Remove from the scene if mesh found
|
|
|
this.meshes.splice(index, 1);
|
|
|
}
|
|
|
//notify the collision coordinator
|
|
@@ -17327,7 +17398,7 @@ var BABYLON;
|
|
|
Scene.prototype.removeSkeleton = function (toRemove) {
|
|
|
var index = this.skeletons.indexOf(toRemove);
|
|
|
if (index !== -1) {
|
|
|
- // Remove from the scene if found
|
|
|
+ // Remove from the scene if found
|
|
|
this.skeletons.splice(index, 1);
|
|
|
}
|
|
|
return index;
|
|
@@ -17335,7 +17406,7 @@ var BABYLON;
|
|
|
Scene.prototype.removeMorphTargetManager = function (toRemove) {
|
|
|
var index = this.morphTargetManagers.indexOf(toRemove);
|
|
|
if (index !== -1) {
|
|
|
- // Remove from the scene if found
|
|
|
+ // Remove from the scene if found
|
|
|
this.morphTargetManagers.splice(index, 1);
|
|
|
}
|
|
|
return index;
|
|
@@ -17343,7 +17414,7 @@ var BABYLON;
|
|
|
Scene.prototype.removeLight = function (toRemove) {
|
|
|
var index = this.lights.indexOf(toRemove);
|
|
|
if (index !== -1) {
|
|
|
- // Remove from the scene if mesh found
|
|
|
+ // Remove from the scene if mesh found
|
|
|
this.lights.splice(index, 1);
|
|
|
this.sortLightsByPriority();
|
|
|
}
|
|
@@ -17353,7 +17424,7 @@ var BABYLON;
|
|
|
Scene.prototype.removeCamera = function (toRemove) {
|
|
|
var index = this.cameras.indexOf(toRemove);
|
|
|
if (index !== -1) {
|
|
|
- // Remove from the scene if mesh found
|
|
|
+ // Remove from the scene if mesh found
|
|
|
this.cameras.splice(index, 1);
|
|
|
}
|
|
|
// Remove from activeCameras
|
|
@@ -18222,15 +18293,47 @@ var BABYLON;
|
|
|
if (this.simplificationQueue && !this.simplificationQueue.running) {
|
|
|
this.simplificationQueue.executeNext();
|
|
|
}
|
|
|
- // Animations
|
|
|
- var deltaTime = Math.max(Scene.MinDeltaTime, Math.min(this._engine.getDeltaTime(), Scene.MaxDeltaTime));
|
|
|
- this._animationRatio = deltaTime * (60.0 / 1000.0);
|
|
|
- this._animate();
|
|
|
- // Physics
|
|
|
- if (this._physicsEngine) {
|
|
|
- BABYLON.Tools.StartPerformanceCounter("Physics");
|
|
|
- this._physicsEngine._step(deltaTime / 1000.0);
|
|
|
- BABYLON.Tools.EndPerformanceCounter("Physics");
|
|
|
+ if (this._engine.isDeterministicLockStep()) {
|
|
|
+ var deltaTime = Math.max(Scene.MinDeltaTime, Math.min(this._engine.getDeltaTime(), Scene.MaxDeltaTime)) / 1000;
|
|
|
+ var defaultTimeStep = this._physicsEngine.getTimeStep();
|
|
|
+ var maxSubSteps = this._engine.getLockstepMaxSteps();
|
|
|
+ this._timeAccumulator += deltaTime;
|
|
|
+ // compute the amount of fixed steps we should have taken since the last step
|
|
|
+ var internalSteps = Math.floor(this._timeAccumulator / defaultTimeStep);
|
|
|
+ internalSteps = Math.min(internalSteps, maxSubSteps);
|
|
|
+ for (this._currentInternalStep = 0; this._currentInternalStep < internalSteps; this._currentInternalStep++) {
|
|
|
+ this.onBeforeStepObservable.notifyObservers(this);
|
|
|
+ // Animations
|
|
|
+ this._animationRatio = defaultTimeStep * (60.0 / 1000.0);
|
|
|
+ this._animate();
|
|
|
+ // Physics
|
|
|
+ if (this._physicsEngine) {
|
|
|
+ BABYLON.Tools.StartPerformanceCounter("Physics");
|
|
|
+ this._physicsEngine._step(defaultTimeStep);
|
|
|
+ BABYLON.Tools.EndPerformanceCounter("Physics");
|
|
|
+ }
|
|
|
+ this._timeAccumulator -= defaultTimeStep;
|
|
|
+ this.onAfterStepObservable.notifyObservers(this);
|
|
|
+ this._currentStepId++;
|
|
|
+ if ((internalSteps > 1) && (this._currentInternalStep != internalSteps - 1)) {
|
|
|
+ // Q: can this be optimized by putting some code in the afterStep callback?
|
|
|
+ // I had to put this code here, otherwise mesh attached to bones of another mesh skeleton,
|
|
|
+ // would return incorrect positions for internal stepIds (non-rendered steps)
|
|
|
+ this._evaluateActiveMeshes();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ // Animations
|
|
|
+ var deltaTime = Math.max(Scene.MinDeltaTime, Math.min(this._engine.getDeltaTime(), Scene.MaxDeltaTime));
|
|
|
+ this._animationRatio = deltaTime * (60.0 / 1000.0);
|
|
|
+ this._animate();
|
|
|
+ // Physics
|
|
|
+ if (this._physicsEngine) {
|
|
|
+ BABYLON.Tools.StartPerformanceCounter("Physics");
|
|
|
+ this._physicsEngine._step(deltaTime / 1000.0);
|
|
|
+ BABYLON.Tools.EndPerformanceCounter("Physics");
|
|
|
+ }
|
|
|
}
|
|
|
// Before render
|
|
|
this.onBeforeRenderObservable.notifyObservers(this);
|
|
@@ -18518,7 +18621,7 @@ var BABYLON;
|
|
|
if (this._depthRenderer) {
|
|
|
this._depthRenderer.dispose();
|
|
|
}
|
|
|
- // Smart arrays
|
|
|
+ // Smart arrays
|
|
|
if (this.activeCamera) {
|
|
|
this.activeCamera._activeMeshes.dispose();
|
|
|
this.activeCamera = null;
|
|
@@ -60144,6 +60247,12 @@ var BABYLON;
|
|
|
if (newTimeStep === void 0) { newTimeStep = 1 / 60; }
|
|
|
this._physicsPlugin.setTimeStep(newTimeStep);
|
|
|
};
|
|
|
+ /**
|
|
|
+ * Get the time step of the physics engine.
|
|
|
+ */
|
|
|
+ PhysicsEngine.prototype.getTimeStep = function () {
|
|
|
+ return this._physicsPlugin.getTimeStep();
|
|
|
+ };
|
|
|
PhysicsEngine.prototype.dispose = function () {
|
|
|
this._impostors.forEach(function (impostor) {
|
|
|
impostor.dispose();
|
|
@@ -60286,6 +60395,9 @@ var BABYLON;
|
|
|
CannonJSPlugin.prototype.setTimeStep = function (timeStep) {
|
|
|
this._fixedTimeStep = timeStep;
|
|
|
};
|
|
|
+ CannonJSPlugin.prototype.getTimeStep = function () {
|
|
|
+ return this._fixedTimeStep;
|
|
|
+ };
|
|
|
CannonJSPlugin.prototype.executeStep = function (delta, impostors) {
|
|
|
// Delta is in seconds, should be provided in milliseconds
|
|
|
this.world.step(this._fixedTimeStep, this._useDeltaForWorldStep ? delta * 1000 : 0, 3);
|
|
@@ -60581,7 +60693,7 @@ var BABYLON;
|
|
|
//calculate the translation
|
|
|
var translation = mesh.getBoundingInfo().boundingBox.centerWorld.subtract(center).subtract(mesh.position).negate();
|
|
|
this._tmpPosition.copyFromFloats(translation.x, translation.y - mesh.getBoundingInfo().boundingBox.extendSizeWorld.y, translation.z);
|
|
|
- //add it inverted to the delta
|
|
|
+ //add it inverted to the delta
|
|
|
this._tmpDeltaPosition.copyFrom(mesh.getBoundingInfo().boundingBox.centerWorld.subtract(c));
|
|
|
this._tmpDeltaPosition.y += mesh.getBoundingInfo().boundingBox.extendSizeWorld.y;
|
|
|
mesh.setPivotMatrix(oldPivot);
|
|
@@ -60724,6 +60836,9 @@ var BABYLON;
|
|
|
OimoJSPlugin.prototype.setTimeStep = function (timeStep) {
|
|
|
this.world.timeStep = timeStep;
|
|
|
};
|
|
|
+ OimoJSPlugin.prototype.getTimeStep = function () {
|
|
|
+ return this.world.timeStep;
|
|
|
+ };
|
|
|
OimoJSPlugin.prototype.executeStep = function (delta, impostors) {
|
|
|
var _this = this;
|
|
|
impostors.forEach(function (impostor) {
|