}
*/
PhysicsRadialExplosionEvent.prototype.getImpostorForceAndContactPoint = function (impostor, origin, radius, strength, falloff) {
if (impostor.mass === 0) {
return null;
}
if (!this._intersectsWithSphere(impostor, origin, radius)) {
return null;
}
if (impostor.object.getClassName() !== 'Mesh' && impostor.object.getClassName() !== 'InstancedMesh') {
return null;
}
var impostorObjectCenter = impostor.getObjectCenter();
var direction = impostorObjectCenter.subtract(origin);
var ray = new BABYLON.Ray(origin, direction, radius);
this._rays.push(ray);
var hit = ray.intersectsMesh(impostor.object);
var contactPoint = hit.pickedPoint;
if (!contactPoint) {
return null;
}
var distanceFromOrigin = BABYLON.Vector3.Distance(origin, contactPoint);
if (distanceFromOrigin > radius) {
return null;
}
var multiplier = falloff === PhysicsRadialImpulseFalloff.Constant
? strength
: strength * (1 - (distanceFromOrigin / radius));
var force = direction.multiplyByFloats(multiplier, multiplier, multiplier);
return { force: force, contactPoint: contactPoint };
};
/**
* Disposes the sphere.
* @param {bolean} force
*/
PhysicsRadialExplosionEvent.prototype.dispose = function (force) {
var _this = this;
if (force === void 0) { force = true; }
if (force) {
this._sphere.dispose();
}
else {
setTimeout(function () {
if (!_this._dataFetched) {
_this._sphere.dispose();
}
}, 0);
}
};
/*** Helpers ***/
PhysicsRadialExplosionEvent.prototype._prepareSphere = function () {
if (!this._sphere) {
this._sphere = BABYLON.MeshBuilder.CreateSphere("radialExplosionEventSphere", this._sphereOptions, this._scene);
this._sphere.isVisible = false;
}
};
PhysicsRadialExplosionEvent.prototype._intersectsWithSphere = function (impostor, origin, radius) {
var impostorObject = impostor.object;
this._prepareSphere();
this._sphere.position = origin;
this._sphere.scaling = new BABYLON.Vector3(radius * 2, radius * 2, radius * 2);
this._sphere._updateBoundingInfo();
this._sphere.computeWorldMatrix(true);
return this._sphere.intersectsMesh(impostorObject, true);
};
return PhysicsRadialExplosionEvent;
}());
BABYLON.PhysicsRadialExplosionEvent = PhysicsRadialExplosionEvent;
/***** Gravitational Field *****/
var PhysicsGravitationalFieldEvent = /** @class */ (function () {
function PhysicsGravitationalFieldEvent(physicsHelper, scene, origin, radius, strength, falloff) {
if (falloff === void 0) { falloff = PhysicsRadialImpulseFalloff.Constant; }
this._dataFetched = false; // check if the has been fetched the data. If not, do cleanup
this._physicsHelper = physicsHelper;
this._scene = scene;
this._origin = origin;
this._radius = radius;
this._strength = strength;
this._falloff = falloff;
this._tickCallback = this._tick.bind(this);
}
/**
* Returns the data related to the gravitational field event (sphere).
* @returns {PhysicsGravitationalFieldEventData}
*/
PhysicsGravitationalFieldEvent.prototype.getData = function () {
this._dataFetched = true;
return {
sphere: this._sphere,
};
};
/**
* Enables the gravitational field.
*/
PhysicsGravitationalFieldEvent.prototype.enable = function () {
this._tickCallback.call(this);
this._scene.registerBeforeRender(this._tickCallback);
};
/**
* Disables the gravitational field.
*/
PhysicsGravitationalFieldEvent.prototype.disable = function () {
this._scene.unregisterBeforeRender(this._tickCallback);
};
/**
* Disposes the sphere.
* @param {bolean} force
*/
PhysicsGravitationalFieldEvent.prototype.dispose = function (force) {
var _this = this;
if (force === void 0) { force = true; }
if (force) {
this._sphere.dispose();
}
else {
setTimeout(function () {
if (!_this._dataFetched) {
_this._sphere.dispose();
}
}, 0);
}
};
PhysicsGravitationalFieldEvent.prototype._tick = function () {
// Since the params won't change, we fetch the event only once
if (this._sphere) {
this._physicsHelper.applyRadialExplosionForce(this._origin, this._radius, this._strength * -1, this._falloff);
}
else {
var radialExplosionEvent = this._physicsHelper.applyRadialExplosionForce(this._origin, this._radius, this._strength * -1, this._falloff);
if (radialExplosionEvent) {
this._sphere = radialExplosionEvent.getData().sphere.clone('radialExplosionEventSphereClone');
}
}
};
return PhysicsGravitationalFieldEvent;
}());
BABYLON.PhysicsGravitationalFieldEvent = PhysicsGravitationalFieldEvent;
/***** Updraft *****/
var PhysicsUpdraftEvent = /** @class */ (function () {
function PhysicsUpdraftEvent(_scene, _origin, _radius, _strength, _height, _updraftMode) {
this._scene = _scene;
this._origin = _origin;
this._radius = _radius;
this._strength = _strength;
this._height = _height;
this._updraftMode = _updraftMode;
this._originTop = BABYLON.Vector3.Zero(); // the most upper part of the cylinder
this._originDirection = BABYLON.Vector3.Zero(); // used if the updraftMode is perpendicular
this._cylinderPosition = BABYLON.Vector3.Zero(); // to keep the cylinders position, because normally the origin is in the center and not on the bottom
this._dataFetched = false; // check if the has been fetched the data. If not, do cleanup
this._physicsEngine = this._scene.getPhysicsEngine();
this._origin.addToRef(new BABYLON.Vector3(0, this._height / 2, 0), this._cylinderPosition);
this._origin.addToRef(new BABYLON.Vector3(0, this._height, 0), this._originTop);
if (this._updraftMode === PhysicsUpdraftMode.Perpendicular) {
this._originDirection = this._origin.subtract(this._originTop).normalize();
}
this._tickCallback = this._tick.bind(this);
}
/**
* Returns the data related to the updraft event (cylinder).
* @returns {PhysicsUpdraftEventData}
*/
PhysicsUpdraftEvent.prototype.getData = function () {
this._dataFetched = true;
return {
cylinder: this._cylinder,
};
};
/**
* Enables the updraft.
*/
PhysicsUpdraftEvent.prototype.enable = function () {
this._tickCallback.call(this);
this._scene.registerBeforeRender(this._tickCallback);
};
/**
* Disables the cortex.
*/
PhysicsUpdraftEvent.prototype.disable = function () {
this._scene.unregisterBeforeRender(this._tickCallback);
};
/**
* Disposes the sphere.
* @param {bolean} force
*/
PhysicsUpdraftEvent.prototype.dispose = function (force) {
var _this = this;
if (force === void 0) { force = true; }
if (force) {
this._cylinder.dispose();
}
else {
setTimeout(function () {
if (!_this._dataFetched) {
_this._cylinder.dispose();
}
}, 0);
}
};
PhysicsUpdraftEvent.prototype.getImpostorForceAndContactPoint = function (impostor) {
if (impostor.mass === 0) {
return null;
}
if (!this._intersectsWithCylinder(impostor)) {
return null;
}
var impostorObjectCenter = impostor.getObjectCenter();
if (this._updraftMode === PhysicsUpdraftMode.Perpendicular) {
var direction = this._originDirection;
}
else {
var direction = impostorObjectCenter.subtract(this._originTop);
}
var multiplier = this._strength * -1;
var force = direction.multiplyByFloats(multiplier, multiplier, multiplier);
return { force: force, contactPoint: impostorObjectCenter };
};
PhysicsUpdraftEvent.prototype._tick = function () {
var _this = this;
this._physicsEngine.getImpostors().forEach(function (impostor) {
var impostorForceAndContactPoint = _this.getImpostorForceAndContactPoint(impostor);
if (!impostorForceAndContactPoint) {
return;
}
impostor.applyForce(impostorForceAndContactPoint.force, impostorForceAndContactPoint.contactPoint);
});
};
/*** Helpers ***/
PhysicsUpdraftEvent.prototype._prepareCylinder = function () {
if (!this._cylinder) {
this._cylinder = BABYLON.MeshBuilder.CreateCylinder("updraftEventCylinder", {
height: this._height,
diameter: this._radius * 2,
}, this._scene);
this._cylinder.isVisible = false;
}
};
PhysicsUpdraftEvent.prototype._intersectsWithCylinder = function (impostor) {
var impostorObject = impostor.object;
this._prepareCylinder();
this._cylinder.position = this._cylinderPosition;
return this._cylinder.intersectsMesh(impostorObject, true);
};
return PhysicsUpdraftEvent;
}());
BABYLON.PhysicsUpdraftEvent = PhysicsUpdraftEvent;
/***** Vortex *****/
var PhysicsVortexEvent = /** @class */ (function () {
function PhysicsVortexEvent(_scene, _origin, _radius, _strength, _height) {
this._scene = _scene;
this._origin = _origin;
this._radius = _radius;
this._strength = _strength;
this._height = _height;
this._originTop = BABYLON.Vector3.Zero(); // the most upper part of the cylinder
this._centripetalForceThreshold = 0.7; // at which distance, relative to the radius the centripetal forces should kick in
this._updraftMultiplier = 0.02;
this._cylinderPosition = BABYLON.Vector3.Zero(); // to keep the cylinders position, because normally the origin is in the center and not on the bottom
this._dataFetched = false; // check if the has been fetched the data. If not, do cleanup
this._physicsEngine = this._scene.getPhysicsEngine();
this._origin.addToRef(new BABYLON.Vector3(0, this._height / 2, 0), this._cylinderPosition);
this._origin.addToRef(new BABYLON.Vector3(0, this._height, 0), this._originTop);
this._tickCallback = this._tick.bind(this);
}
/**
* Returns the data related to the vortex event (cylinder).
* @returns {PhysicsVortexEventData}
*/
PhysicsVortexEvent.prototype.getData = function () {
this._dataFetched = true;
return {
cylinder: this._cylinder,
};
};
/**
* Enables the vortex.
*/
PhysicsVortexEvent.prototype.enable = function () {
this._tickCallback.call(this);
this._scene.registerBeforeRender(this._tickCallback);
};
/**
* Disables the cortex.
*/
PhysicsVortexEvent.prototype.disable = function () {
this._scene.unregisterBeforeRender(this._tickCallback);
};
/**
* Disposes the sphere.
* @param {bolean} force
*/
PhysicsVortexEvent.prototype.dispose = function (force) {
var _this = this;
if (force === void 0) { force = true; }
if (force) {
this._cylinder.dispose();
}
else {
setTimeout(function () {
if (!_this._dataFetched) {
_this._cylinder.dispose();
}
}, 0);
}
};
PhysicsVortexEvent.prototype.getImpostorForceAndContactPoint = function (impostor) {
if (impostor.mass === 0) {
return null;
}
if (!this._intersectsWithCylinder(impostor)) {
return null;
}
if (impostor.object.getClassName() !== 'Mesh' && impostor.object.getClassName() !== 'InstancedMesh') {
return null;
}
var impostorObjectCenter = impostor.getObjectCenter();
var originOnPlane = new BABYLON.Vector3(this._origin.x, impostorObjectCenter.y, this._origin.z); // the distance to the origin as if both objects were on a plane (Y-axis)
var originToImpostorDirection = impostorObjectCenter.subtract(originOnPlane);
var ray = new BABYLON.Ray(originOnPlane, originToImpostorDirection, this._radius);
var hit = ray.intersectsMesh(impostor.object);
var contactPoint = hit.pickedPoint;
if (!contactPoint) {
return null;
}
var absoluteDistanceFromOrigin = hit.distance / this._radius;
var perpendicularDirection = BABYLON.Vector3.Cross(originOnPlane, impostorObjectCenter).normalize();
var directionToOrigin = contactPoint.normalize();
if (absoluteDistanceFromOrigin > this._centripetalForceThreshold) {
directionToOrigin = directionToOrigin.negate();
}
// TODO: find a more physically based solution
if (absoluteDistanceFromOrigin > this._centripetalForceThreshold) {
var forceX = directionToOrigin.x * this._strength / 8;
var forceY = directionToOrigin.y * this._updraftMultiplier;
var forceZ = directionToOrigin.z * this._strength / 8;
}
else {
var forceX = (perpendicularDirection.x + directionToOrigin.x) / 2;
var forceY = this._originTop.y * this._updraftMultiplier;
var forceZ = (perpendicularDirection.z + directionToOrigin.z) / 2;
}
var force = new BABYLON.Vector3(forceX, forceY, forceZ);
force = force.multiplyByFloats(this._strength, this._strength, this._strength);
return { force: force, contactPoint: impostorObjectCenter };
};
PhysicsVortexEvent.prototype._tick = function () {
var _this = this;
this._physicsEngine.getImpostors().forEach(function (impostor) {
var impostorForceAndContactPoint = _this.getImpostorForceAndContactPoint(impostor);
if (!impostorForceAndContactPoint) {
return;
}
impostor.applyForce(impostorForceAndContactPoint.force, impostorForceAndContactPoint.contactPoint);
});
};
/*** Helpers ***/
PhysicsVortexEvent.prototype._prepareCylinder = function () {
if (!this._cylinder) {
this._cylinder = BABYLON.MeshBuilder.CreateCylinder("vortexEventCylinder", {
height: this._height,
diameter: this._radius * 2,
}, this._scene);
this._cylinder.isVisible = false;
}
};
PhysicsVortexEvent.prototype._intersectsWithCylinder = function (impostor) {
var impostorObject = impostor.object;
this._prepareCylinder();
this._cylinder.position = this._cylinderPosition;
return this._cylinder.intersectsMesh(impostorObject, true);
};
return PhysicsVortexEvent;
}());
BABYLON.PhysicsVortexEvent = PhysicsVortexEvent;
/***** Enums *****/
/**
* The strenght of the force in correspondence to the distance of the affected object
*/
var PhysicsRadialImpulseFalloff;
(function (PhysicsRadialImpulseFalloff) {
/** Defines that impulse is constant in strength across it's whole radius */
PhysicsRadialImpulseFalloff[PhysicsRadialImpulseFalloff["Constant"] = 0] = "Constant";
/** DEfines that impulse gets weaker if it's further from the origin */
PhysicsRadialImpulseFalloff[PhysicsRadialImpulseFalloff["Linear"] = 1] = "Linear";
})(PhysicsRadialImpulseFalloff = BABYLON.PhysicsRadialImpulseFalloff || (BABYLON.PhysicsRadialImpulseFalloff = {}));
/**
* The strenght of the force in correspondence to the distance of the affected object
*/
var PhysicsUpdraftMode;
(function (PhysicsUpdraftMode) {
/** Defines that the upstream forces will pull towards the top center of the cylinder */
PhysicsUpdraftMode[PhysicsUpdraftMode["Center"] = 0] = "Center";
/** Defines that once a impostor is inside the cylinder, it will shoot out perpendicular from the ground of the cylinder */
PhysicsUpdraftMode[PhysicsUpdraftMode["Perpendicular"] = 1] = "Perpendicular";
})(PhysicsUpdraftMode = BABYLON.PhysicsUpdraftMode || (BABYLON.PhysicsUpdraftMode = {}));
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.physicsHelper.js.map
var BABYLON;
(function (BABYLON) {
var CannonJSPlugin = /** @class */ (function () {
function CannonJSPlugin(_useDeltaForWorldStep, iterations) {
if (_useDeltaForWorldStep === void 0) { _useDeltaForWorldStep = true; }
if (iterations === void 0) { iterations = 10; }
this._useDeltaForWorldStep = _useDeltaForWorldStep;
this.name = "CannonJSPlugin";
this._physicsMaterials = new Array();
this._fixedTimeStep = 1 / 60;
//See https://github.com/schteppe/CANNON.js/blob/gh-pages/demos/collisionFilter.html
this.BJSCANNON = CANNON;
this._minus90X = new BABYLON.Quaternion(-0.7071067811865475, 0, 0, 0.7071067811865475);
this._plus90X = new BABYLON.Quaternion(0.7071067811865475, 0, 0, 0.7071067811865475);
this._tmpPosition = BABYLON.Vector3.Zero();
this._tmpDeltaPosition = BABYLON.Vector3.Zero();
this._tmpUnityRotation = new BABYLON.Quaternion();
if (!this.isSupported()) {
BABYLON.Tools.Error("CannonJS is not available. Please make sure you included the js file.");
return;
}
this._extendNamespace();
this.world = new this.BJSCANNON.World();
this.world.broadphase = new this.BJSCANNON.NaiveBroadphase();
this.world.solver.iterations = iterations;
}
CannonJSPlugin.prototype.setGravity = function (gravity) {
this.world.gravity.copy(gravity);
};
CannonJSPlugin.prototype.setTimeStep = function (timeStep) {
this._fixedTimeStep = timeStep;
};
CannonJSPlugin.prototype.getTimeStep = function () {
return this._fixedTimeStep;
};
CannonJSPlugin.prototype.executeStep = function (delta, impostors) {
this.world.step(this._fixedTimeStep, this._useDeltaForWorldStep ? delta : 0, 3);
};
CannonJSPlugin.prototype.applyImpulse = function (impostor, force, contactPoint) {
var worldPoint = new this.BJSCANNON.Vec3(contactPoint.x, contactPoint.y, contactPoint.z);
var impulse = new this.BJSCANNON.Vec3(force.x, force.y, force.z);
impostor.physicsBody.applyImpulse(impulse, worldPoint);
};
CannonJSPlugin.prototype.applyForce = function (impostor, force, contactPoint) {
var worldPoint = new this.BJSCANNON.Vec3(contactPoint.x, contactPoint.y, contactPoint.z);
var impulse = new this.BJSCANNON.Vec3(force.x, force.y, force.z);
impostor.physicsBody.applyForce(impulse, worldPoint);
};
CannonJSPlugin.prototype.generatePhysicsBody = function (impostor) {
//parent-child relationship. Does this impostor has a parent impostor?
if (impostor.parent) {
if (impostor.physicsBody) {
this.removePhysicsBody(impostor);
//TODO is that needed?
impostor.forceUpdate();
}
return;
}
//should a new body be created for this impostor?
if (impostor.isBodyInitRequired()) {
var shape = this._createShape(impostor);
//unregister events, if body is being changed
var oldBody = impostor.physicsBody;
if (oldBody) {
this.removePhysicsBody(impostor);
}
//create the body and material
var material = this._addMaterial("mat-" + impostor.uniqueId, impostor.getParam("friction"), impostor.getParam("restitution"));
var bodyCreationObject = {
mass: impostor.getParam("mass"),
material: material
};
// A simple extend, in case native options were used.
var nativeOptions = impostor.getParam("nativeOptions");
for (var key in nativeOptions) {
if (nativeOptions.hasOwnProperty(key)) {
bodyCreationObject[key] = nativeOptions[key];
}
}
impostor.physicsBody = new this.BJSCANNON.Body(bodyCreationObject);
impostor.physicsBody.addEventListener("collide", impostor.onCollide);
this.world.addEventListener("preStep", impostor.beforeStep);
this.world.addEventListener("postStep", impostor.afterStep);
impostor.physicsBody.addShape(shape);
this.world.add(impostor.physicsBody);
//try to keep the body moving in the right direction by taking old properties.
//Should be tested!
if (oldBody) {
['force', 'torque', 'velocity', 'angularVelocity'].forEach(function (param) {
impostor.physicsBody[param].copy(oldBody[param]);
});
}
this._processChildMeshes(impostor);
}
//now update the body's transformation
this._updatePhysicsBodyTransformation(impostor);
};
CannonJSPlugin.prototype._processChildMeshes = function (mainImpostor) {
var _this = this;
var meshChildren = mainImpostor.object.getChildMeshes ? mainImpostor.object.getChildMeshes(true) : [];
var currentRotation = mainImpostor.object.rotationQuaternion;
if (meshChildren.length) {
var processMesh = function (localPosition, mesh) {
if (!currentRotation || !mesh.rotationQuaternion) {
return;
}
var childImpostor = mesh.getPhysicsImpostor();
if (childImpostor) {
var parent = childImpostor.parent;
if (parent !== mainImpostor) {
var pPosition = mesh.getAbsolutePosition().subtract(mainImpostor.object.getAbsolutePosition());
var localRotation = mesh.rotationQuaternion.multiply(BABYLON.Quaternion.Inverse(currentRotation));
if (childImpostor.physicsBody) {
_this.removePhysicsBody(childImpostor);
childImpostor.physicsBody = null;
}
childImpostor.parent = mainImpostor;
childImpostor.resetUpdateFlags();
mainImpostor.physicsBody.addShape(_this._createShape(childImpostor), new _this.BJSCANNON.Vec3(pPosition.x, pPosition.y, pPosition.z), new _this.BJSCANNON.Quaternion(localRotation.x, localRotation.y, localRotation.z, localRotation.w));
//Add the mass of the children.
mainImpostor.physicsBody.mass += childImpostor.getParam("mass");
}
}
currentRotation.multiplyInPlace(mesh.rotationQuaternion);
mesh.getChildMeshes(true).filter(function (m) { return !!m.physicsImpostor; }).forEach(processMesh.bind(_this, mesh.getAbsolutePosition()));
};
meshChildren.filter(function (m) { return !!m.physicsImpostor; }).forEach(processMesh.bind(this, mainImpostor.object.getAbsolutePosition()));
}
};
CannonJSPlugin.prototype.removePhysicsBody = function (impostor) {
impostor.physicsBody.removeEventListener("collide", impostor.onCollide);
this.world.removeEventListener("preStep", impostor.beforeStep);
this.world.removeEventListener("postStep", impostor.afterStep);
this.world.remove(impostor.physicsBody);
};
CannonJSPlugin.prototype.generateJoint = function (impostorJoint) {
var mainBody = impostorJoint.mainImpostor.physicsBody;
var connectedBody = impostorJoint.connectedImpostor.physicsBody;
if (!mainBody || !connectedBody) {
return;
}
var constraint;
var jointData = impostorJoint.joint.jointData;
//TODO - https://github.com/schteppe/this.BJSCANNON.js/blob/gh-pages/demos/collisionFilter.html
var constraintData = {
pivotA: jointData.mainPivot ? new this.BJSCANNON.Vec3().copy(jointData.mainPivot) : null,
pivotB: jointData.connectedPivot ? new this.BJSCANNON.Vec3().copy(jointData.connectedPivot) : null,
axisA: jointData.mainAxis ? new this.BJSCANNON.Vec3().copy(jointData.mainAxis) : null,
axisB: jointData.connectedAxis ? new this.BJSCANNON.Vec3().copy(jointData.connectedAxis) : null,
maxForce: jointData.nativeParams.maxForce,
collideConnected: !!jointData.collision
};
switch (impostorJoint.joint.type) {
case BABYLON.PhysicsJoint.HingeJoint:
case BABYLON.PhysicsJoint.Hinge2Joint:
constraint = new this.BJSCANNON.HingeConstraint(mainBody, connectedBody, constraintData);
break;
case BABYLON.PhysicsJoint.DistanceJoint:
constraint = new this.BJSCANNON.DistanceConstraint(mainBody, connectedBody, jointData.maxDistance || 2);
break;
case BABYLON.PhysicsJoint.SpringJoint:
var springData = jointData;
constraint = new this.BJSCANNON.Spring(mainBody, connectedBody, {
restLength: springData.length,
stiffness: springData.stiffness,
damping: springData.damping,
localAnchorA: constraintData.pivotA,
localAnchorB: constraintData.pivotB
});
break;
case BABYLON.PhysicsJoint.LockJoint:
constraint = new this.BJSCANNON.LockConstraint(mainBody, connectedBody, constraintData);
break;
case BABYLON.PhysicsJoint.PointToPointJoint:
case BABYLON.PhysicsJoint.BallAndSocketJoint:
default:
constraint = new this.BJSCANNON.PointToPointConstraint(mainBody, constraintData.pivotA, connectedBody, constraintData.pivotA, constraintData.maxForce);
break;
}
//set the collideConnected flag after the creation, since DistanceJoint ignores it.
constraint.collideConnected = !!jointData.collision;
impostorJoint.joint.physicsJoint = constraint;
//don't add spring as constraint, as it is not one.
if (impostorJoint.joint.type !== BABYLON.PhysicsJoint.SpringJoint) {
this.world.addConstraint(constraint);
}
else {
impostorJoint.mainImpostor.registerAfterPhysicsStep(function () {
constraint.applyForce();
});
}
};
CannonJSPlugin.prototype.removeJoint = function (impostorJoint) {
this.world.removeConstraint(impostorJoint.joint.physicsJoint);
};
CannonJSPlugin.prototype._addMaterial = function (name, friction, restitution) {
var index;
var mat;
for (index = 0; index < this._physicsMaterials.length; index++) {
mat = this._physicsMaterials[index];
if (mat.friction === friction && mat.restitution === restitution) {
return mat;
}
}
var currentMat = new this.BJSCANNON.Material(name);
currentMat.friction = friction;
currentMat.restitution = restitution;
this._physicsMaterials.push(currentMat);
return currentMat;
};
CannonJSPlugin.prototype._checkWithEpsilon = function (value) {
return value < BABYLON.PhysicsEngine.Epsilon ? BABYLON.PhysicsEngine.Epsilon : value;
};
CannonJSPlugin.prototype._createShape = function (impostor) {
var object = impostor.object;
var returnValue;
var extendSize = impostor.getObjectExtendSize();
switch (impostor.type) {
case BABYLON.PhysicsImpostor.SphereImpostor:
var radiusX = extendSize.x;
var radiusY = extendSize.y;
var radiusZ = extendSize.z;
returnValue = new this.BJSCANNON.Sphere(Math.max(this._checkWithEpsilon(radiusX), this._checkWithEpsilon(radiusY), this._checkWithEpsilon(radiusZ)) / 2);
break;
//TMP also for cylinder - TODO Cannon supports cylinder natively.
case BABYLON.PhysicsImpostor.CylinderImpostor:
returnValue = new this.BJSCANNON.Cylinder(this._checkWithEpsilon(extendSize.x) / 2, this._checkWithEpsilon(extendSize.x) / 2, this._checkWithEpsilon(extendSize.y), 16);
break;
case BABYLON.PhysicsImpostor.BoxImpostor:
var box = extendSize.scale(0.5);
returnValue = new this.BJSCANNON.Box(new this.BJSCANNON.Vec3(this._checkWithEpsilon(box.x), this._checkWithEpsilon(box.y), this._checkWithEpsilon(box.z)));
break;
case BABYLON.PhysicsImpostor.PlaneImpostor:
BABYLON.Tools.Warn("Attention, PlaneImposter might not behave as you expect. Consider using BoxImposter instead");
returnValue = new this.BJSCANNON.Plane();
break;
case BABYLON.PhysicsImpostor.MeshImpostor:
// should transform the vertex data to world coordinates!!
var rawVerts = object.getVerticesData ? object.getVerticesData(BABYLON.VertexBuffer.PositionKind) : [];
var rawFaces = object.getIndices ? object.getIndices() : [];
if (!rawVerts)
return;
// get only scale! so the object could transform correctly.
var oldPosition = object.position.clone();
var oldRotation = object.rotation && object.rotation.clone();
var oldQuaternion = object.rotationQuaternion && object.rotationQuaternion.clone();
object.position.copyFromFloats(0, 0, 0);
object.rotation && object.rotation.copyFromFloats(0, 0, 0);
object.rotationQuaternion && object.rotationQuaternion.copyFrom(impostor.getParentsRotation());
object.rotationQuaternion && object.parent && object.rotationQuaternion.conjugateInPlace();
var transform = object.computeWorldMatrix(true);
// convert rawVerts to object space
var temp = new Array();
var index;
for (index = 0; index < rawVerts.length; index += 3) {
BABYLON.Vector3.TransformCoordinates(BABYLON.Vector3.FromArray(rawVerts, index), transform).toArray(temp, index);
}
BABYLON.Tools.Warn("MeshImpostor only collides against spheres.");
returnValue = new this.BJSCANNON.Trimesh(temp, rawFaces);
//now set back the transformation!
object.position.copyFrom(oldPosition);
oldRotation && object.rotation && object.rotation.copyFrom(oldRotation);
oldQuaternion && object.rotationQuaternion && object.rotationQuaternion.copyFrom(oldQuaternion);
break;
case BABYLON.PhysicsImpostor.HeightmapImpostor:
var oldPosition2 = object.position.clone();
var oldRotation2 = object.rotation && object.rotation.clone();
var oldQuaternion2 = object.rotationQuaternion && object.rotationQuaternion.clone();
object.position.copyFromFloats(0, 0, 0);
object.rotation && object.rotation.copyFromFloats(0, 0, 0);
object.rotationQuaternion && object.rotationQuaternion.copyFrom(impostor.getParentsRotation());
object.rotationQuaternion && object.parent && object.rotationQuaternion.conjugateInPlace();
object.rotationQuaternion && object.rotationQuaternion.multiplyInPlace(this._minus90X);
returnValue = this._createHeightmap(object);
object.position.copyFrom(oldPosition2);
oldRotation2 && object.rotation && object.rotation.copyFrom(oldRotation2);
oldQuaternion2 && object.rotationQuaternion && object.rotationQuaternion.copyFrom(oldQuaternion2);
object.computeWorldMatrix(true);
break;
case BABYLON.PhysicsImpostor.ParticleImpostor:
returnValue = new this.BJSCANNON.Particle();
break;
}
return returnValue;
};
CannonJSPlugin.prototype._createHeightmap = function (object, pointDepth) {
var pos = (object.getVerticesData(BABYLON.VertexBuffer.PositionKind));
var transform = object.computeWorldMatrix(true);
// convert rawVerts to object space
var temp = new Array();
var index;
for (index = 0; index < pos.length; index += 3) {
BABYLON.Vector3.TransformCoordinates(BABYLON.Vector3.FromArray(pos, index), transform).toArray(temp, index);
}
pos = temp;
var matrix = new Array();
//For now pointDepth will not be used and will be automatically calculated.
//Future reference - try and find the best place to add a reference to the pointDepth variable.
var arraySize = pointDepth || ~~(Math.sqrt(pos.length / 3) - 1);
var boundingInfo = object.getBoundingInfo();
var dim = Math.min(boundingInfo.boundingBox.extendSizeWorld.x, boundingInfo.boundingBox.extendSizeWorld.y);
var minY = boundingInfo.boundingBox.extendSizeWorld.z;
var elementSize = dim * 2 / arraySize;
for (var i = 0; i < pos.length; i = i + 3) {
var x = Math.round((pos[i + 0]) / elementSize + arraySize / 2);
var z = Math.round(((pos[i + 1]) / elementSize - arraySize / 2) * -1);
var y = -pos[i + 2] + minY;
if (!matrix[x]) {
matrix[x] = [];
}
if (!matrix[x][z]) {
matrix[x][z] = y;
}
matrix[x][z] = Math.max(y, matrix[x][z]);
}
for (var x = 0; x <= arraySize; ++x) {
if (!matrix[x]) {
var loc = 1;
while (!matrix[(x + loc) % arraySize]) {
loc++;
}
matrix[x] = matrix[(x + loc) % arraySize].slice();
//console.log("missing x", x);
}
for (var z = 0; z <= arraySize; ++z) {
if (!matrix[x][z]) {
var loc = 1;
var newValue;
while (newValue === undefined) {
newValue = matrix[x][(z + loc++) % arraySize];
}
matrix[x][z] = newValue;
}
}
}
var shape = new this.BJSCANNON.Heightfield(matrix, {
elementSize: elementSize
});
//For future reference, needed for body transformation
shape.minY = minY;
return shape;
};
CannonJSPlugin.prototype._updatePhysicsBodyTransformation = function (impostor) {
var object = impostor.object;
//make sure it is updated...
object.computeWorldMatrix && object.computeWorldMatrix(true);
// The delta between the mesh position and the mesh bounding box center
var bInfo = object.getBoundingInfo();
if (!bInfo)
return;
var center = impostor.getObjectCenter();
//m.getAbsolutePosition().subtract(m.getBoundingInfo().boundingBox.centerWorld)
this._tmpDeltaPosition.copyFrom(object.getAbsolutePivotPoint().subtract(center));
this._tmpDeltaPosition.divideInPlace(impostor.object.scaling);
this._tmpPosition.copyFrom(center);
var quaternion = object.rotationQuaternion;
if (!quaternion) {
return;
}
//is shape is a plane or a heightmap, it must be rotated 90 degs in the X axis.
if (impostor.type === BABYLON.PhysicsImpostor.PlaneImpostor || impostor.type === BABYLON.PhysicsImpostor.HeightmapImpostor || impostor.type === BABYLON.PhysicsImpostor.CylinderImpostor) {
//-90 DEG in X, precalculated
quaternion = quaternion.multiply(this._minus90X);
//Invert! (Precalculated, 90 deg in X)
//No need to clone. this will never change.
impostor.setDeltaRotation(this._plus90X);
}
//If it is a heightfield, if should be centered.
if (impostor.type === BABYLON.PhysicsImpostor.HeightmapImpostor) {
var mesh = object;
var boundingInfo = mesh.getBoundingInfo();
//calculate the correct body position:
var rotationQuaternion = mesh.rotationQuaternion;
mesh.rotationQuaternion = this._tmpUnityRotation;
mesh.computeWorldMatrix(true);
//get original center with no rotation
var c = center.clone();
var oldPivot = mesh.getPivotMatrix() || BABYLON.Matrix.Translation(0, 0, 0);
//calculate the new center using a pivot (since this.BJSCANNON.js doesn't center height maps)
var p = BABYLON.Matrix.Translation(boundingInfo.boundingBox.extendSizeWorld.x, 0, -boundingInfo.boundingBox.extendSizeWorld.z);
mesh.setPreTransformMatrix(p);
mesh.computeWorldMatrix(true);
//calculate the translation
var translation = boundingInfo.boundingBox.centerWorld.subtract(center).subtract(mesh.position).negate();
this._tmpPosition.copyFromFloats(translation.x, translation.y - boundingInfo.boundingBox.extendSizeWorld.y, translation.z);
//add it inverted to the delta
this._tmpDeltaPosition.copyFrom(boundingInfo.boundingBox.centerWorld.subtract(c));
this._tmpDeltaPosition.y += boundingInfo.boundingBox.extendSizeWorld.y;
//rotation is back
mesh.rotationQuaternion = rotationQuaternion;
mesh.setPreTransformMatrix(oldPivot);
mesh.computeWorldMatrix(true);
}
else if (impostor.type === BABYLON.PhysicsImpostor.MeshImpostor) {
this._tmpDeltaPosition.copyFromFloats(0, 0, 0);
//this._tmpPosition.copyFrom(object.position);
}
impostor.setDeltaPosition(this._tmpDeltaPosition);
//Now update the impostor object
impostor.physicsBody.position.copy(this._tmpPosition);
impostor.physicsBody.quaternion.copy(quaternion);
};
CannonJSPlugin.prototype.setTransformationFromPhysicsBody = function (impostor) {
impostor.object.position.copyFrom(impostor.physicsBody.position);
if (impostor.object.rotationQuaternion) {
impostor.object.rotationQuaternion.copyFrom(impostor.physicsBody.quaternion);
}
};
CannonJSPlugin.prototype.setPhysicsBodyTransformation = function (impostor, newPosition, newRotation) {
impostor.physicsBody.position.copy(newPosition);
impostor.physicsBody.quaternion.copy(newRotation);
};
CannonJSPlugin.prototype.isSupported = function () {
return this.BJSCANNON !== undefined;
};
CannonJSPlugin.prototype.setLinearVelocity = function (impostor, velocity) {
impostor.physicsBody.velocity.copy(velocity);
};
CannonJSPlugin.prototype.setAngularVelocity = function (impostor, velocity) {
impostor.physicsBody.angularVelocity.copy(velocity);
};
CannonJSPlugin.prototype.getLinearVelocity = function (impostor) {
var v = impostor.physicsBody.velocity;
if (!v) {
return null;
}
return new BABYLON.Vector3(v.x, v.y, v.z);
};
CannonJSPlugin.prototype.getAngularVelocity = function (impostor) {
var v = impostor.physicsBody.angularVelocity;
if (!v) {
return null;
}
return new BABYLON.Vector3(v.x, v.y, v.z);
};
CannonJSPlugin.prototype.setBodyMass = function (impostor, mass) {
impostor.physicsBody.mass = mass;
impostor.physicsBody.updateMassProperties();
};
CannonJSPlugin.prototype.getBodyMass = function (impostor) {
return impostor.physicsBody.mass;
};
CannonJSPlugin.prototype.getBodyFriction = function (impostor) {
return impostor.physicsBody.material.friction;
};
CannonJSPlugin.prototype.setBodyFriction = function (impostor, friction) {
impostor.physicsBody.material.friction = friction;
};
CannonJSPlugin.prototype.getBodyRestitution = function (impostor) {
return impostor.physicsBody.material.restitution;
};
CannonJSPlugin.prototype.setBodyRestitution = function (impostor, restitution) {
impostor.physicsBody.material.restitution = restitution;
};
CannonJSPlugin.prototype.sleepBody = function (impostor) {
impostor.physicsBody.sleep();
};
CannonJSPlugin.prototype.wakeUpBody = function (impostor) {
impostor.physicsBody.wakeUp();
};
CannonJSPlugin.prototype.updateDistanceJoint = function (joint, maxDistance, minDistance) {
joint.physicsJoint.distance = maxDistance;
};
// private enableMotor(joint: IMotorEnabledJoint, motorIndex?: number) {
// if (!motorIndex) {
// joint.physicsJoint.enableMotor();
// }
// }
// private disableMotor(joint: IMotorEnabledJoint, motorIndex?: number) {
// if (!motorIndex) {
// joint.physicsJoint.disableMotor();
// }
// }
CannonJSPlugin.prototype.setMotor = function (joint, speed, maxForce, motorIndex) {
if (!motorIndex) {
joint.physicsJoint.enableMotor();
joint.physicsJoint.setMotorSpeed(speed);
if (maxForce) {
this.setLimit(joint, maxForce);
}
}
};
CannonJSPlugin.prototype.setLimit = function (joint, upperLimit, lowerLimit) {
joint.physicsJoint.motorEquation.maxForce = upperLimit;
joint.physicsJoint.motorEquation.minForce = lowerLimit === void 0 ? -upperLimit : lowerLimit;
};
CannonJSPlugin.prototype.syncMeshWithImpostor = function (mesh, impostor) {
var body = impostor.physicsBody;
mesh.position.x = body.position.x;
mesh.position.y = body.position.y;
mesh.position.z = body.position.z;
if (mesh.rotationQuaternion) {
mesh.rotationQuaternion.x = body.quaternion.x;
mesh.rotationQuaternion.y = body.quaternion.y;
mesh.rotationQuaternion.z = body.quaternion.z;
mesh.rotationQuaternion.w = body.quaternion.w;
}
};
CannonJSPlugin.prototype.getRadius = function (impostor) {
var shape = impostor.physicsBody.shapes[0];
return shape.boundingSphereRadius;
};
CannonJSPlugin.prototype.getBoxSizeToRef = function (impostor, result) {
var shape = impostor.physicsBody.shapes[0];
result.x = shape.halfExtents.x * 2;
result.y = shape.halfExtents.y * 2;
result.z = shape.halfExtents.z * 2;
};
CannonJSPlugin.prototype.dispose = function () {
};
CannonJSPlugin.prototype._extendNamespace = function () {
//this will force cannon to execute at least one step when using interpolation
var step_tmp1 = new this.BJSCANNON.Vec3();
var Engine = this.BJSCANNON;
this.BJSCANNON.World.prototype.step = function (dt, timeSinceLastCalled, maxSubSteps) {
maxSubSteps = maxSubSteps || 10;
timeSinceLastCalled = timeSinceLastCalled || 0;
if (timeSinceLastCalled === 0) {
this.internalStep(dt);
this.time += dt;
}
else {
var internalSteps = Math.floor((this.time + timeSinceLastCalled) / dt) - Math.floor(this.time / dt);
internalSteps = Math.min(internalSteps, maxSubSteps) || 1;
var t0 = performance.now();
for (var i = 0; i !== internalSteps; i++) {
this.internalStep(dt);
if (performance.now() - t0 > dt * 1000) {
break;
}
}
this.time += timeSinceLastCalled;
var h = this.time % dt;
var h_div_dt = h / dt;
var interpvelo = step_tmp1;
var bodies = this.bodies;
for (var j = 0; j !== bodies.length; j++) {
var b = bodies[j];
if (b.type !== Engine.Body.STATIC && b.sleepState !== Engine.Body.SLEEPING) {
b.position.vsub(b.previousPosition, interpvelo);
interpvelo.scale(h_div_dt, interpvelo);
b.position.vadd(interpvelo, b.interpolatedPosition);
}
else {
b.interpolatedPosition.copy(b.position);
b.interpolatedQuaternion.copy(b.quaternion);
}
}
}
};
};
return CannonJSPlugin;
}());
BABYLON.CannonJSPlugin = CannonJSPlugin;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.cannonJSPlugin.js.map
var BABYLON;
(function (BABYLON) {
var OimoJSPlugin = /** @class */ (function () {
function OimoJSPlugin(iterations) {
this.name = "OimoJSPlugin";
this._tmpImpostorsArray = [];
this._tmpPositionVector = BABYLON.Vector3.Zero();
this.BJSOIMO = OIMO;
this.world = new this.BJSOIMO.World({
iterations: iterations
});
this.world.clear();
}
OimoJSPlugin.prototype.setGravity = function (gravity) {
this.world.gravity.copy(gravity);
};
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) {
impostor.beforeStep();
});
this.world.step();
impostors.forEach(function (impostor) {
impostor.afterStep();
//update the ordered impostors array
_this._tmpImpostorsArray[impostor.uniqueId] = impostor;
});
//check for collisions
var contact = this.world.contacts;
while (contact !== null) {
if (contact.touching && !contact.body1.sleeping && !contact.body2.sleeping) {
contact = contact.next;
continue;
}
//is this body colliding with any other? get the impostor
var mainImpostor = this._tmpImpostorsArray[+contact.body1.name];
var collidingImpostor = this._tmpImpostorsArray[+contact.body2.name];
if (!mainImpostor || !collidingImpostor) {
contact = contact.next;
continue;
}
mainImpostor.onCollide({ body: collidingImpostor.physicsBody });
collidingImpostor.onCollide({ body: mainImpostor.physicsBody });
contact = contact.next;
}
};
OimoJSPlugin.prototype.applyImpulse = function (impostor, force, contactPoint) {
var mass = impostor.physicsBody.mass;
impostor.physicsBody.applyImpulse(contactPoint.scale(this.world.invScale), force.scale(this.world.invScale * mass));
};
OimoJSPlugin.prototype.applyForce = function (impostor, force, contactPoint) {
BABYLON.Tools.Warn("Oimo doesn't support applying force. Using impule instead.");
this.applyImpulse(impostor, force, contactPoint);
};
OimoJSPlugin.prototype.generatePhysicsBody = function (impostor) {
var _this = this;
//parent-child relationship. Does this impostor has a parent impostor?
if (impostor.parent) {
if (impostor.physicsBody) {
this.removePhysicsBody(impostor);
//TODO is that needed?
impostor.forceUpdate();
}
return;
}
if (impostor.isBodyInitRequired()) {
var bodyConfig = {
name: impostor.uniqueId,
//Oimo must have mass, also for static objects.
config: [impostor.getParam("mass") || 1, impostor.getParam("friction"), impostor.getParam("restitution")],
size: [],
type: [],
pos: [],
posShape: [],
rot: [],
rotShape: [],
move: impostor.getParam("mass") !== 0,
density: impostor.getParam("mass"),
friction: impostor.getParam("friction"),
restitution: impostor.getParam("restitution"),
//Supporting older versions of Oimo
world: this.world
};
var impostors = [impostor];
var addToArray = function (parent) {
if (!parent.getChildMeshes)
return;
parent.getChildMeshes().forEach(function (m) {
if (m.physicsImpostor) {
impostors.push(m.physicsImpostor);
//m.physicsImpostor._init();
}
});
};
addToArray(impostor.object);
var checkWithEpsilon_1 = function (value) {
return Math.max(value, BABYLON.PhysicsEngine.Epsilon);
};
var globalQuaternion_1 = new BABYLON.Quaternion();
impostors.forEach(function (i) {
if (!i.object.rotationQuaternion) {
return;
}
//get the correct bounding box
var oldQuaternion = i.object.rotationQuaternion;
globalQuaternion_1 = oldQuaternion.clone();
var rot = oldQuaternion.toEulerAngles();
var extendSize = i.getObjectExtendSize();
var radToDeg = 57.295779513082320876;
if (i === impostor) {
var center = impostor.getObjectCenter();
impostor.object.getAbsolutePivotPoint().subtractToRef(center, _this._tmpPositionVector);
_this._tmpPositionVector.divideInPlace(impostor.object.scaling);
//Can also use Array.prototype.push.apply
bodyConfig.pos.push(center.x);
bodyConfig.pos.push(center.y);
bodyConfig.pos.push(center.z);
bodyConfig.posShape.push(0, 0, 0);
//tmp solution
bodyConfig.rot.push(0);
bodyConfig.rot.push(0);
bodyConfig.rot.push(0);
bodyConfig.rotShape.push(0, 0, 0);
}
else {
var localPosition = i.object.getAbsolutePosition().subtract(impostor.object.getAbsolutePosition());
bodyConfig.posShape.push(localPosition.x);
bodyConfig.posShape.push(localPosition.y);
bodyConfig.posShape.push(localPosition.z);
bodyConfig.pos.push(0, 0, 0);
//tmp solution until https://github.com/lo-th/OIMO.js/pull/37 is merged
bodyConfig.rot.push(0);
bodyConfig.rot.push(0);
bodyConfig.rot.push(0);
bodyConfig.rotShape.push(rot.x * radToDeg);
bodyConfig.rotShape.push(rot.y * radToDeg);
bodyConfig.rotShape.push(rot.z * radToDeg);
}
// register mesh
switch (i.type) {
case BABYLON.PhysicsImpostor.ParticleImpostor:
BABYLON.Tools.Warn("No Particle support in OIMO.js. using SphereImpostor instead");
case BABYLON.PhysicsImpostor.SphereImpostor:
var radiusX = extendSize.x;
var radiusY = extendSize.y;
var radiusZ = extendSize.z;
var size = Math.max(checkWithEpsilon_1(radiusX), checkWithEpsilon_1(radiusY), checkWithEpsilon_1(radiusZ)) / 2;
bodyConfig.type.push('sphere');
//due to the way oimo works with compounds, add 3 times
bodyConfig.size.push(size);
bodyConfig.size.push(size);
bodyConfig.size.push(size);
break;
case BABYLON.PhysicsImpostor.CylinderImpostor:
var sizeX = checkWithEpsilon_1(extendSize.x) / 2;
var sizeY = checkWithEpsilon_1(extendSize.y);
bodyConfig.type.push('cylinder');
bodyConfig.size.push(sizeX);
bodyConfig.size.push(sizeY);
//due to the way oimo works with compounds, add one more value.
bodyConfig.size.push(sizeY);
break;
case BABYLON.PhysicsImpostor.PlaneImpostor:
case BABYLON.PhysicsImpostor.BoxImpostor:
default:
var sizeX = checkWithEpsilon_1(extendSize.x);
var sizeY = checkWithEpsilon_1(extendSize.y);
var sizeZ = checkWithEpsilon_1(extendSize.z);
bodyConfig.type.push('box');
//if (i === impostor) {
bodyConfig.size.push(sizeX);
bodyConfig.size.push(sizeY);
bodyConfig.size.push(sizeZ);
//} else {
// bodyConfig.size.push(0,0,0);
//}
break;
}
//actually not needed, but hey...
i.object.rotationQuaternion = oldQuaternion;
});
impostor.physicsBody = this.world.add(bodyConfig);
// set the quaternion, ignoring the previously defined (euler) rotation
impostor.physicsBody.resetQuaternion(globalQuaternion_1);
// update with delta 0, so the body will reveive the new rotation.
impostor.physicsBody.updatePosition(0);
}
else {
this._tmpPositionVector.copyFromFloats(0, 0, 0);
}
impostor.setDeltaPosition(this._tmpPositionVector);
//this._tmpPositionVector.addInPlace(impostor.mesh.getBoundingInfo().boundingBox.center);
//this.setPhysicsBodyTransformation(impostor, this._tmpPositionVector, impostor.mesh.rotationQuaternion);
};
OimoJSPlugin.prototype.removePhysicsBody = function (impostor) {
//impostor.physicsBody.dispose();
//Same as : (older oimo versions)
this.world.removeRigidBody(impostor.physicsBody);
};
OimoJSPlugin.prototype.generateJoint = function (impostorJoint) {
var mainBody = impostorJoint.mainImpostor.physicsBody;
var connectedBody = impostorJoint.connectedImpostor.physicsBody;
if (!mainBody || !connectedBody) {
return;
}
var jointData = impostorJoint.joint.jointData;
var options = jointData.nativeParams || {};
var type;
var nativeJointData = {
body1: mainBody,
body2: connectedBody,
axe1: options.axe1 || (jointData.mainAxis ? jointData.mainAxis.asArray() : null),
axe2: options.axe2 || (jointData.connectedAxis ? jointData.connectedAxis.asArray() : null),
pos1: options.pos1 || (jointData.mainPivot ? jointData.mainPivot.asArray() : null),
pos2: options.pos2 || (jointData.connectedPivot ? jointData.connectedPivot.asArray() : null),
min: options.min,
max: options.max,
collision: options.collision || jointData.collision,
spring: options.spring,
//supporting older version of Oimo
world: this.world
};
switch (impostorJoint.joint.type) {
case BABYLON.PhysicsJoint.BallAndSocketJoint:
type = "jointBall";
break;
case BABYLON.PhysicsJoint.SpringJoint:
BABYLON.Tools.Warn("OIMO.js doesn't support Spring Constraint. Simulating using DistanceJoint instead");
var springData = jointData;
nativeJointData.min = springData.length || nativeJointData.min;
//Max should also be set, just make sure it is at least min
nativeJointData.max = Math.max(nativeJointData.min, nativeJointData.max);
case BABYLON.PhysicsJoint.DistanceJoint:
type = "jointDistance";
nativeJointData.max = jointData.maxDistance;
break;
case BABYLON.PhysicsJoint.PrismaticJoint:
type = "jointPrisme";
break;
case BABYLON.PhysicsJoint.SliderJoint:
type = "jointSlide";
break;
case BABYLON.PhysicsJoint.WheelJoint:
type = "jointWheel";
break;
case BABYLON.PhysicsJoint.HingeJoint:
default:
type = "jointHinge";
break;
}
nativeJointData.type = type;
impostorJoint.joint.physicsJoint = this.world.add(nativeJointData);
};
OimoJSPlugin.prototype.removeJoint = function (impostorJoint) {
//Bug in Oimo prevents us from disposing a joint in the playground
//joint.joint.physicsJoint.dispose();
//So we will bruteforce it!
try {
this.world.removeJoint(impostorJoint.joint.physicsJoint);
}
catch (e) {
BABYLON.Tools.Warn(e);
}
};
OimoJSPlugin.prototype.isSupported = function () {
return this.BJSOIMO !== undefined;
};
OimoJSPlugin.prototype.setTransformationFromPhysicsBody = function (impostor) {
if (!impostor.physicsBody.sleeping) {
//TODO check that
/*if (impostor.physicsBody.shapes.next) {
var parentShape = this._getLastShape(impostor.physicsBody);
impostor.object.position.copyFrom(parentShape.position);
console.log(parentShape.position);
} else {*/
impostor.object.position.copyFrom(impostor.physicsBody.getPosition());
//}
if (impostor.object.rotationQuaternion) {
impostor.object.rotationQuaternion.copyFrom(impostor.physicsBody.getQuaternion());
}
}
};
OimoJSPlugin.prototype.setPhysicsBodyTransformation = function (impostor, newPosition, newRotation) {
var body = impostor.physicsBody;
body.position.copy(newPosition);
body.orientation.copy(newRotation);
body.syncShapes();
body.awake();
};
/*private _getLastShape(body: any): any {
var lastShape = body.shapes;
while (lastShape.next) {
lastShape = lastShape.next;
}
return lastShape;
}*/
OimoJSPlugin.prototype.setLinearVelocity = function (impostor, velocity) {
impostor.physicsBody.linearVelocity.copy(velocity);
};
OimoJSPlugin.prototype.setAngularVelocity = function (impostor, velocity) {
impostor.physicsBody.angularVelocity.copy(velocity);
};
OimoJSPlugin.prototype.getLinearVelocity = function (impostor) {
var v = impostor.physicsBody.linearVelocity;
if (!v) {
return null;
}
return new BABYLON.Vector3(v.x, v.y, v.z);
};
OimoJSPlugin.prototype.getAngularVelocity = function (impostor) {
var v = impostor.physicsBody.angularVelocity;
if (!v) {
return null;
}
return new BABYLON.Vector3(v.x, v.y, v.z);
};
OimoJSPlugin.prototype.setBodyMass = function (impostor, mass) {
var staticBody = mass === 0;
//this will actually set the body's density and not its mass.
//But this is how oimo treats the mass variable.
impostor.physicsBody.shapes.density = staticBody ? 1 : mass;
impostor.physicsBody.setupMass(staticBody ? 0x2 : 0x1);
};
OimoJSPlugin.prototype.getBodyMass = function (impostor) {
return impostor.physicsBody.shapes.density;
};
OimoJSPlugin.prototype.getBodyFriction = function (impostor) {
return impostor.physicsBody.shapes.friction;
};
OimoJSPlugin.prototype.setBodyFriction = function (impostor, friction) {
impostor.physicsBody.shapes.friction = friction;
};
OimoJSPlugin.prototype.getBodyRestitution = function (impostor) {
return impostor.physicsBody.shapes.restitution;
};
OimoJSPlugin.prototype.setBodyRestitution = function (impostor, restitution) {
impostor.physicsBody.shapes.restitution = restitution;
};
OimoJSPlugin.prototype.sleepBody = function (impostor) {
impostor.physicsBody.sleep();
};
OimoJSPlugin.prototype.wakeUpBody = function (impostor) {
impostor.physicsBody.awake();
};
OimoJSPlugin.prototype.updateDistanceJoint = function (joint, maxDistance, minDistance) {
joint.physicsJoint.limitMotor.upperLimit = maxDistance;
if (minDistance !== void 0) {
joint.physicsJoint.limitMotor.lowerLimit = minDistance;
}
};
OimoJSPlugin.prototype.setMotor = function (joint, speed, maxForce, motorIndex) {
//TODO separate rotational and transational motors.
var motor = motorIndex ? joint.physicsJoint.rotationalLimitMotor2 : joint.physicsJoint.rotationalLimitMotor1 || joint.physicsJoint.rotationalLimitMotor || joint.physicsJoint.limitMotor;
if (motor) {
motor.setMotor(speed, maxForce);
}
};
OimoJSPlugin.prototype.setLimit = function (joint, upperLimit, lowerLimit, motorIndex) {
//TODO separate rotational and transational motors.
var motor = motorIndex ? joint.physicsJoint.rotationalLimitMotor2 : joint.physicsJoint.rotationalLimitMotor1 || joint.physicsJoint.rotationalLimitMotor || joint.physicsJoint.limitMotor;
if (motor) {
motor.setLimit(upperLimit, lowerLimit === void 0 ? -upperLimit : lowerLimit);
}
};
OimoJSPlugin.prototype.syncMeshWithImpostor = function (mesh, impostor) {
var body = impostor.physicsBody;
mesh.position.x = body.position.x;
mesh.position.y = body.position.y;
mesh.position.z = body.position.z;
if (mesh.rotationQuaternion) {
mesh.rotationQuaternion.x = body.orientation.x;
mesh.rotationQuaternion.y = body.orientation.y;
mesh.rotationQuaternion.z = body.orientation.z;
mesh.rotationQuaternion.w = body.orientation.s;
}
};
OimoJSPlugin.prototype.getRadius = function (impostor) {
return impostor.physicsBody.shapes.radius;
};
OimoJSPlugin.prototype.getBoxSizeToRef = function (impostor, result) {
var shape = impostor.physicsBody.shapes;
result.x = shape.halfWidth * 2;
result.y = shape.halfHeight * 2;
result.z = shape.halfDepth * 2;
};
OimoJSPlugin.prototype.dispose = function () {
this.world.clear();
};
return OimoJSPlugin;
}());
BABYLON.OimoJSPlugin = OimoJSPlugin;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.oimoJSPlugin.js.map
var BABYLON;
(function (BABYLON) {
// Based on demo done by Brandon Jones - http://media.tojicode.com/webgl-samples/dds.html
// All values and structures referenced from:
// http://msdn.microsoft.com/en-us/library/bb943991.aspx/
var DDS_MAGIC = 0x20534444;
var
//DDSD_CAPS = 0x1,
//DDSD_HEIGHT = 0x2,
//DDSD_WIDTH = 0x4,
//DDSD_PITCH = 0x8,
//DDSD_PIXELFORMAT = 0x1000,
DDSD_MIPMAPCOUNT = 0x20000;
//DDSD_LINEARSIZE = 0x80000,
//DDSD_DEPTH = 0x800000;
// var DDSCAPS_COMPLEX = 0x8,
// DDSCAPS_MIPMAP = 0x400000,
// DDSCAPS_TEXTURE = 0x1000;
var DDSCAPS2_CUBEMAP = 0x200;
// DDSCAPS2_CUBEMAP_POSITIVEX = 0x400,
// DDSCAPS2_CUBEMAP_NEGATIVEX = 0x800,
// DDSCAPS2_CUBEMAP_POSITIVEY = 0x1000,
// DDSCAPS2_CUBEMAP_NEGATIVEY = 0x2000,
// DDSCAPS2_CUBEMAP_POSITIVEZ = 0x4000,
// DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x8000,
// DDSCAPS2_VOLUME = 0x200000;
var
//DDPF_ALPHAPIXELS = 0x1,
//DDPF_ALPHA = 0x2,
DDPF_FOURCC = 0x4, DDPF_RGB = 0x40,
//DDPF_YUV = 0x200,
DDPF_LUMINANCE = 0x20000;
function FourCCToInt32(value) {
return value.charCodeAt(0) +
(value.charCodeAt(1) << 8) +
(value.charCodeAt(2) << 16) +
(value.charCodeAt(3) << 24);
}
function Int32ToFourCC(value) {
return String.fromCharCode(value & 0xff, (value >> 8) & 0xff, (value >> 16) & 0xff, (value >> 24) & 0xff);
}
var FOURCC_DXT1 = FourCCToInt32("DXT1");
var FOURCC_DXT3 = FourCCToInt32("DXT3");
var FOURCC_DXT5 = FourCCToInt32("DXT5");
var FOURCC_DX10 = FourCCToInt32("DX10");
var FOURCC_D3DFMT_R16G16B16A16F = 113;
var FOURCC_D3DFMT_R32G32B32A32F = 116;
var DXGI_FORMAT_R16G16B16A16_FLOAT = 10;
var DXGI_FORMAT_B8G8R8X8_UNORM = 88;
var headerLengthInt = 31; // The header length in 32 bit ints
// Offsets into the header array
var off_magic = 0;
var off_size = 1;
var off_flags = 2;
var off_height = 3;
var off_width = 4;
var off_mipmapCount = 7;
var off_pfFlags = 20;
var off_pfFourCC = 21;
var off_RGBbpp = 22;
var off_RMask = 23;
var off_GMask = 24;
var off_BMask = 25;
var off_AMask = 26;
// var off_caps1 = 27;
var off_caps2 = 28;
// var off_caps3 = 29;
// var off_caps4 = 30;
var off_dxgiFormat = 32;
;
var DDSTools = /** @class */ (function () {
function DDSTools() {
}
DDSTools.GetDDSInfo = function (arrayBuffer) {
var header = new Int32Array(arrayBuffer, 0, headerLengthInt);
var extendedHeader = new Int32Array(arrayBuffer, 0, headerLengthInt + 4);
var mipmapCount = 1;
if (header[off_flags] & DDSD_MIPMAPCOUNT) {
mipmapCount = Math.max(1, header[off_mipmapCount]);
}
var fourCC = header[off_pfFourCC];
var dxgiFormat = (fourCC === FOURCC_DX10) ? extendedHeader[off_dxgiFormat] : 0;
var textureType = BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT;
switch (fourCC) {
case FOURCC_D3DFMT_R16G16B16A16F:
textureType = BABYLON.Engine.TEXTURETYPE_HALF_FLOAT;
break;
case FOURCC_D3DFMT_R32G32B32A32F:
textureType = BABYLON.Engine.TEXTURETYPE_FLOAT;
break;
case FOURCC_DX10:
if (dxgiFormat === DXGI_FORMAT_R16G16B16A16_FLOAT) {
textureType = BABYLON.Engine.TEXTURETYPE_HALF_FLOAT;
break;
}
}
return {
width: header[off_width],
height: header[off_height],
mipmapCount: mipmapCount,
isFourCC: (header[off_pfFlags] & DDPF_FOURCC) === DDPF_FOURCC,
isRGB: (header[off_pfFlags] & DDPF_RGB) === DDPF_RGB,
isLuminance: (header[off_pfFlags] & DDPF_LUMINANCE) === DDPF_LUMINANCE,
isCube: (header[off_caps2] & DDSCAPS2_CUBEMAP) === DDSCAPS2_CUBEMAP,
isCompressed: (fourCC === FOURCC_DXT1 || fourCC === FOURCC_DXT3 || fourCC === FOURCC_DXT5),
dxgiFormat: dxgiFormat,
textureType: textureType
};
};
DDSTools._ToHalfFloat = function (value) {
if (!DDSTools._FloatView) {
DDSTools._FloatView = new Float32Array(1);
DDSTools._Int32View = new Int32Array(DDSTools._FloatView.buffer);
}
DDSTools._FloatView[0] = value;
var x = DDSTools._Int32View[0];
var bits = (x >> 16) & 0x8000; /* Get the sign */
var m = (x >> 12) & 0x07ff; /* Keep one extra bit for rounding */
var e = (x >> 23) & 0xff; /* Using int is faster here */
/* If zero, or denormal, or exponent underflows too much for a denormal
* half, return signed zero. */
if (e < 103) {
return bits;
}
/* If NaN, return NaN. If Inf or exponent overflow, return Inf. */
if (e > 142) {
bits |= 0x7c00;
/* If exponent was 0xff and one mantissa bit was set, it means NaN,
* not Inf, so make sure we set one mantissa bit too. */
bits |= ((e == 255) ? 0 : 1) && (x & 0x007fffff);
return bits;
}
/* If exponent underflows but not too much, return a denormal */
if (e < 113) {
m |= 0x0800;
/* Extra rounding may overflow and set mantissa to 0 and exponent
* to 1, which is OK. */
bits |= (m >> (114 - e)) + ((m >> (113 - e)) & 1);
return bits;
}
bits |= ((e - 112) << 10) | (m >> 1);
bits += m & 1;
return bits;
};
DDSTools._FromHalfFloat = function (value) {
var s = (value & 0x8000) >> 15;
var e = (value & 0x7C00) >> 10;
var f = value & 0x03FF;
if (e === 0) {
return (s ? -1 : 1) * Math.pow(2, -14) * (f / Math.pow(2, 10));
}
else if (e == 0x1F) {
return f ? NaN : ((s ? -1 : 1) * Infinity);
}
return (s ? -1 : 1) * Math.pow(2, e - 15) * (1 + (f / Math.pow(2, 10)));
};
DDSTools._GetHalfFloatAsFloatRGBAArrayBuffer = function (width, height, dataOffset, dataLength, arrayBuffer, lod) {
var destArray = new Float32Array(dataLength);
var srcData = new Uint16Array(arrayBuffer, dataOffset);
var index = 0;
for (var y = 0; y < height; y++) {
for (var x = 0; x < width; x++) {
var srcPos = (x + y * width) * 4;
destArray[index] = DDSTools._FromHalfFloat(srcData[srcPos]);
destArray[index + 1] = DDSTools._FromHalfFloat(srcData[srcPos + 1]);
destArray[index + 2] = DDSTools._FromHalfFloat(srcData[srcPos + 2]);
if (DDSTools.StoreLODInAlphaChannel) {
destArray[index + 3] = lod;
}
else {
destArray[index + 3] = DDSTools._FromHalfFloat(srcData[srcPos + 3]);
}
index += 4;
}
}
return destArray;
};
DDSTools._GetHalfFloatRGBAArrayBuffer = function (width, height, dataOffset, dataLength, arrayBuffer, lod) {
if (DDSTools.StoreLODInAlphaChannel) {
var destArray = new Uint16Array(dataLength);
var srcData = new Uint16Array(arrayBuffer, dataOffset);
var index = 0;
for (var y = 0; y < height; y++) {
for (var x = 0; x < width; x++) {
var srcPos = (x + y * width) * 4;
destArray[index] = srcData[srcPos];
destArray[index + 1] = srcData[srcPos + 1];
destArray[index + 2] = srcData[srcPos + 2];
destArray[index + 3] = DDSTools._ToHalfFloat(lod);
index += 4;
}
}
return destArray;
}
return new Uint16Array(arrayBuffer, dataOffset, dataLength);
};
DDSTools._GetFloatRGBAArrayBuffer = function (width, height, dataOffset, dataLength, arrayBuffer, lod) {
if (DDSTools.StoreLODInAlphaChannel) {
var destArray = new Float32Array(dataLength);
var srcData = new Float32Array(arrayBuffer, dataOffset);
var index = 0;
for (var y = 0; y < height; y++) {
for (var x = 0; x < width; x++) {
var srcPos = (x + y * width) * 4;
destArray[index] = srcData[srcPos];
destArray[index + 1] = srcData[srcPos + 1];
destArray[index + 2] = srcData[srcPos + 2];
destArray[index + 3] = lod;
index += 4;
}
}
return destArray;
}
return new Float32Array(arrayBuffer, dataOffset, dataLength);
};
DDSTools._GetFloatAsUIntRGBAArrayBuffer = function (width, height, dataOffset, dataLength, arrayBuffer, lod) {
var destArray = new Uint8Array(dataLength);
var srcData = new Float32Array(arrayBuffer, dataOffset);
var index = 0;
for (var y = 0; y < height; y++) {
for (var x = 0; x < width; x++) {
var srcPos = (x + y * width) * 4;
destArray[index] = BABYLON.Scalar.Clamp(srcData[srcPos]) * 255;
destArray[index + 1] = BABYLON.Scalar.Clamp(srcData[srcPos + 1]) * 255;
destArray[index + 2] = BABYLON.Scalar.Clamp(srcData[srcPos + 2]) * 255;
if (DDSTools.StoreLODInAlphaChannel) {
destArray[index + 3] = lod;
}
else {
destArray[index + 3] = BABYLON.Scalar.Clamp(srcData[srcPos + 3]) * 255;
}
index += 4;
}
}
return destArray;
};
DDSTools._GetHalfFloatAsUIntRGBAArrayBuffer = function (width, height, dataOffset, dataLength, arrayBuffer, lod) {
var destArray = new Uint8Array(dataLength);
var srcData = new Uint16Array(arrayBuffer, dataOffset);
var index = 0;
for (var y = 0; y < height; y++) {
for (var x = 0; x < width; x++) {
var srcPos = (x + y * width) * 4;
destArray[index] = BABYLON.Scalar.Clamp(DDSTools._FromHalfFloat(srcData[srcPos])) * 255;
destArray[index + 1] = BABYLON.Scalar.Clamp(DDSTools._FromHalfFloat(srcData[srcPos + 1])) * 255;
destArray[index + 2] = BABYLON.Scalar.Clamp(DDSTools._FromHalfFloat(srcData[srcPos + 2])) * 255;
if (DDSTools.StoreLODInAlphaChannel) {
destArray[index + 3] = lod;
}
else {
destArray[index + 3] = BABYLON.Scalar.Clamp(DDSTools._FromHalfFloat(srcData[srcPos + 3])) * 255;
}
index += 4;
}
}
return destArray;
};
DDSTools._GetRGBAArrayBuffer = function (width, height, dataOffset, dataLength, arrayBuffer, rOffset, gOffset, bOffset, aOffset) {
var byteArray = new Uint8Array(dataLength);
var srcData = new Uint8Array(arrayBuffer, dataOffset);
var index = 0;
for (var y = 0; y < height; y++) {
for (var x = 0; x < width; x++) {
var srcPos = (x + y * width) * 4;
byteArray[index] = srcData[srcPos + rOffset];
byteArray[index + 1] = srcData[srcPos + gOffset];
byteArray[index + 2] = srcData[srcPos + bOffset];
byteArray[index + 3] = srcData[srcPos + aOffset];
index += 4;
}
}
return byteArray;
};
DDSTools._ExtractLongWordOrder = function (value) {
if (value === 0 || value === 255 || value === -16777216) {
return 0;
}
return 1 + DDSTools._ExtractLongWordOrder(value >> 8);
};
DDSTools._GetRGBArrayBuffer = function (width, height, dataOffset, dataLength, arrayBuffer, rOffset, gOffset, bOffset) {
var byteArray = new Uint8Array(dataLength);
var srcData = new Uint8Array(arrayBuffer, dataOffset);
var index = 0;
for (var y = 0; y < height; y++) {
for (var x = 0; x < width; x++) {
var srcPos = (x + y * width) * 3;
byteArray[index] = srcData[srcPos + rOffset];
byteArray[index + 1] = srcData[srcPos + gOffset];
byteArray[index + 2] = srcData[srcPos + bOffset];
index += 3;
}
}
return byteArray;
};
DDSTools._GetLuminanceArrayBuffer = function (width, height, dataOffset, dataLength, arrayBuffer) {
var byteArray = new Uint8Array(dataLength);
var srcData = new Uint8Array(arrayBuffer, dataOffset);
var index = 0;
for (var y = 0; y < height; y++) {
for (var x = 0; x < width; x++) {
var srcPos = (x + y * width);
byteArray[index] = srcData[srcPos];
index++;
}
}
return byteArray;
};
/**
* Uploads DDS Levels to a Babylon Texture
* @hidden
*/
DDSTools.UploadDDSLevels = function (engine, texture, arrayBuffer, info, loadMipmaps, faces, lodIndex, currentFace) {
if (lodIndex === void 0) { lodIndex = -1; }
var sphericalPolynomialFaces = null;
if (info.sphericalPolynomial) {
sphericalPolynomialFaces = new Array();
}
var ext = engine.getCaps().s3tc;
var header = new Int32Array(arrayBuffer, 0, headerLengthInt);
var fourCC, width, height, dataLength = 0, dataOffset;
var byteArray, mipmapCount, mip;
var internalCompressedFormat = 0;
var blockBytes = 1;
if (header[off_magic] !== DDS_MAGIC) {
BABYLON.Tools.Error("Invalid magic number in DDS header");
return;
}
if (!info.isFourCC && !info.isRGB && !info.isLuminance) {
BABYLON.Tools.Error("Unsupported format, must contain a FourCC, RGB or LUMINANCE code");
return;
}
if (info.isCompressed && !ext) {
BABYLON.Tools.Error("Compressed textures are not supported on this platform.");
return;
}
var bpp = header[off_RGBbpp];
dataOffset = header[off_size] + 4;
var computeFormats = false;
if (info.isFourCC) {
fourCC = header[off_pfFourCC];
switch (fourCC) {
case FOURCC_DXT1:
blockBytes = 8;
internalCompressedFormat = ext.COMPRESSED_RGBA_S3TC_DXT1_EXT;
break;
case FOURCC_DXT3:
blockBytes = 16;
internalCompressedFormat = ext.COMPRESSED_RGBA_S3TC_DXT3_EXT;
break;
case FOURCC_DXT5:
blockBytes = 16;
internalCompressedFormat = ext.COMPRESSED_RGBA_S3TC_DXT5_EXT;
break;
case FOURCC_D3DFMT_R16G16B16A16F:
computeFormats = true;
break;
case FOURCC_D3DFMT_R32G32B32A32F:
computeFormats = true;
break;
case FOURCC_DX10:
// There is an additionnal header so dataOffset need to be changed
dataOffset += 5 * 4; // 5 uints
var supported = false;
switch (info.dxgiFormat) {
case DXGI_FORMAT_R16G16B16A16_FLOAT:
computeFormats = true;
supported = true;
break;
case DXGI_FORMAT_B8G8R8X8_UNORM:
info.isRGB = true;
info.isFourCC = false;
bpp = 32;
supported = true;
break;
}
if (supported) {
break;
}
default:
console.error("Unsupported FourCC code:", Int32ToFourCC(fourCC));
return;
}
}
var rOffset = DDSTools._ExtractLongWordOrder(header[off_RMask]);
var gOffset = DDSTools._ExtractLongWordOrder(header[off_GMask]);
var bOffset = DDSTools._ExtractLongWordOrder(header[off_BMask]);
var aOffset = DDSTools._ExtractLongWordOrder(header[off_AMask]);
if (computeFormats) {
internalCompressedFormat = engine._getRGBABufferInternalSizedFormat(info.textureType);
}
mipmapCount = 1;
if (header[off_flags] & DDSD_MIPMAPCOUNT && loadMipmaps !== false) {
mipmapCount = Math.max(1, header[off_mipmapCount]);
}
for (var face = 0; face < faces; face++) {
width = header[off_width];
height = header[off_height];
for (mip = 0; mip < mipmapCount; ++mip) {
if (lodIndex === -1 || lodIndex === mip) {
// In case of fixed LOD, if the lod has just been uploaded, early exit.
var i = (lodIndex === -1) ? mip : 0;
if (!info.isCompressed && info.isFourCC) {
texture.format = BABYLON.Engine.TEXTUREFORMAT_RGBA;
dataLength = width * height * 4;
var floatArray = null;
if (engine._badOS || engine._badDesktopOS || (!engine.getCaps().textureHalfFloat && !engine.getCaps().textureFloat)) { // Required because iOS has many issues with float and half float generation
if (bpp === 128) {
floatArray = DDSTools._GetFloatAsUIntRGBAArrayBuffer(width, height, dataOffset, dataLength, arrayBuffer, i);
if (sphericalPolynomialFaces && i == 0) {
sphericalPolynomialFaces.push(DDSTools._GetFloatRGBAArrayBuffer(width, height, dataOffset, dataLength, arrayBuffer, i));
}
}
else if (bpp === 64) {
floatArray = DDSTools._GetHalfFloatAsUIntRGBAArrayBuffer(width, height, dataOffset, dataLength, arrayBuffer, i);
if (sphericalPolynomialFaces && i == 0) {
sphericalPolynomialFaces.push(DDSTools._GetHalfFloatAsFloatRGBAArrayBuffer(width, height, dataOffset, dataLength, arrayBuffer, i));
}
}
texture.type = BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT;
}
else {
if (bpp === 128) {
texture.type = BABYLON.Engine.TEXTURETYPE_FLOAT;
floatArray = DDSTools._GetFloatRGBAArrayBuffer(width, height, dataOffset, dataLength, arrayBuffer, i);
if (sphericalPolynomialFaces && i == 0) {
sphericalPolynomialFaces.push(floatArray);
}
}
else if (bpp === 64 && !engine.getCaps().textureHalfFloat) {
texture.type = BABYLON.Engine.TEXTURETYPE_FLOAT;
floatArray = DDSTools._GetHalfFloatAsFloatRGBAArrayBuffer(width, height, dataOffset, dataLength, arrayBuffer, i);
if (sphericalPolynomialFaces && i == 0) {
sphericalPolynomialFaces.push(floatArray);
}
}
else { // 64
texture.type = BABYLON.Engine.TEXTURETYPE_HALF_FLOAT;
floatArray = DDSTools._GetHalfFloatRGBAArrayBuffer(width, height, dataOffset, dataLength, arrayBuffer, i);
if (sphericalPolynomialFaces && i == 0) {
sphericalPolynomialFaces.push(DDSTools._GetHalfFloatAsFloatRGBAArrayBuffer(width, height, dataOffset, dataLength, arrayBuffer, i));
}
}
}
if (floatArray) {
engine._uploadDataToTextureDirectly(texture, floatArray, face, i);
}
}
else if (info.isRGB) {
texture.type = BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT;
if (bpp === 24) {
texture.format = BABYLON.Engine.TEXTUREFORMAT_RGB;
dataLength = width * height * 3;
byteArray = DDSTools._GetRGBArrayBuffer(width, height, dataOffset, dataLength, arrayBuffer, rOffset, gOffset, bOffset);
engine._uploadDataToTextureDirectly(texture, byteArray, face, i);
}
else { // 32
texture.format = BABYLON.Engine.TEXTUREFORMAT_RGBA;
dataLength = width * height * 4;
byteArray = DDSTools._GetRGBAArrayBuffer(width, height, dataOffset, dataLength, arrayBuffer, rOffset, gOffset, bOffset, aOffset);
engine._uploadDataToTextureDirectly(texture, byteArray, face, i);
}
}
else if (info.isLuminance) {
var unpackAlignment = engine._getUnpackAlignement();
var unpaddedRowSize = width;
var paddedRowSize = Math.floor((width + unpackAlignment - 1) / unpackAlignment) * unpackAlignment;
dataLength = paddedRowSize * (height - 1) + unpaddedRowSize;
byteArray = DDSTools._GetLuminanceArrayBuffer(width, height, dataOffset, dataLength, arrayBuffer);
texture.format = BABYLON.Engine.TEXTUREFORMAT_LUMINANCE;
texture.type = BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT;
engine._uploadDataToTextureDirectly(texture, byteArray, face, i);
}
else {
dataLength = Math.max(4, width) / 4 * Math.max(4, height) / 4 * blockBytes;
byteArray = new Uint8Array(arrayBuffer, dataOffset, dataLength);
texture.type = BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT;
engine._uploadCompressedDataToTextureDirectly(texture, internalCompressedFormat, width, height, byteArray, face, i);
}
}
dataOffset += bpp ? (width * height * (bpp / 8)) : dataLength;
width *= 0.5;
height *= 0.5;
width = Math.max(1.0, width);
height = Math.max(1.0, height);
}
if (currentFace !== undefined) {
// Loading a single face
break;
}
}
if (sphericalPolynomialFaces && sphericalPolynomialFaces.length > 0) {
info.sphericalPolynomial = BABYLON.CubeMapToSphericalPolynomialTools.ConvertCubeMapToSphericalPolynomial({
size: header[off_width],
right: sphericalPolynomialFaces[0],
left: sphericalPolynomialFaces[1],
up: sphericalPolynomialFaces[2],
down: sphericalPolynomialFaces[3],
front: sphericalPolynomialFaces[4],
back: sphericalPolynomialFaces[5],
format: BABYLON.Engine.TEXTUREFORMAT_RGBA,
type: BABYLON.Engine.TEXTURETYPE_FLOAT,
gammaSpace: false,
});
}
else {
info.sphericalPolynomial = undefined;
}
};
DDSTools.StoreLODInAlphaChannel = false;
return DDSTools;
}());
BABYLON.DDSTools = DDSTools;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.dds.js.map
var BABYLON;
(function (BABYLON) {
/**
* Implementation of the DDS Texture Loader.
*/
var DDSTextureLoader = /** @class */ (function () {
function DDSTextureLoader() {
/**
* Defines wether the loader supports cascade loading the different faces.
*/
this.supportCascades = true;
}
/**
* This returns if the loader support the current file information.
* @param extension defines the file extension of the file being loaded
* @param textureFormatInUse defines the current compressed format in use iun the engine
* @param fallback defines the fallback internal texture if any
* @param isBase64 defines whether the texture is encoded as a base64
* @param isBuffer defines whether the texture data are stored as a buffer
* @returns true if the loader can load the specified file
*/
DDSTextureLoader.prototype.canLoad = function (extension, textureFormatInUse, fallback, isBase64, isBuffer) {
return extension.indexOf(".dds") === 0;
};
/**
* Transform the url before loading if required.
* @param rootUrl the url of the texture
* @param textureFormatInUse defines the current compressed format in use iun the engine
* @returns the transformed texture
*/
DDSTextureLoader.prototype.transformUrl = function (rootUrl, textureFormatInUse) {
return rootUrl;
};
/**
* Gets the fallback url in case the load fail. This can return null to allow the default fallback mecanism to work
* @param rootUrl the url of the texture
* @param textureFormatInUse defines the current compressed format in use iun the engine
* @returns the fallback texture
*/
DDSTextureLoader.prototype.getFallbackTextureUrl = function (rootUrl, textureFormatInUse) {
return null;
};
/**
* Uploads the cube texture data to the WebGl Texture. It has alreday been bound.
* @param data contains the texture data
* @param texture defines the BabylonJS internal texture
* @param createPolynomials will be true if polynomials have been requested
* @param onLoad defines the callback to trigger once the texture is ready
* @param onError defines the callback to trigger in case of error
*/
DDSTextureLoader.prototype.loadCubeData = function (imgs, texture, createPolynomials, onLoad, onError) {
var engine = texture.getEngine();
var info;
var loadMipmap = false;
if (Array.isArray(imgs)) {
for (var index = 0; index < imgs.length; index++) {
var data_1 = imgs[index];
info = BABYLON.DDSTools.GetDDSInfo(data_1);
texture.width = info.width;
texture.height = info.height;
loadMipmap = (info.isRGB || info.isLuminance || info.mipmapCount > 1) && texture.generateMipMaps;
engine._unpackFlipY(info.isCompressed);
BABYLON.DDSTools.UploadDDSLevels(engine, texture, data_1, info, loadMipmap, 6, -1, index);
if (!info.isFourCC && info.mipmapCount === 1) {
engine.generateMipMapsForCubemap(texture);
}
}
}
else {
var data = imgs;
info = BABYLON.DDSTools.GetDDSInfo(data);
texture.width = info.width;
texture.height = info.height;
if (createPolynomials) {
info.sphericalPolynomial = new BABYLON.SphericalPolynomial();
}
loadMipmap = (info.isRGB || info.isLuminance || info.mipmapCount > 1) && texture.generateMipMaps;
engine._unpackFlipY(info.isCompressed);
BABYLON.DDSTools.UploadDDSLevels(engine, texture, data, info, loadMipmap, 6);
if (!info.isFourCC && info.mipmapCount === 1) {
engine.generateMipMapsForCubemap(texture);
}
}
engine._setCubeMapTextureParams(loadMipmap);
texture.isReady = true;
if (onLoad) {
onLoad({ isDDS: true, width: texture.width, info: info, data: imgs, texture: texture });
}
};
/**
* Uploads the 2D texture data to the WebGl Texture. It has alreday been bound once in the callback.
* @param data contains the texture data
* @param texture defines the BabylonJS internal texture
* @param callback defines the method to call once ready to upload
*/
DDSTextureLoader.prototype.loadData = function (data, texture, callback) {
var info = BABYLON.DDSTools.GetDDSInfo(data);
var loadMipmap = (info.isRGB || info.isLuminance || info.mipmapCount > 1) && texture.generateMipMaps && ((info.width >> (info.mipmapCount - 1)) === 1);
callback(info.width, info.height, !loadMipmap, info.isFourCC, function () {
BABYLON.DDSTools.UploadDDSLevels(texture.getEngine(), texture, data, info, loadMipmap, 1);
});
};
return DDSTextureLoader;
}());
// Register the loader.
BABYLON.Engine._TextureLoaders.push(new DDSTextureLoader());
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.ddsTextureLoader.js.map
var BABYLON;
(function (BABYLON) {
/*
* Based on jsTGALoader - Javascript loader for TGA file
* By Vincent Thibault
* @blog http://blog.robrowser.com/javascript-tga-loader.html
*/
var TGATools = /** @class */ (function () {
function TGATools() {
}
TGATools.GetTGAHeader = function (data) {
var offset = 0;
var header = {
id_length: data[offset++],
colormap_type: data[offset++],
image_type: data[offset++],
colormap_index: data[offset++] | data[offset++] << 8,
colormap_length: data[offset++] | data[offset++] << 8,
colormap_size: data[offset++],
origin: [
data[offset++] | data[offset++] << 8,
data[offset++] | data[offset++] << 8
],
width: data[offset++] | data[offset++] << 8,
height: data[offset++] | data[offset++] << 8,
pixel_size: data[offset++],
flags: data[offset++]
};
return header;
};
/**
* Uploads TGA content to a Babylon Texture
* @hidden
*/
TGATools.UploadContent = function (texture, data) {
// Not enough data to contain header ?
if (data.length < 19) {
BABYLON.Tools.Error("Unable to load TGA file - Not enough data to contain header");
return;
}
// Read Header
var offset = 18;
var header = TGATools.GetTGAHeader(data);
// Assume it's a valid Targa file.
if (header.id_length + offset > data.length) {
BABYLON.Tools.Error("Unable to load TGA file - Not enough data");
return;
}
// Skip not needed data
offset += header.id_length;
var use_rle = false;
var use_pal = false;
var use_grey = false;
// Get some informations.
switch (header.image_type) {
case TGATools._TYPE_RLE_INDEXED:
use_rle = true;
case TGATools._TYPE_INDEXED:
use_pal = true;
break;
case TGATools._TYPE_RLE_RGB:
use_rle = true;
case TGATools._TYPE_RGB:
// use_rgb = true;
break;
case TGATools._TYPE_RLE_GREY:
use_rle = true;
case TGATools._TYPE_GREY:
use_grey = true;
break;
}
var pixel_data;
// var numAlphaBits = header.flags & 0xf;
var pixel_size = header.pixel_size >> 3;
var pixel_total = header.width * header.height * pixel_size;
// Read palettes
var palettes;
if (use_pal) {
palettes = data.subarray(offset, offset += header.colormap_length * (header.colormap_size >> 3));
}
// Read LRE
if (use_rle) {
pixel_data = new Uint8Array(pixel_total);
var c, count, i;
var localOffset = 0;
var pixels = new Uint8Array(pixel_size);
while (offset < pixel_total && localOffset < pixel_total) {
c = data[offset++];
count = (c & 0x7f) + 1;
// RLE pixels
if (c & 0x80) {
// Bind pixel tmp array
for (i = 0; i < pixel_size; ++i) {
pixels[i] = data[offset++];
}
// Copy pixel array
for (i = 0; i < count; ++i) {
pixel_data.set(pixels, localOffset + i * pixel_size);
}
localOffset += pixel_size * count;
}
// Raw pixels
else {
count *= pixel_size;
for (i = 0; i < count; ++i) {
pixel_data[localOffset + i] = data[offset++];
}
localOffset += count;
}
}
}
// RAW Pixels
else {
pixel_data = data.subarray(offset, offset += (use_pal ? header.width * header.height : pixel_total));
}
// Load to texture
var x_start, y_start, x_step, y_step, y_end, x_end;
switch ((header.flags & TGATools._ORIGIN_MASK) >> TGATools._ORIGIN_SHIFT) {
default:
case TGATools._ORIGIN_UL:
x_start = 0;
x_step = 1;
x_end = header.width;
y_start = 0;
y_step = 1;
y_end = header.height;
break;
case TGATools._ORIGIN_BL:
x_start = 0;
x_step = 1;
x_end = header.width;
y_start = header.height - 1;
y_step = -1;
y_end = -1;
break;
case TGATools._ORIGIN_UR:
x_start = header.width - 1;
x_step = -1;
x_end = -1;
y_start = 0;
y_step = 1;
y_end = header.height;
break;
case TGATools._ORIGIN_BR:
x_start = header.width - 1;
x_step = -1;
x_end = -1;
y_start = header.height - 1;
y_step = -1;
y_end = -1;
break;
}
// Load the specify method
var func = '_getImageData' + (use_grey ? 'Grey' : '') + (header.pixel_size) + 'bits';
var imageData = TGATools[func](header, palettes, pixel_data, y_start, y_step, y_end, x_start, x_step, x_end);
var engine = texture.getEngine();
engine._uploadDataToTextureDirectly(texture, imageData);
};
TGATools._getImageData8bits = function (header, palettes, pixel_data, y_start, y_step, y_end, x_start, x_step, x_end) {
var image = pixel_data, colormap = palettes;
var width = header.width, height = header.height;
var color, i = 0, x, y;
var imageData = new Uint8Array(width * height * 4);
for (y = y_start; y !== y_end; y += y_step) {
for (x = x_start; x !== x_end; x += x_step, i++) {
color = image[i];
imageData[(x + width * y) * 4 + 3] = 255;
imageData[(x + width * y) * 4 + 2] = colormap[(color * 3) + 0];
imageData[(x + width * y) * 4 + 1] = colormap[(color * 3) + 1];
imageData[(x + width * y) * 4 + 0] = colormap[(color * 3) + 2];
}
}
return imageData;
};
TGATools._getImageData16bits = function (header, palettes, pixel_data, y_start, y_step, y_end, x_start, x_step, x_end) {
var image = pixel_data;
var width = header.width, height = header.height;
var color, i = 0, x, y;
var imageData = new Uint8Array(width * height * 4);
for (y = y_start; y !== y_end; y += y_step) {
for (x = x_start; x !== x_end; x += x_step, i += 2) {
color = image[i + 0] + (image[i + 1] << 8); // Inversed ?
var r = (((color & 0x7C00) >> 10) * 255) / 0x1F | 0;
var g = (((color & 0x03E0) >> 5) * 255) / 0x1F | 0;
var b = ((color & 0x001F) * 255) / 0x1F | 0;
imageData[(x + width * y) * 4 + 0] = r;
imageData[(x + width * y) * 4 + 1] = g;
imageData[(x + width * y) * 4 + 2] = b;
imageData[(x + width * y) * 4 + 3] = (color & 0x8000) ? 0 : 255;
}
}
return imageData;
};
TGATools._getImageData24bits = function (header, palettes, pixel_data, y_start, y_step, y_end, x_start, x_step, x_end) {
var image = pixel_data;
var width = header.width, height = header.height;
var i = 0, x, y;
var imageData = new Uint8Array(width * height * 4);
for (y = y_start; y !== y_end; y += y_step) {
for (x = x_start; x !== x_end; x += x_step, i += 3) {
imageData[(x + width * y) * 4 + 3] = 255;
imageData[(x + width * y) * 4 + 2] = image[i + 0];
imageData[(x + width * y) * 4 + 1] = image[i + 1];
imageData[(x + width * y) * 4 + 0] = image[i + 2];
}
}
return imageData;
};
TGATools._getImageData32bits = function (header, palettes, pixel_data, y_start, y_step, y_end, x_start, x_step, x_end) {
var image = pixel_data;
var width = header.width, height = header.height;
var i = 0, x, y;
var imageData = new Uint8Array(width * height * 4);
for (y = y_start; y !== y_end; y += y_step) {
for (x = x_start; x !== x_end; x += x_step, i += 4) {
imageData[(x + width * y) * 4 + 2] = image[i + 0];
imageData[(x + width * y) * 4 + 1] = image[i + 1];
imageData[(x + width * y) * 4 + 0] = image[i + 2];
imageData[(x + width * y) * 4 + 3] = image[i + 3];
}
}
return imageData;
};
TGATools._getImageDataGrey8bits = function (header, palettes, pixel_data, y_start, y_step, y_end, x_start, x_step, x_end) {
var image = pixel_data;
var width = header.width, height = header.height;
var color, i = 0, x, y;
var imageData = new Uint8Array(width * height * 4);
for (y = y_start; y !== y_end; y += y_step) {
for (x = x_start; x !== x_end; x += x_step, i++) {
color = image[i];
imageData[(x + width * y) * 4 + 0] = color;
imageData[(x + width * y) * 4 + 1] = color;
imageData[(x + width * y) * 4 + 2] = color;
imageData[(x + width * y) * 4 + 3] = 255;
}
}
return imageData;
};
TGATools._getImageDataGrey16bits = function (header, palettes, pixel_data, y_start, y_step, y_end, x_start, x_step, x_end) {
var image = pixel_data;
var width = header.width, height = header.height;
var i = 0, x, y;
var imageData = new Uint8Array(width * height * 4);
for (y = y_start; y !== y_end; y += y_step) {
for (x = x_start; x !== x_end; x += x_step, i += 2) {
imageData[(x + width * y) * 4 + 0] = image[i + 0];
imageData[(x + width * y) * 4 + 1] = image[i + 0];
imageData[(x + width * y) * 4 + 2] = image[i + 0];
imageData[(x + width * y) * 4 + 3] = image[i + 1];
}
}
return imageData;
};
//private static _TYPE_NO_DATA = 0;
TGATools._TYPE_INDEXED = 1;
TGATools._TYPE_RGB = 2;
TGATools._TYPE_GREY = 3;
TGATools._TYPE_RLE_INDEXED = 9;
TGATools._TYPE_RLE_RGB = 10;
TGATools._TYPE_RLE_GREY = 11;
TGATools._ORIGIN_MASK = 0x30;
TGATools._ORIGIN_SHIFT = 0x04;
TGATools._ORIGIN_BL = 0x00;
TGATools._ORIGIN_BR = 0x01;
TGATools._ORIGIN_UL = 0x02;
TGATools._ORIGIN_UR = 0x03;
return TGATools;
}());
BABYLON.TGATools = TGATools;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.tga.js.map
var BABYLON;
(function (BABYLON) {
/**
* Implementation of the TGA Texture Loader.
*/
var TGATextureLoader = /** @class */ (function () {
function TGATextureLoader() {
/**
* Defines wether the loader supports cascade loading the different faces.
*/
this.supportCascades = false;
}
/**
* This returns if the loader support the current file information.
* @param extension defines the file extension of the file being loaded
* @param textureFormatInUse defines the current compressed format in use iun the engine
* @param fallback defines the fallback internal texture if any
* @param isBase64 defines whether the texture is encoded as a base64
* @param isBuffer defines whether the texture data are stored as a buffer
* @returns true if the loader can load the specified file
*/
TGATextureLoader.prototype.canLoad = function (extension, textureFormatInUse, fallback, isBase64, isBuffer) {
return extension.indexOf(".tga") === 0;
};
/**
* Transform the url before loading if required.
* @param rootUrl the url of the texture
* @param textureFormatInUse defines the current compressed format in use iun the engine
* @returns the transformed texture
*/
TGATextureLoader.prototype.transformUrl = function (rootUrl, textureFormatInUse) {
return rootUrl;
};
/**
* Gets the fallback url in case the load fail. This can return null to allow the default fallback mecanism to work
* @param rootUrl the url of the texture
* @param textureFormatInUse defines the current compressed format in use iun the engine
* @returns the fallback texture
*/
TGATextureLoader.prototype.getFallbackTextureUrl = function (rootUrl, textureFormatInUse) {
return null;
};
/**
* Uploads the cube texture data to the WebGl Texture. It has alreday been bound.
* @param data contains the texture data
* @param texture defines the BabylonJS internal texture
* @param createPolynomials will be true if polynomials have been requested
* @param onLoad defines the callback to trigger once the texture is ready
* @param onError defines the callback to trigger in case of error
*/
TGATextureLoader.prototype.loadCubeData = function (data, texture, createPolynomials, onLoad, onError) {
throw ".env not supported in Cube.";
};
/**
* Uploads the 2D texture data to the WebGl Texture. It has alreday been bound once in the callback.
* @param data contains the texture data
* @param texture defines the BabylonJS internal texture
* @param callback defines the method to call once ready to upload
*/
TGATextureLoader.prototype.loadData = function (data, texture, callback) {
var uintData = new Uint8Array(data);
var header = BABYLON.TGATools.GetTGAHeader(uintData);
callback(header.width, header.height, texture.generateMipMaps, false, function () {
BABYLON.TGATools.UploadContent(texture, uintData);
});
};
return TGATextureLoader;
}());
// Register the loader.
BABYLON.Engine._TextureLoaders.push(new TGATextureLoader());
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.tgaTextureLoader.js.map
var BABYLON;
(function (BABYLON) {
/**
* for description see https://www.khronos.org/opengles/sdk/tools/KTX/
* for file layout see https://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/
*/
var KhronosTextureContainer = /** @class */ (function () {
/**
* @param {ArrayBuffer} arrayBuffer- contents of the KTX container file
* @param {number} facesExpected- should be either 1 or 6, based whether a cube texture or or
* @param {boolean} threeDExpected- provision for indicating that data should be a 3D texture, not implemented
* @param {boolean} textureArrayExpected- provision for indicating that data should be a texture array, not implemented
*/
function KhronosTextureContainer(arrayBuffer, facesExpected, threeDExpected, textureArrayExpected) {
this.arrayBuffer = arrayBuffer;
// Test that it is a ktx formatted file, based on the first 12 bytes, character representation is:
// '�', 'K', 'T', 'X', ' ', '1', '1', '�', '\r', '\n', '\x1A', '\n'
// 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A
var identifier = new Uint8Array(this.arrayBuffer, 0, 12);
if (identifier[0] !== 0xAB || identifier[1] !== 0x4B || identifier[2] !== 0x54 || identifier[3] !== 0x58 || identifier[4] !== 0x20 || identifier[5] !== 0x31 ||
identifier[6] !== 0x31 || identifier[7] !== 0xBB || identifier[8] !== 0x0D || identifier[9] !== 0x0A || identifier[10] !== 0x1A || identifier[11] !== 0x0A) {
BABYLON.Tools.Error("texture missing KTX identifier");
return;
}
// load the reset of the header in native 32 bit int
var header = new Int32Array(this.arrayBuffer, 12, 13);
// determine of the remaining header values are recorded in the opposite endianness & require conversion
var oppositeEndianess = header[0] === 0x01020304;
// read all the header elements in order they exist in the file, without modification (sans endainness)
this.glType = oppositeEndianess ? this.switchEndainness(header[1]) : header[1]; // must be 0 for compressed textures
this.glTypeSize = oppositeEndianess ? this.switchEndainness(header[2]) : header[2]; // must be 1 for compressed textures
this.glFormat = oppositeEndianess ? this.switchEndainness(header[3]) : header[3]; // must be 0 for compressed textures
this.glInternalFormat = oppositeEndianess ? this.switchEndainness(header[4]) : header[4]; // the value of arg passed to gl.compressedTexImage2D(,,x,,,,)
this.glBaseInternalFormat = oppositeEndianess ? this.switchEndainness(header[5]) : header[5]; // specify GL_RGB, GL_RGBA, GL_ALPHA, etc (un-compressed only)
this.pixelWidth = oppositeEndianess ? this.switchEndainness(header[6]) : header[6]; // level 0 value of arg passed to gl.compressedTexImage2D(,,,x,,,)
this.pixelHeight = oppositeEndianess ? this.switchEndainness(header[7]) : header[7]; // level 0 value of arg passed to gl.compressedTexImage2D(,,,,x,,)
this.pixelDepth = oppositeEndianess ? this.switchEndainness(header[8]) : header[8]; // level 0 value of arg passed to gl.compressedTexImage3D(,,,,,x,,)
this.numberOfArrayElements = oppositeEndianess ? this.switchEndainness(header[9]) : header[9]; // used for texture arrays
this.numberOfFaces = oppositeEndianess ? this.switchEndainness(header[10]) : header[10]; // used for cubemap textures, should either be 1 or 6
this.numberOfMipmapLevels = oppositeEndianess ? this.switchEndainness(header[11]) : header[11]; // number of levels; disregard possibility of 0 for compressed textures
this.bytesOfKeyValueData = oppositeEndianess ? this.switchEndainness(header[12]) : header[12]; // the amount of space after the header for meta-data
// Make sure we have a compressed type. Not only reduces work, but probably better to let dev know they are not compressing.
if (this.glType !== 0) {
BABYLON.Tools.Error("only compressed formats currently supported");
return;
}
else {
// value of zero is an indication to generate mipmaps @ runtime. Not usually allowed for compressed, so disregard.
this.numberOfMipmapLevels = Math.max(1, this.numberOfMipmapLevels);
}
if (this.pixelHeight === 0 || this.pixelDepth !== 0) {
BABYLON.Tools.Error("only 2D textures currently supported");
return;
}
if (this.numberOfArrayElements !== 0) {
BABYLON.Tools.Error("texture arrays not currently supported");
return;
}
if (this.numberOfFaces !== facesExpected) {
BABYLON.Tools.Error("number of faces expected" + facesExpected + ", but found " + this.numberOfFaces);
return;
}
// we now have a completely validated file, so could use existence of loadType as success
// would need to make this more elaborate & adjust checks above to support more than one load type
this.loadType = KhronosTextureContainer.COMPRESSED_2D;
}
// not as fast hardware based, but will probably never need to use
KhronosTextureContainer.prototype.switchEndainness = function (val) {
return ((val & 0xFF) << 24)
| ((val & 0xFF00) << 8)
| ((val >> 8) & 0xFF00)
| ((val >> 24) & 0xFF);
};
/**
* Uploads KTX content to a Babylon Texture.
* It is assumed that the texture has already been created & is currently bound
* @hidden
*/
KhronosTextureContainer.prototype.uploadLevels = function (texture, loadMipmaps) {
switch (this.loadType) {
case KhronosTextureContainer.COMPRESSED_2D:
this._upload2DCompressedLevels(texture, loadMipmaps);
break;
case KhronosTextureContainer.TEX_2D:
case KhronosTextureContainer.COMPRESSED_3D:
case KhronosTextureContainer.TEX_3D:
}
};
KhronosTextureContainer.prototype._upload2DCompressedLevels = function (texture, loadMipmaps) {
// initialize width & height for level 1
var dataOffset = KhronosTextureContainer.HEADER_LEN + this.bytesOfKeyValueData;
var width = this.pixelWidth;
var height = this.pixelHeight;
var mipmapCount = loadMipmaps ? this.numberOfMipmapLevels : 1;
for (var level = 0; level < mipmapCount; level++) {
var imageSize = new Int32Array(this.arrayBuffer, dataOffset, 1)[0]; // size per face, since not supporting array cubemaps
dataOffset += 4; //image data starts from next multiple of 4 offset. Each face refers to same imagesize field above.
for (var face = 0; face < this.numberOfFaces; face++) {
var byteArray = new Uint8Array(this.arrayBuffer, dataOffset, imageSize);
var engine = texture.getEngine();
engine._uploadCompressedDataToTextureDirectly(texture, this.glInternalFormat, width, height, byteArray, face, level);
dataOffset += imageSize; // add size of the image for the next face/mipmap
dataOffset += 3 - ((imageSize + 3) % 4); // add padding for odd sized image
}
width = Math.max(1.0, width * 0.5);
height = Math.max(1.0, height * 0.5);
}
};
KhronosTextureContainer.HEADER_LEN = 12 + (13 * 4); // identifier + header elements (not including key value meta-data pairs)
// load types
KhronosTextureContainer.COMPRESSED_2D = 0; // uses a gl.compressedTexImage2D()
KhronosTextureContainer.COMPRESSED_3D = 1; // uses a gl.compressedTexImage3D()
KhronosTextureContainer.TEX_2D = 2; // uses a gl.texImage2D()
KhronosTextureContainer.TEX_3D = 3; // uses a gl.texImage3D()
return KhronosTextureContainer;
}());
BABYLON.KhronosTextureContainer = KhronosTextureContainer;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.khronosTextureContainer.js.map
var BABYLON;
(function (BABYLON) {
/**
* Implementation of the KTX Texture Loader.
*/
var KTXTextureLoader = /** @class */ (function () {
function KTXTextureLoader() {
/**
* Defines wether the loader supports cascade loading the different faces.
*/
this.supportCascades = false;
}
/**
* This returns if the loader support the current file information.
* @param extension defines the file extension of the file being loaded
* @param textureFormatInUse defines the current compressed format in use iun the engine
* @param fallback defines the fallback internal texture if any
* @param isBase64 defines whether the texture is encoded as a base64
* @param isBuffer defines whether the texture data are stored as a buffer
* @returns true if the loader can load the specified file
*/
KTXTextureLoader.prototype.canLoad = function (extension, textureFormatInUse, fallback, isBase64, isBuffer) {
if (textureFormatInUse && !isBase64 && !fallback && !isBuffer) {
return true;
}
return false;
};
/**
* Transform the url before loading if required.
* @param rootUrl the url of the texture
* @param textureFormatInUse defines the current compressed format in use iun the engine
* @returns the transformed texture
*/
KTXTextureLoader.prototype.transformUrl = function (rootUrl, textureFormatInUse) {
var lastDot = rootUrl.lastIndexOf('.');
return (lastDot > -1 ? rootUrl.substring(0, lastDot) : rootUrl) + textureFormatInUse;
};
/**
* Gets the fallback url in case the load fail. This can return null to allow the default fallback mecanism to work
* @param rootUrl the url of the texture
* @param textureFormatInUse defines the current compressed format in use iun the engine
* @returns the fallback texture
*/
KTXTextureLoader.prototype.getFallbackTextureUrl = function (rootUrl, textureFormatInUse) {
// remove the format appended to the rootUrl in the original createCubeTexture call.
var exp = new RegExp("" + textureFormatInUse + "$");
return rootUrl.replace(exp, "");
};
/**
* Uploads the cube texture data to the WebGl Texture. It has alreday been bound.
* @param data contains the texture data
* @param texture defines the BabylonJS internal texture
* @param createPolynomials will be true if polynomials have been requested
* @param onLoad defines the callback to trigger once the texture is ready
* @param onError defines the callback to trigger in case of error
*/
KTXTextureLoader.prototype.loadCubeData = function (data, texture, createPolynomials, onLoad, onError) {
if (Array.isArray(data)) {
return;
}
var engine = texture.getEngine();
var ktx = new BABYLON.KhronosTextureContainer(data, 6);
var loadMipmap = ktx.numberOfMipmapLevels > 1 && texture.generateMipMaps;
engine._unpackFlipY(true);
ktx.uploadLevels(texture, texture.generateMipMaps);
texture.width = ktx.pixelWidth;
texture.height = ktx.pixelHeight;
engine._setCubeMapTextureParams(loadMipmap);
texture.isReady = true;
};
/**
* Uploads the 2D texture data to the WebGl Texture. It has alreday been bound once in the callback.
* @param data contains the texture data
* @param texture defines the BabylonJS internal texture
* @param callback defines the method to call once ready to upload
*/
KTXTextureLoader.prototype.loadData = function (data, texture, callback) {
var ktx = new BABYLON.KhronosTextureContainer(data, 1);
callback(ktx.pixelWidth, ktx.pixelHeight, false, true, function () {
ktx.uploadLevels(texture, texture.generateMipMaps);
});
};
return KTXTextureLoader;
}());
// Register the loader.
BABYLON.Engine._TextureLoaders.unshift(new KTXTextureLoader());
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.ktxTextureLoader.js.map
var BABYLON;
(function (BABYLON) {
/**
* Sets of helpers addressing the serialization and deserialization of environment texture
* stored in a BabylonJS env file.
* Those files are usually stored as .env files.
*/
var EnvironmentTextureTools = /** @class */ (function () {
function EnvironmentTextureTools() {
}
/**
* Gets the environment info from an env file.
* @param data The array buffer containing the .env bytes.
* @returns the environment file info (the json header) if successfully parsed.
*/
EnvironmentTextureTools.GetEnvInfo = function (data) {
var dataView = new DataView(data);
var pos = 0;
for (var i = 0; i < EnvironmentTextureTools._MagicBytes.length; i++) {
if (dataView.getUint8(pos++) !== EnvironmentTextureTools._MagicBytes[i]) {
BABYLON.Tools.Error('Not a babylon environment map');
return null;
}
}
// Read json manifest - collect characters up to null terminator
var manifestString = '';
var charCode = 0x00;
while ((charCode = dataView.getUint8(pos++))) {
manifestString += String.fromCharCode(charCode);
}
var manifest = JSON.parse(manifestString);
if (manifest.specular) {
// Extend the header with the position of the payload.
manifest.specular.specularDataPosition = pos;
// Fallback to 0.8 exactly if lodGenerationScale is not defined for backward compatibility.
manifest.specular.lodGenerationScale = manifest.specular.lodGenerationScale || 0.8;
}
return manifest;
};
/**
* Creates an environment texture from a loaded cube texture.
* @param texture defines the cube texture to convert in env file
* @return a promise containing the environment data if succesfull.
*/
EnvironmentTextureTools.CreateEnvTextureAsync = function (texture) {
var _this = this;
var internalTexture = texture.getInternalTexture();
if (!internalTexture) {
return Promise.reject("The cube texture is invalid.");
}
if (!texture._prefiltered) {
return Promise.reject("The cube texture is invalid (not prefiltered).");
}
var engine = internalTexture.getEngine();
if (engine && engine.premultipliedAlpha) {
return Promise.reject("Env texture can only be created when the engine is created with the premultipliedAlpha option set to false.");
}
if (texture.textureType === BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT) {
return Promise.reject("The cube texture should allow HDR (Full Float or Half Float).");
}
var canvas = engine.getRenderingCanvas();
if (!canvas) {
return Promise.reject("Env texture can only be created when the engine is associated to a canvas.");
}
var textureType = BABYLON.Engine.TEXTURETYPE_FLOAT;
if (!engine.getCaps().textureFloatRender) {
textureType = BABYLON.Engine.TEXTURETYPE_HALF_FLOAT;
if (!engine.getCaps().textureHalfFloatRender) {
return Promise.reject("Env texture can only be created when the browser supports half float or full float rendering.");
}
}
var cubeWidth = internalTexture.width;
var hostingScene = new BABYLON.Scene(engine);
var specularTextures = {};
var promises = [];
// Read and collect all mipmaps data from the cube.
var mipmapsCount = BABYLON.Scalar.Log2(internalTexture.width);
mipmapsCount = Math.round(mipmapsCount);
var _loop_1 = function (i) {
var faceWidth = Math.pow(2, mipmapsCount - i);
var _loop_2 = function (face) {
var data = texture.readPixels(face, i);
// Creates a temp texture with the face data.
var tempTexture = engine.createRawTexture(data, faceWidth, faceWidth, BABYLON.Engine.TEXTUREFORMAT_RGBA, false, false, BABYLON.Texture.NEAREST_SAMPLINGMODE, null, textureType);
// And rgbdEncode them.
var promise = new Promise(function (resolve, reject) {
var rgbdPostProcess = new BABYLON.PostProcess("rgbdEncode", "rgbdEncode", null, null, 1, null, BABYLON.Texture.NEAREST_SAMPLINGMODE, engine, false, undefined, BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT, undefined, null, false);
rgbdPostProcess.getEffect().executeWhenCompiled(function () {
rgbdPostProcess.onApply = function (effect) {
effect._bindTexture("textureSampler", tempTexture);
};
// As the process needs to happen on the main canvas, keep track of the current size
var currentW = engine.getRenderWidth();
var currentH = engine.getRenderHeight();
// Set the desired size for the texture
engine.setSize(faceWidth, faceWidth);
hostingScene.postProcessManager.directRender([rgbdPostProcess], null);
// Reading datas from WebGL
BABYLON.Tools.ToBlob(canvas, function (blob) {
var fileReader = new FileReader();
fileReader.onload = function (event) {
var arrayBuffer = event.target.result;
specularTextures[i * 6 + face] = arrayBuffer;
resolve();
};
fileReader.readAsArrayBuffer(blob);
});
// Reapply the previous canvas size
engine.setSize(currentW, currentH);
});
});
promises.push(promise);
};
// All faces of the cube.
for (var face = 0; face < 6; face++) {
_loop_2(face);
}
};
for (var i = 0; i <= mipmapsCount; i++) {
_loop_1(i);
}
// Once all the textures haves been collected as RGBD stored in PNGs
return Promise.all(promises).then(function () {
// We can delete the hosting scene keeping track of all the creation objects
hostingScene.dispose();
// Creates the json header for the env texture
var info = {
version: 1,
width: cubeWidth,
irradiance: _this._CreateEnvTextureIrradiance(texture),
specular: {
mipmaps: [],
lodGenerationScale: texture.lodGenerationScale
}
};
// Sets the specular image data information
var position = 0;
for (var i = 0; i <= mipmapsCount; i++) {
for (var face = 0; face < 6; face++) {
var byteLength = specularTextures[i * 6 + face].byteLength;
info.specular.mipmaps.push({
length: byteLength,
position: position
});
position += byteLength;
}
}
// Encode the JSON as an array buffer
var infoString = JSON.stringify(info);
var infoBuffer = new ArrayBuffer(infoString.length + 1);
var infoView = new Uint8Array(infoBuffer); // Limited to ascii subset matching unicode.
for (var i = 0, strLen = infoString.length; i < strLen; i++) {
infoView[i] = infoString.charCodeAt(i);
}
// Ends up with a null terminator for easier parsing
infoView[infoString.length] = 0x00;
// Computes the final required size and creates the storage
var totalSize = EnvironmentTextureTools._MagicBytes.length + position + infoBuffer.byteLength;
var finalBuffer = new ArrayBuffer(totalSize);
var finalBufferView = new Uint8Array(finalBuffer);
var dataView = new DataView(finalBuffer);
// Copy the magic bytes identifying the file in
var pos = 0;
for (var i = 0; i < EnvironmentTextureTools._MagicBytes.length; i++) {
dataView.setUint8(pos++, EnvironmentTextureTools._MagicBytes[i]);
}
// Add the json info
finalBufferView.set(new Uint8Array(infoBuffer), pos);
pos += infoBuffer.byteLength;
// Finally inserts the texture data
for (var i = 0; i <= mipmapsCount; i++) {
for (var face = 0; face < 6; face++) {
var dataBuffer = specularTextures[i * 6 + face];
finalBufferView.set(new Uint8Array(dataBuffer), pos);
pos += dataBuffer.byteLength;
}
}
// Voila
return finalBuffer;
});
};
/**
* Creates a JSON representation of the spherical data.
* @param texture defines the texture containing the polynomials
* @return the JSON representation of the spherical info
*/
EnvironmentTextureTools._CreateEnvTextureIrradiance = function (texture) {
var polynmials = texture.sphericalPolynomial;
if (polynmials == null) {
return null;
}
return {
x: [polynmials.x.x, polynmials.x.y, polynmials.x.z],
y: [polynmials.y.x, polynmials.y.y, polynmials.y.z],
z: [polynmials.z.x, polynmials.z.y, polynmials.z.z],
xx: [polynmials.xx.x, polynmials.xx.y, polynmials.xx.z],
yy: [polynmials.yy.x, polynmials.yy.y, polynmials.yy.z],
zz: [polynmials.zz.x, polynmials.zz.y, polynmials.zz.z],
yz: [polynmials.yz.x, polynmials.yz.y, polynmials.yz.z],
zx: [polynmials.zx.x, polynmials.zx.y, polynmials.zx.z],
xy: [polynmials.xy.x, polynmials.xy.y, polynmials.xy.z]
};
};
/**
* Uploads the texture info contained in the env file to the GPU.
* @param texture defines the internal texture to upload to
* @param arrayBuffer defines the buffer cotaining the data to load
* @param info defines the texture info retrieved through the GetEnvInfo method
* @returns a promise
*/
EnvironmentTextureTools.UploadEnvLevelsAsync = function (texture, arrayBuffer, info) {
if (info.version !== 1) {
throw new Error("Unsupported babylon environment map version \"" + info.version + "\"");
}
var specularInfo = info.specular;
if (!specularInfo) {
// Nothing else parsed so far
return Promise.resolve();
}
// Double checks the enclosed info
var mipmapsCount = BABYLON.Scalar.Log2(info.width);
mipmapsCount = Math.round(mipmapsCount) + 1;
if (specularInfo.mipmaps.length !== 6 * mipmapsCount) {
throw new Error("Unsupported specular mipmaps number \"" + specularInfo.mipmaps.length + "\"");
}
texture._lodGenerationScale = specularInfo.lodGenerationScale;
var imageData = new Array(mipmapsCount);
for (var i = 0; i < mipmapsCount; i++) {
imageData[i] = new Array(6);
for (var face = 0; face < 6; face++) {
var imageInfo = specularInfo.mipmaps[i * 6 + face];
imageData[i][face] = new Uint8Array(arrayBuffer, specularInfo.specularDataPosition + imageInfo.position, imageInfo.length);
}
}
return EnvironmentTextureTools.UploadLevelsAsync(texture, imageData);
};
/**
* Uploads the levels of image data to the GPU.
* @param texture defines the internal texture to upload to
* @param imageData defines the array buffer views of image data [mipmap][face]
* @returns a promise
*/
EnvironmentTextureTools.UploadLevelsAsync = function (texture, imageData) {
if (!BABYLON.Tools.IsExponentOfTwo(texture.width)) {
throw new Error("Texture size must be a power of two");
}
var mipmapsCount = Math.round(BABYLON.Scalar.Log2(texture.width)) + 1;
// Gets everything ready.
var engine = texture.getEngine();
var expandTexture = false;
var generateNonLODTextures = false;
var rgbdPostProcess = null;
var cubeRtt = null;
var lodTextures = null;
var caps = engine.getCaps();
texture.format = BABYLON.Engine.TEXTUREFORMAT_RGBA;
texture.type = BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT;
texture.generateMipMaps = true;
engine.updateTextureSamplingMode(BABYLON.Texture.TRILINEAR_SAMPLINGMODE, texture);
// Add extra process if texture lod is not supported
if (!caps.textureLOD) {
expandTexture = false;
generateNonLODTextures = true;
lodTextures = {};
}
// in webgl 1 there are no ways to either render or copy lod level information for float textures.
else if (engine.webGLVersion < 2) {
expandTexture = false;
}
// If half float available we can uncompress the texture
else if (caps.textureHalfFloatRender && caps.textureHalfFloatLinearFiltering) {
expandTexture = true;
texture.type = BABYLON.Engine.TEXTURETYPE_HALF_FLOAT;
}
// If full float available we can uncompress the texture
else if (caps.textureFloatRender && caps.textureFloatLinearFiltering) {
expandTexture = true;
texture.type = BABYLON.Engine.TEXTURETYPE_FLOAT;
}
// Expand the texture if possible
if (expandTexture) {
// Simply run through the decode PP
rgbdPostProcess = new BABYLON.PostProcess("rgbdDecode", "rgbdDecode", null, null, 1, null, BABYLON.Texture.TRILINEAR_SAMPLINGMODE, engine, false, undefined, texture.type, undefined, null, false);
texture._isRGBD = false;
texture.invertY = false;
cubeRtt = engine.createRenderTargetCubeTexture(texture.width, {
generateDepthBuffer: false,
generateMipMaps: true,
generateStencilBuffer: false,
samplingMode: BABYLON.Texture.TRILINEAR_SAMPLINGMODE,
type: texture.type,
format: BABYLON.Engine.TEXTUREFORMAT_RGBA
});
}
else {
texture._isRGBD = true;
texture.invertY = true;
// In case of missing support, applies the same patch than DDS files.
if (generateNonLODTextures) {
var mipSlices = 3;
var scale = texture._lodGenerationScale;
var offset = texture._lodGenerationOffset;
for (var i = 0; i < mipSlices; i++) {
//compute LOD from even spacing in smoothness (matching shader calculation)
var smoothness = i / (mipSlices - 1);
var roughness = 1 - smoothness;
var minLODIndex = offset; // roughness = 0
var maxLODIndex = (mipmapsCount - 1) * scale + offset; // roughness = 1 (mipmaps start from 0)
var lodIndex = minLODIndex + (maxLODIndex - minLODIndex) * roughness;
var mipmapIndex = Math.round(Math.min(Math.max(lodIndex, 0), maxLODIndex));
var glTextureFromLod = new BABYLON.InternalTexture(engine, BABYLON.InternalTexture.DATASOURCE_TEMP);
glTextureFromLod.isCube = true;
glTextureFromLod.invertY = true;
glTextureFromLod.generateMipMaps = false;
engine.updateTextureSamplingMode(BABYLON.Texture.LINEAR_LINEAR, glTextureFromLod);
// Wrap in a base texture for easy binding.
var lodTexture = new BABYLON.BaseTexture(null);
lodTexture.isCube = true;
lodTexture._texture = glTextureFromLod;
lodTextures[mipmapIndex] = lodTexture;
switch (i) {
case 0:
texture._lodTextureLow = lodTexture;
break;
case 1:
texture._lodTextureMid = lodTexture;
break;
case 2:
texture._lodTextureHigh = lodTexture;
break;
}
}
}
}
var promises = [];
var _loop_3 = function (i) {
var _loop_4 = function (face) {
// Constructs an image element from image data
var bytes = imageData[i][face];
var blob = new Blob([bytes], { type: 'image/png' });
var url = URL.createObjectURL(blob);
var image = new Image();
image.src = url;
// Enqueue promise to upload to the texture.
var promise = new Promise(function (resolve, reject) {
image.onload = function () {
if (expandTexture) {
var tempTexture_1 = engine.createTexture(null, true, true, null, BABYLON.Texture.NEAREST_SAMPLINGMODE, null, function (message) {
reject(message);
}, image);
rgbdPostProcess.getEffect().executeWhenCompiled(function () {
// Uncompress the data to a RTT
rgbdPostProcess.onApply = function (effect) {
effect._bindTexture("textureSampler", tempTexture_1);
effect.setFloat2("scale", 1, 1);
};
engine.scenes[0].postProcessManager.directRender([rgbdPostProcess], cubeRtt, true, face, i);
// Cleanup
engine.restoreDefaultFramebuffer();
tempTexture_1.dispose();
window.URL.revokeObjectURL(url);
resolve();
});
}
else {
engine._uploadImageToTexture(texture, image, face, i);
// Upload the face to the non lod texture support
if (generateNonLODTextures) {
var lodTexture = lodTextures[i];
if (lodTexture) {
engine._uploadImageToTexture(lodTexture._texture, image, face, 0);
}
}
resolve();
}
};
image.onerror = function (error) {
reject(error);
};
});
promises.push(promise);
};
// All faces
for (var face = 0; face < 6; face++) {
_loop_4(face);
}
};
// All mipmaps up to provided number of images
for (var i = 0; i < imageData.length; i++) {
_loop_3(i);
}
// Fill remaining mipmaps with black textures.
if (imageData.length < mipmapsCount) {
var data = void 0;
var size = Math.pow(2, mipmapsCount - 1 - imageData.length);
var dataLength = size * size * 4;
switch (texture.type) {
case BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT: {
data = new Uint8Array(dataLength);
break;
}
case BABYLON.Engine.TEXTURETYPE_HALF_FLOAT: {
data = new Uint16Array(dataLength);
break;
}
case BABYLON.Engine.TEXTURETYPE_FLOAT: {
data = new Float32Array(dataLength);
break;
}
}
for (var i = imageData.length; i < mipmapsCount; i++) {
for (var face = 0; face < 6; face++) {
engine._uploadArrayBufferViewToTexture(texture, data, face, i);
}
}
}
// Once all done, finishes the cleanup and return
return Promise.all(promises).then(function () {
// Release temp RTT.
if (cubeRtt) {
engine._releaseFramebufferObjects(cubeRtt);
cubeRtt._swapAndDie(texture);
}
// Release temp Post Process.
if (rgbdPostProcess) {
rgbdPostProcess.dispose();
}
// Flag internal texture as ready in case they are in use.
if (generateNonLODTextures) {
if (texture._lodTextureHigh && texture._lodTextureHigh._texture) {
texture._lodTextureHigh._texture.isReady = true;
}
if (texture._lodTextureMid && texture._lodTextureMid._texture) {
texture._lodTextureMid._texture.isReady = true;
}
if (texture._lodTextureLow && texture._lodTextureLow._texture) {
texture._lodTextureLow._texture.isReady = true;
}
}
});
};
/**
* Uploads spherical polynomials information to the texture.
* @param texture defines the texture we are trying to upload the information to
* @param info defines the environment texture info retrieved through the GetEnvInfo method
*/
EnvironmentTextureTools.UploadEnvSpherical = function (texture, info) {
if (info.version !== 1) {
BABYLON.Tools.Warn('Unsupported babylon environment map version "' + info.version + '"');
}
var irradianceInfo = info.irradiance;
if (!irradianceInfo) {
return;
}
var sp = new BABYLON.SphericalPolynomial();
BABYLON.Vector3.FromArrayToRef(irradianceInfo.x, 0, sp.x);
BABYLON.Vector3.FromArrayToRef(irradianceInfo.y, 0, sp.y);
BABYLON.Vector3.FromArrayToRef(irradianceInfo.z, 0, sp.z);
BABYLON.Vector3.FromArrayToRef(irradianceInfo.xx, 0, sp.xx);
BABYLON.Vector3.FromArrayToRef(irradianceInfo.yy, 0, sp.yy);
BABYLON.Vector3.FromArrayToRef(irradianceInfo.zz, 0, sp.zz);
BABYLON.Vector3.FromArrayToRef(irradianceInfo.yz, 0, sp.yz);
BABYLON.Vector3.FromArrayToRef(irradianceInfo.zx, 0, sp.zx);
BABYLON.Vector3.FromArrayToRef(irradianceInfo.xy, 0, sp.xy);
texture._sphericalPolynomial = sp;
};
/**
* Magic number identifying the env file.
*/
EnvironmentTextureTools._MagicBytes = [0x86, 0x16, 0x87, 0x96, 0xf6, 0xd6, 0x96, 0x36];
return EnvironmentTextureTools;
}());
BABYLON.EnvironmentTextureTools = EnvironmentTextureTools;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.environmentTextureTools.js.map
var BABYLON;
(function (BABYLON) {
/**
* Implementation of the ENV Texture Loader.
*/
var ENVTextureLoader = /** @class */ (function () {
function ENVTextureLoader() {
/**
* Defines wether the loader supports cascade loading the different faces.
*/
this.supportCascades = false;
}
/**
* This returns if the loader support the current file information.
* @param extension defines the file extension of the file being loaded
* @param textureFormatInUse defines the current compressed format in use iun the engine
* @param fallback defines the fallback internal texture if any
* @param isBase64 defines whether the texture is encoded as a base64
* @param isBuffer defines whether the texture data are stored as a buffer
* @returns true if the loader can load the specified file
*/
ENVTextureLoader.prototype.canLoad = function (extension, textureFormatInUse, fallback, isBase64, isBuffer) {
return extension.indexOf(".env") === 0;
};
/**
* Transform the url before loading if required.
* @param rootUrl the url of the texture
* @param textureFormatInUse defines the current compressed format in use iun the engine
* @returns the transformed texture
*/
ENVTextureLoader.prototype.transformUrl = function (rootUrl, textureFormatInUse) {
return rootUrl;
};
/**
* Gets the fallback url in case the load fail. This can return null to allow the default fallback mecanism to work
* @param rootUrl the url of the texture
* @param textureFormatInUse defines the current compressed format in use iun the engine
* @returns the fallback texture
*/
ENVTextureLoader.prototype.getFallbackTextureUrl = function (rootUrl, textureFormatInUse) {
return null;
};
/**
* Uploads the cube texture data to the WebGl Texture. It has alreday been bound.
* @param data contains the texture data
* @param texture defines the BabylonJS internal texture
* @param createPolynomials will be true if polynomials have been requested
* @param onLoad defines the callback to trigger once the texture is ready
* @param onError defines the callback to trigger in case of error
*/
ENVTextureLoader.prototype.loadCubeData = function (data, texture, createPolynomials, onLoad, onError) {
if (Array.isArray(data)) {
return;
}
data = data;
var info = BABYLON.EnvironmentTextureTools.GetEnvInfo(data);
if (info) {
texture.width = info.width;
texture.height = info.width;
BABYLON.EnvironmentTextureTools.UploadEnvSpherical(texture, info);
BABYLON.EnvironmentTextureTools.UploadEnvLevelsAsync(texture, data, info).then(function () {
texture.isReady = true;
if (onLoad) {
onLoad();
}
});
}
else if (onError) {
onError("Can not parse the environment file", null);
}
};
/**
* Uploads the 2D texture data to the WebGl Texture. It has alreday been bound once in the callback.
* @param data contains the texture data
* @param texture defines the BabylonJS internal texture
* @param callback defines the method to call once ready to upload
*/
ENVTextureLoader.prototype.loadData = function (data, texture, callback) {
throw ".env not supported in 2d.";
};
return ENVTextureLoader;
}());
// Register the loader.
BABYLON.Engine._TextureLoaders.push(new ENVTextureLoader());
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.envTextureLoader.js.map
var BABYLON;
(function (BABYLON) {
/**
* Renders a layer on top of an existing scene
*/
var UtilityLayerRenderer = /** @class */ (function () {
/**
* Instantiates a UtilityLayerRenderer
* @param originalScene the original scene that will be rendered on top of
*/
function UtilityLayerRenderer(/** the original scene that will be rendered on top of */ originalScene) {
var _this = this;
this.originalScene = originalScene;
this._pointerCaptures = {};
this._lastPointerEvents = {};
/**
* If the utility layer should automatically be rendered on top of existing scene
*/
this.shouldRender = true;
/**
* If set to true, only pointer down onPointerObservable events will be blocked when picking is occluded by original scene
*/
this.onlyCheckPointerDownEvents = true;
/**
* If set to false, only pointerUp, pointerDown and pointerMove will be sent to the utilityLayerScene (false by default)
*/
this.processAllEvents = false;
/**
* Observable raised when the pointer move from the utility layer scene to the main scene
*/
this.onPointerOutObservable = new BABYLON.Observable();
// Create scene which will be rendered in the foreground and remove it from being referenced by engine to avoid interfering with existing app
this.utilityLayerScene = new BABYLON.Scene(originalScene.getEngine());
this.utilityLayerScene._allowPostProcessClear = false;
originalScene.getEngine().scenes.pop();
// Detach controls on utility scene, events will be fired by logic below to handle picking priority
this.utilityLayerScene.detachControl();
this._originalPointerObserver = originalScene.onPrePointerObservable.add(function (prePointerInfo, eventState) {
if (!_this.processAllEvents) {
if (prePointerInfo.type !== BABYLON.PointerEventTypes.POINTERMOVE
&& prePointerInfo.type !== BABYLON.PointerEventTypes.POINTERUP
&& prePointerInfo.type !== BABYLON.PointerEventTypes.POINTERDOWN) {
return;
}
}
var pointerEvent = (prePointerInfo.event);
if (originalScene.isPointerCaptured(pointerEvent.pointerId)) {
_this._pointerCaptures[pointerEvent.pointerId] = false;
return;
}
var utilityScenePick = prePointerInfo.ray ? _this.utilityLayerScene.pickWithRay(prePointerInfo.ray) : _this.utilityLayerScene.pick(originalScene.pointerX, originalScene.pointerY);
if (!prePointerInfo.ray && utilityScenePick) {
prePointerInfo.ray = utilityScenePick.ray;
}
// always fire the prepointer oversvable
_this.utilityLayerScene.onPrePointerObservable.notifyObservers(prePointerInfo);
// allow every non pointer down event to flow to the utility layer
if (_this.onlyCheckPointerDownEvents && prePointerInfo.type != BABYLON.PointerEventTypes.POINTERDOWN) {
if (!prePointerInfo.skipOnPointerObservable) {
_this.utilityLayerScene.onPointerObservable.notifyObservers(new BABYLON.PointerInfo(prePointerInfo.type, prePointerInfo.event, utilityScenePick));
}
if (prePointerInfo.type === BABYLON.PointerEventTypes.POINTERUP && _this._pointerCaptures[pointerEvent.pointerId]) {
_this._pointerCaptures[pointerEvent.pointerId] = false;
}
return;
}
if (_this.utilityLayerScene.autoClearDepthAndStencil) {
// If this layer is an overlay, check if this layer was hit and if so, skip pointer events for the main scene
if (utilityScenePick && utilityScenePick.hit) {
if (!prePointerInfo.skipOnPointerObservable) {
_this.utilityLayerScene.onPointerObservable.notifyObservers(new BABYLON.PointerInfo(prePointerInfo.type, prePointerInfo.event, utilityScenePick));
}
prePointerInfo.skipOnPointerObservable = true;
}
}
else {
var originalScenePick = prePointerInfo.ray ? originalScene.pickWithRay(prePointerInfo.ray) : originalScene.pick(originalScene.pointerX, originalScene.pointerY);
var pointerEvent_1 = (prePointerInfo.event);
// If the layer can be occluded by the original scene, only fire pointer events to the first layer that hit they ray
if (originalScenePick && utilityScenePick) {
// No pick in utility scene
if (utilityScenePick.distance === 0 && originalScenePick.pickedMesh) {
if (_this.mainSceneTrackerPredicate && _this.mainSceneTrackerPredicate(originalScenePick.pickedMesh)) {
// We touched an utility mesh present in the main scene
_this._notifyObservers(prePointerInfo, originalScenePick, pointerEvent_1);
prePointerInfo.skipOnPointerObservable = true;
}
else if (prePointerInfo.type === BABYLON.PointerEventTypes.POINTERDOWN) {
_this._pointerCaptures[pointerEvent_1.pointerId] = true;
}
}
else if (!_this._pointerCaptures[pointerEvent_1.pointerId] && (utilityScenePick.distance < originalScenePick.distance || originalScenePick.distance === 0)) {
// We pick something in utility scene or the pick in utility is closer than the one in main scene
_this._notifyObservers(prePointerInfo, utilityScenePick, pointerEvent_1);
// If a previous utility layer set this, do not unset this
if (!prePointerInfo.skipOnPointerObservable) {
prePointerInfo.skipOnPointerObservable = utilityScenePick.distance > 0;
}
}
else if (!_this._pointerCaptures[pointerEvent_1.pointerId] && (utilityScenePick.distance > originalScenePick.distance)) {
// We have a pick in both scenes but main is closer than utility
// We touched an utility mesh present in the main scene
if (_this.mainSceneTrackerPredicate && _this.mainSceneTrackerPredicate(originalScenePick.pickedMesh)) {
_this._notifyObservers(prePointerInfo, originalScenePick, pointerEvent_1);
prePointerInfo.skipOnPointerObservable = true;
}
else if (_this._lastPointerEvents[pointerEvent_1.pointerId]) {
// We need to send a last pointerup to the utilityLayerScene to make sure animations can complete
_this.onPointerOutObservable.notifyObservers(pointerEvent_1.pointerId);
delete _this._lastPointerEvents[pointerEvent_1.pointerId];
}
}
if (prePointerInfo.type === BABYLON.PointerEventTypes.POINTERUP && _this._pointerCaptures[pointerEvent_1.pointerId]) {
_this._pointerCaptures[pointerEvent_1.pointerId] = false;
}
}
}
});
// Render directly on top of existing scene without clearing
this.utilityLayerScene.autoClear = false;
this._afterRenderObserver = this.originalScene.onAfterRenderObservable.add(function () {
if (_this.shouldRender) {
_this.render();
}
});
this._sceneDisposeObserver = this.originalScene.onDisposeObservable.add(function () {
_this.dispose();
});
this._updateCamera();
}
Object.defineProperty(UtilityLayerRenderer, "DefaultUtilityLayer", {
/**
* A shared utility layer that can be used to overlay objects into a scene (Depth map of the previous scene is cleared before drawing on top of it)
*/
get: function () {
if (UtilityLayerRenderer._DefaultUtilityLayer == null) {
UtilityLayerRenderer._DefaultUtilityLayer = new UtilityLayerRenderer(BABYLON.Engine.LastCreatedScene);
UtilityLayerRenderer._DefaultUtilityLayer.originalScene.onDisposeObservable.addOnce(function () {
UtilityLayerRenderer._DefaultUtilityLayer = null;
});
}
return UtilityLayerRenderer._DefaultUtilityLayer;
},
enumerable: true,
configurable: true
});
Object.defineProperty(UtilityLayerRenderer, "DefaultKeepDepthUtilityLayer", {
/**
* A shared utility layer that can be used to embed objects into a scene (Depth map of the previous scene is not cleared before drawing on top of it)
*/
get: function () {
if (UtilityLayerRenderer._DefaultKeepDepthUtilityLayer == null) {
UtilityLayerRenderer._DefaultKeepDepthUtilityLayer = new UtilityLayerRenderer(BABYLON.Engine.LastCreatedScene);
UtilityLayerRenderer._DefaultKeepDepthUtilityLayer.utilityLayerScene.autoClearDepthAndStencil = false;
UtilityLayerRenderer._DefaultKeepDepthUtilityLayer.originalScene.onDisposeObservable.addOnce(function () {
UtilityLayerRenderer._DefaultKeepDepthUtilityLayer = null;
});
}
return UtilityLayerRenderer._DefaultKeepDepthUtilityLayer;
},
enumerable: true,
configurable: true
});
UtilityLayerRenderer.prototype._notifyObservers = function (prePointerInfo, pickInfo, pointerEvent) {
if (!prePointerInfo.skipOnPointerObservable) {
this.utilityLayerScene.onPointerObservable.notifyObservers(new BABYLON.PointerInfo(prePointerInfo.type, prePointerInfo.event, pickInfo));
this._lastPointerEvents[pointerEvent.pointerId] = pointerEvent.pointerType;
}
};
/**
* Renders the utility layers scene on top of the original scene
*/
UtilityLayerRenderer.prototype.render = function () {
this._updateCamera();
if (this.utilityLayerScene.activeCamera) {
// Set the camera's scene to utility layers scene
var oldScene = this.utilityLayerScene.activeCamera.getScene();
var camera = this.utilityLayerScene.activeCamera;
camera._scene = this.utilityLayerScene;
if (camera.leftCamera) {
camera.leftCamera._scene = this.utilityLayerScene;
}
if (camera.rightCamera) {
camera.rightCamera._scene = this.utilityLayerScene;
}
this.utilityLayerScene.render(false);
// Reset camera's scene back to original
camera._scene = oldScene;
if (camera.leftCamera) {
camera.leftCamera._scene = oldScene;
}
if (camera.rightCamera) {
camera.rightCamera._scene = oldScene;
}
}
};
/**
* Disposes of the renderer
*/
UtilityLayerRenderer.prototype.dispose = function () {
this.onPointerOutObservable.clear();
if (this._afterRenderObserver) {
this.originalScene.onAfterRenderObservable.remove(this._afterRenderObserver);
}
if (this._sceneDisposeObserver) {
this.originalScene.onDisposeObservable.remove(this._sceneDisposeObserver);
}
if (this._originalPointerObserver) {
this.originalScene.onPrePointerObservable.remove(this._originalPointerObserver);
}
this.utilityLayerScene.dispose();
};
UtilityLayerRenderer.prototype._updateCamera = function () {
this.utilityLayerScene.activeCamera = this.originalScene.activeCamera;
};
UtilityLayerRenderer._DefaultUtilityLayer = null;
UtilityLayerRenderer._DefaultKeepDepthUtilityLayer = null;
return UtilityLayerRenderer;
}());
BABYLON.UtilityLayerRenderer = UtilityLayerRenderer;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.utilityLayerRenderer.js.map
//# sourceMappingURL=babylon.behavior.js.map
var BABYLON;
(function (BABYLON) {
/**
* A behavior that when attached to a mesh will allow the mesh to be dragged around the screen based on pointer events
*/
var PointerDragBehavior = /** @class */ (function () {
/**
* Creates a pointer drag behavior that can be attached to a mesh
* @param options The drag axis or normal of the plane that will be dragged across. If no options are specified the drag plane will always face the ray's origin (eg. camera)
*/
function PointerDragBehavior(options) {
/**
* The maximum tolerated angle between the drag plane and dragging pointer rays to trigger pointer events. Set to 0 to allow any angle (default: 0)
*/
this.maxDragAngle = 0;
/**
* @hidden
*/
this._useAlternatePickedPointAboveMaxDragAngle = false;
/**
* The id of the pointer that is currently interacting with the behavior (-1 when no pointer is active)
*/
this.currentDraggingPointerID = -1;
/**
* If the behavior is currently in a dragging state
*/
this.dragging = false;
/**
* The distance towards the target drag position to move each frame. This can be useful to avoid jitter. Set this to 1 for no delay. (Default: 0.2)
*/
this.dragDeltaRatio = 0.2;
/**
* If the drag plane orientation should be updated during the dragging (Default: true)
*/
this.updateDragPlane = true;
// Debug mode will display drag planes to help visualize behavior
this._debugMode = false;
this._moving = false;
/**
* Fires each time the attached mesh is dragged with the pointer
* * delta between last drag position and current drag position in world space
* * dragDistance along the drag axis
* * dragPlaneNormal normal of the current drag plane used during the drag
* * dragPlanePoint in world space where the drag intersects the drag plane
*/
this.onDragObservable = new BABYLON.Observable();
/**
* Fires each time a drag begins (eg. mouse down on mesh)
*/
this.onDragStartObservable = new BABYLON.Observable();
/**
* Fires each time a drag ends (eg. mouse release after drag)
*/
this.onDragEndObservable = new BABYLON.Observable();
/**
* If the attached mesh should be moved when dragged
*/
this.moveAttached = true;
/**
* If the drag behavior will react to drag events (Default: true)
*/
this.enabled = true;
/**
* If camera controls should be detached during the drag
*/
this.detachCameraControls = true;
/**
* If set, the drag plane/axis will be rotated based on the attached mesh's world rotation (Default: true)
*/
this.useObjectOrienationForDragging = true;
this._tmpVector = new BABYLON.Vector3(0, 0, 0);
this._alternatePickedPoint = new BABYLON.Vector3(0, 0, 0);
this._worldDragAxis = new BABYLON.Vector3(0, 0, 0);
// Variables to avoid instantiation in the below method
this._pointA = new BABYLON.Vector3(0, 0, 0);
this._pointB = new BABYLON.Vector3(0, 0, 0);
this._pointC = new BABYLON.Vector3(0, 0, 0);
this._lineA = new BABYLON.Vector3(0, 0, 0);
this._lineB = new BABYLON.Vector3(0, 0, 0);
this._localAxis = new BABYLON.Vector3(0, 0, 0);
this._lookAt = new BABYLON.Vector3(0, 0, 0);
this._options = options ? options : {};
var optionCount = 0;
if (this._options.dragAxis) {
optionCount++;
}
if (this._options.dragPlaneNormal) {
optionCount++;
}
if (optionCount > 1) {
throw "Multiple drag modes specified in dragBehavior options. Only one expected";
}
}
Object.defineProperty(PointerDragBehavior.prototype, "name", {
/**
* The name of the behavior
*/
get: function () {
return "PointerDrag";
},
enumerable: true,
configurable: true
});
/**
* Initializes the behavior
*/
PointerDragBehavior.prototype.init = function () { };
/**
* Attaches the drag behavior the passed in mesh
* @param ownerNode The mesh that will be dragged around once attached
*/
PointerDragBehavior.prototype.attach = function (ownerNode) {
var _this = this;
this._scene = ownerNode.getScene();
this._attachedNode = ownerNode;
// Initialize drag plane to not interfere with existing scene
if (!PointerDragBehavior._planeScene) {
if (this._debugMode) {
PointerDragBehavior._planeScene = this._scene;
}
else {
PointerDragBehavior._planeScene = new BABYLON.Scene(this._scene.getEngine());
PointerDragBehavior._planeScene.detachControl();
this._scene.getEngine().scenes.pop();
this._scene.onDisposeObservable.addOnce(function () {
PointerDragBehavior._planeScene.dispose();
PointerDragBehavior._planeScene = null;
});
}
}
this._dragPlane = BABYLON.Mesh.CreatePlane("pointerDragPlane", this._debugMode ? 1 : 10000, PointerDragBehavior._planeScene, false, BABYLON.Mesh.DOUBLESIDE);
// State of the drag
this.lastDragPosition = new BABYLON.Vector3(0, 0, 0);
var delta = new BABYLON.Vector3(0, 0, 0);
var dragLength = 0;
var targetPosition = new BABYLON.Vector3(0, 0, 0);
var pickPredicate = function (m) {
return _this._attachedNode == m || m.isDescendantOf(_this._attachedNode);
};
var attachedElement = null;
this._pointerObserver = this._scene.onPointerObservable.add(function (pointerInfo, eventState) {
if (!_this.enabled) {
return;
}
if (pointerInfo.type == BABYLON.PointerEventTypes.POINTERDOWN) {
if (!_this.dragging && pointerInfo.pickInfo && pointerInfo.pickInfo.hit && pointerInfo.pickInfo.pickedMesh && pointerInfo.pickInfo.pickedPoint && pointerInfo.pickInfo.ray && pickPredicate(pointerInfo.pickInfo.pickedMesh)) {
_this._updateDragPlanePosition(pointerInfo.pickInfo.ray, pointerInfo.pickInfo.pickedPoint);
var pickedPoint = _this._pickWithRayOnDragPlane(pointerInfo.pickInfo.ray);
if (pickedPoint) {
_this.dragging = true;
_this.currentDraggingPointerID = pointerInfo.event.pointerId;
_this.lastDragPosition.copyFrom(pickedPoint);
_this.onDragStartObservable.notifyObservers({ dragPlanePoint: pickedPoint, pointerId: _this.currentDraggingPointerID });
targetPosition.copyFrom(_this._attachedNode.absolutePosition);
// Detatch camera controls
if (_this.detachCameraControls && _this._scene.activeCamera && !_this._scene.activeCamera.leftCamera) {
if (_this._scene.activeCamera.inputs.attachedElement) {
attachedElement = _this._scene.activeCamera.inputs.attachedElement;
_this._scene.activeCamera.detachControl(_this._scene.activeCamera.inputs.attachedElement);
}
else {
attachedElement = null;
}
}
}
}
}
else if (pointerInfo.type == BABYLON.PointerEventTypes.POINTERUP) {
if (_this.currentDraggingPointerID == pointerInfo.event.pointerId) {
_this.releaseDrag();
// Reattach camera controls
if (_this.detachCameraControls && attachedElement && _this._scene.activeCamera && !_this._scene.activeCamera.leftCamera) {
_this._scene.activeCamera.attachControl(attachedElement, true);
}
}
}
else if (pointerInfo.type == BABYLON.PointerEventTypes.POINTERMOVE) {
if (_this.currentDraggingPointerID == pointerInfo.event.pointerId && _this.dragging && pointerInfo.pickInfo && pointerInfo.pickInfo.ray) {
_this._moving = true;
var pickedPoint = _this._pickWithRayOnDragPlane(pointerInfo.pickInfo.ray);
if (pickedPoint) {
if (_this.updateDragPlane) {
_this._updateDragPlanePosition(pointerInfo.pickInfo.ray, pickedPoint);
}
// depending on the drag mode option drag accordingly
if (_this._options.dragAxis) {
// Convert local drag axis to world
BABYLON.Vector3.TransformCoordinatesToRef(_this._options.dragAxis, _this._attachedNode.getWorldMatrix().getRotationMatrix(), _this._worldDragAxis);
// Project delta drag from the drag plane onto the drag axis
pickedPoint.subtractToRef(_this.lastDragPosition, _this._tmpVector);
dragLength = BABYLON.Vector3.Dot(_this._tmpVector, _this._worldDragAxis);
_this._worldDragAxis.scaleToRef(dragLength, delta);
}
else {
dragLength = delta.length();
pickedPoint.subtractToRef(_this.lastDragPosition, delta);
}
targetPosition.addInPlace(delta);
_this.onDragObservable.notifyObservers({ dragDistance: dragLength, delta: delta, dragPlanePoint: pickedPoint, dragPlaneNormal: _this._dragPlane.forward, pointerId: _this.currentDraggingPointerID });
_this.lastDragPosition.copyFrom(pickedPoint);
}
}
}
});
this._beforeRenderObserver = this._scene.onBeforeRenderObservable.add(function () {
if (_this._moving && _this.moveAttached) {
// Slowly move mesh to avoid jitter
targetPosition.subtractToRef(_this._attachedNode.absolutePosition, _this._tmpVector);
_this._tmpVector.scaleInPlace(0.2);
_this._attachedNode.getAbsolutePosition().addToRef(_this._tmpVector, _this._tmpVector);
_this._attachedNode.setAbsolutePosition(_this._tmpVector);
}
});
};
PointerDragBehavior.prototype.releaseDrag = function () {
this.dragging = false;
this.onDragEndObservable.notifyObservers({ dragPlanePoint: this.lastDragPosition, pointerId: this.currentDraggingPointerID });
this.currentDraggingPointerID = -1;
this._moving = false;
};
PointerDragBehavior.prototype._pickWithRayOnDragPlane = function (ray) {
var _this = this;
if (!ray) {
return null;
}
// Calculate angle between plane normal and ray
var angle = Math.acos(BABYLON.Vector3.Dot(this._dragPlane.forward, ray.direction));
// Correct if ray is casted from oposite side
if (angle > Math.PI / 2) {
angle = Math.PI - angle;
}
// If the angle is too perpendicular to the plane pick another point on the plane where it is looking
if (this.maxDragAngle > 0 && angle > this.maxDragAngle) {
if (this._useAlternatePickedPointAboveMaxDragAngle) {
// Invert ray direction along the towards object axis
this._tmpVector.copyFrom(ray.direction);
this._attachedNode.absolutePosition.subtractToRef(ray.origin, this._alternatePickedPoint);
this._alternatePickedPoint.normalize();
this._alternatePickedPoint.scaleInPlace(-2 * BABYLON.Vector3.Dot(this._alternatePickedPoint, this._tmpVector));
this._tmpVector.addInPlace(this._alternatePickedPoint);
// Project resulting vector onto the drag plane and add it to the attached nodes absolute position to get a picked point
var dot = BABYLON.Vector3.Dot(this._dragPlane.forward, this._tmpVector);
this._dragPlane.forward.scaleToRef(-dot, this._alternatePickedPoint);
this._alternatePickedPoint.addInPlace(this._tmpVector);
this._alternatePickedPoint.addInPlace(this._attachedNode.absolutePosition);
return this._alternatePickedPoint;
}
else {
return null;
}
}
var pickResult = PointerDragBehavior._planeScene.pickWithRay(ray, function (m) { return m == _this._dragPlane; });
if (pickResult && pickResult.hit && pickResult.pickedMesh && pickResult.pickedPoint) {
return pickResult.pickedPoint;
}
else {
return null;
}
};
// Position the drag plane based on the attached mesh position, for single axis rotate the plane along the axis to face the camera
PointerDragBehavior.prototype._updateDragPlanePosition = function (ray, dragPlanePosition) {
this._pointA.copyFrom(dragPlanePosition);
if (this._options.dragAxis) {
this.useObjectOrienationForDragging ? BABYLON.Vector3.TransformCoordinatesToRef(this._options.dragAxis, this._attachedNode.getWorldMatrix().getRotationMatrix(), this._localAxis) : this._localAxis.copyFrom(this._options.dragAxis);
// Calculate plane normal in direction of camera but perpendicular to drag axis
this._pointA.addToRef(this._localAxis, this._pointB); // towards drag axis
ray.origin.subtractToRef(this._pointA, this._pointC);
this._pointA.addToRef(this._pointC.normalize(), this._pointC); // towards camera
// Get perpendicular line from direction to camera and drag axis
this._pointB.subtractToRef(this._pointA, this._lineA);
this._pointC.subtractToRef(this._pointA, this._lineB);
BABYLON.Vector3.CrossToRef(this._lineA, this._lineB, this._lookAt);
// Get perpendicular line from previous result and drag axis to adjust lineB to be perpendiculat to camera
BABYLON.Vector3.CrossToRef(this._lineA, this._lookAt, this._lookAt);
this._lookAt.normalize();
this._dragPlane.position.copyFrom(this._pointA);
this._pointA.subtractToRef(this._lookAt, this._lookAt);
this._dragPlane.lookAt(this._lookAt);
}
else if (this._options.dragPlaneNormal) {
this.useObjectOrienationForDragging ? BABYLON.Vector3.TransformCoordinatesToRef(this._options.dragPlaneNormal, this._attachedNode.getWorldMatrix().getRotationMatrix(), this._localAxis) : this._localAxis.copyFrom(this._options.dragPlaneNormal);
this._dragPlane.position.copyFrom(this._pointA);
this._pointA.subtractToRef(this._localAxis, this._lookAt);
this._dragPlane.lookAt(this._lookAt);
}
else {
this._dragPlane.position.copyFrom(this._pointA);
this._dragPlane.lookAt(ray.origin);
}
this._dragPlane.computeWorldMatrix(true);
};
/**
* Detaches the behavior from the mesh
*/
PointerDragBehavior.prototype.detach = function () {
if (this._pointerObserver) {
this._scene.onPointerObservable.remove(this._pointerObserver);
}
if (this._beforeRenderObserver) {
this._scene.onBeforeRenderObservable.remove(this._beforeRenderObserver);
}
};
return PointerDragBehavior;
}());
BABYLON.PointerDragBehavior = PointerDragBehavior;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.pointerDragBehavior.js.map
var BABYLON;
(function (BABYLON) {
/**
* A behavior that when attached to a mesh will allow the mesh to be scaled
*/
var MultiPointerScaleBehavior = /** @class */ (function () {
function MultiPointerScaleBehavior() {
this._startDistance = 0;
this._initialScale = new BABYLON.Vector3(0, 0, 0);
this._targetScale = new BABYLON.Vector3(0, 0, 0);
this._sceneRenderObserver = null;
this._dragBehaviorA = new BABYLON.PointerDragBehavior({});
this._dragBehaviorA.moveAttached = false;
this._dragBehaviorB = new BABYLON.PointerDragBehavior({});
this._dragBehaviorB.moveAttached = false;
}
Object.defineProperty(MultiPointerScaleBehavior.prototype, "name", {
/**
* The name of the behavior
*/
get: function () {
return "MultiPointerScale";
},
enumerable: true,
configurable: true
});
/**
* Initializes the behavior
*/
MultiPointerScaleBehavior.prototype.init = function () { };
MultiPointerScaleBehavior.prototype._getCurrentDistance = function () {
return this._dragBehaviorA.lastDragPosition.subtract(this._dragBehaviorB.lastDragPosition).length();
};
/**
* Attaches the scale behavior the passed in mesh
* @param ownerNode The mesh that will be scaled around once attached
*/
MultiPointerScaleBehavior.prototype.attach = function (ownerNode) {
var _this = this;
this._ownerNode = ownerNode;
// Create 2 drag behaviors such that each will only be triggered by a separate pointer
this._dragBehaviorA.onDragStartObservable.add(function (e) {
if (_this._dragBehaviorA.dragging && _this._dragBehaviorB.dragging) {
if (_this._dragBehaviorA.currentDraggingPointerID == _this._dragBehaviorB.currentDraggingPointerID) {
_this._dragBehaviorA.releaseDrag();
}
else {
_this._initialScale.copyFrom(ownerNode.scaling);
_this._startDistance = _this._getCurrentDistance();
}
}
});
this._dragBehaviorB.onDragStartObservable.add(function (e) {
if (_this._dragBehaviorA.dragging && _this._dragBehaviorB.dragging) {
if (_this._dragBehaviorA.currentDraggingPointerID == _this._dragBehaviorB.currentDraggingPointerID) {
_this._dragBehaviorB.releaseDrag();
}
else {
_this._initialScale.copyFrom(ownerNode.scaling);
_this._startDistance = _this._getCurrentDistance();
}
}
});
// Once both drag behaviors are active scale based on the distance between the two pointers
[this._dragBehaviorA, this._dragBehaviorB].forEach(function (behavior) {
behavior.onDragObservable.add(function () {
if (_this._dragBehaviorA.dragging && _this._dragBehaviorB.dragging) {
var ratio = _this._getCurrentDistance() / _this._startDistance;
_this._initialScale.scaleToRef(ratio, _this._targetScale);
}
});
});
ownerNode.addBehavior(this._dragBehaviorA);
ownerNode.addBehavior(this._dragBehaviorB);
// On every frame move towards target scaling to avoid jitter caused by vr controllers
this._sceneRenderObserver = ownerNode.getScene().onBeforeRenderObservable.add(function () {
if (_this._dragBehaviorA.dragging && _this._dragBehaviorB.dragging) {
var change = _this._targetScale.subtract(ownerNode.scaling).scaleInPlace(0.1);
if (change.length() > 0.01) {
ownerNode.scaling.addInPlace(change);
}
}
});
};
/**
* Detaches the behavior from the mesh
*/
MultiPointerScaleBehavior.prototype.detach = function () {
var _this = this;
this._ownerNode.getScene().onBeforeRenderObservable.remove(this._sceneRenderObserver);
[this._dragBehaviorA, this._dragBehaviorB].forEach(function (behavior) {
behavior.onDragStartObservable.clear();
behavior.onDragObservable.clear();
_this._ownerNode.removeBehavior(behavior);
});
};
return MultiPointerScaleBehavior;
}());
BABYLON.MultiPointerScaleBehavior = MultiPointerScaleBehavior;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.multiPointerScaleBehavior.js.map
var BABYLON;
(function (BABYLON) {
/**
* A behavior that when attached to a mesh will allow the mesh to be dragged around based on directions and origin of the pointer's ray
*/
var SixDofDragBehavior = /** @class */ (function () {
function SixDofDragBehavior() {
this._sceneRenderObserver = null;
this._targetPosition = new BABYLON.Vector3(0, 0, 0);
this._moving = false;
this._startingOrientation = new BABYLON.Quaternion();
/**
* How much faster the object should move when the controller is moving towards it. This is useful to bring objects that are far away from the user to them faster. Set this to 0 to avoid any speed increase. (Default: 3)
*/
this.zDragFactor = 3;
/**
* If the behavior is currently in a dragging state
*/
this.dragging = false;
/**
* The distance towards the target drag position to move each frame. This can be useful to avoid jitter. Set this to 1 for no delay. (Default: 0.2)
*/
this.dragDeltaRatio = 0.2;
/**
* The id of the pointer that is currently interacting with the behavior (-1 when no pointer is active)
*/
this.currentDraggingPointerID = -1;
/**
* If camera controls should be detached during the drag
*/
this.detachCameraControls = true;
}
Object.defineProperty(SixDofDragBehavior.prototype, "name", {
/**
* The name of the behavior
*/
get: function () {
return "SixDofDrag";
},
enumerable: true,
configurable: true
});
/**
* Initializes the behavior
*/
SixDofDragBehavior.prototype.init = function () { };
/**
* Attaches the scale behavior the passed in mesh
* @param ownerNode The mesh that will be scaled around once attached
*/
SixDofDragBehavior.prototype.attach = function (ownerNode) {
var _this = this;
this._ownerNode = ownerNode;
this._scene = this._ownerNode.getScene();
if (!SixDofDragBehavior._virtualScene) {
SixDofDragBehavior._virtualScene = new BABYLON.Scene(this._scene.getEngine());
this._scene.getEngine().scenes.pop();
}
var pickedMesh = null;
var lastSixDofOriginPosition = new BABYLON.Vector3(0, 0, 0);
// Setup virtual meshes to be used for dragging without dirtying the existing scene
this._virtualOriginMesh = new BABYLON.AbstractMesh("", SixDofDragBehavior._virtualScene);
this._virtualOriginMesh.rotationQuaternion = new BABYLON.Quaternion();
this._virtualDragMesh = new BABYLON.AbstractMesh("", SixDofDragBehavior._virtualScene);
this._virtualDragMesh.rotationQuaternion = new BABYLON.Quaternion();
var pickPredicate = function (m) {
return _this._ownerNode == m || m.isDescendantOf(_this._ownerNode);
};
var attachedElement = null;
this._pointerObserver = this._scene.onPointerObservable.add(function (pointerInfo, eventState) {
if (pointerInfo.type == BABYLON.PointerEventTypes.POINTERDOWN) {
if (!_this.dragging && pointerInfo.pickInfo && pointerInfo.pickInfo.hit && pointerInfo.pickInfo.pickedMesh && pointerInfo.pickInfo.ray && pickPredicate(pointerInfo.pickInfo.pickedMesh)) {
if (_this._scene.activeCamera && _this._scene.activeCamera.cameraRigMode == BABYLON.Camera.RIG_MODE_NONE) {
pointerInfo.pickInfo.ray.origin.copyFrom(_this._scene.activeCamera.position);
}
pickedMesh = _this._ownerNode;
lastSixDofOriginPosition.copyFrom(pointerInfo.pickInfo.ray.origin);
// Set position and orientation of the controller
_this._virtualOriginMesh.position.copyFrom(pointerInfo.pickInfo.ray.origin);
_this._virtualOriginMesh.lookAt(pointerInfo.pickInfo.ray.origin.subtract(pointerInfo.pickInfo.ray.direction));
// Attach the virtual drag mesh to the virtual origin mesh so it can be dragged
_this._virtualOriginMesh.removeChild(_this._virtualDragMesh);
_this._virtualDragMesh.position.copyFrom(pickedMesh.absolutePosition);
if (!pickedMesh.rotationQuaternion) {
pickedMesh.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(pickedMesh.rotation.y, pickedMesh.rotation.x, pickedMesh.rotation.z);
}
var oldParent = pickedMesh.parent;
pickedMesh.setParent(null);
_this._virtualDragMesh.rotationQuaternion.copyFrom(pickedMesh.rotationQuaternion);
pickedMesh.setParent(oldParent);
_this._virtualOriginMesh.addChild(_this._virtualDragMesh);
// Update state
_this._targetPosition.copyFrom(_this._virtualDragMesh.absolutePosition);
_this.dragging = true;
_this.currentDraggingPointerID = pointerInfo.event.pointerId;
// Detatch camera controls
if (_this.detachCameraControls && _this._scene.activeCamera && !_this._scene.activeCamera.leftCamera) {
if (_this._scene.activeCamera.inputs.attachedElement) {
attachedElement = _this._scene.activeCamera.inputs.attachedElement;
_this._scene.activeCamera.detachControl(_this._scene.activeCamera.inputs.attachedElement);
}
else {
attachedElement = null;
}
}
}
}
else if (pointerInfo.type == BABYLON.PointerEventTypes.POINTERUP) {
if (_this.currentDraggingPointerID == pointerInfo.event.pointerId) {
_this.dragging = false;
_this._moving = false;
_this.currentDraggingPointerID = -1;
pickedMesh = null;
_this._virtualOriginMesh.removeChild(_this._virtualDragMesh);
// Reattach camera controls
if (_this.detachCameraControls && attachedElement && _this._scene.activeCamera && !_this._scene.activeCamera.leftCamera) {
_this._scene.activeCamera.attachControl(attachedElement, true);
}
}
}
else if (pointerInfo.type == BABYLON.PointerEventTypes.POINTERMOVE) {
if (_this.currentDraggingPointerID == pointerInfo.event.pointerId && _this.dragging && pointerInfo.pickInfo && pointerInfo.pickInfo.ray && pickedMesh) {
var zDragFactor = _this.zDragFactor;
if (_this._scene.activeCamera && _this._scene.activeCamera.cameraRigMode == BABYLON.Camera.RIG_MODE_NONE) {
pointerInfo.pickInfo.ray.origin.copyFrom(_this._scene.activeCamera.position);
zDragFactor = 0;
}
// Calculate controller drag distance in controller space
var originDragDifference = pointerInfo.pickInfo.ray.origin.subtract(lastSixDofOriginPosition);
lastSixDofOriginPosition.copyFrom(pointerInfo.pickInfo.ray.origin);
var localOriginDragDifference = -BABYLON.Vector3.Dot(originDragDifference, pointerInfo.pickInfo.ray.direction);
_this._virtualOriginMesh.addChild(_this._virtualDragMesh);
// Determine how much the controller moved to/away towards the dragged object and use this to move the object further when its further away
_this._virtualDragMesh.position.z -= _this._virtualDragMesh.position.z < 1 ? localOriginDragDifference * _this.zDragFactor : localOriginDragDifference * zDragFactor * _this._virtualDragMesh.position.z;
if (_this._virtualDragMesh.position.z < 0) {
_this._virtualDragMesh.position.z = 0;
}
// Update the controller position
_this._virtualOriginMesh.position.copyFrom(pointerInfo.pickInfo.ray.origin);
_this._virtualOriginMesh.lookAt(pointerInfo.pickInfo.ray.origin.subtract(pointerInfo.pickInfo.ray.direction));
_this._virtualOriginMesh.removeChild(_this._virtualDragMesh);
// Move the virtualObjectsPosition into the picked mesh's space if needed
_this._targetPosition.copyFrom(_this._virtualDragMesh.absolutePosition);
if (pickedMesh.parent) {
BABYLON.Vector3.TransformCoordinatesToRef(_this._targetPosition, BABYLON.Matrix.Invert(pickedMesh.parent.getWorldMatrix()), _this._targetPosition);
}
if (!_this._moving) {
_this._startingOrientation.copyFrom(_this._virtualDragMesh.rotationQuaternion);
}
_this._moving = true;
}
}
});
var tmpQuaternion = new BABYLON.Quaternion();
// On every frame move towards target scaling to avoid jitter caused by vr controllers
this._sceneRenderObserver = ownerNode.getScene().onBeforeRenderObservable.add(function () {
if (_this.dragging && _this._moving && pickedMesh) {
// Slowly move mesh to avoid jitter
pickedMesh.position.addInPlace(_this._targetPosition.subtract(pickedMesh.position).scale(_this.dragDeltaRatio));
// Get change in rotation
tmpQuaternion.copyFrom(_this._startingOrientation);
tmpQuaternion.x = -tmpQuaternion.x;
tmpQuaternion.y = -tmpQuaternion.y;
tmpQuaternion.z = -tmpQuaternion.z;
_this._virtualDragMesh.rotationQuaternion.multiplyToRef(tmpQuaternion, tmpQuaternion);
// Convert change in rotation to only y axis rotation
BABYLON.Quaternion.RotationYawPitchRollToRef(tmpQuaternion.toEulerAngles("xyz").y, 0, 0, tmpQuaternion);
tmpQuaternion.multiplyToRef(_this._startingOrientation, tmpQuaternion);
// Slowly move mesh to avoid jitter
var oldParent = pickedMesh.parent;
pickedMesh.setParent(null);
BABYLON.Quaternion.SlerpToRef(pickedMesh.rotationQuaternion, tmpQuaternion, _this.dragDeltaRatio, pickedMesh.rotationQuaternion);
pickedMesh.setParent(oldParent);
}
});
};
/**
* Detaches the behavior from the mesh
*/
SixDofDragBehavior.prototype.detach = function () {
if (this._scene) {
this._scene.onPointerObservable.remove(this._pointerObserver);
}
if (this._ownerNode) {
this._ownerNode.getScene().onBeforeRenderObservable.remove(this._sceneRenderObserver);
}
if (this._virtualOriginMesh) {
this._virtualOriginMesh.dispose();
}
if (this._virtualDragMesh) {
this._virtualDragMesh.dispose();
}
};
return SixDofDragBehavior;
}());
BABYLON.SixDofDragBehavior = SixDofDragBehavior;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.sixDofDragBehavior.js.map
var BABYLON;
(function (BABYLON) {
/**
* @hidden
*/
var FaceDirectionInfo = /** @class */ (function () {
function FaceDirectionInfo(direction, rotatedDirection, diff, ignore) {
if (rotatedDirection === void 0) { rotatedDirection = new BABYLON.Vector3(); }
if (diff === void 0) { diff = 0; }
if (ignore === void 0) { ignore = false; }
this.direction = direction;
this.rotatedDirection = rotatedDirection;
this.diff = diff;
this.ignore = ignore;
}
return FaceDirectionInfo;
}());
/**
* A behavior that when attached to a mesh will will place a specified node on the meshes face pointing towards the camera
*/
var AttachToBoxBehavior = /** @class */ (function () {
/**
* Creates the AttachToBoxBehavior, used to attach UI to the closest face of the box to a camera
* @param ui The transform node that should be attched to the mesh
*/
function AttachToBoxBehavior(ui) {
this.ui = ui;
/**
* The name of the behavior
*/
this.name = "AttachToBoxBehavior";
/**
* The distance away from the face of the mesh that the UI should be attached to (default: 0.15)
*/
this.distanceAwayFromFace = 0.15;
/**
* The distance from the bottom of the face that the UI should be attached to (default: 0.15)
*/
this.distanceAwayFromBottomOfFace = 0.15;
this._faceVectors = [new FaceDirectionInfo(BABYLON.Vector3.Up()), new FaceDirectionInfo(BABYLON.Vector3.Down()), new FaceDirectionInfo(BABYLON.Vector3.Left()), new FaceDirectionInfo(BABYLON.Vector3.Right()), new FaceDirectionInfo(BABYLON.Vector3.Forward()), new FaceDirectionInfo(BABYLON.Vector3.Forward().scaleInPlace(-1))];
this._tmpMatrix = new BABYLON.Matrix();
this._tmpVector = new BABYLON.Vector3();
this._zeroVector = BABYLON.Vector3.Zero();
this._lookAtTmpMatrix = new BABYLON.Matrix();
/* Does nothing */
}
/**
* Initializes the behavior
*/
AttachToBoxBehavior.prototype.init = function () {
/* Does nothing */
};
AttachToBoxBehavior.prototype._closestFace = function (targetDirection) {
var _this = this;
// Go over each face and calculate the angle between the face's normal and targetDirection
this._faceVectors.forEach(function (v) {
if (!_this._target.rotationQuaternion) {
_this._target.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(_this._target.rotation.y, _this._target.rotation.x, _this._target.rotation.z);
}
_this._target.rotationQuaternion.toRotationMatrix(_this._tmpMatrix);
BABYLON.Vector3.TransformCoordinatesToRef(v.direction, _this._tmpMatrix, v.rotatedDirection);
v.diff = BABYLON.Vector3.GetAngleBetweenVectors(v.rotatedDirection, targetDirection, BABYLON.Vector3.Cross(v.rotatedDirection, targetDirection));
});
// Return the face information of the one with the normal closeset to target direction
return this._faceVectors.reduce(function (min, p) {
if (min.ignore) {
return p;
}
else if (p.ignore) {
return min;
}
else {
return min.diff < p.diff ? min : p;
}
}, this._faceVectors[0]);
};
AttachToBoxBehavior.prototype._lookAtToRef = function (pos, up, ref) {
if (up === void 0) { up = new BABYLON.Vector3(0, 1, 0); }
BABYLON.Matrix.LookAtLHToRef(this._zeroVector, pos, up, this._lookAtTmpMatrix);
this._lookAtTmpMatrix.invert();
BABYLON.Quaternion.FromRotationMatrixToRef(this._lookAtTmpMatrix, ref);
};
/**
* Attaches the AttachToBoxBehavior to the passed in mesh
* @param target The mesh that the specified node will be attached to
*/
AttachToBoxBehavior.prototype.attach = function (target) {
var _this = this;
this._target = target;
this._scene = this._target.getScene();
// Every frame, update the app bars position
this._onRenderObserver = this._scene.onBeforeRenderObservable.add(function () {
if (!_this._scene.activeCamera) {
return;
}
// Find the face closest to the cameras position
var cameraPos = _this._scene.activeCamera.position;
if (_this._scene.activeCamera.devicePosition) {
cameraPos = _this._scene.activeCamera.devicePosition;
}
var facing = _this._closestFace(cameraPos.subtract(target.position));
if (_this._scene.activeCamera.leftCamera) {
_this._scene.activeCamera.leftCamera.computeWorldMatrix().getRotationMatrixToRef(_this._tmpMatrix);
}
else {
_this._scene.activeCamera.computeWorldMatrix().getRotationMatrixToRef(_this._tmpMatrix);
}
// Get camera up direction
BABYLON.Vector3.TransformCoordinatesToRef(BABYLON.Vector3.Up(), _this._tmpMatrix, _this._tmpVector);
// Ignore faces to not select a parrelel face for the up vector of the UI
_this._faceVectors.forEach(function (v) {
if (facing.direction.x && v.direction.x) {
v.ignore = true;
}
if (facing.direction.y && v.direction.y) {
v.ignore = true;
}
if (facing.direction.z && v.direction.z) {
v.ignore = true;
}
});
var facingUp = _this._closestFace(_this._tmpVector);
// Unignore faces
_this._faceVectors.forEach(function (v) {
v.ignore = false;
});
// Position the app bar on that face
_this.ui.position.copyFrom(target.position);
if (facing.direction.x) {
facing.rotatedDirection.scaleToRef((target.scaling.x / 2) + _this.distanceAwayFromFace, _this._tmpVector);
_this.ui.position.addInPlace(_this._tmpVector);
}
if (facing.direction.y) {
facing.rotatedDirection.scaleToRef((target.scaling.y / 2) + _this.distanceAwayFromFace, _this._tmpVector);
_this.ui.position.addInPlace(_this._tmpVector);
}
if (facing.direction.z) {
facing.rotatedDirection.scaleToRef((target.scaling.z / 2) + _this.distanceAwayFromFace, _this._tmpVector);
_this.ui.position.addInPlace(_this._tmpVector);
}
// Rotate to be oriented properly to the camera
if (!_this.ui.rotationQuaternion) {
_this.ui.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(_this.ui.rotation.y, _this.ui.rotation.x, _this.ui.rotation.z);
}
facing.rotatedDirection.scaleToRef(-1, _this._tmpVector);
_this._lookAtToRef(_this._tmpVector, facingUp.rotatedDirection, _this.ui.rotationQuaternion);
// Place ui the correct distance from the bottom of the mesh
if (facingUp.direction.x) {
_this.ui.up.scaleToRef(_this.distanceAwayFromBottomOfFace - target.scaling.x / 2, _this._tmpVector);
}
if (facingUp.direction.y) {
_this.ui.up.scaleToRef(_this.distanceAwayFromBottomOfFace - target.scaling.y / 2, _this._tmpVector);
}
if (facingUp.direction.z) {
_this.ui.up.scaleToRef(_this.distanceAwayFromBottomOfFace - target.scaling.z / 2, _this._tmpVector);
}
_this.ui.position.addInPlace(_this._tmpVector);
});
};
/**
* Detaches the behavior from the mesh
*/
AttachToBoxBehavior.prototype.detach = function () {
this._scene.onBeforeRenderObservable.remove(this._onRenderObserver);
};
return AttachToBoxBehavior;
}());
BABYLON.AttachToBoxBehavior = AttachToBoxBehavior;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.attachToBoxBehavior.js.map
var BABYLON;
(function (BABYLON) {
/**
* Renders gizmos on top of an existing scene which provide controls for position, rotation, etc.
*/
var Gizmo = /** @class */ (function () {
/**
* Creates a gizmo
* @param gizmoLayer The utility layer the gizmo will be added to
*/
function Gizmo(/** The utility layer the gizmo will be added to */ gizmoLayer) {
if (gizmoLayer === void 0) { gizmoLayer = BABYLON.UtilityLayerRenderer.DefaultUtilityLayer; }
var _this = this;
this.gizmoLayer = gizmoLayer;
this._scaleFactor = 3;
this._tmpMatrix = new BABYLON.Matrix();
/**
* If a custom mesh has been set (Default: false)
*/
this._customMeshSet = false;
/**
* If set the gizmo's rotation will be updated to match the attached mesh each frame (Default: true)
*/
this.updateGizmoRotationToMatchAttachedMesh = true;
/**
* If set the gizmo's position will be updated to match the attached mesh each frame (Default: true)
*/
this.updateGizmoPositionToMatchAttachedMesh = true;
/**
* When set, the gizmo will always appear the same size no matter where the camera is (default: false)
*/
this._updateScale = true;
this._interactionsEnabled = true;
this._tempVector = new BABYLON.Vector3();
this._rootMesh = new BABYLON.Mesh("gizmoRootNode", gizmoLayer.utilityLayerScene);
this._beforeRenderObserver = this.gizmoLayer.utilityLayerScene.onBeforeRenderObservable.add(function () {
_this._update();
});
this.attachedMesh = null;
}
Object.defineProperty(Gizmo.prototype, "attachedMesh", {
/**
* Mesh that the gizmo will be attached to. (eg. on a drag gizmo the mesh that will be dragged)
* * When set, interactions will be enabled
*/
get: function () {
return this._attachedMesh;
},
set: function (value) {
this._attachedMesh = value;
this._rootMesh.setEnabled(value ? true : false);
this._attachedMeshChanged(value);
},
enumerable: true,
configurable: true
});
/**
* Disposes and replaces the current meshes in the gizmo with the specified mesh
* @param mesh The mesh to replace the default mesh of the gizmo
*/
Gizmo.prototype.setCustomMesh = function (mesh) {
if (mesh.getScene() != this.gizmoLayer.utilityLayerScene) {
throw "When setting a custom mesh on a gizmo, the custom meshes scene must be the same as the gizmos (eg. gizmo.gizmoLayer.utilityLayerScene)";
}
this._rootMesh.getChildMeshes().forEach(function (c) {
c.dispose();
});
mesh.parent = this._rootMesh;
this._customMeshSet = true;
};
Gizmo.prototype._attachedMeshChanged = function (value) {
};
/**
* @hidden
* Updates the gizmo to match the attached mesh's position/rotation
*/
Gizmo.prototype._update = function () {
if (this.attachedMesh) {
if (this.updateGizmoRotationToMatchAttachedMesh) {
if (!this._rootMesh.rotationQuaternion) {
this._rootMesh.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(this._rootMesh.rotation.y, this._rootMesh.rotation.x, this._rootMesh.rotation.z);
}
// Remove scaling before getting rotation matrix to get rotation matrix unmodified by scale
this._tempVector.copyFrom(this.attachedMesh.scaling);
if (this.attachedMesh.scaling.x < 0) {
this.attachedMesh.scaling.x *= -1;
}
if (this.attachedMesh.scaling.y < 0) {
this.attachedMesh.scaling.y *= -1;
}
if (this.attachedMesh.scaling.z < 0) {
this.attachedMesh.scaling.z *= -1;
}
this.attachedMesh.computeWorldMatrix().getRotationMatrixToRef(this._tmpMatrix);
this.attachedMesh.scaling.copyFrom(this._tempVector);
this.attachedMesh.computeWorldMatrix();
BABYLON.Quaternion.FromRotationMatrixToRef(this._tmpMatrix, this._rootMesh.rotationQuaternion);
}
if (this.updateGizmoPositionToMatchAttachedMesh) {
this._rootMesh.position.copyFrom(this.attachedMesh.absolutePosition);
}
if (this._updateScale && this.gizmoLayer.utilityLayerScene.activeCamera && this.attachedMesh) {
var cameraPosition = this.gizmoLayer.utilityLayerScene.activeCamera.position;
if (this.gizmoLayer.utilityLayerScene.activeCamera.devicePosition) {
cameraPosition = this.gizmoLayer.utilityLayerScene.activeCamera.devicePosition;
}
this._rootMesh.position.subtractToRef(cameraPosition, this._tempVector);
var dist = this._tempVector.length() / this._scaleFactor;
this._rootMesh.scaling.set(dist, dist, dist);
}
}
};
/**
* Disposes of the gizmo
*/
Gizmo.prototype.dispose = function () {
this._rootMesh.dispose();
if (this._beforeRenderObserver) {
this.gizmoLayer.utilityLayerScene.onBeforeRenderObservable.remove(this._beforeRenderObserver);
}
};
return Gizmo;
}());
BABYLON.Gizmo = Gizmo;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.gizmo.js.map
var BABYLON;
(function (BABYLON) {
/**
* Single axis drag gizmo
*/
var AxisDragGizmo = /** @class */ (function (_super) {
__extends(AxisDragGizmo, _super);
/**
* Creates an AxisDragGizmo
* @param gizmoLayer The utility layer the gizmo will be added to
* @param dragAxis The axis which the gizmo will be able to drag on
* @param color The color of the gizmo
*/
function AxisDragGizmo(dragAxis, color, gizmoLayer) {
if (color === void 0) { color = BABYLON.Color3.Gray(); }
if (gizmoLayer === void 0) { gizmoLayer = BABYLON.UtilityLayerRenderer.DefaultUtilityLayer; }
var _this = _super.call(this, gizmoLayer) || this;
_this._pointerObserver = null;
/**
* Drag distance in babylon units that the gizmo will snap to when dragged (Default: 0)
*/
_this.snapDistance = 0;
/**
* Event that fires each time the gizmo snaps to a new location.
* * snapDistance is the the change in distance
*/
_this.onSnapObservable = new BABYLON.Observable();
// Create Material
var coloredMaterial = new BABYLON.StandardMaterial("", gizmoLayer.utilityLayerScene);
coloredMaterial.disableLighting = true;
coloredMaterial.emissiveColor = color;
var hoverMaterial = new BABYLON.StandardMaterial("", gizmoLayer.utilityLayerScene);
hoverMaterial.disableLighting = true;
hoverMaterial.emissiveColor = color.add(new BABYLON.Color3(0.2, 0.2, 0.2));
// Build mesh on root node
var arrow = new BABYLON.AbstractMesh("", gizmoLayer.utilityLayerScene);
var arrowMesh = BABYLON.MeshBuilder.CreateCylinder("yPosMesh", { diameterTop: 0, height: 1.5, diameterBottom: 0.75, tessellation: 96 }, gizmoLayer.utilityLayerScene);
var arrowTail = BABYLON.MeshBuilder.CreateLines("yPosMesh", { points: [new BABYLON.Vector3(0, 0, 0), new BABYLON.Vector3(0, 1.5, 0)] }, gizmoLayer.utilityLayerScene);
arrowTail.color = coloredMaterial.emissiveColor;
arrow.addChild(arrowMesh);
arrow.addChild(arrowTail);
// Position arrow pointing in its drag axis
arrowMesh.scaling.scaleInPlace(0.05);
arrowMesh.material = coloredMaterial;
arrowMesh.rotation.x = Math.PI / 2;
arrowMesh.position.z += 0.3;
arrowTail.scaling.scaleInPlace(0.2);
arrowTail.rotation.x = Math.PI / 2;
arrowTail.material = coloredMaterial;
arrow.lookAt(_this._rootMesh.position.subtract(dragAxis));
_this._rootMesh.addChild(arrow);
var currentSnapDragDistance = 0;
var tmpVector = new BABYLON.Vector3();
var tmpSnapEvent = { snapDistance: 0 };
// Add drag behavior to handle events when the gizmo is dragged
_this.dragBehavior = new BABYLON.PointerDragBehavior({ dragAxis: dragAxis });
_this.dragBehavior.moveAttached = false;
_this._rootMesh.addBehavior(_this.dragBehavior);
_this.dragBehavior.onDragObservable.add(function (event) {
if (_this.attachedMesh) {
// Snapping logic
if (_this.snapDistance == 0) {
_this.attachedMesh.position.addInPlace(event.delta);
}
else {
currentSnapDragDistance += event.dragDistance;
if (Math.abs(currentSnapDragDistance) > _this.snapDistance) {
var dragSteps = Math.floor(Math.abs(currentSnapDragDistance) / _this.snapDistance);
currentSnapDragDistance = currentSnapDragDistance % _this.snapDistance;
event.delta.normalizeToRef(tmpVector);
tmpVector.scaleInPlace(_this.snapDistance * dragSteps);
_this.attachedMesh.position.addInPlace(tmpVector);
tmpSnapEvent.snapDistance = _this.snapDistance * dragSteps;
_this.onSnapObservable.notifyObservers(tmpSnapEvent);
}
}
}
});
_this._pointerObserver = gizmoLayer.utilityLayerScene.onPointerObservable.add(function (pointerInfo, eventState) {
if (_this._customMeshSet) {
return;
}
var isHovered = pointerInfo.pickInfo && (_this._rootMesh.getChildMeshes().indexOf(pointerInfo.pickInfo.pickedMesh) != -1);
var material = isHovered ? hoverMaterial : coloredMaterial;
_this._rootMesh.getChildMeshes().forEach(function (m) {
m.material = material;
if (m.color) {
m.color = material.emissiveColor;
}
});
});
return _this;
}
AxisDragGizmo.prototype._attachedMeshChanged = function (value) {
if (this.dragBehavior) {
this.dragBehavior.enabled = value ? true : false;
}
};
/**
* Disposes of the gizmo
*/
AxisDragGizmo.prototype.dispose = function () {
this.onSnapObservable.clear();
this.gizmoLayer.utilityLayerScene.onPointerObservable.remove(this._pointerObserver);
this.dragBehavior.detach();
_super.prototype.dispose.call(this);
};
return AxisDragGizmo;
}(BABYLON.Gizmo));
BABYLON.AxisDragGizmo = AxisDragGizmo;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.axisDragGizmo.js.map
var BABYLON;
(function (BABYLON) {
/**
* Single axis scale gizmo
*/
var AxisScaleGizmo = /** @class */ (function (_super) {
__extends(AxisScaleGizmo, _super);
/**
* Creates an AxisScaleGizmo
* @param gizmoLayer The utility layer the gizmo will be added to
* @param dragAxis The axis which the gizmo will be able to scale on
* @param color The color of the gizmo
*/
function AxisScaleGizmo(dragAxis, color, gizmoLayer) {
if (color === void 0) { color = BABYLON.Color3.Gray(); }
if (gizmoLayer === void 0) { gizmoLayer = BABYLON.UtilityLayerRenderer.DefaultUtilityLayer; }
var _this = _super.call(this, gizmoLayer) || this;
_this._pointerObserver = null;
/**
* Scale distance in babylon units that the gizmo will snap to when dragged (Default: 0)
*/
_this.snapDistance = 0;
/**
* Event that fires each time the gizmo snaps to a new location.
* * snapDistance is the the change in distance
*/
_this.onSnapObservable = new BABYLON.Observable();
// Create Material
var coloredMaterial = new BABYLON.StandardMaterial("", gizmoLayer.utilityLayerScene);
coloredMaterial.disableLighting = true;
coloredMaterial.emissiveColor = color;
var hoverMaterial = new BABYLON.StandardMaterial("", gizmoLayer.utilityLayerScene);
hoverMaterial.disableLighting = true;
hoverMaterial.emissiveColor = color.add(new BABYLON.Color3(0.2, 0.2, 0.2));
// Build mesh on root node
var arrow = new BABYLON.AbstractMesh("", gizmoLayer.utilityLayerScene);
var arrowMesh = BABYLON.MeshBuilder.CreateBox("yPosMesh", { size: 0.4 }, gizmoLayer.utilityLayerScene);
var arrowTail = BABYLON.MeshBuilder.CreateLines("yPosMesh", { points: [new BABYLON.Vector3(0, 0, 0), new BABYLON.Vector3(0, 1.5, 0)] }, gizmoLayer.utilityLayerScene);
arrowTail.color = coloredMaterial.emissiveColor;
arrow.addChild(arrowMesh);
arrow.addChild(arrowTail);
// Position arrow pointing in its drag axis
arrowMesh.scaling.scaleInPlace(0.1);
arrowMesh.material = coloredMaterial;
arrowMesh.rotation.x = Math.PI / 2;
arrowMesh.position.z += 0.3;
arrowTail.scaling.scaleInPlace(0.2);
arrowTail.rotation.x = Math.PI / 2;
arrowTail.material = coloredMaterial;
arrow.lookAt(_this._rootMesh.position.subtract(dragAxis));
_this._rootMesh.addChild(arrow);
// Add drag behavior to handle events when the gizmo is dragged
_this.dragBehavior = new BABYLON.PointerDragBehavior({ dragAxis: dragAxis });
_this.dragBehavior.moveAttached = false;
_this._rootMesh.addBehavior(_this.dragBehavior);
var currentSnapDragDistance = 0;
var tmpVector = new BABYLON.Vector3();
var tmpSnapEvent = { snapDistance: 0 };
_this.dragBehavior.onDragObservable.add(function (event) {
if (_this.attachedMesh) {
// Snapping logic
var snapped = false;
var dragSteps = 0;
if (_this.snapDistance == 0) {
dragAxis.scaleToRef(event.dragDistance, tmpVector);
}
else {
currentSnapDragDistance += event.dragDistance;
if (Math.abs(currentSnapDragDistance) > _this.snapDistance) {
dragSteps = Math.floor(currentSnapDragDistance / _this.snapDistance);
currentSnapDragDistance = currentSnapDragDistance % _this.snapDistance;
dragAxis.scaleToRef(_this.snapDistance * dragSteps, tmpVector);
snapped = true;
}
else {
tmpVector.scaleInPlace(0);
}
}
_this.attachedMesh.scaling.addInPlace(tmpVector);
if (snapped) {
tmpSnapEvent.snapDistance = _this.snapDistance * dragSteps;
_this.onSnapObservable.notifyObservers(tmpSnapEvent);
}
}
});
_this._pointerObserver = gizmoLayer.utilityLayerScene.onPointerObservable.add(function (pointerInfo, eventState) {
if (_this._customMeshSet) {
return;
}
var isHovered = pointerInfo.pickInfo && (_this._rootMesh.getChildMeshes().indexOf(pointerInfo.pickInfo.pickedMesh) != -1);
var material = isHovered ? hoverMaterial : coloredMaterial;
_this._rootMesh.getChildMeshes().forEach(function (m) {
m.material = material;
if (m.color) {
m.color = material.emissiveColor;
}
});
});
return _this;
}
AxisScaleGizmo.prototype._attachedMeshChanged = function (value) {
if (this.dragBehavior) {
this.dragBehavior.enabled = value ? true : false;
}
};
/**
* Disposes of the gizmo
*/
AxisScaleGizmo.prototype.dispose = function () {
this.onSnapObservable.clear();
this.gizmoLayer.utilityLayerScene.onPointerObservable.remove(this._pointerObserver);
this.dragBehavior.detach();
_super.prototype.dispose.call(this);
};
return AxisScaleGizmo;
}(BABYLON.Gizmo));
BABYLON.AxisScaleGizmo = AxisScaleGizmo;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.axisScaleGizmo.js.map
var BABYLON;
(function (BABYLON) {
/**
* Single plane rotation gizmo
*/
var PlaneRotationGizmo = /** @class */ (function (_super) {
__extends(PlaneRotationGizmo, _super);
/**
* Creates a PlaneRotationGizmo
* @param gizmoLayer The utility layer the gizmo will be added to
* @param planeNormal The normal of the plane which the gizmo will be able to rotate on
* @param color The color of the gizmo
*/
function PlaneRotationGizmo(planeNormal, color, gizmoLayer) {
if (color === void 0) { color = BABYLON.Color3.Gray(); }
if (gizmoLayer === void 0) { gizmoLayer = BABYLON.UtilityLayerRenderer.DefaultUtilityLayer; }
var _this = _super.call(this, gizmoLayer) || this;
_this._pointerObserver = null;
/**
* Rotation distance in radians that the gizmo will snap to (Default: 0)
*/
_this.snapDistance = 0;
/**
* Event that fires each time the gizmo snaps to a new location.
* * snapDistance is the the change in distance
*/
_this.onSnapObservable = new BABYLON.Observable();
// Create Material
var coloredMaterial = new BABYLON.StandardMaterial("", gizmoLayer.utilityLayerScene);
coloredMaterial.disableLighting = true;
coloredMaterial.emissiveColor = color;
var hoverMaterial = new BABYLON.StandardMaterial("", gizmoLayer.utilityLayerScene);
hoverMaterial.disableLighting = true;
hoverMaterial.emissiveColor = color.add(new BABYLON.Color3(0.2, 0.2, 0.2));
// Build mesh on root node
var parentMesh = new BABYLON.AbstractMesh("", gizmoLayer.utilityLayerScene);
// Create circle out of lines
var tessellation = 20;
var radius = 2;
var points = new Array();
for (var i = 0; i < tessellation; i++) {
var radian = (2 * Math.PI) * (i / (tessellation - 1));
points.push(new BABYLON.Vector3(radius * Math.sin(radian), 0, radius * Math.cos(radian)));
}
var rotationMesh = BABYLON.Mesh.CreateLines("", points, gizmoLayer.utilityLayerScene);
rotationMesh.color = coloredMaterial.emissiveColor;
// Position arrow pointing in its drag axis
rotationMesh.scaling.scaleInPlace(0.1);
rotationMesh.material = coloredMaterial;
rotationMesh.rotation.x = Math.PI / 2;
parentMesh.addChild(rotationMesh);
parentMesh.lookAt(_this._rootMesh.position.subtract(planeNormal));
_this._rootMesh.addChild(parentMesh);
// Add drag behavior to handle events when the gizmo is dragged
_this.dragBehavior = new BABYLON.PointerDragBehavior({ dragPlaneNormal: planeNormal });
_this.dragBehavior.moveAttached = false;
_this.dragBehavior.maxDragAngle = Math.PI * 9 / 20;
_this.dragBehavior._useAlternatePickedPointAboveMaxDragAngle = true;
_this._rootMesh.addBehavior(_this.dragBehavior);
var lastDragPosition = new BABYLON.Vector3();
_this.dragBehavior.onDragStartObservable.add(function (e) {
if (_this.attachedMesh) {
lastDragPosition.copyFrom(e.dragPlanePoint);
}
});
var rotationMatrix = new BABYLON.Matrix();
var planeNormalTowardsCamera = new BABYLON.Vector3();
var localPlaneNormalTowardsCamera = new BABYLON.Vector3();
var tmpSnapEvent = { snapDistance: 0 };
var currentSnapDragDistance = 0;
_this.dragBehavior.onDragObservable.add(function (event) {
if (_this.attachedMesh) {
if (!_this.attachedMesh.rotationQuaternion) {
_this.attachedMesh.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(_this.attachedMesh.rotation.y, _this.attachedMesh.rotation.x, _this.attachedMesh.rotation.z);
}
// Calc angle over full 360 degree (https://stackoverflow.com/questions/43493711/the-angle-between-two-3d-vectors-with-a-result-range-0-360)
var newVector = event.dragPlanePoint.subtract(_this.attachedMesh.position).normalize();
var originalVector = lastDragPosition.subtract(_this.attachedMesh.position).normalize();
var cross = BABYLON.Vector3.Cross(newVector, originalVector);
var dot = BABYLON.Vector3.Dot(newVector, originalVector);
var angle = Math.atan2(cross.length(), dot);
planeNormalTowardsCamera.copyFrom(planeNormal);
localPlaneNormalTowardsCamera.copyFrom(planeNormal);
if (_this.updateGizmoRotationToMatchAttachedMesh) {
_this.attachedMesh.rotationQuaternion.toRotationMatrix(rotationMatrix);
localPlaneNormalTowardsCamera = BABYLON.Vector3.TransformCoordinates(planeNormalTowardsCamera, rotationMatrix);
}
// Flip up vector depending on which side the camera is on
if (gizmoLayer.utilityLayerScene.activeCamera) {
var camVec = gizmoLayer.utilityLayerScene.activeCamera.position.subtract(_this.attachedMesh.position);
if (BABYLON.Vector3.Dot(camVec, localPlaneNormalTowardsCamera) > 0) {
planeNormalTowardsCamera.scaleInPlace(-1);
localPlaneNormalTowardsCamera.scaleInPlace(-1);
}
}
var halfCircleSide = BABYLON.Vector3.Dot(localPlaneNormalTowardsCamera, cross) > 0.0;
if (halfCircleSide)
angle = -angle;
// Snapping logic
var snapped = false;
if (_this.snapDistance != 0) {
currentSnapDragDistance += angle;
if (Math.abs(currentSnapDragDistance) > _this.snapDistance) {
var dragSteps = Math.floor(currentSnapDragDistance / _this.snapDistance);
currentSnapDragDistance = currentSnapDragDistance % _this.snapDistance;
angle = _this.snapDistance * dragSteps;
snapped = true;
}
else {
angle = 0;
}
}
// Convert angle and axis to quaternion (http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm)
var quaternionCoefficient = Math.sin(angle / 2);
var amountToRotate = new BABYLON.Quaternion(planeNormalTowardsCamera.x * quaternionCoefficient, planeNormalTowardsCamera.y * quaternionCoefficient, planeNormalTowardsCamera.z * quaternionCoefficient, Math.cos(angle / 2));
if (_this.updateGizmoRotationToMatchAttachedMesh) {
// Rotate selected mesh quaternion over fixed axis
_this.attachedMesh.rotationQuaternion.multiplyToRef(amountToRotate, _this.attachedMesh.rotationQuaternion);
}
else {
// Rotate selected mesh quaternion over rotated axis
amountToRotate.multiplyToRef(_this.attachedMesh.rotationQuaternion, _this.attachedMesh.rotationQuaternion);
}
lastDragPosition.copyFrom(event.dragPlanePoint);
if (snapped) {
tmpSnapEvent.snapDistance = angle;
_this.onSnapObservable.notifyObservers(tmpSnapEvent);
}
}
});
_this._pointerObserver = gizmoLayer.utilityLayerScene.onPointerObservable.add(function (pointerInfo, eventState) {
if (_this._customMeshSet) {
return;
}
var isHovered = pointerInfo.pickInfo && (_this._rootMesh.getChildMeshes().indexOf(pointerInfo.pickInfo.pickedMesh) != -1);
var material = isHovered ? hoverMaterial : coloredMaterial;
_this._rootMesh.getChildMeshes().forEach(function (m) {
m.material = material;
if (m.color) {
m.color = material.emissiveColor;
}
});
});
return _this;
}
PlaneRotationGizmo.prototype._attachedMeshChanged = function (value) {
if (this.dragBehavior) {
this.dragBehavior.enabled = value ? true : false;
}
};
/**
* Disposes of the gizmo
*/
PlaneRotationGizmo.prototype.dispose = function () {
this.onSnapObservable.clear();
this.gizmoLayer.utilityLayerScene.onPointerObservable.remove(this._pointerObserver);
this.dragBehavior.detach();
_super.prototype.dispose.call(this);
};
return PlaneRotationGizmo;
}(BABYLON.Gizmo));
BABYLON.PlaneRotationGizmo = PlaneRotationGizmo;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.planeRotationGizmo.js.map
var BABYLON;
(function (BABYLON) {
/**
* Gizmo that enables dragging a mesh along 3 axis
*/
var PositionGizmo = /** @class */ (function (_super) {
__extends(PositionGizmo, _super);
/**
* Creates a PositionGizmo
* @param gizmoLayer The utility layer the gizmo will be added to
*/
function PositionGizmo(gizmoLayer) {
if (gizmoLayer === void 0) { gizmoLayer = BABYLON.UtilityLayerRenderer.DefaultUtilityLayer; }
var _this = _super.call(this, gizmoLayer) || this;
_this.xGizmo = new BABYLON.AxisDragGizmo(new BABYLON.Vector3(1, 0, 0), BABYLON.Color3.Green().scale(0.5), gizmoLayer);
_this.yGizmo = new BABYLON.AxisDragGizmo(new BABYLON.Vector3(0, 1, 0), BABYLON.Color3.Red().scale(0.5), gizmoLayer);
_this.zGizmo = new BABYLON.AxisDragGizmo(new BABYLON.Vector3(0, 0, 1), BABYLON.Color3.Blue().scale(0.5), gizmoLayer);
_this.attachedMesh = null;
return _this;
}
Object.defineProperty(PositionGizmo.prototype, "attachedMesh", {
set: function (mesh) {
if (this.xGizmo) {
this.xGizmo.attachedMesh = mesh;
this.yGizmo.attachedMesh = mesh;
this.zGizmo.attachedMesh = mesh;
}
},
enumerable: true,
configurable: true
});
Object.defineProperty(PositionGizmo.prototype, "updateGizmoRotationToMatchAttachedMesh", {
get: function () {
return this.xGizmo.updateGizmoRotationToMatchAttachedMesh;
},
set: function (value) {
if (this.xGizmo) {
this.xGizmo.updateGizmoRotationToMatchAttachedMesh = value;
this.yGizmo.updateGizmoRotationToMatchAttachedMesh = value;
this.zGizmo.updateGizmoRotationToMatchAttachedMesh = value;
}
},
enumerable: true,
configurable: true
});
/**
* Disposes of the gizmo
*/
PositionGizmo.prototype.dispose = function () {
this.xGizmo.dispose();
this.yGizmo.dispose();
this.zGizmo.dispose();
};
/**
* CustomMeshes are not supported by this gizmo
* @param mesh The mesh to replace the default mesh of the gizmo
*/
PositionGizmo.prototype.setCustomMesh = function (mesh) {
BABYLON.Tools.Error("Custom meshes are not supported on this gizmo, please set the custom meshes on the gizmos contained within this one (gizmo.xGizmo, gizmo.yGizmo, gizmo.zGizmo)");
};
return PositionGizmo;
}(BABYLON.Gizmo));
BABYLON.PositionGizmo = PositionGizmo;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.positionGizmo.js.map
var BABYLON;
(function (BABYLON) {
/**
* Gizmo that enables rotating a mesh along 3 axis
*/
var RotationGizmo = /** @class */ (function (_super) {
__extends(RotationGizmo, _super);
/**
* Creates a RotationGizmo
* @param gizmoLayer The utility layer the gizmo will be added to
*/
function RotationGizmo(gizmoLayer) {
if (gizmoLayer === void 0) { gizmoLayer = BABYLON.UtilityLayerRenderer.DefaultUtilityLayer; }
var _this = _super.call(this, gizmoLayer) || this;
_this.xGizmo = new BABYLON.PlaneRotationGizmo(new BABYLON.Vector3(1, 0, 0), BABYLON.Color3.Green().scale(0.5), gizmoLayer);
_this.yGizmo = new BABYLON.PlaneRotationGizmo(new BABYLON.Vector3(0, 1, 0), BABYLON.Color3.Red().scale(0.5), gizmoLayer);
_this.zGizmo = new BABYLON.PlaneRotationGizmo(new BABYLON.Vector3(0, 0, 1), BABYLON.Color3.Blue().scale(0.5), gizmoLayer);
_this.attachedMesh = null;
return _this;
}
Object.defineProperty(RotationGizmo.prototype, "attachedMesh", {
set: function (mesh) {
if (this.xGizmo) {
this.xGizmo.attachedMesh = mesh;
this.yGizmo.attachedMesh = mesh;
this.zGizmo.attachedMesh = mesh;
}
},
enumerable: true,
configurable: true
});
Object.defineProperty(RotationGizmo.prototype, "updateGizmoRotationToMatchAttachedMesh", {
get: function () {
return this.xGizmo.updateGizmoRotationToMatchAttachedMesh;
},
set: function (value) {
if (this.xGizmo) {
this.xGizmo.updateGizmoRotationToMatchAttachedMesh = value;
this.yGizmo.updateGizmoRotationToMatchAttachedMesh = value;
this.zGizmo.updateGizmoRotationToMatchAttachedMesh = value;
}
},
enumerable: true,
configurable: true
});
/**
* Disposes of the gizmo
*/
RotationGizmo.prototype.dispose = function () {
this.xGizmo.dispose();
this.yGizmo.dispose();
this.zGizmo.dispose();
};
/**
* CustomMeshes are not supported by this gizmo
* @param mesh The mesh to replace the default mesh of the gizmo
*/
RotationGizmo.prototype.setCustomMesh = function (mesh) {
BABYLON.Tools.Error("Custom meshes are not supported on this gizmo, please set the custom meshes on the gizmos contained within this one (gizmo.xGizmo, gizmo.yGizmo, gizmo.zGizmo)");
};
return RotationGizmo;
}(BABYLON.Gizmo));
BABYLON.RotationGizmo = RotationGizmo;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.rotationGizmo.js.map
var BABYLON;
(function (BABYLON) {
/**
* Gizmo that enables scaling a mesh along 3 axis
*/
var ScaleGizmo = /** @class */ (function (_super) {
__extends(ScaleGizmo, _super);
/**
* Creates a ScaleGizmo
* @param gizmoLayer The utility layer the gizmo will be added to
*/
function ScaleGizmo(gizmoLayer) {
if (gizmoLayer === void 0) { gizmoLayer = BABYLON.UtilityLayerRenderer.DefaultUtilityLayer; }
var _this = _super.call(this, gizmoLayer) || this;
_this.xGizmo = new BABYLON.AxisScaleGizmo(new BABYLON.Vector3(1, 0, 0), BABYLON.Color3.Green().scale(0.5), gizmoLayer);
_this.yGizmo = new BABYLON.AxisScaleGizmo(new BABYLON.Vector3(0, 1, 0), BABYLON.Color3.Red().scale(0.5), gizmoLayer);
_this.zGizmo = new BABYLON.AxisScaleGizmo(new BABYLON.Vector3(0, 0, 1), BABYLON.Color3.Blue().scale(0.5), gizmoLayer);
_this.attachedMesh = null;
return _this;
}
Object.defineProperty(ScaleGizmo.prototype, "attachedMesh", {
set: function (mesh) {
if (this.xGizmo) {
this.xGizmo.attachedMesh = mesh;
this.yGizmo.attachedMesh = mesh;
this.zGizmo.attachedMesh = mesh;
}
},
enumerable: true,
configurable: true
});
Object.defineProperty(ScaleGizmo.prototype, "updateGizmoRotationToMatchAttachedMesh", {
get: function () {
return this.xGizmo.updateGizmoRotationToMatchAttachedMesh;
},
set: function (value) {
if (this.xGizmo) {
this.xGizmo.updateGizmoRotationToMatchAttachedMesh = value;
this.yGizmo.updateGizmoRotationToMatchAttachedMesh = value;
this.zGizmo.updateGizmoRotationToMatchAttachedMesh = value;
}
},
enumerable: true,
configurable: true
});
/**
* Disposes of the gizmo
*/
ScaleGizmo.prototype.dispose = function () {
this.xGizmo.dispose();
this.yGizmo.dispose();
this.zGizmo.dispose();
};
return ScaleGizmo;
}(BABYLON.Gizmo));
BABYLON.ScaleGizmo = ScaleGizmo;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.scaleGizmo.js.map
var BABYLON;
(function (BABYLON) {
/**
* Bounding box gizmo
*/
var BoundingBoxGizmo = /** @class */ (function (_super) {
__extends(BoundingBoxGizmo, _super);
/**
* Creates an BoundingBoxGizmo
* @param gizmoLayer The utility layer the gizmo will be added to
* @param color The color of the gizmo
*/
function BoundingBoxGizmo(color, gizmoLayer) {
if (color === void 0) { color = BABYLON.Color3.Gray(); }
if (gizmoLayer === void 0) { gizmoLayer = BABYLON.UtilityLayerRenderer.DefaultKeepDepthUtilityLayer; }
var _this = _super.call(this, gizmoLayer) || this;
_this._boundingDimensions = new BABYLON.Vector3(1, 1, 1);
_this._renderObserver = null;
_this._pointerObserver = null;
_this._scaleDragSpeed = 0.2;
_this._tmpQuaternion = new BABYLON.Quaternion();
_this._tmpVector = new BABYLON.Vector3(0, 0, 0);
/**
* The size of the rotation spheres attached to the bounding box (Default: 0.1)
*/
_this.rotationSphereSize = 0.1;
/**
* The size of the scale boxes attached to the bounding box (Default: 0.1)
*/
_this.scaleBoxSize = 0.1;
/**
* If set, the rotation spheres and scale boxes will increase in size based on the distance away from the camera to have a consistent screen size (Default: false)
*/
_this.fixedDragMeshScreenSize = false;
/**
* The distance away from the object which the draggable meshes should appear world sized when fixedDragMeshScreenSize is set to true (default: 10)
*/
_this.fixedDragMeshScreenSizeDistanceFactor = 10;
/**
* Fired when a rotation sphere or scale box is dragged
*/
_this.onDragStartObservable = new BABYLON.Observable();
/**
* Fired when a rotation sphere or scale box drag is started
*/
_this.onDragObservable = new BABYLON.Observable();
/**
* Fired when a rotation sphere or scale box drag is needed
*/
_this.onDragEndObservable = new BABYLON.Observable();
_this._existingMeshScale = new BABYLON.Vector3();
// Do not update the gizmo's scale so it has a fixed size to the object its attached to
_this._updateScale = false;
_this._anchorMesh = new BABYLON.AbstractMesh("anchor", gizmoLayer.utilityLayerScene);
// Create Materials
var coloredMaterial = new BABYLON.StandardMaterial("", gizmoLayer.utilityLayerScene);
coloredMaterial.disableLighting = true;
coloredMaterial.emissiveColor = color;
var hoverColoredMaterial = new BABYLON.StandardMaterial("", gizmoLayer.utilityLayerScene);
hoverColoredMaterial.disableLighting = true;
hoverColoredMaterial.emissiveColor = color.clone().add(new BABYLON.Color3(0.2, 0.2, 0.2));
// Build bounding box out of lines
_this._lineBoundingBox = new BABYLON.AbstractMesh("", gizmoLayer.utilityLayerScene);
_this._lineBoundingBox.rotationQuaternion = new BABYLON.Quaternion();
var lines = [];
lines.push(BABYLON.MeshBuilder.CreateLines("lines", { points: [new BABYLON.Vector3(0, 0, 0), new BABYLON.Vector3(_this._boundingDimensions.x, 0, 0)] }, gizmoLayer.utilityLayerScene));
lines.push(BABYLON.MeshBuilder.CreateLines("lines", { points: [new BABYLON.Vector3(0, 0, 0), new BABYLON.Vector3(0, _this._boundingDimensions.y, 0)] }, gizmoLayer.utilityLayerScene));
lines.push(BABYLON.MeshBuilder.CreateLines("lines", { points: [new BABYLON.Vector3(0, 0, 0), new BABYLON.Vector3(0, 0, _this._boundingDimensions.z)] }, gizmoLayer.utilityLayerScene));
lines.push(BABYLON.MeshBuilder.CreateLines("lines", { points: [new BABYLON.Vector3(_this._boundingDimensions.x, 0, 0), new BABYLON.Vector3(_this._boundingDimensions.x, _this._boundingDimensions.y, 0)] }, gizmoLayer.utilityLayerScene));
lines.push(BABYLON.MeshBuilder.CreateLines("lines", { points: [new BABYLON.Vector3(_this._boundingDimensions.x, 0, 0), new BABYLON.Vector3(_this._boundingDimensions.x, 0, _this._boundingDimensions.z)] }, gizmoLayer.utilityLayerScene));
lines.push(BABYLON.MeshBuilder.CreateLines("lines", { points: [new BABYLON.Vector3(0, _this._boundingDimensions.y, 0), new BABYLON.Vector3(_this._boundingDimensions.x, _this._boundingDimensions.y, 0)] }, gizmoLayer.utilityLayerScene));
lines.push(BABYLON.MeshBuilder.CreateLines("lines", { points: [new BABYLON.Vector3(0, _this._boundingDimensions.y, 0), new BABYLON.Vector3(0, _this._boundingDimensions.y, _this._boundingDimensions.z)] }, gizmoLayer.utilityLayerScene));
lines.push(BABYLON.MeshBuilder.CreateLines("lines", { points: [new BABYLON.Vector3(0, 0, _this._boundingDimensions.z), new BABYLON.Vector3(_this._boundingDimensions.x, 0, _this._boundingDimensions.z)] }, gizmoLayer.utilityLayerScene));
lines.push(BABYLON.MeshBuilder.CreateLines("lines", { points: [new BABYLON.Vector3(0, 0, _this._boundingDimensions.z), new BABYLON.Vector3(0, _this._boundingDimensions.y, _this._boundingDimensions.z)] }, gizmoLayer.utilityLayerScene));
lines.push(BABYLON.MeshBuilder.CreateLines("lines", { points: [new BABYLON.Vector3(_this._boundingDimensions.x, _this._boundingDimensions.y, _this._boundingDimensions.z), new BABYLON.Vector3(0, _this._boundingDimensions.y, _this._boundingDimensions.z)] }, gizmoLayer.utilityLayerScene));
lines.push(BABYLON.MeshBuilder.CreateLines("lines", { points: [new BABYLON.Vector3(_this._boundingDimensions.x, _this._boundingDimensions.y, _this._boundingDimensions.z), new BABYLON.Vector3(_this._boundingDimensions.x, 0, _this._boundingDimensions.z)] }, gizmoLayer.utilityLayerScene));
lines.push(BABYLON.MeshBuilder.CreateLines("lines", { points: [new BABYLON.Vector3(_this._boundingDimensions.x, _this._boundingDimensions.y, _this._boundingDimensions.z), new BABYLON.Vector3(_this._boundingDimensions.x, _this._boundingDimensions.y, 0)] }, gizmoLayer.utilityLayerScene));
lines.forEach(function (l) {
l.color = color;
l.position.addInPlace(new BABYLON.Vector3(-_this._boundingDimensions.x / 2, -_this._boundingDimensions.y / 2, -_this._boundingDimensions.z / 2));
l.isPickable = false;
_this._lineBoundingBox.addChild(l);
});
_this._rootMesh.addChild(_this._lineBoundingBox);
// Create rotation spheres
_this._rotateSpheresParent = new BABYLON.AbstractMesh("", gizmoLayer.utilityLayerScene);
_this._rotateSpheresParent.rotationQuaternion = new BABYLON.Quaternion();
var _loop_1 = function (i_1) {
var sphere = BABYLON.MeshBuilder.CreateSphere("", { diameter: 1 }, gizmoLayer.utilityLayerScene);
sphere.rotationQuaternion = new BABYLON.Quaternion();
sphere.material = coloredMaterial;
// Drag behavior
_dragBehavior = new BABYLON.PointerDragBehavior({});
_dragBehavior.moveAttached = false;
_dragBehavior.updateDragPlane = false;
sphere.addBehavior(_dragBehavior);
var startingTurnDirection = new BABYLON.Vector3(1, 0, 0);
var totalTurnAmountOfDrag = 0;
_dragBehavior.onDragStartObservable.add(function (event) {
startingTurnDirection.copyFrom(sphere.forward);
totalTurnAmountOfDrag = 0;
});
_dragBehavior.onDragObservable.add(function (event) {
_this.onDragObservable.notifyObservers({});
if (_this.attachedMesh) {
var worldDragDirection = startingTurnDirection;
// Project the world right on to the drag plane
var toSub = event.dragPlaneNormal.scale(BABYLON.Vector3.Dot(event.dragPlaneNormal, worldDragDirection));
var dragAxis = worldDragDirection.subtract(toSub).normalizeToNew();
// project drag delta on to the resulting drag axis and rotate based on that
var projectDist = -BABYLON.Vector3.Dot(dragAxis, event.delta);
// Make rotation relative to size of mesh.
projectDist = (projectDist / _this._boundingDimensions.length()) * _this._anchorMesh.scaling.length();
// Rotate based on axis
if (!_this.attachedMesh.rotationQuaternion) {
_this.attachedMesh.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(_this.attachedMesh.rotation.y, _this.attachedMesh.rotation.x, _this.attachedMesh.rotation.z);
}
if (!_this._anchorMesh.rotationQuaternion) {
_this._anchorMesh.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(_this._anchorMesh.rotation.y, _this._anchorMesh.rotation.x, _this._anchorMesh.rotation.z);
}
// Do not allow the object to turn more than a full circle
totalTurnAmountOfDrag += projectDist;
if (Math.abs(totalTurnAmountOfDrag) <= 2 * Math.PI) {
if (i_1 >= 8) {
BABYLON.Quaternion.RotationYawPitchRollToRef(0, 0, projectDist, _this._tmpQuaternion);
}
else if (i_1 >= 4) {
BABYLON.Quaternion.RotationYawPitchRollToRef(projectDist, 0, 0, _this._tmpQuaternion);
}
else {
BABYLON.Quaternion.RotationYawPitchRollToRef(0, projectDist, 0, _this._tmpQuaternion);
}
// Rotate around center of bounding box
_this._anchorMesh.addChild(_this.attachedMesh);
_this._anchorMesh.rotationQuaternion.multiplyToRef(_this._tmpQuaternion, _this._anchorMesh.rotationQuaternion);
_this._anchorMesh.removeChild(_this.attachedMesh);
}
_this.updateBoundingBox();
}
});
// Selection/deselection
_dragBehavior.onDragStartObservable.add(function () {
_this.onDragStartObservable.notifyObservers({});
_this._selectNode(sphere);
});
_dragBehavior.onDragEndObservable.add(function () {
_this.onDragEndObservable.notifyObservers({});
_this._selectNode(null);
});
this_1._rotateSpheresParent.addChild(sphere);
};
var this_1 = this, _dragBehavior;
for (var i_1 = 0; i_1 < 12; i_1++) {
_loop_1(i_1);
}
_this._rootMesh.addChild(_this._rotateSpheresParent);
// Create scale cubes
_this._scaleBoxesParent = new BABYLON.AbstractMesh("", gizmoLayer.utilityLayerScene);
_this._scaleBoxesParent.rotationQuaternion = new BABYLON.Quaternion();
for (var i = 0; i < 2; i++) {
for (var j = 0; j < 2; j++) {
var _loop_2 = function () {
var box = BABYLON.MeshBuilder.CreateBox("", { size: 1 }, gizmoLayer.utilityLayerScene);
box.material = coloredMaterial;
// Dragging logic
var dragAxis = new BABYLON.Vector3(i == 0 ? -1 : 1, j == 0 ? -1 : 1, k == 0 ? -1 : 1);
_dragBehavior = new BABYLON.PointerDragBehavior({ dragAxis: dragAxis });
_dragBehavior.moveAttached = false;
box.addBehavior(_dragBehavior);
_dragBehavior.onDragObservable.add(function (event) {
_this.onDragObservable.notifyObservers({});
if (_this.attachedMesh) {
var relativeDragDistance = (event.dragDistance / _this._boundingDimensions.length()) * _this._anchorMesh.scaling.length();
var deltaScale = new BABYLON.Vector3(relativeDragDistance, relativeDragDistance, relativeDragDistance);
deltaScale.scaleInPlace(_this._scaleDragSpeed);
_this.updateBoundingBox();
// Scale from the position of the opposite corner
box.absolutePosition.subtractToRef(_this._anchorMesh.position, _this._tmpVector);
_this._anchorMesh.position.subtractInPlace(_this._tmpVector);
_this._anchorMesh.addChild(_this.attachedMesh);
_this._anchorMesh.scaling.addInPlace(deltaScale);
if (_this._anchorMesh.scaling.x < 0 || _this._anchorMesh.scaling.y < 0 || _this._anchorMesh.scaling.z < 0) {
_this._anchorMesh.scaling.subtractInPlace(deltaScale);
}
_this._anchorMesh.removeChild(_this.attachedMesh);
}
});
// Selection/deselection
_dragBehavior.onDragStartObservable.add(function () {
_this.onDragStartObservable.notifyObservers({});
_this._selectNode(box);
});
_dragBehavior.onDragEndObservable.add(function () {
_this.onDragEndObservable.notifyObservers({});
_this._selectNode(null);
});
this_2._scaleBoxesParent.addChild(box);
};
var this_2 = this, _dragBehavior;
for (var k = 0; k < 2; k++) {
_loop_2();
}
}
}
_this._rootMesh.addChild(_this._scaleBoxesParent);
// Hover color change
var pointerIds = new Array();
_this._pointerObserver = gizmoLayer.utilityLayerScene.onPointerObservable.add(function (pointerInfo, eventState) {
if (!pointerIds[pointerInfo.event.pointerId]) {
_this._rotateSpheresParent.getChildMeshes().concat(_this._scaleBoxesParent.getChildMeshes()).forEach(function (mesh) {
if (pointerInfo.pickInfo && pointerInfo.pickInfo.pickedMesh == mesh) {
pointerIds[pointerInfo.event.pointerId] = mesh;
mesh.material = hoverColoredMaterial;
}
});
}
else {
if (pointerInfo.pickInfo && pointerInfo.pickInfo.pickedMesh != pointerIds[pointerInfo.event.pointerId]) {
pointerIds[pointerInfo.event.pointerId].material = coloredMaterial;
delete pointerIds[pointerInfo.event.pointerId];
}
}
});
// Update bounding box positions
_this._renderObserver = _this.gizmoLayer.originalScene.onBeforeRenderObservable.add(function () {
// Only update the bouding box if scaling has changed
if (_this.attachedMesh && !_this._existingMeshScale.equals(_this.attachedMesh.scaling)) {
_this.updateBoundingBox();
}
});
_this.updateBoundingBox();
return _this;
}
BoundingBoxGizmo.prototype._attachedMeshChanged = function (value) {
if (value) {
// Reset anchor mesh to match attached mesh's scale
// This is needed to avoid invalid box/sphere position on first drag
this._anchorMesh.addChild(value);
this._anchorMesh.removeChild(value);
this.updateBoundingBox();
}
};
BoundingBoxGizmo.prototype._selectNode = function (selectedMesh) {
this._rotateSpheresParent.getChildMeshes()
.concat(this._scaleBoxesParent.getChildMeshes()).forEach(function (m, i) {
m.isVisible = (!selectedMesh || m == selectedMesh);
});
};
BoundingBoxGizmo.prototype._recurseComputeWorld = function (mesh) {
var _this = this;
mesh.computeWorldMatrix(true);
mesh.getChildMeshes().forEach(function (m) {
_this._recurseComputeWorld(m);
});
};
/**
* Updates the bounding box information for the Gizmo
*/
BoundingBoxGizmo.prototype.updateBoundingBox = function () {
this._update();
if (this.attachedMesh) {
// Rotate based on axis
if (!this.attachedMesh.rotationQuaternion) {
this.attachedMesh.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(this.attachedMesh.rotation.y, this.attachedMesh.rotation.x, this.attachedMesh.rotation.z);
}
if (!this._anchorMesh.rotationQuaternion) {
this._anchorMesh.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(this._anchorMesh.rotation.y, this._anchorMesh.rotation.x, this._anchorMesh.rotation.z);
}
this._anchorMesh.rotationQuaternion.copyFrom(this.attachedMesh.rotationQuaternion);
// Store original position and reset mesh to origin before computing the bounding box
this._tmpQuaternion.copyFrom(this.attachedMesh.rotationQuaternion);
this._tmpVector.copyFrom(this.attachedMesh.position);
this.attachedMesh.rotationQuaternion.set(0, 0, 0, 1);
this.attachedMesh.position.set(0, 0, 0);
// Update bounding dimensions/positions
var boundingMinMax = this.attachedMesh.getHierarchyBoundingVectors();
boundingMinMax.max.subtractToRef(boundingMinMax.min, this._boundingDimensions);
// Update gizmo to match bounding box scaling and rotation
this._lineBoundingBox.scaling.copyFrom(this._boundingDimensions);
this._lineBoundingBox.position.set((boundingMinMax.max.x + boundingMinMax.min.x) / 2, (boundingMinMax.max.y + boundingMinMax.min.y) / 2, (boundingMinMax.max.z + boundingMinMax.min.z) / 2);
this._rotateSpheresParent.position.copyFrom(this._lineBoundingBox.position);
this._scaleBoxesParent.position.copyFrom(this._lineBoundingBox.position);
this._lineBoundingBox.computeWorldMatrix();
this._anchorMesh.position.copyFrom(this._lineBoundingBox.absolutePosition);
// restore position/rotation values
this.attachedMesh.rotationQuaternion.copyFrom(this._tmpQuaternion);
this.attachedMesh.position.copyFrom(this._tmpVector);
this._recurseComputeWorld(this.attachedMesh);
}
// Update rotation sphere locations
var rotateSpheres = this._rotateSpheresParent.getChildMeshes();
for (var i = 0; i < 3; i++) {
for (var j = 0; j < 2; j++) {
for (var k = 0; k < 2; k++) {
var index = ((i * 4) + (j * 2)) + k;
if (i == 0) {
rotateSpheres[index].position.set(this._boundingDimensions.x / 2, this._boundingDimensions.y * j, this._boundingDimensions.z * k);
rotateSpheres[index].position.addInPlace(new BABYLON.Vector3(-this._boundingDimensions.x / 2, -this._boundingDimensions.y / 2, -this._boundingDimensions.z / 2));
rotateSpheres[index].lookAt(BABYLON.Vector3.Cross(BABYLON.Vector3.Right(), rotateSpheres[index].position.normalizeToNew()).normalizeToNew().add(rotateSpheres[index].position));
}
if (i == 1) {
rotateSpheres[index].position.set(this._boundingDimensions.x * j, this._boundingDimensions.y / 2, this._boundingDimensions.z * k);
rotateSpheres[index].position.addInPlace(new BABYLON.Vector3(-this._boundingDimensions.x / 2, -this._boundingDimensions.y / 2, -this._boundingDimensions.z / 2));
rotateSpheres[index].lookAt(BABYLON.Vector3.Cross(BABYLON.Vector3.Up(), rotateSpheres[index].position.normalizeToNew()).normalizeToNew().add(rotateSpheres[index].position));
}
if (i == 2) {
rotateSpheres[index].position.set(this._boundingDimensions.x * j, this._boundingDimensions.y * k, this._boundingDimensions.z / 2);
rotateSpheres[index].position.addInPlace(new BABYLON.Vector3(-this._boundingDimensions.x / 2, -this._boundingDimensions.y / 2, -this._boundingDimensions.z / 2));
rotateSpheres[index].lookAt(BABYLON.Vector3.Cross(BABYLON.Vector3.Forward(), rotateSpheres[index].position.normalizeToNew()).normalizeToNew().add(rotateSpheres[index].position));
}
if (this.fixedDragMeshScreenSize) {
this._rootMesh.computeWorldMatrix();
this._rotateSpheresParent.computeWorldMatrix();
rotateSpheres[index].computeWorldMatrix();
rotateSpheres[index].absolutePosition.subtractToRef(this.gizmoLayer.utilityLayerScene.activeCamera.position, this._tmpVector);
var distanceFromCamera = this.rotationSphereSize * this._tmpVector.length() / this.fixedDragMeshScreenSizeDistanceFactor;
rotateSpheres[index].scaling.set(distanceFromCamera, distanceFromCamera, distanceFromCamera);
}
else {
rotateSpheres[index].scaling.set(this.rotationSphereSize, this.rotationSphereSize, this.rotationSphereSize);
}
}
}
}
// Update scale box locations
var scaleBoxes = this._scaleBoxesParent.getChildMeshes();
for (var i = 0; i < 2; i++) {
for (var j = 0; j < 2; j++) {
for (var k = 0; k < 2; k++) {
var index = ((i * 4) + (j * 2)) + k;
if (scaleBoxes[index]) {
scaleBoxes[index].position.set(this._boundingDimensions.x * i, this._boundingDimensions.y * j, this._boundingDimensions.z * k);
scaleBoxes[index].position.addInPlace(new BABYLON.Vector3(-this._boundingDimensions.x / 2, -this._boundingDimensions.y / 2, -this._boundingDimensions.z / 2));
if (this.fixedDragMeshScreenSize) {
this._rootMesh.computeWorldMatrix();
this._scaleBoxesParent.computeWorldMatrix();
scaleBoxes[index].computeWorldMatrix();
scaleBoxes[index].absolutePosition.subtractToRef(this.gizmoLayer.utilityLayerScene.activeCamera.position, this._tmpVector);
var distanceFromCamera = this.scaleBoxSize * this._tmpVector.length() / this.fixedDragMeshScreenSizeDistanceFactor;
scaleBoxes[index].scaling.set(distanceFromCamera, distanceFromCamera, distanceFromCamera);
}
else {
scaleBoxes[index].scaling.set(this.scaleBoxSize, this.scaleBoxSize, this.scaleBoxSize);
}
}
}
}
}
if (this.attachedMesh) {
this._existingMeshScale.copyFrom(this.attachedMesh.scaling);
}
};
/**
* Enables rotation on the specified axis and disables rotation on the others
* @param axis The list of axis that should be enabled (eg. "xy" or "xyz")
*/
BoundingBoxGizmo.prototype.setEnabledRotationAxis = function (axis) {
this._rotateSpheresParent.getChildMeshes().forEach(function (m, i) {
if (i < 4) {
m.setEnabled(axis.indexOf("x") != -1);
}
else if (i < 8) {
m.setEnabled(axis.indexOf("y") != -1);
}
else {
m.setEnabled(axis.indexOf("z") != -1);
}
});
};
/**
* Disposes of the gizmo
*/
BoundingBoxGizmo.prototype.dispose = function () {
this.gizmoLayer.utilityLayerScene.onPointerObservable.remove(this._pointerObserver);
this.gizmoLayer.originalScene.onBeforeRenderObservable.remove(this._renderObserver);
this._lineBoundingBox.dispose();
this._rotateSpheresParent.dispose();
this._scaleBoxesParent.dispose();
_super.prototype.dispose.call(this);
};
/**
* Makes a mesh not pickable and wraps the mesh inside of a bounding box mesh that is pickable. (This is useful to avoid picking within complex geometry)
* @param mesh the mesh to wrap in the bounding box mesh and make not pickable
* @returns the bounding box mesh with the passed in mesh as a child
*/
BoundingBoxGizmo.MakeNotPickableAndWrapInBoundingBox = function (mesh) {
var makeNotPickable = function (root) {
root.isPickable = false;
root.getChildMeshes().forEach(function (c) {
makeNotPickable(c);
});
};
makeNotPickable(mesh);
// Reset position to get boudning box from origin with no rotation
if (!mesh.rotationQuaternion) {
mesh.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(mesh.rotation.y, mesh.rotation.x, mesh.rotation.z);
}
var oldPos = mesh.position.clone();
var oldRot = mesh.rotationQuaternion.clone();
mesh.rotationQuaternion.set(0, 0, 0, 1);
mesh.position.set(0, 0, 0);
// Update bounding dimensions/positions
var box = BABYLON.MeshBuilder.CreateBox("box", { size: 1 }, mesh.getScene());
var boundingMinMax = mesh.getHierarchyBoundingVectors();
boundingMinMax.max.subtractToRef(boundingMinMax.min, box.scaling);
box.position.set((boundingMinMax.max.x + boundingMinMax.min.x) / 2, (boundingMinMax.max.y + boundingMinMax.min.y) / 2, (boundingMinMax.max.z + boundingMinMax.min.z) / 2);
// Restore original positions
mesh.addChild(box);
mesh.rotationQuaternion.copyFrom(oldRot);
mesh.position.copyFrom(oldPos);
// Reverse parenting
mesh.removeChild(box);
box.addChild(mesh);
box.visibility = 0;
return box;
};
/**
* CustomMeshes are not supported by this gizmo
* @param mesh The mesh to replace the default mesh of the gizmo
*/
BoundingBoxGizmo.prototype.setCustomMesh = function (mesh) {
BABYLON.Tools.Error("Custom meshes are not supported on this gizmo");
};
return BoundingBoxGizmo;
}(BABYLON.Gizmo));
BABYLON.BoundingBoxGizmo = BoundingBoxGizmo;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.boundingBoxGizmo.js.map
var BABYLON;
(function (BABYLON) {
/**
* Helps setup gizmo's in the scene to rotate/scale/position meshes
*/
var GizmoManager = /** @class */ (function () {
/**
* Instatiates a gizmo manager
* @param scene the scene to overlay the gizmos on top of
*/
function GizmoManager(scene) {
var _this = this;
this.scene = scene;
this._gizmosEnabled = { positionGizmo: false, rotationGizmo: false, scaleGizmo: false, boundingBoxGizmo: false };
this._pointerObserver = null;
this._attachedMesh = null;
this._boundingBoxColor = BABYLON.Color3.FromHexString("#0984e3");
this._dragBehavior = new BABYLON.SixDofDragBehavior();
/**
* Array of meshes which will have the gizmo attached when a pointer selected them. If null, all meshes are attachable. (Default: null)
*/
this.attachableMeshes = null;
/**
* If pointer events should perform attaching/detaching a gizmo, if false this can be done manually via attachToMesh. (Default: true)
*/
this.usePointerToAttachGizmos = true;
this.gizmos = { positionGizmo: null, rotationGizmo: null, scaleGizmo: null, boundingBoxGizmo: null };
// Instatiate/dispose gizmos based on pointer actions
this._pointerObserver = scene.onPointerObservable.add(function (pointerInfo, state) {
if (!_this.usePointerToAttachGizmos) {
return;
}
if (pointerInfo.type == BABYLON.PointerEventTypes.POINTERDOWN) {
if (pointerInfo.pickInfo && pointerInfo.pickInfo.pickedMesh) {
var node = pointerInfo.pickInfo.pickedMesh;
if (_this.attachableMeshes == null) {
// Attach to the most parent node
while (node && node.parent != null) {
node = node.parent;
}
}
else {
// Attach to the parent node that is an attachableMesh
var found = false;
_this.attachableMeshes.forEach(function (mesh) {
if (node && (node == mesh || node.isDescendantOf(mesh))) {
node = mesh;
found = true;
}
});
if (!found) {
node = null;
}
}
if (node instanceof BABYLON.AbstractMesh) {
_this.attachToMesh(node);
}
}
else {
_this.attachToMesh(null);
}
}
});
}
/**
* Attaches a set of gizmos to the specified mesh
* @param mesh The mesh the gizmo's should be attached to
*/
GizmoManager.prototype.attachToMesh = function (mesh) {
if (this._attachedMesh) {
this._attachedMesh.removeBehavior(this._dragBehavior);
}
this._attachedMesh = mesh;
for (var key in this.gizmos) {
var gizmo = (this.gizmos[key]);
if (gizmo && this._gizmosEnabled[key]) {
gizmo.attachedMesh = mesh;
}
}
if (this.boundingBoxGizmoEnabled && this._attachedMesh) {
this._attachedMesh.addBehavior(this._dragBehavior);
}
};
Object.defineProperty(GizmoManager.prototype, "positionGizmoEnabled", {
get: function () {
return this._gizmosEnabled.positionGizmo;
},
/**
* If the position gizmo is enabled
*/
set: function (value) {
if (value) {
this.gizmos.positionGizmo = this.gizmos.positionGizmo || new BABYLON.PositionGizmo();
this.gizmos.positionGizmo.updateGizmoRotationToMatchAttachedMesh = false;
this.gizmos.positionGizmo.attachedMesh = this._attachedMesh;
}
else if (this.gizmos.positionGizmo) {
this.gizmos.positionGizmo.attachedMesh = null;
}
this._gizmosEnabled.positionGizmo = value;
},
enumerable: true,
configurable: true
});
Object.defineProperty(GizmoManager.prototype, "rotationGizmoEnabled", {
get: function () {
return this._gizmosEnabled.rotationGizmo;
},
/**
* If the rotation gizmo is enabled
*/
set: function (value) {
if (value) {
this.gizmos.rotationGizmo = this.gizmos.rotationGizmo || new BABYLON.RotationGizmo();
this.gizmos.rotationGizmo.updateGizmoRotationToMatchAttachedMesh = false;
this.gizmos.rotationGizmo.attachedMesh = this._attachedMesh;
}
else if (this.gizmos.rotationGizmo) {
this.gizmos.rotationGizmo.attachedMesh = null;
}
this._gizmosEnabled.rotationGizmo = value;
},
enumerable: true,
configurable: true
});
Object.defineProperty(GizmoManager.prototype, "scaleGizmoEnabled", {
get: function () {
return this._gizmosEnabled.scaleGizmo;
},
/**
* If the scale gizmo is enabled
*/
set: function (value) {
if (value) {
this.gizmos.scaleGizmo = this.gizmos.scaleGizmo || new BABYLON.ScaleGizmo();
this.gizmos.scaleGizmo.attachedMesh = this._attachedMesh;
}
else if (this.gizmos.scaleGizmo) {
this.gizmos.scaleGizmo.attachedMesh = null;
}
this._gizmosEnabled.scaleGizmo = value;
},
enumerable: true,
configurable: true
});
Object.defineProperty(GizmoManager.prototype, "boundingBoxGizmoEnabled", {
get: function () {
return this._gizmosEnabled.boundingBoxGizmo;
},
/**
* If the boundingBox gizmo is enabled
*/
set: function (value) {
if (value) {
this.gizmos.boundingBoxGizmo = this.gizmos.boundingBoxGizmo || new BABYLON.BoundingBoxGizmo(this._boundingBoxColor);
this.gizmos.boundingBoxGizmo.attachedMesh = this._attachedMesh;
if (this._attachedMesh) {
this._attachedMesh.removeBehavior(this._dragBehavior);
this._attachedMesh.addBehavior(this._dragBehavior);
}
}
else if (this.gizmos.boundingBoxGizmo) {
this.gizmos.boundingBoxGizmo.attachedMesh = null;
}
this._gizmosEnabled.boundingBoxGizmo = value;
},
enumerable: true,
configurable: true
});
/**
* Disposes of the gizmo manager
*/
GizmoManager.prototype.dispose = function () {
this.scene.onPointerObservable.remove(this._pointerObserver);
for (var key in this.gizmos) {
var gizmo = (this.gizmos[key]);
if (gizmo) {
gizmo.dispose();
}
}
this._dragBehavior.detach();
this._gizmoLayer.dispose();
};
return GizmoManager;
}());
BABYLON.GizmoManager = GizmoManager;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.gizmoManager.js.map
var BABYLON;
(function (BABYLON) {
/**
* Defines a target to use with MorphTargetManager
* @see http://doc.babylonjs.com/how_to/how_to_use_morphtargets
*/
var MorphTarget = /** @class */ (function () {
/**
* Creates a new MorphTarget
* @param name defines the name of the target
* @param influence defines the influence to use
*/
function MorphTarget(
/** defines the name of the target */
name, influence, scene) {
if (influence === void 0) { influence = 0; }
if (scene === void 0) { scene = null; }
this.name = name;
/**
* Gets or sets the list of animations
*/
this.animations = new Array();
this._positions = null;
this._normals = null;
this._tangents = null;
/**
* Observable raised when the influence changes
*/
this.onInfluenceChanged = new BABYLON.Observable();
this._animationPropertiesOverride = null;
this._scene = scene || BABYLON.Engine.LastCreatedScene;
this.influence = influence;
}
Object.defineProperty(MorphTarget.prototype, "influence", {
/**
* Gets or sets the influence of this target (ie. its weight in the overall morphing)
*/
get: function () {
return this._influence;
},
set: function (influence) {
if (this._influence === influence) {
return;
}
var previous = this._influence;
this._influence = influence;
if (this.onInfluenceChanged.hasObservers) {
this.onInfluenceChanged.notifyObservers(previous === 0 || influence === 0);
}
},
enumerable: true,
configurable: true
});
Object.defineProperty(MorphTarget.prototype, "animationPropertiesOverride", {
/**
* Gets or sets the animation properties override
*/
get: function () {
if (!this._animationPropertiesOverride && this._scene) {
return this._scene.animationPropertiesOverride;
}
return this._animationPropertiesOverride;
},
set: function (value) {
this._animationPropertiesOverride = value;
},
enumerable: true,
configurable: true
});
Object.defineProperty(MorphTarget.prototype, "hasPositions", {
/**
* Gets a boolean defining if the target contains position data
*/
get: function () {
return !!this._positions;
},
enumerable: true,
configurable: true
});
Object.defineProperty(MorphTarget.prototype, "hasNormals", {
/**
* Gets a boolean defining if the target contains normal data
*/
get: function () {
return !!this._normals;
},
enumerable: true,
configurable: true
});
Object.defineProperty(MorphTarget.prototype, "hasTangents", {
/**
* Gets a boolean defining if the target contains tangent data
*/
get: function () {
return !!this._tangents;
},
enumerable: true,
configurable: true
});
/**
* Affects position data to this target
* @param data defines the position data to use
*/
MorphTarget.prototype.setPositions = function (data) {
this._positions = data;
};
/**
* Gets the position data stored in this target
* @returns a FloatArray containing the position data (or null if not present)
*/
MorphTarget.prototype.getPositions = function () {
return this._positions;
};
/**
* Affects normal data to this target
* @param data defines the normal data to use
*/
MorphTarget.prototype.setNormals = function (data) {
this._normals = data;
};
/**
* Gets the normal data stored in this target
* @returns a FloatArray containing the normal data (or null if not present)
*/
MorphTarget.prototype.getNormals = function () {
return this._normals;
};
/**
* Affects tangent data to this target
* @param data defines the tangent data to use
*/
MorphTarget.prototype.setTangents = function (data) {
this._tangents = data;
};
/**
* Gets the tangent data stored in this target
* @returns a FloatArray containing the tangent data (or null if not present)
*/
MorphTarget.prototype.getTangents = function () {
return this._tangents;
};
/**
* Serializes the current target into a Serialization object
* @returns the serialized object
*/
MorphTarget.prototype.serialize = function () {
var serializationObject = {};
serializationObject.name = this.name;
serializationObject.influence = this.influence;
serializationObject.positions = Array.prototype.slice.call(this.getPositions());
if (this.hasNormals) {
serializationObject.normals = Array.prototype.slice.call(this.getNormals());
}
if (this.hasTangents) {
serializationObject.tangents = Array.prototype.slice.call(this.getTangents());
}
// Animations
BABYLON.Animation.AppendSerializedAnimations(this, serializationObject);
return serializationObject;
};
// Statics
/**
* Creates a new target from serialized data
* @param serializationObject defines the serialized data to use
* @returns a new MorphTarget
*/
MorphTarget.Parse = function (serializationObject) {
var result = new MorphTarget(serializationObject.name, serializationObject.influence);
result.setPositions(serializationObject.positions);
if (serializationObject.normals) {
result.setNormals(serializationObject.normals);
}
if (serializationObject.tangents) {
result.setTangents(serializationObject.tangents);
}
// Animations
if (serializationObject.animations) {
for (var animationIndex = 0; animationIndex < serializationObject.animations.length; animationIndex++) {
var parsedAnimation = serializationObject.animations[animationIndex];
result.animations.push(BABYLON.Animation.Parse(parsedAnimation));
}
}
return result;
};
/**
* Creates a MorphTarget from mesh data
* @param mesh defines the source mesh
* @param name defines the name to use for the new target
* @param influence defines the influence to attach to the target
* @returns a new MorphTarget
*/
MorphTarget.FromMesh = function (mesh, name, influence) {
if (!name) {
name = mesh.name;
}
var result = new MorphTarget(name, influence, mesh.getScene());
result.setPositions(mesh.getVerticesData(BABYLON.VertexBuffer.PositionKind));
if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.NormalKind)) {
result.setNormals(mesh.getVerticesData(BABYLON.VertexBuffer.NormalKind));
}
if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.TangentKind)) {
result.setTangents(mesh.getVerticesData(BABYLON.VertexBuffer.TangentKind));
}
return result;
};
return MorphTarget;
}());
BABYLON.MorphTarget = MorphTarget;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.morphTarget.js.map
var BABYLON;
(function (BABYLON) {
/**
* This class is used to deform meshes using morphing between different targets
* @see http://doc.babylonjs.com/how_to/how_to_use_morphtargets
*/
var MorphTargetManager = /** @class */ (function () {
/**
* Creates a new MorphTargetManager
* @param scene defines the current scene
*/
function MorphTargetManager(scene) {
if (scene === void 0) { scene = null; }
this._targets = new Array();
this._targetObservable = new Array();
this._activeTargets = new BABYLON.SmartArray(16);
this._supportsNormals = false;
this._supportsTangents = false;
this._vertexCount = 0;
this._uniqueId = 0;
this._tempInfluences = new Array();
if (!scene) {
scene = BABYLON.Engine.LastCreatedScene;
}
this._scene = scene;
if (this._scene) {
this._scene.morphTargetManagers.push(this);
this._uniqueId = this._scene.getUniqueId();
}
}
Object.defineProperty(MorphTargetManager.prototype, "uniqueId", {
/**
* Gets the unique ID of this manager
*/
get: function () {
return this._uniqueId;
},
enumerable: true,
configurable: true
});
Object.defineProperty(MorphTargetManager.prototype, "vertexCount", {
/**
* Gets the number of vertices handled by this manager
*/
get: function () {
return this._vertexCount;
},
enumerable: true,
configurable: true
});
Object.defineProperty(MorphTargetManager.prototype, "supportsNormals", {
/**
* Gets a boolean indicating if this manager supports morphing of normals
*/
get: function () {
return this._supportsNormals;
},
enumerable: true,
configurable: true
});
Object.defineProperty(MorphTargetManager.prototype, "supportsTangents", {
/**
* Gets a boolean indicating if this manager supports morphing of tangents
*/
get: function () {
return this._supportsTangents;
},
enumerable: true,
configurable: true
});
Object.defineProperty(MorphTargetManager.prototype, "numTargets", {
/**
* Gets the number of targets stored in this manager
*/
get: function () {
return this._targets.length;
},
enumerable: true,
configurable: true
});
Object.defineProperty(MorphTargetManager.prototype, "numInfluencers", {
/**
* Gets the number of influencers (ie. the number of targets with influences > 0)
*/
get: function () {
return this._activeTargets.length;
},
enumerable: true,
configurable: true
});
Object.defineProperty(MorphTargetManager.prototype, "influences", {
/**
* Gets the list of influences (one per target)
*/
get: function () {
return this._influences;
},
enumerable: true,
configurable: true
});
/**
* Gets the active target at specified index. An active target is a target with an influence > 0
* @param index defines the index to check
* @returns the requested target
*/
MorphTargetManager.prototype.getActiveTarget = function (index) {
return this._activeTargets.data[index];
};
/**
* Gets the target at specified index
* @param index defines the index to check
* @returns the requested target
*/
MorphTargetManager.prototype.getTarget = function (index) {
return this._targets[index];
};
/**
* Add a new target to this manager
* @param target defines the target to add
*/
MorphTargetManager.prototype.addTarget = function (target) {
var _this = this;
this._targets.push(target);
this._targetObservable.push(target.onInfluenceChanged.add(function (needUpdate) {
_this._syncActiveTargets(needUpdate);
}));
this._syncActiveTargets(true);
};
/**
* Removes a target from the manager
* @param target defines the target to remove
*/
MorphTargetManager.prototype.removeTarget = function (target) {
var index = this._targets.indexOf(target);
if (index >= 0) {
this._targets.splice(index, 1);
target.onInfluenceChanged.remove(this._targetObservable.splice(index, 1)[0]);
this._syncActiveTargets(true);
}
};
/**
* Serializes the current manager into a Serialization object
* @returns the serialized object
*/
MorphTargetManager.prototype.serialize = function () {
var serializationObject = {};
serializationObject.id = this.uniqueId;
serializationObject.targets = [];
for (var _i = 0, _a = this._targets; _i < _a.length; _i++) {
var target = _a[_i];
serializationObject.targets.push(target.serialize());
}
return serializationObject;
};
MorphTargetManager.prototype._syncActiveTargets = function (needUpdate) {
var influenceCount = 0;
this._activeTargets.reset();
this._supportsNormals = true;
this._supportsTangents = true;
this._vertexCount = 0;
for (var _i = 0, _a = this._targets; _i < _a.length; _i++) {
var target = _a[_i];
this._activeTargets.push(target);
this._tempInfluences[influenceCount++] = target.influence;
var positions = target.getPositions();
if (positions) {
this._supportsNormals = this._supportsNormals && target.hasNormals;
this._supportsTangents = this._supportsTangents && target.hasTangents;
var vertexCount = positions.length / 3;
if (this._vertexCount === 0) {
this._vertexCount = vertexCount;
}
else if (this._vertexCount !== vertexCount) {
BABYLON.Tools.Error("Incompatible target. Targets must all have the same vertices count.");
return;
}
}
}
if (!this._influences || this._influences.length !== influenceCount) {
this._influences = new Float32Array(influenceCount);
}
for (var index = 0; index < influenceCount; index++) {
this._influences[index] = this._tempInfluences[index];
}
if (needUpdate) {
this.synchronize();
}
};
/**
* Syncrhonize the targets with all the meshes using this morph target manager
*/
MorphTargetManager.prototype.synchronize = function () {
if (!this._scene) {
return;
}
// Flag meshes as dirty to resync with the active targets
for (var _i = 0, _a = this._scene.meshes; _i < _a.length; _i++) {
var mesh = _a[_i];
if (mesh.morphTargetManager === this) {
mesh._syncGeometryWithMorphTargetManager();
}
}
};
// Statics
/**
* Creates a new MorphTargetManager from serialized data
* @param serializationObject defines the serialized data
* @param scene defines the hosting scene
* @returns the new MorphTargetManager
*/
MorphTargetManager.Parse = function (serializationObject, scene) {
var result = new MorphTargetManager(scene);
result._uniqueId = serializationObject.id;
for (var _i = 0, _a = serializationObject.targets; _i < _a.length; _i++) {
var targetData = _a[_i];
result.addTarget(BABYLON.MorphTarget.Parse(targetData));
}
return result;
};
return MorphTargetManager;
}());
BABYLON.MorphTargetManager = MorphTargetManager;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.morphTargetManager.js.map
var BABYLON;
(function (BABYLON) {
var Octree = /** @class */ (function () {
function Octree(creationFunc, maxBlockCapacity, maxDepth) {
if (maxDepth === void 0) { maxDepth = 2; }
this.maxDepth = maxDepth;
this.dynamicContent = new Array();
this._maxBlockCapacity = maxBlockCapacity || 64;
this._selectionContent = new BABYLON.SmartArrayNoDuplicate(1024);
this._creationFunc = creationFunc;
}
// Methods
Octree.prototype.update = function (worldMin, worldMax, entries) {
Octree._CreateBlocks(worldMin, worldMax, entries, this._maxBlockCapacity, 0, this.maxDepth, this, this._creationFunc);
};
Octree.prototype.addMesh = function (entry) {
for (var index = 0; index < this.blocks.length; index++) {
var block = this.blocks[index];
block.addEntry(entry);
}
};
Octree.prototype.select = function (frustumPlanes, allowDuplicate) {
this._selectionContent.reset();
for (var index = 0; index < this.blocks.length; index++) {
var block = this.blocks[index];
block.select(frustumPlanes, this._selectionContent, allowDuplicate);
}
if (allowDuplicate) {
this._selectionContent.concat(this.dynamicContent);
}
else {
this._selectionContent.concatWithNoDuplicate(this.dynamicContent);
}
return this._selectionContent;
};
Octree.prototype.intersects = function (sphereCenter, sphereRadius, allowDuplicate) {
this._selectionContent.reset();
for (var index = 0; index < this.blocks.length; index++) {
var block = this.blocks[index];
block.intersects(sphereCenter, sphereRadius, this._selectionContent, allowDuplicate);
}
if (allowDuplicate) {
this._selectionContent.concat(this.dynamicContent);
}
else {
this._selectionContent.concatWithNoDuplicate(this.dynamicContent);
}
return this._selectionContent;
};
Octree.prototype.intersectsRay = function (ray) {
this._selectionContent.reset();
for (var index = 0; index < this.blocks.length; index++) {
var block = this.blocks[index];
block.intersectsRay(ray, this._selectionContent);
}
this._selectionContent.concatWithNoDuplicate(this.dynamicContent);
return this._selectionContent;
};
Octree._CreateBlocks = function (worldMin, worldMax, entries, maxBlockCapacity, currentDepth, maxDepth, target, creationFunc) {
target.blocks = new Array();
var blockSize = new BABYLON.Vector3((worldMax.x - worldMin.x) / 2, (worldMax.y - worldMin.y) / 2, (worldMax.z - worldMin.z) / 2);
// Segmenting space
for (var x = 0; x < 2; x++) {
for (var y = 0; y < 2; y++) {
for (var z = 0; z < 2; z++) {
var localMin = worldMin.add(blockSize.multiplyByFloats(x, y, z));
var localMax = worldMin.add(blockSize.multiplyByFloats(x + 1, y + 1, z + 1));
var block = new BABYLON.OctreeBlock(localMin, localMax, maxBlockCapacity, currentDepth + 1, maxDepth, creationFunc);
block.addEntries(entries);
target.blocks.push(block);
}
}
}
};
Octree.CreationFuncForMeshes = function (entry, block) {
var boundingInfo = entry.getBoundingInfo();
if (!entry.isBlocked && boundingInfo.boundingBox.intersectsMinMax(block.minPoint, block.maxPoint)) {
block.entries.push(entry);
}
};
Octree.CreationFuncForSubMeshes = function (entry, block) {
var boundingInfo = entry.getBoundingInfo();
if (boundingInfo.boundingBox.intersectsMinMax(block.minPoint, block.maxPoint)) {
block.entries.push(entry);
}
};
return Octree;
}());
BABYLON.Octree = Octree;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.octree.js.map
var BABYLON;
(function (BABYLON) {
var OctreeBlock = /** @class */ (function () {
function OctreeBlock(minPoint, maxPoint, capacity, depth, maxDepth, creationFunc) {
this.entries = new Array();
this._boundingVectors = new Array();
this._capacity = capacity;
this._depth = depth;
this._maxDepth = maxDepth;
this._creationFunc = creationFunc;
this._minPoint = minPoint;
this._maxPoint = maxPoint;
this._boundingVectors.push(minPoint.clone());
this._boundingVectors.push(maxPoint.clone());
this._boundingVectors.push(minPoint.clone());
this._boundingVectors[2].x = maxPoint.x;
this._boundingVectors.push(minPoint.clone());
this._boundingVectors[3].y = maxPoint.y;
this._boundingVectors.push(minPoint.clone());
this._boundingVectors[4].z = maxPoint.z;
this._boundingVectors.push(maxPoint.clone());
this._boundingVectors[5].z = minPoint.z;
this._boundingVectors.push(maxPoint.clone());
this._boundingVectors[6].x = minPoint.x;
this._boundingVectors.push(maxPoint.clone());
this._boundingVectors[7].y = minPoint.y;
}
Object.defineProperty(OctreeBlock.prototype, "capacity", {
// Property
get: function () {
return this._capacity;
},
enumerable: true,
configurable: true
});
Object.defineProperty(OctreeBlock.prototype, "minPoint", {
get: function () {
return this._minPoint;
},
enumerable: true,
configurable: true
});
Object.defineProperty(OctreeBlock.prototype, "maxPoint", {
get: function () {
return this._maxPoint;
},
enumerable: true,
configurable: true
});
// Methods
OctreeBlock.prototype.addEntry = function (entry) {
if (this.blocks) {
for (var index = 0; index < this.blocks.length; index++) {
var block = this.blocks[index];
block.addEntry(entry);
}
return;
}
this._creationFunc(entry, this);
if (this.entries.length > this.capacity && this._depth < this._maxDepth) {
this.createInnerBlocks();
}
};
OctreeBlock.prototype.addEntries = function (entries) {
for (var index = 0; index < entries.length; index++) {
var mesh = entries[index];
this.addEntry(mesh);
}
};
OctreeBlock.prototype.select = function (frustumPlanes, selection, allowDuplicate) {
if (BABYLON.BoundingBox.IsInFrustum(this._boundingVectors, frustumPlanes)) {
if (this.blocks) {
for (var index = 0; index < this.blocks.length; index++) {
var block = this.blocks[index];
block.select(frustumPlanes, selection, allowDuplicate);
}
return;
}
if (allowDuplicate) {
selection.concat(this.entries);
}
else {
selection.concatWithNoDuplicate(this.entries);
}
}
};
OctreeBlock.prototype.intersects = function (sphereCenter, sphereRadius, selection, allowDuplicate) {
if (BABYLON.BoundingBox.IntersectsSphere(this._minPoint, this._maxPoint, sphereCenter, sphereRadius)) {
if (this.blocks) {
for (var index = 0; index < this.blocks.length; index++) {
var block = this.blocks[index];
block.intersects(sphereCenter, sphereRadius, selection, allowDuplicate);
}
return;
}
if (allowDuplicate) {
selection.concat(this.entries);
}
else {
selection.concatWithNoDuplicate(this.entries);
}
}
};
OctreeBlock.prototype.intersectsRay = function (ray, selection) {
if (ray.intersectsBoxMinMax(this._minPoint, this._maxPoint)) {
if (this.blocks) {
for (var index = 0; index < this.blocks.length; index++) {
var block = this.blocks[index];
block.intersectsRay(ray, selection);
}
return;
}
selection.concatWithNoDuplicate(this.entries);
}
};
OctreeBlock.prototype.createInnerBlocks = function () {
BABYLON.Octree._CreateBlocks(this._minPoint, this._maxPoint, this.entries, this._capacity, this._depth, this._maxDepth, this, this._creationFunc);
};
return OctreeBlock;
}());
BABYLON.OctreeBlock = OctreeBlock;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.octreeBlock.js.map
var BABYLON;
(function (BABYLON) {
/**
* Postprocess used to generate anaglyphic rendering
*/
var AnaglyphPostProcess = /** @class */ (function (_super) {
__extends(AnaglyphPostProcess, _super);
/**
* Creates a new AnaglyphPostProcess
* @param name defines postprocess name
* @param options defines creation options or target ratio scale
* @param rigCameras defines cameras using this postprocess
* @param samplingMode defines required sampling mode (BABYLON.Texture.NEAREST_SAMPLINGMODE by default)
* @param engine defines hosting engine
* @param reusable defines if the postprocess will be reused multiple times per frame
*/
function AnaglyphPostProcess(name, options, rigCameras, samplingMode, engine, reusable) {
var _this = _super.call(this, name, "anaglyph", null, ["leftSampler"], options, rigCameras[1], samplingMode, engine, reusable) || this;
_this._passedProcess = rigCameras[0]._rigPostProcess;
_this.onApplyObservable.add(function (effect) {
effect.setTextureFromPostProcess("leftSampler", _this._passedProcess);
});
return _this;
}
return AnaglyphPostProcess;
}(BABYLON.PostProcess));
BABYLON.AnaglyphPostProcess = AnaglyphPostProcess;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.anaglyphPostProcess.js.map
var BABYLON;
(function (BABYLON) {
BABYLON.Node.AddNodeConstructor("AnaglyphArcRotateCamera", function (name, scene, options) {
return function () { return new AnaglyphArcRotateCamera(name, 0, 0, 1.0, BABYLON.Vector3.Zero(), options.interaxial_distance, scene); };
});
/**
* Camera used to simulate anaglyphic rendering (based on ArcRotateCamera)
*/
var AnaglyphArcRotateCamera = /** @class */ (function (_super) {
__extends(AnaglyphArcRotateCamera, _super);
/**
* Creates a new AnaglyphArcRotateCamera
* @param name defines camera name
* @param alpha defines alpha angle (in radians)
* @param beta defines beta angle (in radians)
* @param radius defines radius
* @param target defines camera target
* @param interaxialDistance defines distance between each color axis
* @param scene defines the hosting scene
*/
function AnaglyphArcRotateCamera(name, alpha, beta, radius, target, interaxialDistance, scene) {
var _this = _super.call(this, name, alpha, beta, radius, target, scene) || this;
_this.interaxialDistance = interaxialDistance;
_this.setCameraRigMode(BABYLON.Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH, { interaxialDistance: interaxialDistance });
return _this;
}
/**
* Gets camera class name
* @returns AnaglyphArcRotateCamera
*/
AnaglyphArcRotateCamera.prototype.getClassName = function () {
return "AnaglyphArcRotateCamera";
};
return AnaglyphArcRotateCamera;
}(BABYLON.ArcRotateCamera));
BABYLON.AnaglyphArcRotateCamera = AnaglyphArcRotateCamera;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.anaglyphArcRotateCamera.js.map
var BABYLON;
(function (BABYLON) {
BABYLON.Node.AddNodeConstructor("AnaglyphFreeCamera", function (name, scene, options) {
return function () { return new AnaglyphFreeCamera(name, BABYLON.Vector3.Zero(), options.interaxial_distance, scene); };
});
/**
* Camera used to simulate anaglyphic rendering (based on FreeCamera)
*/
var AnaglyphFreeCamera = /** @class */ (function (_super) {
__extends(AnaglyphFreeCamera, _super);
/**
* Creates a new AnaglyphFreeCamera
* @param name defines camera name
* @param position defines initial position
* @param interaxialDistance defines distance between each color axis
* @param scene defines the hosting scene
*/
function AnaglyphFreeCamera(name, position, interaxialDistance, scene) {
var _this = _super.call(this, name, position, scene) || this;
_this.interaxialDistance = interaxialDistance;
_this.setCameraRigMode(BABYLON.Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH, { interaxialDistance: interaxialDistance });
return _this;
}
/**
* Gets camera class name
* @returns AnaglyphFreeCamera
*/
AnaglyphFreeCamera.prototype.getClassName = function () {
return "AnaglyphFreeCamera";
};
return AnaglyphFreeCamera;
}(BABYLON.FreeCamera));
BABYLON.AnaglyphFreeCamera = AnaglyphFreeCamera;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.anaglyphFreeCamera.js.map
var BABYLON;
(function (BABYLON) {
BABYLON.Node.AddNodeConstructor("AnaglyphGamepadCamera", function (name, scene, options) {
return function () { return new AnaglyphGamepadCamera(name, BABYLON.Vector3.Zero(), options.interaxial_distance, scene); };
});
/**
* Camera used to simulate anaglyphic rendering (based on GamepadCamera)
*/
var AnaglyphGamepadCamera = /** @class */ (function (_super) {
__extends(AnaglyphGamepadCamera, _super);
/**
* Creates a new AnaglyphGamepadCamera
* @param name defines camera name
* @param position defines initial position
* @param interaxialDistance defines distance between each color axis
* @param scene defines the hosting scene
*/
function AnaglyphGamepadCamera(name, position, interaxialDistance, scene) {
var _this = _super.call(this, name, position, scene) || this;
_this.interaxialDistance = interaxialDistance;
_this.setCameraRigMode(BABYLON.Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH, { interaxialDistance: interaxialDistance });
return _this;
}
/**
* Gets camera class name
* @returns AnaglyphGamepadCamera
*/
AnaglyphGamepadCamera.prototype.getClassName = function () {
return "AnaglyphGamepadCamera";
};
return AnaglyphGamepadCamera;
}(BABYLON.GamepadCamera));
BABYLON.AnaglyphGamepadCamera = AnaglyphGamepadCamera;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.anaglyphGamepadCamera.js.map
var BABYLON;
(function (BABYLON) {
BABYLON.Node.AddNodeConstructor("AnaglyphUniversalCamera", function (name, scene, options) {
return function () { return new AnaglyphUniversalCamera(name, BABYLON.Vector3.Zero(), options.interaxial_distance, scene); };
});
/**
* Camera used to simulate anaglyphic rendering (based on UniversalCamera)
*/
var AnaglyphUniversalCamera = /** @class */ (function (_super) {
__extends(AnaglyphUniversalCamera, _super);
/**
* Creates a new AnaglyphUniversalCamera
* @param name defines camera name
* @param position defines initial position
* @param interaxialDistance defines distance between each color axis
* @param scene defines the hosting scene
*/
function AnaglyphUniversalCamera(name, position, interaxialDistance, scene) {
var _this = _super.call(this, name, position, scene) || this;
_this.interaxialDistance = interaxialDistance;
_this.setCameraRigMode(BABYLON.Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH, { interaxialDistance: interaxialDistance });
return _this;
}
/**
* Gets camera class name
* @returns AnaglyphUniversalCamera
*/
AnaglyphUniversalCamera.prototype.getClassName = function () {
return "AnaglyphUniversalCamera";
};
return AnaglyphUniversalCamera;
}(BABYLON.UniversalCamera));
BABYLON.AnaglyphUniversalCamera = AnaglyphUniversalCamera;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.anaglyphUniversalCamera.js.map
var BABYLON;
(function (BABYLON) {
var StereoscopicInterlacePostProcess = /** @class */ (function (_super) {
__extends(StereoscopicInterlacePostProcess, _super);
function StereoscopicInterlacePostProcess(name, rigCameras, isStereoscopicHoriz, samplingMode, engine, reusable) {
var _this = _super.call(this, name, "stereoscopicInterlace", ['stepSize'], ['camASampler'], 1, rigCameras[1], samplingMode, engine, reusable, isStereoscopicHoriz ? "#define IS_STEREOSCOPIC_HORIZ 1" : undefined) || this;
_this._passedProcess = rigCameras[0]._rigPostProcess;
_this._stepSize = new BABYLON.Vector2(1 / _this.width, 1 / _this.height);
_this.onSizeChangedObservable.add(function () {
_this._stepSize = new BABYLON.Vector2(1 / _this.width, 1 / _this.height);
});
_this.onApplyObservable.add(function (effect) {
effect.setTextureFromPostProcess("camASampler", _this._passedProcess);
effect.setFloat2("stepSize", _this._stepSize.x, _this._stepSize.y);
});
return _this;
}
return StereoscopicInterlacePostProcess;
}(BABYLON.PostProcess));
BABYLON.StereoscopicInterlacePostProcess = StereoscopicInterlacePostProcess;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.stereoscopicInterlacePostProcess.js.map
var BABYLON;
(function (BABYLON) {
BABYLON.Node.AddNodeConstructor("StereoscopicArcRotateCamera", function (name, scene, options) {
return function () { return new StereoscopicArcRotateCamera(name, 0, 0, 1.0, BABYLON.Vector3.Zero(), options.interaxial_distance, options.isStereoscopicSideBySide, scene); };
});
/**
* Camera used to simulate stereoscopic rendering (based on ArcRotateCamera)
*/
var StereoscopicArcRotateCamera = /** @class */ (function (_super) {
__extends(StereoscopicArcRotateCamera, _super);
/**
* Creates a new StereoscopicArcRotateCamera
* @param name defines camera name
* @param alpha defines alpha angle (in radians)
* @param beta defines beta angle (in radians)
* @param radius defines radius
* @param target defines camera target
* @param interaxialDistance defines distance between each color axis
* @param isStereoscopicSideBySide defines is stereoscopic is done side by side or over under
* @param scene defines the hosting scene
*/
function StereoscopicArcRotateCamera(name, alpha, beta, radius, target, interaxialDistance, isStereoscopicSideBySide, scene) {
var _this = _super.call(this, name, alpha, beta, radius, target, scene) || this;
_this.interaxialDistance = interaxialDistance;
_this.isStereoscopicSideBySide = isStereoscopicSideBySide;
_this.setCameraRigMode(isStereoscopicSideBySide ? BABYLON.Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL : BABYLON.Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER, { interaxialDistance: interaxialDistance });
return _this;
}
/**
* Gets camera class name
* @returns StereoscopicArcRotateCamera
*/
StereoscopicArcRotateCamera.prototype.getClassName = function () {
return "StereoscopicArcRotateCamera";
};
return StereoscopicArcRotateCamera;
}(BABYLON.ArcRotateCamera));
BABYLON.StereoscopicArcRotateCamera = StereoscopicArcRotateCamera;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.stereoscopicArcRotateCamera.js.map
var BABYLON;
(function (BABYLON) {
BABYLON.Node.AddNodeConstructor("StereoscopicFreeCamera", function (name, scene, options) {
return function () { return new StereoscopicFreeCamera(name, BABYLON.Vector3.Zero(), options.interaxial_distance, options.isStereoscopicSideBySide, scene); };
});
/**
* Camera used to simulate stereoscopic rendering (based on FreeCamera)
*/
var StereoscopicFreeCamera = /** @class */ (function (_super) {
__extends(StereoscopicFreeCamera, _super);
/**
* Creates a new StereoscopicFreeCamera
* @param name defines camera name
* @param position defines initial position
* @param interaxialDistance defines distance between each color axis
* @param isStereoscopicSideBySide defines is stereoscopic is done side by side or over under
* @param scene defines the hosting scene
*/
function StereoscopicFreeCamera(name, position, interaxialDistance, isStereoscopicSideBySide, scene) {
var _this = _super.call(this, name, position, scene) || this;
_this.interaxialDistance = interaxialDistance;
_this.isStereoscopicSideBySide = isStereoscopicSideBySide;
_this.setCameraRigMode(isStereoscopicSideBySide ? BABYLON.Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL : BABYLON.Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER, { interaxialDistance: interaxialDistance });
return _this;
}
/**
* Gets camera class name
* @returns StereoscopicFreeCamera
*/
StereoscopicFreeCamera.prototype.getClassName = function () {
return "StereoscopicFreeCamera";
};
return StereoscopicFreeCamera;
}(BABYLON.FreeCamera));
BABYLON.StereoscopicFreeCamera = StereoscopicFreeCamera;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.stereoscopicFreeCamera.js.map
var BABYLON;
(function (BABYLON) {
BABYLON.Node.AddNodeConstructor("StereoscopicGamepadCamera", function (name, scene, options) {
return function () { return new StereoscopicGamepadCamera(name, BABYLON.Vector3.Zero(), options.interaxial_distance, options.isStereoscopicSideBySide, scene); };
});
/**
* Camera used to simulate stereoscopic rendering (based on GamepadCamera)
*/
var StereoscopicGamepadCamera = /** @class */ (function (_super) {
__extends(StereoscopicGamepadCamera, _super);
/**
* Creates a new StereoscopicGamepadCamera
* @param name defines camera name
* @param position defines initial position
* @param interaxialDistance defines distance between each color axis
* @param isStereoscopicSideBySide defines is stereoscopic is done side by side or over under
* @param scene defines the hosting scene
*/
function StereoscopicGamepadCamera(name, position, interaxialDistance, isStereoscopicSideBySide, scene) {
var _this = _super.call(this, name, position, scene) || this;
_this.interaxialDistance = interaxialDistance;
_this.isStereoscopicSideBySide = isStereoscopicSideBySide;
_this.setCameraRigMode(isStereoscopicSideBySide ? BABYLON.Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL : BABYLON.Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER, { interaxialDistance: interaxialDistance });
return _this;
}
/**
* Gets camera class name
* @returns StereoscopicGamepadCamera
*/
StereoscopicGamepadCamera.prototype.getClassName = function () {
return "StereoscopicGamepadCamera";
};
return StereoscopicGamepadCamera;
}(BABYLON.GamepadCamera));
BABYLON.StereoscopicGamepadCamera = StereoscopicGamepadCamera;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.stereoscopicGamepadCamera.js.map
var BABYLON;
(function (BABYLON) {
BABYLON.Node.AddNodeConstructor("StereoscopicFreeCamera", function (name, scene, options) {
return function () { return new StereoscopicUniversalCamera(name, BABYLON.Vector3.Zero(), options.interaxial_distance, options.isStereoscopicSideBySide, scene); };
});
/**
* Camera used to simulate stereoscopic rendering (based on UniversalCamera)
*/
var StereoscopicUniversalCamera = /** @class */ (function (_super) {
__extends(StereoscopicUniversalCamera, _super);
/**
* Creates a new StereoscopicUniversalCamera
* @param name defines camera name
* @param position defines initial position
* @param interaxialDistance defines distance between each color axis
* @param isStereoscopicSideBySide defines is stereoscopic is done side by side or over under
* @param scene defines the hosting scene
*/
function StereoscopicUniversalCamera(name, position, interaxialDistance, isStereoscopicSideBySide, scene) {
var _this = _super.call(this, name, position, scene) || this;
_this.interaxialDistance = interaxialDistance;
_this.isStereoscopicSideBySide = isStereoscopicSideBySide;
_this.setCameraRigMode(isStereoscopicSideBySide ? BABYLON.Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL : BABYLON.Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER, { interaxialDistance: interaxialDistance });
return _this;
}
/**
* Gets camera class name
* @returns StereoscopicUniversalCamera
*/
StereoscopicUniversalCamera.prototype.getClassName = function () {
return "StereoscopicUniversalCamera";
};
return StereoscopicUniversalCamera;
}(BABYLON.UniversalCamera));
BABYLON.StereoscopicUniversalCamera = StereoscopicUniversalCamera;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.stereoscopicUniversalCamera.js.map
var BABYLON;
(function (BABYLON) {
var VRDistortionCorrectionPostProcess = /** @class */ (function (_super) {
__extends(VRDistortionCorrectionPostProcess, _super);
function VRDistortionCorrectionPostProcess(name, camera, isRightEye, vrMetrics) {
var _this = _super.call(this, name, "vrDistortionCorrection", [
'LensCenter',
'Scale',
'ScaleIn',
'HmdWarpParam'
], null, vrMetrics.postProcessScaleFactor, camera, BABYLON.Texture.BILINEAR_SAMPLINGMODE) || this;
_this._isRightEye = isRightEye;
_this._distortionFactors = vrMetrics.distortionK;
_this._postProcessScaleFactor = vrMetrics.postProcessScaleFactor;
_this._lensCenterOffset = vrMetrics.lensCenterOffset;
_this.adaptScaleToCurrentViewport = true;
_this.onSizeChangedObservable.add(function () {
_this._scaleIn = new BABYLON.Vector2(2, 2 / _this.aspectRatio);
_this._scaleFactor = new BABYLON.Vector2(.5 * (1 / _this._postProcessScaleFactor), .5 * (1 / _this._postProcessScaleFactor) * _this.aspectRatio);
_this._lensCenter = new BABYLON.Vector2(_this._isRightEye ? 0.5 - _this._lensCenterOffset * 0.5 : 0.5 + _this._lensCenterOffset * 0.5, 0.5);
});
_this.onApplyObservable.add(function (effect) {
effect.setFloat2("LensCenter", _this._lensCenter.x, _this._lensCenter.y);
effect.setFloat2("Scale", _this._scaleFactor.x, _this._scaleFactor.y);
effect.setFloat2("ScaleIn", _this._scaleIn.x, _this._scaleIn.y);
effect.setFloat4("HmdWarpParam", _this._distortionFactors[0], _this._distortionFactors[1], _this._distortionFactors[2], _this._distortionFactors[3]);
});
return _this;
}
return VRDistortionCorrectionPostProcess;
}(BABYLON.PostProcess));
BABYLON.VRDistortionCorrectionPostProcess = VRDistortionCorrectionPostProcess;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.vrDistortionCorrectionPostProcess.js.map
var BABYLON;
(function (BABYLON) {
/**
* Takes information about the orientation of the device as reported by the deviceorientation event to orient the camera.
* Screen rotation is taken into account.
*/
var FreeCameraDeviceOrientationInput = /** @class */ (function () {
function FreeCameraDeviceOrientationInput() {
var _this = this;
this._screenOrientationAngle = 0;
this._screenQuaternion = new BABYLON.Quaternion();
this._alpha = 0;
this._beta = 0;
this._gamma = 0;
this._orientationChanged = function () {
_this._screenOrientationAngle = (window.orientation !== undefined ? +window.orientation : (window.screen.orientation && window.screen.orientation['angle'] ? window.screen.orientation.angle : 0));
_this._screenOrientationAngle = -BABYLON.Tools.ToRadians(_this._screenOrientationAngle / 2);
_this._screenQuaternion.copyFromFloats(0, Math.sin(_this._screenOrientationAngle), 0, Math.cos(_this._screenOrientationAngle));
};
this._deviceOrientation = function (evt) {
_this._alpha = evt.alpha !== null ? evt.alpha : 0;
_this._beta = evt.beta !== null ? evt.beta : 0;
_this._gamma = evt.gamma !== null ? evt.gamma : 0;
};
this._constantTranform = new BABYLON.Quaternion(-Math.sqrt(0.5), 0, 0, Math.sqrt(0.5));
this._orientationChanged();
}
Object.defineProperty(FreeCameraDeviceOrientationInput.prototype, "camera", {
get: function () {
return this._camera;
},
set: function (camera) {
this._camera = camera;
if (this._camera != null && !this._camera.rotationQuaternion) {
this._camera.rotationQuaternion = new BABYLON.Quaternion();
}
},
enumerable: true,
configurable: true
});
FreeCameraDeviceOrientationInput.prototype.attachControl = function (element, noPreventDefault) {
window.addEventListener("orientationchange", this._orientationChanged);
window.addEventListener("deviceorientation", this._deviceOrientation);
//In certain cases, the attach control is called AFTER orientation was changed,
//So this is needed.
this._orientationChanged();
};
FreeCameraDeviceOrientationInput.prototype.detachControl = function (element) {
window.removeEventListener("orientationchange", this._orientationChanged);
window.removeEventListener("deviceorientation", this._deviceOrientation);
};
FreeCameraDeviceOrientationInput.prototype.checkInputs = function () {
//if no device orientation provided, don't update the rotation.
//Only testing against alpha under the assumption thatnorientation will never be so exact when set.
if (!this._alpha)
return;
BABYLON.Quaternion.RotationYawPitchRollToRef(BABYLON.Tools.ToRadians(this._alpha), BABYLON.Tools.ToRadians(this._beta), -BABYLON.Tools.ToRadians(this._gamma), this.camera.rotationQuaternion);
this._camera.rotationQuaternion.multiplyInPlace(this._screenQuaternion);
this._camera.rotationQuaternion.multiplyInPlace(this._constantTranform);
//Mirror on XY Plane
this._camera.rotationQuaternion.z *= -1;
this._camera.rotationQuaternion.w *= -1;
};
FreeCameraDeviceOrientationInput.prototype.getClassName = function () {
return "FreeCameraDeviceOrientationInput";
};
FreeCameraDeviceOrientationInput.prototype.getSimpleName = function () {
return "deviceOrientation";
};
return FreeCameraDeviceOrientationInput;
}());
BABYLON.FreeCameraDeviceOrientationInput = FreeCameraDeviceOrientationInput;
BABYLON.CameraInputTypes["FreeCameraDeviceOrientationInput"] = FreeCameraDeviceOrientationInput;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.freeCameraDeviceOrientationInput.js.map
var BABYLON;
(function (BABYLON) {
var ArcRotateCameraVRDeviceOrientationInput = /** @class */ (function () {
function ArcRotateCameraVRDeviceOrientationInput() {
this.alphaCorrection = 1;
this.betaCorrection = 1;
this.gammaCorrection = 1;
this._alpha = 0;
this._gamma = 0;
this._dirty = false;
this._deviceOrientationHandler = this._onOrientationEvent.bind(this);
}
ArcRotateCameraVRDeviceOrientationInput.prototype.attachControl = function (element, noPreventDefault) {
this.camera.attachControl(element, noPreventDefault);
window.addEventListener("deviceorientation", this._deviceOrientationHandler);
};
ArcRotateCameraVRDeviceOrientationInput.prototype._onOrientationEvent = function (evt) {
if (evt.alpha !== null) {
this._alpha = +evt.alpha | 0;
}
if (evt.gamma !== null) {
this._gamma = +evt.gamma | 0;
}
this._dirty = true;
};
ArcRotateCameraVRDeviceOrientationInput.prototype.checkInputs = function () {
if (this._dirty) {
this._dirty = false;
if (this._gamma < 0) {
this._gamma = 180 + this._gamma;
}
this.camera.alpha = (-this._alpha / 180.0 * Math.PI) % Math.PI * 2;
this.camera.beta = (this._gamma / 180.0 * Math.PI);
}
};
ArcRotateCameraVRDeviceOrientationInput.prototype.detachControl = function (element) {
window.removeEventListener("deviceorientation", this._deviceOrientationHandler);
};
ArcRotateCameraVRDeviceOrientationInput.prototype.getClassName = function () {
return "ArcRotateCameraVRDeviceOrientationInput";
};
ArcRotateCameraVRDeviceOrientationInput.prototype.getSimpleName = function () {
return "VRDeviceOrientation";
};
return ArcRotateCameraVRDeviceOrientationInput;
}());
BABYLON.ArcRotateCameraVRDeviceOrientationInput = ArcRotateCameraVRDeviceOrientationInput;
BABYLON.CameraInputTypes["ArcRotateCameraVRDeviceOrientationInput"] = ArcRotateCameraVRDeviceOrientationInput;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.arcRotateCameraVRDeviceOrientationInput.js.map
var BABYLON;
(function (BABYLON) {
var VRCameraMetrics = /** @class */ (function () {
function VRCameraMetrics() {
this.compensateDistortion = true;
}
Object.defineProperty(VRCameraMetrics.prototype, "aspectRatio", {
get: function () {
return this.hResolution / (2 * this.vResolution);
},
enumerable: true,
configurable: true
});
Object.defineProperty(VRCameraMetrics.prototype, "aspectRatioFov", {
get: function () {
return (2 * Math.atan((this.postProcessScaleFactor * this.vScreenSize) / (2 * this.eyeToScreenDistance)));
},
enumerable: true,
configurable: true
});
Object.defineProperty(VRCameraMetrics.prototype, "leftHMatrix", {
get: function () {
var meters = (this.hScreenSize / 4) - (this.lensSeparationDistance / 2);
var h = (4 * meters) / this.hScreenSize;
return BABYLON.Matrix.Translation(h, 0, 0);
},
enumerable: true,
configurable: true
});
Object.defineProperty(VRCameraMetrics.prototype, "rightHMatrix", {
get: function () {
var meters = (this.hScreenSize / 4) - (this.lensSeparationDistance / 2);
var h = (4 * meters) / this.hScreenSize;
return BABYLON.Matrix.Translation(-h, 0, 0);
},
enumerable: true,
configurable: true
});
Object.defineProperty(VRCameraMetrics.prototype, "leftPreViewMatrix", {
get: function () {
return BABYLON.Matrix.Translation(0.5 * this.interpupillaryDistance, 0, 0);
},
enumerable: true,
configurable: true
});
Object.defineProperty(VRCameraMetrics.prototype, "rightPreViewMatrix", {
get: function () {
return BABYLON.Matrix.Translation(-0.5 * this.interpupillaryDistance, 0, 0);
},
enumerable: true,
configurable: true
});
VRCameraMetrics.GetDefault = function () {
var result = new VRCameraMetrics();
result.hResolution = 1280;
result.vResolution = 800;
result.hScreenSize = 0.149759993;
result.vScreenSize = 0.0935999975;
result.vScreenCenter = 0.0467999987;
result.eyeToScreenDistance = 0.0410000011;
result.lensSeparationDistance = 0.0635000020;
result.interpupillaryDistance = 0.0640000030;
result.distortionK = [1.0, 0.219999999, 0.239999995, 0.0];
result.chromaAbCorrection = [0.995999992, -0.00400000019, 1.01400006, 0.0];
result.postProcessScaleFactor = 1.714605507808412;
result.lensCenterOffset = 0.151976421;
return result;
};
return VRCameraMetrics;
}());
BABYLON.VRCameraMetrics = VRCameraMetrics;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.vrCameraMetrics.js.map
var BABYLON;
(function (BABYLON) {
BABYLON.Node.AddNodeConstructor("WebVRFreeCamera", function (name, scene) {
return function () { return new WebVRFreeCamera(name, BABYLON.Vector3.Zero(), scene); };
});
BABYLON.Node.AddNodeConstructor("WebVRGamepadCamera", function (name, scene) {
return function () { return new WebVRFreeCamera(name, BABYLON.Vector3.Zero(), scene); };
});
/**
* This represents a WebVR camera.
* The WebVR camera is Babylon's simple interface to interaction with Windows Mixed Reality, HTC Vive and Oculus Rift.
* @example http://doc.babylonjs.com/how_to/webvr_camera
*/
var WebVRFreeCamera = /** @class */ (function (_super) {
__extends(WebVRFreeCamera, _super);
/**
* Instantiates a WebVRFreeCamera.
* @param name The name of the WebVRFreeCamera
* @param position The starting anchor position for the camera
* @param scene The scene the camera belongs to
* @param webVROptions a set of customizable options for the webVRCamera
*/
function WebVRFreeCamera(name, position, scene, webVROptions) {
if (webVROptions === void 0) { webVROptions = {}; }
var _this = _super.call(this, name, position, scene) || this;
_this.webVROptions = webVROptions;
/**
* The vrDisplay tied to the camera. See https://developer.mozilla.org/en-US/docs/Web/API/VRDisplay
*/
_this._vrDevice = null;
/**
* The rawPose of the vrDevice.
*/
_this.rawPose = null;
_this._specsVersion = "1.1";
_this._attached = false;
_this._descendants = [];
// Represents device position and rotation in room space. Should only be used to help calculate babylon space values
_this._deviceRoomPosition = BABYLON.Vector3.Zero();
/** @hidden */
_this._deviceRoomRotationQuaternion = BABYLON.Quaternion.Identity();
_this._standingMatrix = null;
/**
* Represents device position in babylon space.
*/
_this.devicePosition = BABYLON.Vector3.Zero();
/**
* Represents device rotation in babylon space.
*/
_this.deviceRotationQuaternion = BABYLON.Quaternion.Identity();
/**
* The scale of the device to be used when translating from device space to babylon space.
*/
_this.deviceScaleFactor = 1;
_this._deviceToWorld = BABYLON.Matrix.Identity();
_this._worldToDevice = BABYLON.Matrix.Identity();
/**
* References to the webVR controllers for the vrDevice.
*/
_this.controllers = [];
/**
* Emits an event when a controller is attached.
*/
_this.onControllersAttachedObservable = new BABYLON.Observable();
/**
* Emits an event when a controller's mesh has been loaded;
*/
_this.onControllerMeshLoadedObservable = new BABYLON.Observable();
/**
* Emits an event when the HMD's pose has been updated.
*/
_this.onPoseUpdatedFromDeviceObservable = new BABYLON.Observable();
_this._poseSet = false;
/**
* If the rig cameras be used as parent instead of this camera.
*/
_this.rigParenting = true;
_this._defaultHeight = undefined;
_this._workingVector = BABYLON.Vector3.Zero();
_this._oneVector = BABYLON.Vector3.One();
_this._workingMatrix = BABYLON.Matrix.Identity();
_this._cache.position = BABYLON.Vector3.Zero();
if (webVROptions.defaultHeight) {
_this._defaultHeight = webVROptions.defaultHeight;
_this.position.y = _this._defaultHeight;
}
_this.minZ = 0.1;
//legacy support - the compensation boolean was removed.
if (arguments.length === 5) {
_this.webVROptions = arguments[4];
}
// default webVR options
if (_this.webVROptions.trackPosition == undefined) {
_this.webVROptions.trackPosition = true;
}
if (_this.webVROptions.controllerMeshes == undefined) {
_this.webVROptions.controllerMeshes = true;
}
if (_this.webVROptions.defaultLightingOnControllers == undefined) {
_this.webVROptions.defaultLightingOnControllers = true;
}
_this.rotationQuaternion = new BABYLON.Quaternion();
if (_this.webVROptions && _this.webVROptions.positionScale) {
_this.deviceScaleFactor = _this.webVROptions.positionScale;
}
//enable VR
var engine = _this.getEngine();
_this._onVREnabled = function (success) { if (success) {
_this.initControllers();
} };
engine.onVRRequestPresentComplete.add(_this._onVREnabled);
engine.initWebVR().add(function (event) {
if (!event.vrDisplay || _this._vrDevice === event.vrDisplay) {
return;
}
_this._vrDevice = event.vrDisplay;
//reset the rig parameters.
_this.setCameraRigMode(BABYLON.Camera.RIG_MODE_WEBVR, { parentCamera: _this, vrDisplay: _this._vrDevice, frameData: _this._frameData, specs: _this._specsVersion });
if (_this._attached) {
_this.getEngine().enableVR();
}
});
if (typeof (VRFrameData) !== "undefined")
_this._frameData = new VRFrameData();
/**
* The idea behind the following lines:
* objects that have the camera as parent should actually have the rig cameras as a parent.
* BUT, each of those cameras has a different view matrix, which means that if we set the parent to the first rig camera,
* the second will not show it correctly.
*
* To solve this - each object that has the camera as parent will be added to a protected array.
* When the rig camera renders, it will take this array and set all of those to be its children.
* This way, the right camera will be used as a parent, and the mesh will be rendered correctly.
* Amazing!
*/
scene.onBeforeCameraRenderObservable.add(function (camera) {
if (camera.parent === _this && _this.rigParenting) {
_this._descendants = _this.getDescendants(true, function (n) {
// don't take the cameras or the controllers!
var isController = _this.controllers.some(function (controller) { return controller._mesh === n; });
var isRigCamera = _this._rigCameras.indexOf(n) !== -1;
return !isController && !isRigCamera;
});
_this._descendants.forEach(function (node) {
node.parent = camera;
});
}
});
scene.onAfterCameraRenderObservable.add(function (camera) {
if (camera.parent === _this && _this.rigParenting) {
_this._descendants.forEach(function (node) {
node.parent = _this;
});
}
});
return _this;
}
/**
* Gets the device distance from the ground in meters.
* @returns the distance in meters from the vrDevice to ground in device space. If standing matrix is not supported for the vrDevice 0 is returned.
*/
WebVRFreeCamera.prototype.deviceDistanceToRoomGround = function () {
if (this._standingMatrix) {
// Add standing matrix offset to get real offset from ground in room
this._standingMatrix.getTranslationToRef(this._workingVector);
return this._deviceRoomPosition.y + this._workingVector.y;
}
//If VRDisplay does not inform stage parameters and no default height is set we fallback to zero.
return this._defaultHeight || 0;
};
/**
* Enables the standing matrix when supported. This can be used to position the user's view the correct height from the ground.
* @param callback will be called when the standing matrix is set. Callback parameter is if the standing matrix is supported.
*/
WebVRFreeCamera.prototype.useStandingMatrix = function (callback) {
var _this = this;
if (callback === void 0) { callback = function (bool) { }; }
// Use standing matrix if available
this.getEngine().initWebVRAsync().then(function (result) {
if (!result.vrDisplay || !result.vrDisplay.stageParameters || !result.vrDisplay.stageParameters.sittingToStandingTransform) {
callback(false);
}
else {
_this._standingMatrix = new BABYLON.Matrix();
BABYLON.Matrix.FromFloat32ArrayToRefScaled(result.vrDisplay.stageParameters.sittingToStandingTransform, 0, 1, _this._standingMatrix);
if (!_this.getScene().useRightHandedSystem) {
[2, 6, 8, 9, 14].forEach(function (num) {
if (_this._standingMatrix) {
_this._standingMatrix.m[num] *= -1;
}
});
}
callback(true);
}
});
};
/**
* Enables the standing matrix when supported. This can be used to position the user's view the correct height from the ground.
* @returns A promise with a boolean set to if the standing matrix is supported.
*/
WebVRFreeCamera.prototype.useStandingMatrixAsync = function () {
var _this = this;
return new Promise(function (res, rej) {
_this.useStandingMatrix(function (supported) {
res(supported);
});
});
};
/**
* Disposes the camera
*/
WebVRFreeCamera.prototype.dispose = function () {
this.getEngine().onVRRequestPresentComplete.removeCallback(this._onVREnabled);
_super.prototype.dispose.call(this);
};
/**
* Gets a vrController by name.
* @param name The name of the controller to retreive
* @returns the controller matching the name specified or null if not found
*/
WebVRFreeCamera.prototype.getControllerByName = function (name) {
for (var _i = 0, _a = this.controllers; _i < _a.length; _i++) {
var gp = _a[_i];
if (gp.hand === name) {
return gp;
}
}
return null;
};
Object.defineProperty(WebVRFreeCamera.prototype, "leftController", {
/**
* The controller corrisponding to the users left hand.
*/
get: function () {
if (!this._leftController) {
this._leftController = this.getControllerByName("left");
}
return this._leftController;
},
enumerable: true,
configurable: true
});
;
Object.defineProperty(WebVRFreeCamera.prototype, "rightController", {
/**
* The controller corrisponding to the users right hand.
*/
get: function () {
if (!this._rightController) {
this._rightController = this.getControllerByName("right");
}
return this._rightController;
},
enumerable: true,
configurable: true
});
;
/**
* Casts a ray forward from the vrCamera's gaze.
* @param length Length of the ray (default: 100)
* @returns the ray corrisponding to the gaze
*/
WebVRFreeCamera.prototype.getForwardRay = function (length) {
if (length === void 0) { length = 100; }
if (this.leftCamera) {
// Use left eye to avoid computation to compute center on every call
return _super.prototype.getForwardRay.call(this, length, this.leftCamera.getWorldMatrix(), this.leftCamera.globalPosition); // Need the actual rendered camera
}
else {
return _super.prototype.getForwardRay.call(this, length);
}
};
/**
* Updates the camera based on device's frame data
*/
WebVRFreeCamera.prototype._checkInputs = function () {
if (this._vrDevice && this._vrDevice.isPresenting) {
this._vrDevice.getFrameData(this._frameData);
this.updateFromDevice(this._frameData.pose);
}
_super.prototype._checkInputs.call(this);
};
/**
* Updates the poseControlled values based on the input device pose.
* @param poseData Pose coming from the device
*/
WebVRFreeCamera.prototype.updateFromDevice = function (poseData) {
if (poseData && poseData.orientation) {
this.rawPose = poseData;
this._deviceRoomRotationQuaternion.copyFromFloats(poseData.orientation[0], poseData.orientation[1], -poseData.orientation[2], -poseData.orientation[3]);
if (this.getScene().useRightHandedSystem) {
this._deviceRoomRotationQuaternion.z *= -1;
this._deviceRoomRotationQuaternion.w *= -1;
}
if (this.webVROptions.trackPosition && this.rawPose.position) {
this._deviceRoomPosition.copyFromFloats(this.rawPose.position[0], this.rawPose.position[1], -this.rawPose.position[2]);
if (this.getScene().useRightHandedSystem) {
this._deviceRoomPosition.z *= -1;
}
}
this._poseSet = true;
}
};
/**
* WebVR's attach control will start broadcasting frames to the device.
* Note that in certain browsers (chrome for example) this function must be called
* within a user-interaction callback. Example:
* scene.onPointerDown = function() { camera.attachControl(canvas); }
*
* @param element html element to attach the vrDevice to
* @param noPreventDefault prevent the default html element operation when attaching the vrDevice
*/
WebVRFreeCamera.prototype.attachControl = function (element, noPreventDefault) {
_super.prototype.attachControl.call(this, element, noPreventDefault);
this._attached = true;
noPreventDefault = BABYLON.Camera.ForceAttachControlToAlwaysPreventDefault ? false : noPreventDefault;
if (this._vrDevice) {
this.getEngine().enableVR();
}
};
/**
* Detaches the camera from the html element and disables VR
*
* @param element html element to detach from
*/
WebVRFreeCamera.prototype.detachControl = function (element) {
this.getScene().gamepadManager.onGamepadConnectedObservable.remove(this._onGamepadConnectedObserver);
this.getScene().gamepadManager.onGamepadDisconnectedObservable.remove(this._onGamepadDisconnectedObserver);
_super.prototype.detachControl.call(this, element);
this._attached = false;
this.getEngine().disableVR();
};
/**
* @returns the name of this class
*/
WebVRFreeCamera.prototype.getClassName = function () {
return "WebVRFreeCamera";
};
/**
* Calls resetPose on the vrDisplay
* See: https://developer.mozilla.org/en-US/docs/Web/API/VRDisplay/resetPose
*/
WebVRFreeCamera.prototype.resetToCurrentRotation = function () {
//uses the vrDisplay's "resetPose()".
//pitch and roll won't be affected.
this._vrDevice.resetPose();
};
/**
* Updates the rig cameras (left and right eye)
*/
WebVRFreeCamera.prototype._updateRigCameras = function () {
var camLeft = this._rigCameras[0];
var camRight = this._rigCameras[1];
camLeft.rotationQuaternion.copyFrom(this._deviceRoomRotationQuaternion);
camRight.rotationQuaternion.copyFrom(this._deviceRoomRotationQuaternion);
camLeft.position.copyFrom(this._deviceRoomPosition);
camRight.position.copyFrom(this._deviceRoomPosition);
};
/**
* Updates the cached values of the camera
* @param ignoreParentClass ignores updating the parent class's cache (default: false)
*/
WebVRFreeCamera.prototype._updateCache = function (ignoreParentClass) {
var _this = this;
if (!this.rotationQuaternion.equals(this._cache.rotationQuaternion) || !this.position.equals(this._cache.position)) {
// Update to ensure devicePosition is up to date with most recent _deviceRoomPosition
if (!this.updateCacheCalled) {
// make sure it is only called once per loop. this.update() might cause an infinite loop.
this.updateCacheCalled = true;
this.update();
}
// Set working vector to the device position in room space rotated by the new rotation
this.rotationQuaternion.toRotationMatrix(this._workingMatrix);
BABYLON.Vector3.TransformCoordinatesToRef(this._deviceRoomPosition, this._workingMatrix, this._workingVector);
// Subtract this vector from the current device position in world to get the translation for the device world matrix
this.devicePosition.subtractToRef(this._workingVector, this._workingVector);
BABYLON.Matrix.ComposeToRef(this._oneVector, this.rotationQuaternion, this._workingVector, this._deviceToWorld);
// Add translation from anchor position
this._deviceToWorld.getTranslationToRef(this._workingVector);
this._workingVector.addInPlace(this.position);
this._workingVector.subtractInPlace(this._cache.position);
this._deviceToWorld.setTranslation(this._workingVector);
// Set an inverted matrix to be used when updating the camera
this._deviceToWorld.invertToRef(this._worldToDevice);
// Update the gamepad to ensure the mesh is updated on the same frame as camera
this.controllers.forEach(function (controller) {
controller._deviceToWorld.copyFrom(_this._deviceToWorld);
controller.update();
});
}
if (!ignoreParentClass) {
_super.prototype._updateCache.call(this);
}
this.updateCacheCalled = false;
};
/**
* Updates the current device position and rotation in the babylon world
*/
WebVRFreeCamera.prototype.update = function () {
// Get current device position in babylon world
BABYLON.Vector3.TransformCoordinatesToRef(this._deviceRoomPosition, this._deviceToWorld, this.devicePosition);
// Get current device rotation in babylon world
BABYLON.Matrix.FromQuaternionToRef(this._deviceRoomRotationQuaternion, this._workingMatrix);
this._workingMatrix.multiplyToRef(this._deviceToWorld, this._workingMatrix);
BABYLON.Quaternion.FromRotationMatrixToRef(this._workingMatrix, this.deviceRotationQuaternion);
if (this._poseSet) {
this.onPoseUpdatedFromDeviceObservable.notifyObservers(null);
}
_super.prototype.update.call(this);
};
/**
* Gets the view matrix of this camera (Always set to identity as left and right eye cameras contain the actual view matrix)
* @returns an identity matrix
*/
WebVRFreeCamera.prototype._getViewMatrix = function () {
return BABYLON.Matrix.Identity();
};
/**
* This function is called by the two RIG cameras.
* 'this' is the left or right camera (and NOT (!!!) the WebVRFreeCamera instance)
*/
WebVRFreeCamera.prototype._getWebVRViewMatrix = function () {
var _this = this;
// Update the parent camera prior to using a child camera to avoid desynchronization
var parentCamera = this._cameraRigParams["parentCamera"];
parentCamera._updateCache();
//WebVR 1.1
var viewArray = this._cameraRigParams["left"] ? this._cameraRigParams["frameData"].leftViewMatrix : this._cameraRigParams["frameData"].rightViewMatrix;
BABYLON.Matrix.FromArrayToRef(viewArray, 0, this._webvrViewMatrix);
if (!this.getScene().useRightHandedSystem) {
[2, 6, 8, 9, 14].forEach(function (num) {
_this._webvrViewMatrix.m[num] *= -1;
});
}
// update the camera rotation matrix
this._webvrViewMatrix.getRotationMatrixToRef(this._cameraRotationMatrix);
BABYLON.Vector3.TransformCoordinatesToRef(this._referencePoint, this._cameraRotationMatrix, this._transformedReferencePoint);
// Computing target and final matrix
this.position.addToRef(this._transformedReferencePoint, this._currentTarget);
// should the view matrix be updated with scale and position offset?
if (parentCamera.deviceScaleFactor !== 1) {
this._webvrViewMatrix.invert();
// scale the position, if set
if (parentCamera.deviceScaleFactor) {
this._webvrViewMatrix.m[12] *= parentCamera.deviceScaleFactor;
this._webvrViewMatrix.m[13] *= parentCamera.deviceScaleFactor;
this._webvrViewMatrix.m[14] *= parentCamera.deviceScaleFactor;
}
this._webvrViewMatrix.invert();
}
parentCamera._worldToDevice.multiplyToRef(this._webvrViewMatrix, this._webvrViewMatrix);
// Compute global position
this._workingMatrix = this._workingMatrix || BABYLON.Matrix.Identity();
this._webvrViewMatrix.invertToRef(this._workingMatrix);
this._workingMatrix.multiplyToRef(parentCamera.getWorldMatrix(), this._workingMatrix);
this._workingMatrix.getTranslationToRef(this._globalPosition);
this._markSyncedWithParent();
return this._webvrViewMatrix;
};
WebVRFreeCamera.prototype._getWebVRProjectionMatrix = function () {
var _this = this;
var parentCamera = this.parent;
parentCamera._vrDevice.depthNear = parentCamera.minZ;
parentCamera._vrDevice.depthFar = parentCamera.maxZ;
var projectionArray = this._cameraRigParams["left"] ? this._cameraRigParams["frameData"].leftProjectionMatrix : this._cameraRigParams["frameData"].rightProjectionMatrix;
BABYLON.Matrix.FromArrayToRef(projectionArray, 0, this._projectionMatrix);
//babylon compatible matrix
if (!this.getScene().useRightHandedSystem) {
[8, 9, 10, 11].forEach(function (num) {
_this._projectionMatrix.m[num] *= -1;
});
}
return this._projectionMatrix;
};
/**
* Initializes the controllers and their meshes
*/
WebVRFreeCamera.prototype.initControllers = function () {
var _this = this;
this.controllers = [];
var manager = this.getScene().gamepadManager;
this._onGamepadDisconnectedObserver = manager.onGamepadDisconnectedObservable.add(function (gamepad) {
if (gamepad.type === BABYLON.Gamepad.POSE_ENABLED) {
var webVrController = gamepad;
if (webVrController.defaultModel) {
webVrController.defaultModel.setEnabled(false);
}
if (webVrController.hand === "right") {
_this._rightController = null;
}
if (webVrController.hand === "left") {
_this._leftController = null;
}
var controllerIndex = _this.controllers.indexOf(webVrController);
if (controllerIndex !== -1) {
_this.controllers.splice(controllerIndex, 1);
}
}
});
this._onGamepadConnectedObserver = manager.onGamepadConnectedObservable.add(function (gamepad) {
if (gamepad.type === BABYLON.Gamepad.POSE_ENABLED) {
var webVrController_1 = gamepad;
webVrController_1.deviceScaleFactor = _this.deviceScaleFactor;
webVrController_1._deviceToWorld.copyFrom(_this._deviceToWorld);
if (_this.webVROptions.controllerMeshes) {
if (webVrController_1.defaultModel) {
webVrController_1.defaultModel.setEnabled(true);
}
else {
// Load the meshes
webVrController_1.initControllerMesh(_this.getScene(), function (loadedMesh) {
loadedMesh.scaling.scaleInPlace(_this.deviceScaleFactor);
_this.onControllerMeshLoadedObservable.notifyObservers(webVrController_1);
if (_this.webVROptions.defaultLightingOnControllers) {
if (!_this._lightOnControllers) {
_this._lightOnControllers = new BABYLON.HemisphericLight("vrControllersLight", new BABYLON.Vector3(0, 1, 0), _this.getScene());
}
var activateLightOnSubMeshes_1 = function (mesh, light) {
var children = mesh.getChildren();
if (children.length !== 0) {
children.forEach(function (mesh) {
light.includedOnlyMeshes.push(mesh);
activateLightOnSubMeshes_1(mesh, light);
});
}
};
_this._lightOnControllers.includedOnlyMeshes.push(loadedMesh);
activateLightOnSubMeshes_1(loadedMesh, _this._lightOnControllers);
}
});
}
}
webVrController_1.attachToPoseControlledCamera(_this);
// since this is async - sanity check. Is the controller already stored?
if (_this.controllers.indexOf(webVrController_1) === -1) {
//add to the controllers array
_this.controllers.push(webVrController_1);
// Forced to add some control code for Vive as it doesn't always fill properly the "hand" property
// Sometimes, both controllers are set correctly (left and right), sometimes none, sometimes only one of them...
// So we're overriding setting left & right manually to be sure
var firstViveWandDetected = false;
for (var i = 0; i < _this.controllers.length; i++) {
if (_this.controllers[i].controllerType === BABYLON.PoseEnabledControllerType.VIVE) {
if (!firstViveWandDetected) {
firstViveWandDetected = true;
_this.controllers[i].hand = "left";
}
else {
_this.controllers[i].hand = "right";
}
}
}
//did we find enough controllers? Great! let the developer know.
if (_this.controllers.length >= 2) {
_this.onControllersAttachedObservable.notifyObservers(_this.controllers);
}
}
}
});
};
return WebVRFreeCamera;
}(BABYLON.FreeCamera));
BABYLON.WebVRFreeCamera = WebVRFreeCamera;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.webVRCamera.js.map
var BABYLON;
(function (BABYLON) {
BABYLON.Node.AddNodeConstructor("DeviceOrientationCamera", function (name, scene) {
return function () { return new DeviceOrientationCamera(name, BABYLON.Vector3.Zero(), scene); };
});
// We're mainly based on the logic defined into the FreeCamera code
/**
* This is a camera specifically designed to react to device orientation events such as a modern mobile device
* being tilted forward or back and left or right.
*/
var DeviceOrientationCamera = /** @class */ (function (_super) {
__extends(DeviceOrientationCamera, _super);
/**
* Creates a new device orientation camera
* @param name The name of the camera
* @param position The start position camera
* @param scene The scene the camera belongs to
*/
function DeviceOrientationCamera(name, position, scene) {
var _this = _super.call(this, name, position, scene) || this;
_this._quaternionCache = new BABYLON.Quaternion();
_this.inputs.addDeviceOrientation();
return _this;
}
/**
* Gets the current instance class name ("DeviceOrientationCamera").
* This helps avoiding instanceof at run time.
* @returns the class name
*/
DeviceOrientationCamera.prototype.getClassName = function () {
return "DeviceOrientationCamera";
};
/**
* Checks and applies the current values of the inputs to the camera. (Internal use only)
*/
DeviceOrientationCamera.prototype._checkInputs = function () {
_super.prototype._checkInputs.call(this);
this._quaternionCache.copyFrom(this.rotationQuaternion);
if (this._initialQuaternion) {
this._initialQuaternion.multiplyToRef(this.rotationQuaternion, this.rotationQuaternion);
}
};
/**
* Reset the camera to its default orientation on the specified axis only.
* @param axis The axis to reset
*/
DeviceOrientationCamera.prototype.resetToCurrentRotation = function (axis) {
var _this = this;
if (axis === void 0) { axis = BABYLON.Axis.Y; }
//can only work if this camera has a rotation quaternion already.
if (!this.rotationQuaternion)
return;
if (!this._initialQuaternion) {
this._initialQuaternion = new BABYLON.Quaternion();
}
this._initialQuaternion.copyFrom(this._quaternionCache || this.rotationQuaternion);
['x', 'y', 'z'].forEach(function (axisName) {
if (!axis[axisName]) {
_this._initialQuaternion[axisName] = 0;
}
else {
_this._initialQuaternion[axisName] *= -1;
}
});
this._initialQuaternion.normalize();
//force rotation update
this._initialQuaternion.multiplyToRef(this.rotationQuaternion, this.rotationQuaternion);
};
return DeviceOrientationCamera;
}(BABYLON.FreeCamera));
BABYLON.DeviceOrientationCamera = DeviceOrientationCamera;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.deviceOrientationCamera.js.map
var BABYLON;
(function (BABYLON) {
BABYLON.Node.AddNodeConstructor("VRDeviceOrientationFreeCamera", function (name, scene) {
return function () { return new VRDeviceOrientationFreeCamera(name, BABYLON.Vector3.Zero(), scene); };
});
var VRDeviceOrientationFreeCamera = /** @class */ (function (_super) {
__extends(VRDeviceOrientationFreeCamera, _super);
function VRDeviceOrientationFreeCamera(name, position, scene, compensateDistortion, vrCameraMetrics) {
if (compensateDistortion === void 0) { compensateDistortion = true; }
if (vrCameraMetrics === void 0) { vrCameraMetrics = BABYLON.VRCameraMetrics.GetDefault(); }
var _this = _super.call(this, name, position, scene) || this;
vrCameraMetrics.compensateDistortion = compensateDistortion;
_this.setCameraRigMode(BABYLON.Camera.RIG_MODE_VR, { vrCameraMetrics: vrCameraMetrics });
return _this;
}
VRDeviceOrientationFreeCamera.prototype.getClassName = function () {
return "VRDeviceOrientationFreeCamera";
};
return VRDeviceOrientationFreeCamera;
}(BABYLON.DeviceOrientationCamera));
BABYLON.VRDeviceOrientationFreeCamera = VRDeviceOrientationFreeCamera;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.vrDeviceOrientationFreeCamera.js.map
var BABYLON;
(function (BABYLON) {
BABYLON.Node.AddNodeConstructor("VRDeviceOrientationFreeCamera", function (name, scene) {
return function () { return new VRDeviceOrientationArcRotateCamera(name, 0, 0, 1.0, BABYLON.Vector3.Zero(), scene); };
});
var VRDeviceOrientationArcRotateCamera = /** @class */ (function (_super) {
__extends(VRDeviceOrientationArcRotateCamera, _super);
function VRDeviceOrientationArcRotateCamera(name, alpha, beta, radius, target, scene, compensateDistortion, vrCameraMetrics) {
if (compensateDistortion === void 0) { compensateDistortion = true; }
if (vrCameraMetrics === void 0) { vrCameraMetrics = BABYLON.VRCameraMetrics.GetDefault(); }
var _this = _super.call(this, name, alpha, beta, radius, target, scene) || this;
vrCameraMetrics.compensateDistortion = compensateDistortion;
_this.setCameraRigMode(BABYLON.Camera.RIG_MODE_VR, { vrCameraMetrics: vrCameraMetrics });
_this.inputs.addVRDeviceOrientation();
return _this;
}
VRDeviceOrientationArcRotateCamera.prototype.getClassName = function () {
return "VRDeviceOrientationArcRotateCamera";
};
return VRDeviceOrientationArcRotateCamera;
}(BABYLON.ArcRotateCamera));
BABYLON.VRDeviceOrientationArcRotateCamera = VRDeviceOrientationArcRotateCamera;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.vrDeviceOrientationArcRotateCamera.js.map
var BABYLON;
(function (BABYLON) {
BABYLON.Node.AddNodeConstructor("VRDeviceOrientationGamepadCamera", function (name, scene) {
return function () { return new VRDeviceOrientationGamepadCamera(name, BABYLON.Vector3.Zero(), scene); };
});
var VRDeviceOrientationGamepadCamera = /** @class */ (function (_super) {
__extends(VRDeviceOrientationGamepadCamera, _super);
function VRDeviceOrientationGamepadCamera(name, position, scene, compensateDistortion, vrCameraMetrics) {
if (compensateDistortion === void 0) { compensateDistortion = true; }
if (vrCameraMetrics === void 0) { vrCameraMetrics = BABYLON.VRCameraMetrics.GetDefault(); }
var _this = _super.call(this, name, position, scene, compensateDistortion, vrCameraMetrics) || this;
_this.inputs.addGamepad();
return _this;
}
VRDeviceOrientationGamepadCamera.prototype.getClassName = function () {
return "VRDeviceOrientationGamepadCamera";
};
return VRDeviceOrientationGamepadCamera;
}(BABYLON.VRDeviceOrientationFreeCamera));
BABYLON.VRDeviceOrientationGamepadCamera = VRDeviceOrientationGamepadCamera;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.vrDeviceOrientationGamepadCamera.js.map
var BABYLON;
(function (BABYLON) {
var VRExperienceHelperGazer = /** @class */ (function () {
function VRExperienceHelperGazer(scene, gazeTrackerToClone) {
if (gazeTrackerToClone === void 0) { gazeTrackerToClone = null; }
this.scene = scene;
this._pointerDownOnMeshAsked = false;
this._isActionableMesh = false;
this._teleportationRequestInitiated = false;
this._teleportationBackRequestInitiated = false;
this._rotationRightAsked = false;
this._rotationLeftAsked = false;
this._dpadPressed = true;
this._activePointer = false;
this._id = VRExperienceHelperGazer._idCounter++;
// Gaze tracker
if (!gazeTrackerToClone) {
this._gazeTracker = BABYLON.Mesh.CreateTorus("gazeTracker", 0.0035, 0.0025, 20, scene, false);
this._gazeTracker.bakeCurrentTransformIntoVertices();
this._gazeTracker.isPickable = false;
this._gazeTracker.isVisible = false;
var targetMat = new BABYLON.StandardMaterial("targetMat", scene);
targetMat.specularColor = BABYLON.Color3.Black();
targetMat.emissiveColor = new BABYLON.Color3(0.7, 0.7, 0.7);
targetMat.backFaceCulling = false;
this._gazeTracker.material = targetMat;
}
else {
this._gazeTracker = gazeTrackerToClone.clone("gazeTracker");
}
}
VRExperienceHelperGazer.prototype._getForwardRay = function (length) {
return new BABYLON.Ray(BABYLON.Vector3.Zero(), new BABYLON.Vector3(0, 0, length));
};
VRExperienceHelperGazer.prototype._selectionPointerDown = function () {
this._pointerDownOnMeshAsked = true;
if (this._currentHit) {
this.scene.simulatePointerDown(this._currentHit, { pointerId: this._id });
}
};
VRExperienceHelperGazer.prototype._selectionPointerUp = function () {
if (this._currentHit) {
this.scene.simulatePointerUp(this._currentHit, { pointerId: this._id });
}
this._pointerDownOnMeshAsked = false;
};
VRExperienceHelperGazer.prototype._activatePointer = function () {
this._activePointer = true;
};
VRExperienceHelperGazer.prototype._deactivatePointer = function () {
this._activePointer = false;
};
VRExperienceHelperGazer.prototype._updatePointerDistance = function (distance) {
if (distance === void 0) { distance = 100; }
};
VRExperienceHelperGazer.prototype.dispose = function () {
this._interactionsEnabled = false;
this._teleportationEnabled = false;
if (this._gazeTracker) {
this._gazeTracker.dispose();
}
};
VRExperienceHelperGazer._idCounter = 0;
return VRExperienceHelperGazer;
}());
var VRExperienceHelperControllerGazer = /** @class */ (function (_super) {
__extends(VRExperienceHelperControllerGazer, _super);
function VRExperienceHelperControllerGazer(webVRController, scene, gazeTrackerToClone) {
var _this = _super.call(this, scene, gazeTrackerToClone) || this;
_this.webVRController = webVRController;
// Laser pointer
_this._laserPointer = BABYLON.Mesh.CreateCylinder("laserPointer", 1, 0.004, 0.0002, 20, 1, scene, false);
var laserPointerMaterial = new BABYLON.StandardMaterial("laserPointerMat", scene);
laserPointerMaterial.emissiveColor = new BABYLON.Color3(0.7, 0.7, 0.7);
laserPointerMaterial.alpha = 0.6;
_this._laserPointer.material = laserPointerMaterial;
_this._laserPointer.rotation.x = Math.PI / 2;
_this._laserPointer.position.z = -0.5;
_this._laserPointer.isVisible = false;
_this._laserPointer.isPickable = false;
if (!webVRController.mesh) {
// Create an empty mesh that is used prior to loading the high quality model
var preloadMesh = new BABYLON.Mesh("preloadControllerMesh", scene);
var preloadPointerPose = new BABYLON.Mesh(BABYLON.PoseEnabledController.POINTING_POSE, scene);
preloadPointerPose.rotation.x = -0.7;
preloadMesh.addChild(preloadPointerPose);
webVRController.attachToMesh(preloadMesh);
}
_this._setLaserPointerParent(webVRController.mesh);
_this._meshAttachedObserver = webVRController._meshAttachedObservable.add(function (mesh) {
_this._setLaserPointerParent(mesh);
});
return _this;
}
VRExperienceHelperControllerGazer.prototype._getForwardRay = function (length) {
return this.webVRController.getForwardRay(length);
};
VRExperienceHelperControllerGazer.prototype._activatePointer = function () {
_super.prototype._activatePointer.call(this);
this._laserPointer.isVisible = true;
};
VRExperienceHelperControllerGazer.prototype._deactivatePointer = function () {
_super.prototype._deactivatePointer.call(this);
this._laserPointer.isVisible = false;
};
VRExperienceHelperControllerGazer.prototype._setLaserPointerColor = function (color) {
this._laserPointer.material.emissiveColor = color;
};
VRExperienceHelperControllerGazer.prototype._setLaserPointerParent = function (mesh) {
var makeNotPick = function (root) {
root.isPickable = false;
root.getChildMeshes().forEach(function (c) {
makeNotPick(c);
});
};
makeNotPick(mesh);
var childMeshes = mesh.getChildMeshes();
this.webVRController._pointingPoseNode = null;
for (var i = 0; i < childMeshes.length; i++) {
if (childMeshes[i].name && childMeshes[i].name.indexOf(BABYLON.PoseEnabledController.POINTING_POSE) >= 0) {
mesh = childMeshes[i];
this.webVRController._pointingPoseNode = mesh;
break;
}
}
this._laserPointer.parent = mesh;
};
VRExperienceHelperControllerGazer.prototype._updatePointerDistance = function (distance) {
if (distance === void 0) { distance = 100; }
this._laserPointer.scaling.y = distance;
this._laserPointer.position.z = -distance / 2;
};
VRExperienceHelperControllerGazer.prototype.dispose = function () {
_super.prototype.dispose.call(this);
this._laserPointer.dispose();
if (this._meshAttachedObserver) {
this.webVRController._meshAttachedObservable.remove(this._meshAttachedObserver);
}
};
return VRExperienceHelperControllerGazer;
}(VRExperienceHelperGazer));
var VRExperienceHelperCameraGazer = /** @class */ (function (_super) {
__extends(VRExperienceHelperCameraGazer, _super);
function VRExperienceHelperCameraGazer(getCamera, scene) {
var _this = _super.call(this, scene) || this;
_this.getCamera = getCamera;
return _this;
}
VRExperienceHelperCameraGazer.prototype._getForwardRay = function (length) {
var camera = this.getCamera();
if (camera) {
return camera.getForwardRay(length);
}
else {
return new BABYLON.Ray(BABYLON.Vector3.Zero(), BABYLON.Vector3.Forward());
}
};
return VRExperienceHelperCameraGazer;
}(VRExperienceHelperGazer));
/**
* Helps to quickly add VR support to an existing scene.
* See http://doc.babylonjs.com/how_to/webvr_helper
*/
var VRExperienceHelper = /** @class */ (function () {
/**
* Instantiates a VRExperienceHelper.
* Helps to quickly add VR support to an existing scene.
* @param scene The scene the VRExperienceHelper belongs to.
* @param webVROptions Options to modify the vr experience helper's behavior.
*/
function VRExperienceHelper(scene, /** Options to modify the vr experience helper's behavior. */ webVROptions) {
if (webVROptions === void 0) { webVROptions = {}; }
var _this = this;
this.webVROptions = webVROptions;
// Can the system support WebVR, even if a headset isn't plugged in?
this._webVRsupported = false;
// If WebVR is supported, is a headset plugged in and are we ready to present?
this._webVRready = false;
// Are we waiting for the requestPresent callback to complete?
this._webVRrequesting = false;
// Are we presenting to the headset right now?
this._webVRpresenting = false;
// Are we presenting in the fullscreen fallback?
this._fullscreenVRpresenting = false;
/**
* Observable raised when entering VR.
*/
this.onEnteringVRObservable = new BABYLON.Observable();
/**
* Observable raised when exiting VR.
*/
this.onExitingVRObservable = new BABYLON.Observable();
/**
* Observable raised when controller mesh is loaded.
*/
this.onControllerMeshLoadedObservable = new BABYLON.Observable();
this._useCustomVRButton = false;
this._teleportationRequested = false;
this._teleportActive = false;
this._floorMeshesCollection = [];
this._rotationAllowed = true;
this._teleportBackwardsVector = new BABYLON.Vector3(0, -1, -1);
this._isDefaultTeleportationTarget = true;
this._teleportationFillColor = "#444444";
this._teleportationBorderColor = "#FFFFFF";
this._rotationAngle = 0;
this._haloCenter = new BABYLON.Vector3(0, 0, 0);
this._padSensibilityUp = 0.65;
this._padSensibilityDown = 0.35;
this.leftController = null;
this.rightController = null;
/**
* Observable raised when a new mesh is selected based on meshSelectionPredicate
*/
this.onNewMeshSelected = new BABYLON.Observable();
/**
* Observable raised when a new mesh is picked based on meshSelectionPredicate
*/
this.onNewMeshPicked = new BABYLON.Observable();
/**
* Observable raised before camera teleportation
*/
this.onBeforeCameraTeleport = new BABYLON.Observable();
/**
* Observable raised after camera teleportation
*/
this.onAfterCameraTeleport = new BABYLON.Observable();
/**
* Observable raised when current selected mesh gets unselected
*/
this.onSelectedMeshUnselected = new BABYLON.Observable();
/**
* Set teleportation enabled. If set to false camera teleportation will be disabled but camera rotation will be kept.
*/
this.teleportationEnabled = true;
this._teleportationInitialized = false;
this._interactionsEnabled = false;
this._interactionsRequested = false;
this._displayGaze = true;
this._displayLaserPointer = true;
this._onResize = function () {
_this.moveButtonToBottomRight();
if (_this._fullscreenVRpresenting && _this._webVRready) {
_this.exitVR();
}
};
this._onFullscreenChange = function () {
if (document.fullscreen !== undefined) {
_this._fullscreenVRpresenting = document.fullscreen;
}
else if (document.mozFullScreen !== undefined) {
_this._fullscreenVRpresenting = document.mozFullScreen;
}
else if (document.webkitIsFullScreen !== undefined) {
_this._fullscreenVRpresenting = document.webkitIsFullScreen;
}
else if (document.msIsFullScreen !== undefined) {
_this._fullscreenVRpresenting = document.msIsFullScreen;
}
else if (document.msFullscreenElement !== undefined) {
_this._fullscreenVRpresenting = document.msFullscreenElement;
}
if (!_this._fullscreenVRpresenting && _this._canvas) {
_this.exitVR();
if (!_this._useCustomVRButton) {
_this._btnVR.style.top = _this._canvas.offsetTop + _this._canvas.offsetHeight - 70 + "px";
_this._btnVR.style.left = _this._canvas.offsetLeft + _this._canvas.offsetWidth - 100 + "px";
}
}
};
this.beforeRender = function () {
if (_this.leftController && _this.leftController._activePointer) {
_this._castRayAndSelectObject(_this.leftController);
}
if (_this.rightController && _this.rightController._activePointer) {
_this._castRayAndSelectObject(_this.rightController);
}
if (_this._noControllerIsActive) {
_this._castRayAndSelectObject(_this._cameraGazer);
}
else {
_this._cameraGazer._gazeTracker.isVisible = false;
}
};
this._onNewGamepadConnected = function (gamepad) {
if (gamepad.type !== BABYLON.Gamepad.POSE_ENABLED) {
if (gamepad.leftStick) {
gamepad.onleftstickchanged(function (stickValues) {
if (_this._teleportationInitialized && _this.teleportationEnabled) {
// Listening to classic/xbox gamepad only if no VR controller is active
if ((!_this.leftController && !_this.rightController) ||
((_this.leftController && !_this.leftController._activePointer) &&
(_this.rightController && !_this.rightController._activePointer))) {
_this._checkTeleportWithRay(stickValues, _this._cameraGazer);
_this._checkTeleportBackwards(stickValues, _this._cameraGazer);
}
}
});
}
if (gamepad.rightStick) {
gamepad.onrightstickchanged(function (stickValues) {
if (_this._teleportationInitialized) {
_this._checkRotate(stickValues, _this._cameraGazer);
}
});
}
if (gamepad.type === BABYLON.Gamepad.XBOX) {
gamepad.onbuttondown(function (buttonPressed) {
if (_this._interactionsEnabled && buttonPressed === BABYLON.Xbox360Button.A) {
_this._cameraGazer._selectionPointerDown();
}
});
gamepad.onbuttonup(function (buttonPressed) {
if (_this._interactionsEnabled && buttonPressed === BABYLON.Xbox360Button.A) {
_this._cameraGazer._selectionPointerUp();
}
});
}
}
else {
var webVRController = gamepad;
var controller = new VRExperienceHelperControllerGazer(webVRController, _this._scene, _this._cameraGazer._gazeTracker);
if (webVRController.hand === "right" || (_this.leftController && _this.leftController.webVRController != webVRController)) {
_this.rightController = controller;
}
else {
_this.leftController = controller;
}
_this._tryEnableInteractionOnController(controller);
}
};
// This only succeeds if the controller's mesh exists for the controller so this must be called whenever new controller is connected or when mesh is loaded
this._tryEnableInteractionOnController = function (controller) {
if (_this._interactionsRequested && !controller._interactionsEnabled) {
_this._enableInteractionOnController(controller);
}
if (_this._teleportationRequested && !controller._teleportationEnabled) {
_this._enableTeleportationOnController(controller);
}
};
this._onNewGamepadDisconnected = function (gamepad) {
if (gamepad instanceof BABYLON.WebVRController) {
if (gamepad.hand === "left" && _this.leftController != null) {
_this.leftController.dispose();
_this.leftController = null;
}
if (gamepad.hand === "right" && _this.rightController != null) {
_this.rightController.dispose();
_this.rightController = null;
}
}
};
this._workingVector = BABYLON.Vector3.Zero();
this._workingQuaternion = BABYLON.Quaternion.Identity();
this._workingMatrix = BABYLON.Matrix.Identity();
this._scene = scene;
this._canvas = scene.getEngine().getRenderingCanvas();
// Parse options
if (webVROptions.createFallbackVRDeviceOrientationFreeCamera === undefined) {
webVROptions.createFallbackVRDeviceOrientationFreeCamera = true;
}
if (webVROptions.createDeviceOrientationCamera === undefined) {
webVROptions.createDeviceOrientationCamera = true;
}
if (webVROptions.laserToggle === undefined) {
webVROptions.laserToggle = true;
}
if (webVROptions.defaultHeight === undefined) {
webVROptions.defaultHeight = 1.7;
}
if (webVROptions.useCustomVRButton) {
this._useCustomVRButton = true;
if (webVROptions.customVRButton) {
this._btnVR = webVROptions.customVRButton;
}
}
if (webVROptions.rayLength) {
this._rayLength = webVROptions.rayLength;
}
this._defaultHeight = webVROptions.defaultHeight;
if (webVROptions.positionScale) {
this._rayLength *= webVROptions.positionScale;
this._defaultHeight *= webVROptions.positionScale;
}
// Set position
if (this._scene.activeCamera) {
this._position = this._scene.activeCamera.position.clone();
}
else {
this._position = new BABYLON.Vector3(0, this._defaultHeight, 0);
}
// Set non-vr camera
if (webVROptions.createDeviceOrientationCamera || !this._scene.activeCamera) {
this._deviceOrientationCamera = new BABYLON.DeviceOrientationCamera("deviceOrientationVRHelper", this._position.clone(), scene);
// Copy data from existing camera
if (this._scene.activeCamera) {
this._deviceOrientationCamera.minZ = this._scene.activeCamera.minZ;
this._deviceOrientationCamera.maxZ = this._scene.activeCamera.maxZ;
// Set rotation from previous camera
if (this._scene.activeCamera instanceof BABYLON.TargetCamera && this._scene.activeCamera.rotation) {
var targetCamera = this._scene.activeCamera;
if (targetCamera.rotationQuaternion) {
this._deviceOrientationCamera.rotationQuaternion.copyFrom(targetCamera.rotationQuaternion);
}
else {
this._deviceOrientationCamera.rotationQuaternion.copyFrom(BABYLON.Quaternion.RotationYawPitchRoll(targetCamera.rotation.y, targetCamera.rotation.x, targetCamera.rotation.z));
}
this._deviceOrientationCamera.rotation = targetCamera.rotation.clone();
}
}
this._scene.activeCamera = this._deviceOrientationCamera;
if (this._canvas) {
this._scene.activeCamera.attachControl(this._canvas);
}
}
else {
this._existingCamera = this._scene.activeCamera;
}
// Create VR cameras
if (webVROptions.createFallbackVRDeviceOrientationFreeCamera) {
this._vrDeviceOrientationCamera = new BABYLON.VRDeviceOrientationFreeCamera("VRDeviceOrientationVRHelper", this._position, this._scene);
}
this._webVRCamera = new BABYLON.WebVRFreeCamera("WebVRHelper", this._position, this._scene, webVROptions);
this._webVRCamera.useStandingMatrix();
this._cameraGazer = new VRExperienceHelperCameraGazer(function () { return _this.currentVRCamera; }, scene);
// Create default button
if (!this._useCustomVRButton) {
this._btnVR = document.createElement("BUTTON");
this._btnVR.className = "babylonVRicon";
this._btnVR.id = "babylonVRiconbtn";
this._btnVR.title = "Click to switch to VR";
var css = ".babylonVRicon { position: absolute; right: 20px; height: 50px; width: 80px; background-color: rgba(51,51,51,0.7); background-image: url(data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%222048%22%20height%3D%221152%22%20viewBox%3D%220%200%202048%201152%22%20version%3D%221.1%22%3E%3Cpath%20transform%3D%22rotate%28180%201024%2C576.0000000000001%29%22%20d%3D%22m1109%2C896q17%2C0%2030%2C-12t13%2C-30t-12.5%2C-30.5t-30.5%2C-12.5l-170%2C0q-18%2C0%20-30.5%2C12.5t-12.5%2C30.5t13%2C30t30%2C12l170%2C0zm-85%2C256q59%2C0%20132.5%2C-1.5t154.5%2C-5.5t164.5%2C-11.5t163%2C-20t150%2C-30t124.5%2C-41.5q23%2C-11%2042%2C-24t38%2C-30q27%2C-25%2041%2C-61.5t14%2C-72.5l0%2C-257q0%2C-123%20-47%2C-232t-128%2C-190t-190%2C-128t-232%2C-47l-81%2C0q-37%2C0%20-68.5%2C14t-60.5%2C34.5t-55.5%2C45t-53%2C45t-53%2C34.5t-55.5%2C14t-55.5%2C-14t-53%2C-34.5t-53%2C-45t-55.5%2C-45t-60.5%2C-34.5t-68.5%2C-14l-81%2C0q-123%2C0%20-232%2C47t-190%2C128t-128%2C190t-47%2C232l0%2C257q0%2C68%2038%2C115t97%2C73q54%2C24%20124.5%2C41.5t150%2C30t163%2C20t164.5%2C11.5t154.5%2C5.5t132.5%2C1.5zm939%2C-298q0%2C39%20-24.5%2C67t-58.5%2C42q-54%2C23%20-122%2C39.5t-143.5%2C28t-155.5%2C19t-157%2C11t-148.5%2C5t-129.5%2C1.5q-59%2C0%20-130%2C-1.5t-148%2C-5t-157%2C-11t-155.5%2C-19t-143.5%2C-28t-122%2C-39.5q-34%2C-14%20-58.5%2C-42t-24.5%2C-67l0%2C-257q0%2C-106%2040.5%2C-199t110%2C-162.5t162.5%2C-109.5t199%2C-40l81%2C0q27%2C0%2052%2C14t50%2C34.5t51%2C44.5t55.5%2C44.5t63.5%2C34.5t74%2C14t74%2C-14t63.5%2C-34.5t55.5%2C-44.5t51%2C-44.5t50%2C-34.5t52%2C-14l14%2C0q37%2C0%2070%2C0.5t64.5%2C4.5t63.5%2C12t68%2C23q71%2C30%20128.5%2C78.5t98.5%2C110t63.5%2C133.5t22.5%2C149l0%2C257z%22%20fill%3D%22white%22%20/%3E%3C/svg%3E%0A); background-size: 80%; background-repeat:no-repeat; background-position: center; border: none; outline: none; transition: transform 0.125s ease-out } .babylonVRicon:hover { transform: scale(1.05) } .babylonVRicon:active {background-color: rgba(51,51,51,1) } .babylonVRicon:focus {background-color: rgba(51,51,51,1) }";
css += ".babylonVRicon.vrdisplaypresenting { display: none; }";
// TODO: Add user feedback so that they know what state the VRDisplay is in (disconnected, connected, entering-VR)
// css += ".babylonVRicon.vrdisplaysupported { }";
// css += ".babylonVRicon.vrdisplayready { }";
// css += ".babylonVRicon.vrdisplayrequesting { }";
var style = document.createElement('style');
style.appendChild(document.createTextNode(css));
document.getElementsByTagName('head')[0].appendChild(style);
this.moveButtonToBottomRight();
}
// VR button click event
if (this._btnVR) {
this._btnVR.addEventListener("click", function () {
if (!_this.isInVRMode) {
_this.enterVR();
}
else {
_this.exitVR();
}
});
}
// Window events
window.addEventListener("resize", this._onResize);
document.addEventListener("fullscreenchange", this._onFullscreenChange, false);
document.addEventListener("mozfullscreenchange", this._onFullscreenChange, false);
document.addEventListener("webkitfullscreenchange", this._onFullscreenChange, false);
document.addEventListener("msfullscreenchange", this._onFullscreenChange, false);
document.onmsfullscreenchange = this._onFullscreenChange;
// Display vr button when headset is connected
if (webVROptions.createFallbackVRDeviceOrientationFreeCamera) {
this.displayVRButton();
}
else {
this._scene.getEngine().onVRDisplayChangedObservable.add(function (e) {
if (e.vrDisplay) {
_this.displayVRButton();
}
});
}
// Exiting VR mode using 'ESC' key on desktop
this._onKeyDown = function (event) {
if (event.keyCode === 27 && _this.isInVRMode) {
_this.exitVR();
}
};
document.addEventListener("keydown", this._onKeyDown);
// Exiting VR mode double tapping the touch screen
this._scene.onPrePointerObservable.add(function (pointerInfo, eventState) {
if (_this.isInVRMode) {
_this.exitVR();
if (_this._fullscreenVRpresenting) {
_this._scene.getEngine().switchFullscreen(true);
}
}
}, BABYLON.PointerEventTypes.POINTERDOUBLETAP, false);
// Listen for WebVR display changes
this._onVRDisplayChanged = function (eventArgs) { return _this.onVRDisplayChanged(eventArgs); };
this._onVrDisplayPresentChange = function () { return _this.onVrDisplayPresentChange(); };
this._onVRRequestPresentStart = function () {
_this._webVRrequesting = true;
_this.updateButtonVisibility();
};
this._onVRRequestPresentComplete = function (success) {
_this._webVRrequesting = false;
_this.updateButtonVisibility();
};
scene.getEngine().onVRDisplayChangedObservable.add(this._onVRDisplayChanged);
scene.getEngine().onVRRequestPresentStart.add(this._onVRRequestPresentStart);
scene.getEngine().onVRRequestPresentComplete.add(this._onVRRequestPresentComplete);
window.addEventListener('vrdisplaypresentchange', this._onVrDisplayPresentChange);
scene.onDisposeObservable.add(function () {
_this.dispose();
});
// Gamepad connection events
this._webVRCamera.onControllerMeshLoadedObservable.add(function (webVRController) { return _this._onDefaultMeshLoaded(webVRController); });
this._scene.gamepadManager.onGamepadConnectedObservable.add(this._onNewGamepadConnected);
this._scene.gamepadManager.onGamepadDisconnectedObservable.add(this._onNewGamepadDisconnected);
this.updateButtonVisibility();
//create easing functions
this._circleEase = new BABYLON.CircleEase();
this._circleEase.setEasingMode(BABYLON.EasingFunction.EASINGMODE_EASEINOUT);
if (this.webVROptions.floorMeshes) {
this.enableTeleportation({ floorMeshes: this.webVROptions.floorMeshes });
}
}
Object.defineProperty(VRExperienceHelper.prototype, "onEnteringVR", {
/** Return this.onEnteringVRObservable
* Note: This one is for backward compatibility. Please use onEnteringVRObservable directly
*/
get: function () {
return this.onEnteringVRObservable;
},
enumerable: true,
configurable: true
});
Object.defineProperty(VRExperienceHelper.prototype, "onExitingVR", {
/** Return this.onExitingVRObservable
* Note: This one is for backward compatibility. Please use onExitingVRObservable directly
*/
get: function () {
return this.onExitingVRObservable;
},
enumerable: true,
configurable: true
});
Object.defineProperty(VRExperienceHelper.prototype, "onControllerMeshLoaded", {
/** Return this.onControllerMeshLoadedObservable
* Note: This one is for backward compatibility. Please use onControllerMeshLoadedObservable directly
*/
get: function () {
return this.onControllerMeshLoadedObservable;
},
enumerable: true,
configurable: true
});
Object.defineProperty(VRExperienceHelper.prototype, "teleportationTarget", {
/**
* The mesh used to display where the user is going to teleport.
*/
get: function () {
return this._teleportationTarget;
},
/**
* Sets the mesh to be used to display where the user is going to teleport.
*/
set: function (value) {
if (value) {
value.name = "teleportationTarget";
this._isDefaultTeleportationTarget = false;
this._teleportationTarget = value;
}
},
enumerable: true,
configurable: true
});
Object.defineProperty(VRExperienceHelper.prototype, "gazeTrackerMesh", {
/**
* The mesh used to display where the user is selecting,
* when set bakeCurrentTransformIntoVertices will be called on the mesh.
* See http://doc.babylonjs.com/resources/baking_transformations
*/
get: function () {
return this._cameraGazer._gazeTracker;
},
set: function (value) {
if (value) {
this._cameraGazer._gazeTracker = value;
this._cameraGazer._gazeTracker.bakeCurrentTransformIntoVertices();
this._cameraGazer._gazeTracker.isPickable = false;
this._cameraGazer._gazeTracker.isVisible = false;
this._cameraGazer._gazeTracker.name = "gazeTracker";
if (this.leftController) {
this.leftController._gazeTracker = this._cameraGazer._gazeTracker.clone("gazeTracker");
}
if (this.rightController) {
this.rightController._gazeTracker = this._cameraGazer._gazeTracker.clone("gazeTracker");
}
}
},
enumerable: true,
configurable: true
});
Object.defineProperty(VRExperienceHelper.prototype, "displayGaze", {
/**
* If the ray of the gaze should be displayed.
*/
get: function () {
return this._displayGaze;
},
/**
* Sets if the ray of the gaze should be displayed.
*/
set: function (value) {
this._displayGaze = value;
if (!value) {
this._cameraGazer._gazeTracker.isVisible = false;
if (this.leftController) {
this.leftController._gazeTracker.isVisible = false;
}
if (this.rightController) {
this.rightController._gazeTracker.isVisible = false;
}
}
},
enumerable: true,
configurable: true
});
Object.defineProperty(VRExperienceHelper.prototype, "displayLaserPointer", {
/**
* If the ray of the LaserPointer should be displayed.
*/
get: function () {
return this._displayLaserPointer;
},
/**
* Sets if the ray of the LaserPointer should be displayed.
*/
set: function (value) {
this._displayLaserPointer = value;
if (!value) {
if (this.rightController) {
this.rightController._deactivatePointer();
this.rightController._gazeTracker.isVisible = false;
}
if (this.leftController) {
this.leftController._deactivatePointer();
this.leftController._gazeTracker.isVisible = false;
}
}
else {
if (this.rightController) {
this.rightController._activatePointer();
}
if (this.leftController) {
this.leftController._activatePointer();
}
}
},
enumerable: true,
configurable: true
});
Object.defineProperty(VRExperienceHelper.prototype, "deviceOrientationCamera", {
/**
* The deviceOrientationCamera used as the camera when not in VR.
*/
get: function () {
return this._deviceOrientationCamera;
},
enumerable: true,
configurable: true
});
Object.defineProperty(VRExperienceHelper.prototype, "currentVRCamera", {
/**
* Based on the current WebVR support, returns the current VR camera used.
*/
get: function () {
if (this._webVRready) {
return this._webVRCamera;
}
else {
return this._scene.activeCamera;
}
},
enumerable: true,
configurable: true
});
Object.defineProperty(VRExperienceHelper.prototype, "webVRCamera", {
/**
* The webVRCamera which is used when in VR.
*/
get: function () {
return this._webVRCamera;
},
enumerable: true,
configurable: true
});
Object.defineProperty(VRExperienceHelper.prototype, "vrDeviceOrientationCamera", {
/**
* The deviceOrientationCamera that is used as a fallback when vr device is not connected.
*/
get: function () {
return this._vrDeviceOrientationCamera;
},
enumerable: true,
configurable: true
});
Object.defineProperty(VRExperienceHelper.prototype, "_teleportationRequestInitiated", {
get: function () {
var result = this._cameraGazer._teleportationRequestInitiated
|| (this.leftController !== null && this.leftController._teleportationRequestInitiated)
|| (this.rightController !== null && this.rightController._teleportationRequestInitiated);
return result;
},
enumerable: true,
configurable: true
});
// Raised when one of the controller has loaded successfully its associated default mesh
VRExperienceHelper.prototype._onDefaultMeshLoaded = function (webVRController) {
if (this.leftController && this.leftController.webVRController == webVRController) {
if (webVRController.mesh) {
this.leftController._setLaserPointerParent(webVRController.mesh);
}
}
if (this.rightController && this.rightController.webVRController == webVRController) {
if (webVRController.mesh) {
this.rightController._setLaserPointerParent(webVRController.mesh);
}
}
try {
this.onControllerMeshLoadedObservable.notifyObservers(webVRController);
}
catch (err) {
BABYLON.Tools.Warn("Error in your custom logic onControllerMeshLoaded: " + err);
}
};
Object.defineProperty(VRExperienceHelper.prototype, "isInVRMode", {
/**
* Gets a value indicating if we are currently in VR mode.
*/
get: function () {
return this._webVRpresenting || this._fullscreenVRpresenting;
},
enumerable: true,
configurable: true
});
VRExperienceHelper.prototype.onVrDisplayPresentChange = function () {
var vrDisplay = this._scene.getEngine().getVRDevice();
if (vrDisplay) {
var wasPresenting = this._webVRpresenting;
// A VR display is connected
this._webVRpresenting = vrDisplay.isPresenting;
if (wasPresenting && !this._webVRpresenting)
this.exitVR();
}
else {
BABYLON.Tools.Warn('Detected VRDisplayPresentChange on an unknown VRDisplay. Did you can enterVR on the vrExperienceHelper?');
}
this.updateButtonVisibility();
};
VRExperienceHelper.prototype.onVRDisplayChanged = function (eventArgs) {
this._webVRsupported = eventArgs.vrSupported;
this._webVRready = !!eventArgs.vrDisplay;
this._webVRpresenting = eventArgs.vrDisplay && eventArgs.vrDisplay.isPresenting;
this.updateButtonVisibility();
};
VRExperienceHelper.prototype.moveButtonToBottomRight = function () {
if (this._canvas && !this._useCustomVRButton) {
this._btnVR.style.top = this._canvas.offsetTop + this._canvas.offsetHeight - 70 + "px";
this._btnVR.style.left = this._canvas.offsetLeft + this._canvas.offsetWidth - 100 + "px";
}
};
VRExperienceHelper.prototype.displayVRButton = function () {
if (!this._useCustomVRButton && !this._btnVRDisplayed) {
document.body.appendChild(this._btnVR);
this._btnVRDisplayed = true;
}
};
VRExperienceHelper.prototype.updateButtonVisibility = function () {
if (!this._btnVR || this._useCustomVRButton) {
return;
}
this._btnVR.className = "babylonVRicon";
if (this.isInVRMode) {
this._btnVR.className += " vrdisplaypresenting";
}
else {
if (this._webVRready)
this._btnVR.className += " vrdisplayready";
if (this._webVRsupported)
this._btnVR.className += " vrdisplaysupported";
if (this._webVRrequesting)
this._btnVR.className += " vrdisplayrequesting";
}
};
/**
* Attempt to enter VR. If a headset is connected and ready, will request present on that.
* Otherwise, will use the fullscreen API.
*/
VRExperienceHelper.prototype.enterVR = function () {
if (this.onEnteringVRObservable) {
try {
this.onEnteringVRObservable.notifyObservers(this);
}
catch (err) {
BABYLON.Tools.Warn("Error in your custom logic onEnteringVR: " + err);
}
}
if (this._scene.activeCamera) {
this._position = this._scene.activeCamera.position.clone();
// make sure that we return to the last active camera
this._existingCamera = this._scene.activeCamera;
}
if (this._webVRrequesting)
return;
// If WebVR is supported and a headset is connected
if (this._webVRready) {
if (!this._webVRpresenting) {
this._webVRCamera.position = this._position;
this._scene.activeCamera = this._webVRCamera;
}
}
else if (this._vrDeviceOrientationCamera) {
this._vrDeviceOrientationCamera.position = this._position;
if (this._scene.activeCamera) {
this._vrDeviceOrientationCamera.minZ = this._scene.activeCamera.minZ;
}
this._scene.activeCamera = this._vrDeviceOrientationCamera;
this._scene.getEngine().switchFullscreen(true);
this.updateButtonVisibility();
}
if (this._scene.activeCamera && this._canvas) {
this._scene.activeCamera.attachControl(this._canvas);
}
if (this._interactionsEnabled) {
this._scene.registerBeforeRender(this.beforeRender);
}
};
/**
* Attempt to exit VR, or fullscreen.
*/
VRExperienceHelper.prototype.exitVR = function () {
if (this.onExitingVRObservable) {
try {
this.onExitingVRObservable.notifyObservers(this);
}
catch (err) {
BABYLON.Tools.Warn("Error in your custom logic onExitingVR: " + err);
}
}
if (this._webVRpresenting) {
this._scene.getEngine().disableVR();
}
if (this._scene.activeCamera) {
this._position = this._scene.activeCamera.position.clone();
}
if (this._deviceOrientationCamera) {
this._deviceOrientationCamera.position = this._position;
this._scene.activeCamera = this._deviceOrientationCamera;
if (this._canvas) {
this._scene.activeCamera.attachControl(this._canvas);
}
}
else if (this._existingCamera) {
this._existingCamera.position = this._position;
this._scene.activeCamera = this._existingCamera;
}
this.updateButtonVisibility();
if (this._interactionsEnabled) {
this._scene.unregisterBeforeRender(this.beforeRender);
}
// resize to update width and height when exiting vr exits fullscreen
this._scene.getEngine().resize();
};
Object.defineProperty(VRExperienceHelper.prototype, "position", {
/**
* The position of the vr experience helper.
*/
get: function () {
return this._position;
},
/**
* Sets the position of the vr experience helper.
*/
set: function (value) {
this._position = value;
if (this._scene.activeCamera) {
this._scene.activeCamera.position = value;
}
},
enumerable: true,
configurable: true
});
/**
* Enables controllers and user interactions such as selecting and object or clicking on an object.
*/
VRExperienceHelper.prototype.enableInteractions = function () {
var _this = this;
if (!this._interactionsEnabled) {
this._interactionsRequested = true;
if (this.leftController) {
this._enableInteractionOnController(this.leftController);
}
if (this.rightController) {
this._enableInteractionOnController(this.rightController);
}
this.raySelectionPredicate = function (mesh) {
return mesh.isVisible && mesh.isPickable;
};
this.meshSelectionPredicate = function (mesh) {
return true;
};
this._raySelectionPredicate = function (mesh) {
if (_this._isTeleportationFloor(mesh) || (mesh.name.indexOf("gazeTracker") === -1
&& mesh.name.indexOf("teleportationTarget") === -1
&& mesh.name.indexOf("torusTeleportation") === -1)) {
return _this.raySelectionPredicate(mesh);
}
return false;
};
this._interactionsEnabled = true;
}
};
Object.defineProperty(VRExperienceHelper.prototype, "_noControllerIsActive", {
get: function () {
return !(this.leftController && this.leftController._activePointer) && !(this.rightController && this.rightController._activePointer);
},
enumerable: true,
configurable: true
});
VRExperienceHelper.prototype._isTeleportationFloor = function (mesh) {
for (var i = 0; i < this._floorMeshesCollection.length; i++) {
if (this._floorMeshesCollection[i].id === mesh.id) {
return true;
}
}
if (this._floorMeshName && mesh.name === this._floorMeshName) {
return true;
}
return false;
};
/**
* Adds a floor mesh to be used for teleportation.
* @param floorMesh the mesh to be used for teleportation.
*/
VRExperienceHelper.prototype.addFloorMesh = function (floorMesh) {
if (!this._floorMeshesCollection) {
return;
}
if (this._floorMeshesCollection.indexOf(floorMesh) > -1) {
return;
}
this._floorMeshesCollection.push(floorMesh);
};
/**
* Removes a floor mesh from being used for teleportation.
* @param floorMesh the mesh to be removed.
*/
VRExperienceHelper.prototype.removeFloorMesh = function (floorMesh) {
if (!this._floorMeshesCollection) {
return;
}
var meshIndex = this._floorMeshesCollection.indexOf(floorMesh);
if (meshIndex !== -1) {
this._floorMeshesCollection.splice(meshIndex, 1);
}
};
/**
* Enables interactions and teleportation using the VR controllers and gaze.
* @param vrTeleportationOptions options to modify teleportation behavior.
*/
VRExperienceHelper.prototype.enableTeleportation = function (vrTeleportationOptions) {
if (vrTeleportationOptions === void 0) { vrTeleportationOptions = {}; }
if (!this._teleportationInitialized) {
this._teleportationRequested = true;
this.enableInteractions();
if (vrTeleportationOptions.floorMeshName) {
this._floorMeshName = vrTeleportationOptions.floorMeshName;
}
if (vrTeleportationOptions.floorMeshes) {
this._floorMeshesCollection = vrTeleportationOptions.floorMeshes;
}
if (this.leftController != null) {
this._enableTeleportationOnController(this.leftController);
}
if (this.rightController != null) {
this._enableTeleportationOnController(this.rightController);
}
// Creates an image processing post process for the vignette not relying
// on the main scene configuration for image processing to reduce setup and spaces
// (gamma/linear) conflicts.
var imageProcessingConfiguration = new BABYLON.ImageProcessingConfiguration();
imageProcessingConfiguration.vignetteColor = new BABYLON.Color4(0, 0, 0, 0);
imageProcessingConfiguration.vignetteEnabled = true;
this._postProcessMove = new BABYLON.ImageProcessingPostProcess("postProcessMove", 1.0, this._webVRCamera, undefined, undefined, undefined, undefined, imageProcessingConfiguration);
this._webVRCamera.detachPostProcess(this._postProcessMove);
this._teleportationInitialized = true;
if (this._isDefaultTeleportationTarget) {
this._createTeleportationCircles();
this._teleportationTarget.scaling.scaleInPlace(this._webVRCamera.deviceScaleFactor);
}
}
};
VRExperienceHelper.prototype._enableInteractionOnController = function (controller) {
var _this = this;
var controllerMesh = controller.webVRController.mesh;
if (controllerMesh) {
controller._interactionsEnabled = true;
controller._activatePointer();
if (this.webVROptions.laserToggle) {
controller.webVRController.onMainButtonStateChangedObservable.add(function (stateObject) {
// Enabling / disabling laserPointer
if (_this._displayLaserPointer && stateObject.value === 1) {
if (controller._activePointer) {
controller._deactivatePointer();
}
else {
controller._activatePointer();
}
if (_this.displayGaze) {
controller._gazeTracker.isVisible = controller._activePointer;
}
}
});
}
controller.webVRController.onTriggerStateChangedObservable.add(function (stateObject) {
var gazer = controller;
if (_this._noControllerIsActive) {
gazer = _this._cameraGazer;
}
if (!gazer._pointerDownOnMeshAsked) {
if (stateObject.value > _this._padSensibilityUp) {
gazer._selectionPointerDown();
}
}
else if (stateObject.value < _this._padSensibilityDown) {
gazer._selectionPointerUp();
}
});
}
};
VRExperienceHelper.prototype._checkTeleportWithRay = function (stateObject, gazer) {
// Dont teleport if another gaze already requested teleportation
if (this._teleportationRequestInitiated && !gazer._teleportationRequestInitiated) {
return;
}
if (!gazer._teleportationRequestInitiated) {
if (stateObject.y < -this._padSensibilityUp && gazer._dpadPressed) {
gazer._activatePointer();
gazer._teleportationRequestInitiated = true;
}
}
else {
// Listening to the proper controller values changes to confirm teleportation
if (Math.sqrt(stateObject.y * stateObject.y + stateObject.x * stateObject.x) < this._padSensibilityDown) {
if (this._teleportActive) {
this._teleportCamera(this._haloCenter);
}
gazer._teleportationRequestInitiated = false;
}
}
};
VRExperienceHelper.prototype._checkRotate = function (stateObject, gazer) {
// Only rotate when user is not currently selecting a teleportation location
if (gazer._teleportationRequestInitiated) {
return;
}
if (!gazer._rotationLeftAsked) {
if (stateObject.x < -this._padSensibilityUp && gazer._dpadPressed) {
gazer._rotationLeftAsked = true;
if (this._rotationAllowed) {
this._rotateCamera(false);
}
}
}
else {
if (stateObject.x > -this._padSensibilityDown) {
gazer._rotationLeftAsked = false;
}
}
if (!gazer._rotationRightAsked) {
if (stateObject.x > this._padSensibilityUp && gazer._dpadPressed) {
gazer._rotationRightAsked = true;
if (this._rotationAllowed) {
this._rotateCamera(true);
}
}
}
else {
if (stateObject.x < this._padSensibilityDown) {
gazer._rotationRightAsked = false;
}
}
};
VRExperienceHelper.prototype._checkTeleportBackwards = function (stateObject, gazer) {
// Only teleport backwards when user is not currently selecting a teleportation location
if (gazer._teleportationRequestInitiated) {
return;
}
// Teleport backwards
if (stateObject.y > this._padSensibilityUp && gazer._dpadPressed) {
if (!gazer._teleportationBackRequestInitiated) {
if (!this.currentVRCamera) {
return;
}
// Get rotation and position of the current camera
var rotation = BABYLON.Quaternion.FromRotationMatrix(this.currentVRCamera.getWorldMatrix().getRotationMatrix());
var position = this.currentVRCamera.position;
// If the camera has device position, use that instead
if (this.currentVRCamera.devicePosition && this.currentVRCamera.deviceRotationQuaternion) {
rotation = this.currentVRCamera.deviceRotationQuaternion;
position = this.currentVRCamera.devicePosition;
}
// Get matrix with only the y rotation of the device rotation
rotation.toEulerAnglesToRef(this._workingVector);
this._workingVector.z = 0;
this._workingVector.x = 0;
BABYLON.Quaternion.RotationYawPitchRollToRef(this._workingVector.y, this._workingVector.x, this._workingVector.z, this._workingQuaternion);
this._workingQuaternion.toRotationMatrix(this._workingMatrix);
// Rotate backwards ray by device rotation to cast at the ground behind the user
BABYLON.Vector3.TransformCoordinatesToRef(this._teleportBackwardsVector, this._workingMatrix, this._workingVector);
// Teleport if ray hit the ground and is not to far away eg. backwards off a cliff
var ray = new BABYLON.Ray(position, this._workingVector);
var hit = this._scene.pickWithRay(ray, this._raySelectionPredicate);
if (hit && hit.pickedPoint && hit.pickedMesh && this._isTeleportationFloor(hit.pickedMesh) && hit.distance < 5) {
this._teleportCamera(hit.pickedPoint);
}
gazer._teleportationBackRequestInitiated = true;
}
}
else {
gazer._teleportationBackRequestInitiated = false;
}
};
VRExperienceHelper.prototype._enableTeleportationOnController = function (controller) {
var _this = this;
var controllerMesh = controller.webVRController.mesh;
if (controllerMesh) {
if (!controller._interactionsEnabled) {
this._enableInteractionOnController(controller);
}
controller._interactionsEnabled = true;
controller._teleportationEnabled = true;
if (controller.webVRController.controllerType === BABYLON.PoseEnabledControllerType.VIVE) {
controller._dpadPressed = false;
controller.webVRController.onPadStateChangedObservable.add(function (stateObject) {
controller._dpadPressed = stateObject.pressed;
if (!controller._dpadPressed) {
controller._rotationLeftAsked = false;
controller._rotationRightAsked = false;
controller._teleportationBackRequestInitiated = false;
}
});
}
controller.webVRController.onPadValuesChangedObservable.add(function (stateObject) {
if (_this.teleportationEnabled) {
_this._checkTeleportBackwards(stateObject, controller);
_this._checkTeleportWithRay(stateObject, controller);
}
_this._checkRotate(stateObject, controller);
});
}
};
VRExperienceHelper.prototype._createTeleportationCircles = function () {
this._teleportationTarget = BABYLON.Mesh.CreateGround("teleportationTarget", 2, 2, 2, this._scene);
this._teleportationTarget.isPickable = false;
var length = 512;
var dynamicTexture = new BABYLON.DynamicTexture("DynamicTexture", length, this._scene, true);
dynamicTexture.hasAlpha = true;
var context = dynamicTexture.getContext();
var centerX = length / 2;
var centerY = length / 2;
var radius = 200;
context.beginPath();
context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
context.fillStyle = this._teleportationFillColor;
context.fill();
context.lineWidth = 10;
context.strokeStyle = this._teleportationBorderColor;
context.stroke();
context.closePath();
dynamicTexture.update();
var teleportationCircleMaterial = new BABYLON.StandardMaterial("TextPlaneMaterial", this._scene);
teleportationCircleMaterial.diffuseTexture = dynamicTexture;
this._teleportationTarget.material = teleportationCircleMaterial;
var torus = BABYLON.Mesh.CreateTorus("torusTeleportation", 0.75, 0.1, 25, this._scene, false);
torus.isPickable = false;
torus.parent = this._teleportationTarget;
var animationInnerCircle = new BABYLON.Animation("animationInnerCircle", "position.y", 30, BABYLON.Animation.ANIMATIONTYPE_FLOAT, BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE);
var keys = [];
keys.push({
frame: 0,
value: 0
});
keys.push({
frame: 30,
value: 0.4
});
keys.push({
frame: 60,
value: 0
});
animationInnerCircle.setKeys(keys);
var easingFunction = new BABYLON.SineEase();
easingFunction.setEasingMode(BABYLON.EasingFunction.EASINGMODE_EASEINOUT);
animationInnerCircle.setEasingFunction(easingFunction);
torus.animations = [];
torus.animations.push(animationInnerCircle);
this._scene.beginAnimation(torus, 0, 60, true);
this._hideTeleportationTarget();
};
VRExperienceHelper.prototype._displayTeleportationTarget = function () {
this._teleportActive = true;
if (this._teleportationInitialized) {
this._teleportationTarget.isVisible = true;
if (this._isDefaultTeleportationTarget) {
this._teleportationTarget.getChildren()[0].isVisible = true;
}
}
};
VRExperienceHelper.prototype._hideTeleportationTarget = function () {
this._teleportActive = false;
if (this._teleportationInitialized) {
this._teleportationTarget.isVisible = false;
if (this._isDefaultTeleportationTarget) {
this._teleportationTarget.getChildren()[0].isVisible = false;
}
}
};
VRExperienceHelper.prototype._rotateCamera = function (right) {
var _this = this;
if (!(this.currentVRCamera instanceof BABYLON.FreeCamera)) {
return;
}
if (right) {
this._rotationAngle++;
}
else {
this._rotationAngle--;
}
this.currentVRCamera.animations = [];
var target = BABYLON.Quaternion.FromRotationMatrix(BABYLON.Matrix.RotationY(Math.PI / 4 * this._rotationAngle));
var animationRotation = new BABYLON.Animation("animationRotation", "rotationQuaternion", 90, BABYLON.Animation.ANIMATIONTYPE_QUATERNION, BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT);
var animationRotationKeys = [];
animationRotationKeys.push({
frame: 0,
value: this.currentVRCamera.rotationQuaternion
});
animationRotationKeys.push({
frame: 6,
value: target
});
animationRotation.setKeys(animationRotationKeys);
animationRotation.setEasingFunction(this._circleEase);
this.currentVRCamera.animations.push(animationRotation);
this._postProcessMove.animations = [];
var animationPP = new BABYLON.Animation("animationPP", "vignetteWeight", 90, BABYLON.Animation.ANIMATIONTYPE_FLOAT, BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT);
var vignetteWeightKeys = [];
vignetteWeightKeys.push({
frame: 0,
value: 0
});
vignetteWeightKeys.push({
frame: 3,
value: 4
});
vignetteWeightKeys.push({
frame: 6,
value: 0
});
animationPP.setKeys(vignetteWeightKeys);
animationPP.setEasingFunction(this._circleEase);
this._postProcessMove.animations.push(animationPP);
var animationPP2 = new BABYLON.Animation("animationPP2", "vignetteStretch", 90, BABYLON.Animation.ANIMATIONTYPE_FLOAT, BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT);
var vignetteStretchKeys = [];
vignetteStretchKeys.push({
frame: 0,
value: 0
});
vignetteStretchKeys.push({
frame: 3,
value: 10
});
vignetteStretchKeys.push({
frame: 6,
value: 0
});
animationPP2.setKeys(vignetteStretchKeys);
animationPP2.setEasingFunction(this._circleEase);
this._postProcessMove.animations.push(animationPP2);
this._postProcessMove.imageProcessingConfiguration.vignetteWeight = 0;
this._postProcessMove.imageProcessingConfiguration.vignetteStretch = 0;
this._postProcessMove.samples = 4;
this._webVRCamera.attachPostProcess(this._postProcessMove);
this._scene.beginAnimation(this._postProcessMove, 0, 6, false, 1, function () {
_this._webVRCamera.detachPostProcess(_this._postProcessMove);
});
this._scene.beginAnimation(this.currentVRCamera, 0, 6, false, 1);
};
VRExperienceHelper.prototype._moveTeleportationSelectorTo = function (hit, gazer, ray) {
if (hit.pickedPoint) {
if (gazer._teleportationRequestInitiated) {
this._displayTeleportationTarget();
this._haloCenter.copyFrom(hit.pickedPoint);
this._teleportationTarget.position.copyFrom(hit.pickedPoint);
}
var pickNormal = this._convertNormalToDirectionOfRay(hit.getNormal(true, false), ray);
if (pickNormal) {
var axis1 = BABYLON.Vector3.Cross(BABYLON.Axis.Y, pickNormal);
var axis2 = BABYLON.Vector3.Cross(pickNormal, axis1);
BABYLON.Vector3.RotationFromAxisToRef(axis2, pickNormal, axis1, this._teleportationTarget.rotation);
}
this._teleportationTarget.position.y += 0.1;
}
};
VRExperienceHelper.prototype._teleportCamera = function (location) {
var _this = this;
if (!(this.currentVRCamera instanceof BABYLON.FreeCamera)) {
return;
}
// Teleport the hmd to where the user is looking by moving the anchor to where they are looking minus the
// offset of the headset from the anchor.
if (this.webVRCamera.leftCamera) {
this._workingVector.copyFrom(this.webVRCamera.leftCamera.globalPosition);
this._workingVector.subtractInPlace(this.webVRCamera.position);
location.subtractToRef(this._workingVector, this._workingVector);
}
else {
this._workingVector.copyFrom(location);
}
// Add height to account for user's height offset
if (this.isInVRMode) {
this._workingVector.y += this.webVRCamera.deviceDistanceToRoomGround() * this._webVRCamera.deviceScaleFactor;
}
else {
this._workingVector.y += this._defaultHeight;
}
this.onBeforeCameraTeleport.notifyObservers(this._workingVector);
// Create animation from the camera's position to the new location
this.currentVRCamera.animations = [];
var animationCameraTeleportation = new BABYLON.Animation("animationCameraTeleportation", "position", 90, BABYLON.Animation.ANIMATIONTYPE_VECTOR3, BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT);
var animationCameraTeleportationKeys = [{
frame: 0,
value: this.currentVRCamera.position
},
{
frame: 11,
value: this._workingVector
}
];
animationCameraTeleportation.setKeys(animationCameraTeleportationKeys);
animationCameraTeleportation.setEasingFunction(this._circleEase);
this.currentVRCamera.animations.push(animationCameraTeleportation);
this._postProcessMove.animations = [];
var animationPP = new BABYLON.Animation("animationPP", "vignetteWeight", 90, BABYLON.Animation.ANIMATIONTYPE_FLOAT, BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT);
var vignetteWeightKeys = [];
vignetteWeightKeys.push({
frame: 0,
value: 0
});
vignetteWeightKeys.push({
frame: 5,
value: 8
});
vignetteWeightKeys.push({
frame: 11,
value: 0
});
animationPP.setKeys(vignetteWeightKeys);
this._postProcessMove.animations.push(animationPP);
var animationPP2 = new BABYLON.Animation("animationPP2", "vignetteStretch", 90, BABYLON.Animation.ANIMATIONTYPE_FLOAT, BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT);
var vignetteStretchKeys = [];
vignetteStretchKeys.push({
frame: 0,
value: 0
});
vignetteStretchKeys.push({
frame: 5,
value: 10
});
vignetteStretchKeys.push({
frame: 11,
value: 0
});
animationPP2.setKeys(vignetteStretchKeys);
this._postProcessMove.animations.push(animationPP2);
this._postProcessMove.imageProcessingConfiguration.vignetteWeight = 0;
this._postProcessMove.imageProcessingConfiguration.vignetteStretch = 0;
this._webVRCamera.attachPostProcess(this._postProcessMove);
this._scene.beginAnimation(this._postProcessMove, 0, 11, false, 1, function () {
_this._webVRCamera.detachPostProcess(_this._postProcessMove);
});
this._scene.beginAnimation(this.currentVRCamera, 0, 11, false, 1, function () {
_this.onAfterCameraTeleport.notifyObservers(_this._workingVector);
});
this._hideTeleportationTarget();
};
VRExperienceHelper.prototype._convertNormalToDirectionOfRay = function (normal, ray) {
if (normal) {
var angle = Math.acos(BABYLON.Vector3.Dot(normal, ray.direction));
if (angle < Math.PI / 2) {
normal.scaleInPlace(-1);
}
}
return normal;
};
VRExperienceHelper.prototype._castRayAndSelectObject = function (gazer) {
if (!(this.currentVRCamera instanceof BABYLON.FreeCamera)) {
return;
}
var ray = gazer._getForwardRay(this._rayLength);
var hit = this._scene.pickWithRay(ray, this._raySelectionPredicate);
if (hit) {
// Populate the contrllers mesh that can be used for drag/drop
if (gazer._laserPointer) {
hit.originMesh = gazer._laserPointer.parent;
}
this._scene.simulatePointerMove(hit, { pointerId: gazer._id });
}
gazer._currentHit = hit;
// Moving the gazeTracker on the mesh face targetted
if (hit && hit.pickedPoint) {
if (this._displayGaze) {
var multiplier = 1;
gazer._gazeTracker.isVisible = true;
if (gazer._isActionableMesh) {
multiplier = 3;
}
gazer._gazeTracker.scaling.x = hit.distance * multiplier;
gazer._gazeTracker.scaling.y = hit.distance * multiplier;
gazer._gazeTracker.scaling.z = hit.distance * multiplier;
var pickNormal = this._convertNormalToDirectionOfRay(hit.getNormal(), ray);
// To avoid z-fighting
var deltaFighting = 0.002;
if (pickNormal) {
var axis1 = BABYLON.Vector3.Cross(BABYLON.Axis.Y, pickNormal);
var axis2 = BABYLON.Vector3.Cross(pickNormal, axis1);
BABYLON.Vector3.RotationFromAxisToRef(axis2, pickNormal, axis1, gazer._gazeTracker.rotation);
}
gazer._gazeTracker.position.copyFrom(hit.pickedPoint);
if (gazer._gazeTracker.position.x < 0) {
gazer._gazeTracker.position.x += deltaFighting;
}
else {
gazer._gazeTracker.position.x -= deltaFighting;
}
if (gazer._gazeTracker.position.y < 0) {
gazer._gazeTracker.position.y += deltaFighting;
}
else {
gazer._gazeTracker.position.y -= deltaFighting;
}
if (gazer._gazeTracker.position.z < 0) {
gazer._gazeTracker.position.z += deltaFighting;
}
else {
gazer._gazeTracker.position.z -= deltaFighting;
}
}
// Changing the size of the laser pointer based on the distance from the targetted point
gazer._updatePointerDistance(hit.distance);
}
else {
gazer._updatePointerDistance();
gazer._gazeTracker.isVisible = false;
}
if (hit && hit.pickedMesh) {
// The object selected is the floor, we're in a teleportation scenario
if (this._teleportationInitialized && this._isTeleportationFloor(hit.pickedMesh) && hit.pickedPoint) {
// Moving the teleportation area to this targetted point
//Raise onSelectedMeshUnselected observable if ray collided floor mesh/meshes and a non floor mesh was previously selected
if (gazer._currentMeshSelected && !this._isTeleportationFloor(gazer._currentMeshSelected)) {
this._notifySelectedMeshUnselected(gazer._currentMeshSelected);
}
gazer._currentMeshSelected = null;
if (gazer._teleportationRequestInitiated) {
this._moveTeleportationSelectorTo(hit, gazer, ray);
}
return;
}
// If not, we're in a selection scenario
//this._teleportationAllowed = false;
if (hit.pickedMesh !== gazer._currentMeshSelected) {
if (this.meshSelectionPredicate(hit.pickedMesh)) {
this.onNewMeshPicked.notifyObservers(hit);
gazer._currentMeshSelected = hit.pickedMesh;
if (hit.pickedMesh.isPickable && hit.pickedMesh.actionManager) {
this.changeGazeColor(new BABYLON.Color3(0, 0, 1));
this.changeLaserColor(new BABYLON.Color3(0.2, 0.2, 1));
gazer._isActionableMesh = true;
}
else {
this.changeGazeColor(new BABYLON.Color3(0.7, 0.7, 0.7));
this.changeLaserColor(new BABYLON.Color3(0.7, 0.7, 0.7));
gazer._isActionableMesh = false;
}
try {
this.onNewMeshSelected.notifyObservers(hit.pickedMesh);
}
catch (err) {
BABYLON.Tools.Warn("Error in your custom logic onNewMeshSelected: " + err);
}
}
else {
this._notifySelectedMeshUnselected(gazer._currentMeshSelected);
gazer._currentMeshSelected = null;
this.changeGazeColor(new BABYLON.Color3(0.7, 0.7, 0.7));
this.changeLaserColor(new BABYLON.Color3(0.7, 0.7, 0.7));
}
}
}
else {
this._notifySelectedMeshUnselected(gazer._currentMeshSelected);
gazer._currentMeshSelected = null;
//this._teleportationAllowed = false;
this.changeGazeColor(new BABYLON.Color3(0.7, 0.7, 0.7));
this.changeLaserColor(new BABYLON.Color3(0.7, 0.7, 0.7));
}
};
VRExperienceHelper.prototype._notifySelectedMeshUnselected = function (mesh) {
if (mesh) {
this.onSelectedMeshUnselected.notifyObservers(mesh);
}
};
/**
* Sets the color of the laser ray from the vr controllers.
* @param color new color for the ray.
*/
VRExperienceHelper.prototype.changeLaserColor = function (color) {
if (this.leftController) {
this.leftController._setLaserPointerColor(color);
}
if (this.rightController) {
this.rightController._setLaserPointerColor(color);
}
};
/**
* Sets the color of the ray from the vr headsets gaze.
* @param color new color for the ray.
*/
VRExperienceHelper.prototype.changeGazeColor = function (color) {
if (!this._cameraGazer._gazeTracker.material) {
return;
}
this._cameraGazer._gazeTracker.material.emissiveColor = color;
if (this.leftController) {
this.leftController._gazeTracker.material.emissiveColor = color;
}
if (this.rightController) {
this.rightController._gazeTracker.material.emissiveColor = color;
}
};
/**
* Exits VR and disposes of the vr experience helper
*/
VRExperienceHelper.prototype.dispose = function () {
if (this.isInVRMode) {
this.exitVR();
}
if (this._postProcessMove) {
this._postProcessMove.dispose();
}
if (this._webVRCamera) {
this._webVRCamera.dispose();
}
if (this._vrDeviceOrientationCamera) {
this._vrDeviceOrientationCamera.dispose();
}
if (!this._useCustomVRButton && this._btnVR.parentNode) {
document.body.removeChild(this._btnVR);
}
if (this._deviceOrientationCamera && (this._scene.activeCamera != this._deviceOrientationCamera)) {
this._deviceOrientationCamera.dispose();
}
if (this._cameraGazer) {
this._cameraGazer.dispose();
}
if (this.leftController) {
this.leftController.dispose();
}
if (this.rightController) {
this.rightController.dispose();
}
if (this._teleportationTarget) {
this._teleportationTarget.dispose();
}
this._floorMeshesCollection = [];
document.removeEventListener("keydown", this._onKeyDown);
window.removeEventListener('vrdisplaypresentchange', this._onVrDisplayPresentChange);
window.removeEventListener("resize", this._onResize);
document.removeEventListener("fullscreenchange", this._onFullscreenChange);
document.removeEventListener("mozfullscreenchange", this._onFullscreenChange);
document.removeEventListener("webkitfullscreenchange", this._onFullscreenChange);
document.removeEventListener("msfullscreenchange", this._onFullscreenChange);
document.onmsfullscreenchange = null;
this._scene.getEngine().onVRDisplayChangedObservable.removeCallback(this._onVRDisplayChanged);
this._scene.getEngine().onVRRequestPresentStart.removeCallback(this._onVRRequestPresentStart);
this._scene.getEngine().onVRRequestPresentComplete.removeCallback(this._onVRRequestPresentComplete);
window.removeEventListener('vrdisplaypresentchange', this._onVrDisplayPresentChange);
this._scene.gamepadManager.onGamepadConnectedObservable.removeCallback(this._onNewGamepadConnected);
this._scene.gamepadManager.onGamepadDisconnectedObservable.removeCallback(this._onNewGamepadDisconnected);
this._scene.unregisterBeforeRender(this.beforeRender);
};
/**
* Gets the name of the VRExperienceHelper class
* @returns "VRExperienceHelper"
*/
VRExperienceHelper.prototype.getClassName = function () {
return "VRExperienceHelper";
};
return VRExperienceHelper;
}());
BABYLON.VRExperienceHelper = VRExperienceHelper;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.vrExperienceHelper.js.map
// Mainly based on these 2 articles :
// Creating an universal virtual touch joystick working for all Touch models thanks to Hand.JS : http://blogs.msdn.com/b/davrous/archive/2013/02/22/creating-an-universal-virtual-touch-joystick-working-for-all-touch-models-thanks-to-hand-js.aspx
// & on Seb Lee-Delisle original work: http://seb.ly/2011/04/multi-touch-game-controller-in-javascripthtml5-for-ipad/
var BABYLON;
(function (BABYLON) {
/**
* Defines the potential axis of a Joystick
*/
var JoystickAxis;
(function (JoystickAxis) {
/** X axis */
JoystickAxis[JoystickAxis["X"] = 0] = "X";
/** Y axis */
JoystickAxis[JoystickAxis["Y"] = 1] = "Y";
/** Z axis */
JoystickAxis[JoystickAxis["Z"] = 2] = "Z";
})(JoystickAxis = BABYLON.JoystickAxis || (BABYLON.JoystickAxis = {}));
/**
* Class used to define virtual joystick (used in touch mode)
*/
var VirtualJoystick = /** @class */ (function () {
/**
* Creates a new virtual joystick
* @param leftJoystick defines that the joystick is for left hand (false by default)
*/
function VirtualJoystick(leftJoystick) {
var _this = this;
if (leftJoystick) {
this._leftJoystick = true;
}
else {
this._leftJoystick = false;
}
VirtualJoystick._globalJoystickIndex++;
// By default left & right arrow keys are moving the X
// and up & down keys are moving the Y
this._axisTargetedByLeftAndRight = JoystickAxis.X;
this._axisTargetedByUpAndDown = JoystickAxis.Y;
this.reverseLeftRight = false;
this.reverseUpDown = false;
// collections of pointers
this._touches = new BABYLON.StringDictionary();
this.deltaPosition = BABYLON.Vector3.Zero();
this._joystickSensibility = 25;
this._inversedSensibility = 1 / (this._joystickSensibility / 1000);
this._onResize = function (evt) {
VirtualJoystick.vjCanvasWidth = window.innerWidth;
VirtualJoystick.vjCanvasHeight = window.innerHeight;
if (VirtualJoystick.vjCanvas) {
VirtualJoystick.vjCanvas.width = VirtualJoystick.vjCanvasWidth;
VirtualJoystick.vjCanvas.height = VirtualJoystick.vjCanvasHeight;
}
VirtualJoystick.halfWidth = VirtualJoystick.vjCanvasWidth / 2;
};
// injecting a canvas element on top of the canvas 3D game
if (!VirtualJoystick.vjCanvas) {
window.addEventListener("resize", this._onResize, false);
VirtualJoystick.vjCanvas = document.createElement("canvas");
VirtualJoystick.vjCanvasWidth = window.innerWidth;
VirtualJoystick.vjCanvasHeight = window.innerHeight;
VirtualJoystick.vjCanvas.width = window.innerWidth;
VirtualJoystick.vjCanvas.height = window.innerHeight;
VirtualJoystick.vjCanvas.style.width = "100%";
VirtualJoystick.vjCanvas.style.height = "100%";
VirtualJoystick.vjCanvas.style.position = "absolute";
VirtualJoystick.vjCanvas.style.backgroundColor = "transparent";
VirtualJoystick.vjCanvas.style.top = "0px";
VirtualJoystick.vjCanvas.style.left = "0px";
VirtualJoystick.vjCanvas.style.zIndex = "5";
VirtualJoystick.vjCanvas.style.msTouchAction = "none";
// Support for jQuery PEP polyfill
VirtualJoystick.vjCanvas.setAttribute("touch-action", "none");
var context = VirtualJoystick.vjCanvas.getContext('2d');
if (!context) {
throw new Error("Unable to create canvas for virtual joystick");
}
VirtualJoystick.vjCanvasContext = context;
VirtualJoystick.vjCanvasContext.strokeStyle = "#ffffff";
VirtualJoystick.vjCanvasContext.lineWidth = 2;
document.body.appendChild(VirtualJoystick.vjCanvas);
}
VirtualJoystick.halfWidth = VirtualJoystick.vjCanvas.width / 2;
this.pressed = false;
// default joystick color
this._joystickColor = "cyan";
this._joystickPointerID = -1;
// current joystick position
this._joystickPointerPos = new BABYLON.Vector2(0, 0);
this._joystickPreviousPointerPos = new BABYLON.Vector2(0, 0);
// origin joystick position
this._joystickPointerStartPos = new BABYLON.Vector2(0, 0);
this._deltaJoystickVector = new BABYLON.Vector2(0, 0);
this._onPointerDownHandlerRef = function (evt) {
_this._onPointerDown(evt);
};
this._onPointerMoveHandlerRef = function (evt) {
_this._onPointerMove(evt);
};
this._onPointerUpHandlerRef = function (evt) {
_this._onPointerUp(evt);
};
VirtualJoystick.vjCanvas.addEventListener('pointerdown', this._onPointerDownHandlerRef, false);
VirtualJoystick.vjCanvas.addEventListener('pointermove', this._onPointerMoveHandlerRef, false);
VirtualJoystick.vjCanvas.addEventListener('pointerup', this._onPointerUpHandlerRef, false);
VirtualJoystick.vjCanvas.addEventListener('pointerout', this._onPointerUpHandlerRef, false);
VirtualJoystick.vjCanvas.addEventListener("contextmenu", function (evt) {
evt.preventDefault(); // Disables system menu
}, false);
requestAnimationFrame(function () { _this._drawVirtualJoystick(); });
}
/**
* Defines joystick sensibility (ie. the ratio beteen a physical move and virtual joystick position change)
* @param newJoystickSensibility defines the new sensibility
*/
VirtualJoystick.prototype.setJoystickSensibility = function (newJoystickSensibility) {
this._joystickSensibility = newJoystickSensibility;
this._inversedSensibility = 1 / (this._joystickSensibility / 1000);
};
VirtualJoystick.prototype._onPointerDown = function (e) {
var positionOnScreenCondition;
e.preventDefault();
if (this._leftJoystick === true) {
positionOnScreenCondition = (e.clientX < VirtualJoystick.halfWidth);
}
else {
positionOnScreenCondition = (e.clientX > VirtualJoystick.halfWidth);
}
if (positionOnScreenCondition && this._joystickPointerID < 0) {
// First contact will be dedicated to the virtual joystick
this._joystickPointerID = e.pointerId;
this._joystickPointerStartPos.x = e.clientX;
this._joystickPointerStartPos.y = e.clientY;
this._joystickPointerPos = this._joystickPointerStartPos.clone();
this._joystickPreviousPointerPos = this._joystickPointerStartPos.clone();
this._deltaJoystickVector.x = 0;
this._deltaJoystickVector.y = 0;
this.pressed = true;
this._touches.add(e.pointerId.toString(), e);
}
else {
// You can only trigger the action buttons with a joystick declared
if (VirtualJoystick._globalJoystickIndex < 2 && this._action) {
this._action();
this._touches.add(e.pointerId.toString(), { x: e.clientX, y: e.clientY, prevX: e.clientX, prevY: e.clientY });
}
}
};
VirtualJoystick.prototype._onPointerMove = function (e) {
// If the current pointer is the one associated to the joystick (first touch contact)
if (this._joystickPointerID == e.pointerId) {
this._joystickPointerPos.x = e.clientX;
this._joystickPointerPos.y = e.clientY;
this._deltaJoystickVector = this._joystickPointerPos.clone();
this._deltaJoystickVector = this._deltaJoystickVector.subtract(this._joystickPointerStartPos);
var directionLeftRight = this.reverseLeftRight ? -1 : 1;
var deltaJoystickX = directionLeftRight * this._deltaJoystickVector.x / this._inversedSensibility;
switch (this._axisTargetedByLeftAndRight) {
case JoystickAxis.X:
this.deltaPosition.x = Math.min(1, Math.max(-1, deltaJoystickX));
break;
case JoystickAxis.Y:
this.deltaPosition.y = Math.min(1, Math.max(-1, deltaJoystickX));
break;
case JoystickAxis.Z:
this.deltaPosition.z = Math.min(1, Math.max(-1, deltaJoystickX));
break;
}
var directionUpDown = this.reverseUpDown ? 1 : -1;
var deltaJoystickY = directionUpDown * this._deltaJoystickVector.y / this._inversedSensibility;
switch (this._axisTargetedByUpAndDown) {
case JoystickAxis.X:
this.deltaPosition.x = Math.min(1, Math.max(-1, deltaJoystickY));
break;
case JoystickAxis.Y:
this.deltaPosition.y = Math.min(1, Math.max(-1, deltaJoystickY));
break;
case JoystickAxis.Z:
this.deltaPosition.z = Math.min(1, Math.max(-1, deltaJoystickY));
break;
}
}
else {
var data = this._touches.get(e.pointerId.toString());
if (data) {
data.x = e.clientX;
data.y = e.clientY;
}
}
};
VirtualJoystick.prototype._onPointerUp = function (e) {
if (this._joystickPointerID == e.pointerId) {
VirtualJoystick.vjCanvasContext.clearRect(this._joystickPointerStartPos.x - 64, this._joystickPointerStartPos.y - 64, 128, 128);
VirtualJoystick.vjCanvasContext.clearRect(this._joystickPreviousPointerPos.x - 42, this._joystickPreviousPointerPos.y - 42, 84, 84);
this._joystickPointerID = -1;
this.pressed = false;
}
else {
var touch = this._touches.get(e.pointerId.toString());
if (touch) {
VirtualJoystick.vjCanvasContext.clearRect(touch.prevX - 44, touch.prevY - 44, 88, 88);
}
}
this._deltaJoystickVector.x = 0;
this._deltaJoystickVector.y = 0;
this._touches.remove(e.pointerId.toString());
};
/**
* Change the color of the virtual joystick
* @param newColor a string that must be a CSS color value (like "red") or the hexa value (like "#FF0000")
*/
VirtualJoystick.prototype.setJoystickColor = function (newColor) {
this._joystickColor = newColor;
};
/**
* Defines a callback to call when the joystick is touched
* @param action defines the callback
*/
VirtualJoystick.prototype.setActionOnTouch = function (action) {
this._action = action;
};
/**
* Defines which axis you'd like to control for left & right
* @param axis defines the axis to use
*/
VirtualJoystick.prototype.setAxisForLeftRight = function (axis) {
switch (axis) {
case JoystickAxis.X:
case JoystickAxis.Y:
case JoystickAxis.Z:
this._axisTargetedByLeftAndRight = axis;
break;
default:
this._axisTargetedByLeftAndRight = JoystickAxis.X;
break;
}
};
/**
* Defines which axis you'd like to control for up & down
* @param axis defines the axis to use
*/
VirtualJoystick.prototype.setAxisForUpDown = function (axis) {
switch (axis) {
case JoystickAxis.X:
case JoystickAxis.Y:
case JoystickAxis.Z:
this._axisTargetedByUpAndDown = axis;
break;
default:
this._axisTargetedByUpAndDown = JoystickAxis.Y;
break;
}
};
VirtualJoystick.prototype._drawVirtualJoystick = function () {
var _this = this;
if (this.pressed) {
this._touches.forEach(function (key, touch) {
if (touch.pointerId === _this._joystickPointerID) {
VirtualJoystick.vjCanvasContext.clearRect(_this._joystickPointerStartPos.x - 64, _this._joystickPointerStartPos.y - 64, 128, 128);
VirtualJoystick.vjCanvasContext.clearRect(_this._joystickPreviousPointerPos.x - 42, _this._joystickPreviousPointerPos.y - 42, 84, 84);
VirtualJoystick.vjCanvasContext.beginPath();
VirtualJoystick.vjCanvasContext.lineWidth = 6;
VirtualJoystick.vjCanvasContext.strokeStyle = _this._joystickColor;
VirtualJoystick.vjCanvasContext.arc(_this._joystickPointerStartPos.x, _this._joystickPointerStartPos.y, 40, 0, Math.PI * 2, true);
VirtualJoystick.vjCanvasContext.stroke();
VirtualJoystick.vjCanvasContext.closePath();
VirtualJoystick.vjCanvasContext.beginPath();
VirtualJoystick.vjCanvasContext.strokeStyle = _this._joystickColor;
VirtualJoystick.vjCanvasContext.lineWidth = 2;
VirtualJoystick.vjCanvasContext.arc(_this._joystickPointerStartPos.x, _this._joystickPointerStartPos.y, 60, 0, Math.PI * 2, true);
VirtualJoystick.vjCanvasContext.stroke();
VirtualJoystick.vjCanvasContext.closePath();
VirtualJoystick.vjCanvasContext.beginPath();
VirtualJoystick.vjCanvasContext.strokeStyle = _this._joystickColor;
VirtualJoystick.vjCanvasContext.arc(_this._joystickPointerPos.x, _this._joystickPointerPos.y, 40, 0, Math.PI * 2, true);
VirtualJoystick.vjCanvasContext.stroke();
VirtualJoystick.vjCanvasContext.closePath();
_this._joystickPreviousPointerPos = _this._joystickPointerPos.clone();
}
else {
VirtualJoystick.vjCanvasContext.clearRect(touch.prevX - 44, touch.prevY - 44, 88, 88);
VirtualJoystick.vjCanvasContext.beginPath();
VirtualJoystick.vjCanvasContext.fillStyle = "white";
VirtualJoystick.vjCanvasContext.beginPath();
VirtualJoystick.vjCanvasContext.strokeStyle = "red";
VirtualJoystick.vjCanvasContext.lineWidth = 6;
VirtualJoystick.vjCanvasContext.arc(touch.x, touch.y, 40, 0, Math.PI * 2, true);
VirtualJoystick.vjCanvasContext.stroke();
VirtualJoystick.vjCanvasContext.closePath();
touch.prevX = touch.x;
touch.prevY = touch.y;
}
;
});
}
requestAnimationFrame(function () { _this._drawVirtualJoystick(); });
};
/**
* Release internal HTML canvas
*/
VirtualJoystick.prototype.releaseCanvas = function () {
if (VirtualJoystick.vjCanvas) {
VirtualJoystick.vjCanvas.removeEventListener('pointerdown', this._onPointerDownHandlerRef);
VirtualJoystick.vjCanvas.removeEventListener('pointermove', this._onPointerMoveHandlerRef);
VirtualJoystick.vjCanvas.removeEventListener('pointerup', this._onPointerUpHandlerRef);
VirtualJoystick.vjCanvas.removeEventListener('pointerout', this._onPointerUpHandlerRef);
window.removeEventListener("resize", this._onResize);
document.body.removeChild(VirtualJoystick.vjCanvas);
VirtualJoystick.vjCanvas = null;
}
};
// Used to draw the virtual joystick inside a 2D canvas on top of the WebGL rendering canvas
VirtualJoystick._globalJoystickIndex = 0;
return VirtualJoystick;
}());
BABYLON.VirtualJoystick = VirtualJoystick;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.virtualJoystick.js.map
var BABYLON;
(function (BABYLON) {
BABYLON.Node.AddNodeConstructor("VirtualJoysticksCamera", function (name, scene) {
return function () { return new VirtualJoysticksCamera(name, BABYLON.Vector3.Zero(), scene); };
});
// We're mainly based on the logic defined into the FreeCamera code
var VirtualJoysticksCamera = /** @class */ (function (_super) {
__extends(VirtualJoysticksCamera, _super);
function VirtualJoysticksCamera(name, position, scene) {
var _this = _super.call(this, name, position, scene) || this;
_this.inputs.addVirtualJoystick();
return _this;
}
VirtualJoysticksCamera.prototype.getClassName = function () {
return "VirtualJoysticksCamera";
};
return VirtualJoysticksCamera;
}(BABYLON.FreeCamera));
BABYLON.VirtualJoysticksCamera = VirtualJoysticksCamera;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.virtualJoysticksCamera.js.map
var BABYLON;
(function (BABYLON) {
var FreeCameraVirtualJoystickInput = /** @class */ (function () {
function FreeCameraVirtualJoystickInput() {
}
FreeCameraVirtualJoystickInput.prototype.getLeftJoystick = function () {
return this._leftjoystick;
};
FreeCameraVirtualJoystickInput.prototype.getRightJoystick = function () {
return this._rightjoystick;
};
FreeCameraVirtualJoystickInput.prototype.checkInputs = function () {
if (this._leftjoystick) {
var camera = this.camera;
var speed = camera._computeLocalCameraSpeed() * 50;
var cameraTransform = BABYLON.Matrix.RotationYawPitchRoll(camera.rotation.y, camera.rotation.x, 0);
var deltaTransform = BABYLON.Vector3.TransformCoordinates(new BABYLON.Vector3(this._leftjoystick.deltaPosition.x * speed, this._leftjoystick.deltaPosition.y * speed, this._leftjoystick.deltaPosition.z * speed), cameraTransform);
camera.cameraDirection = camera.cameraDirection.add(deltaTransform);
camera.cameraRotation = camera.cameraRotation.addVector3(this._rightjoystick.deltaPosition);
if (!this._leftjoystick.pressed) {
this._leftjoystick.deltaPosition = this._leftjoystick.deltaPosition.scale(0.9);
}
if (!this._rightjoystick.pressed) {
this._rightjoystick.deltaPosition = this._rightjoystick.deltaPosition.scale(0.9);
}
}
};
FreeCameraVirtualJoystickInput.prototype.attachControl = function (element, noPreventDefault) {
this._leftjoystick = new BABYLON.VirtualJoystick(true);
this._leftjoystick.setAxisForUpDown(BABYLON.JoystickAxis.Z);
this._leftjoystick.setAxisForLeftRight(BABYLON.JoystickAxis.X);
this._leftjoystick.setJoystickSensibility(0.15);
this._rightjoystick = new BABYLON.VirtualJoystick(false);
this._rightjoystick.setAxisForUpDown(BABYLON.JoystickAxis.X);
this._rightjoystick.setAxisForLeftRight(BABYLON.JoystickAxis.Y);
this._rightjoystick.reverseUpDown = true;
this._rightjoystick.setJoystickSensibility(0.05);
this._rightjoystick.setJoystickColor("yellow");
};
FreeCameraVirtualJoystickInput.prototype.detachControl = function (element) {
this._leftjoystick.releaseCanvas();
this._rightjoystick.releaseCanvas();
};
FreeCameraVirtualJoystickInput.prototype.getClassName = function () {
return "FreeCameraVirtualJoystickInput";
};
FreeCameraVirtualJoystickInput.prototype.getSimpleName = function () {
return "virtualJoystick";
};
return FreeCameraVirtualJoystickInput;
}());
BABYLON.FreeCameraVirtualJoystickInput = FreeCameraVirtualJoystickInput;
BABYLON.CameraInputTypes["FreeCameraVirtualJoystickInput"] = FreeCameraVirtualJoystickInput;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.freeCameraVirtualJoystickInput.js.map
var BABYLON;
(function (BABYLON) {
var SimplificationSettings = /** @class */ (function () {
function SimplificationSettings(quality, distance, optimizeMesh) {
this.quality = quality;
this.distance = distance;
this.optimizeMesh = optimizeMesh;
}
return SimplificationSettings;
}());
BABYLON.SimplificationSettings = SimplificationSettings;
var SimplificationQueue = /** @class */ (function () {
function SimplificationQueue() {
this.running = false;
this._simplificationArray = [];
}
SimplificationQueue.prototype.addTask = function (task) {
this._simplificationArray.push(task);
};
SimplificationQueue.prototype.executeNext = function () {
var task = this._simplificationArray.pop();
if (task) {
this.running = true;
this.runSimplification(task);
}
else {
this.running = false;
}
};
SimplificationQueue.prototype.runSimplification = function (task) {
var _this = this;
if (task.parallelProcessing) {
//parallel simplifier
task.settings.forEach(function (setting) {
var simplifier = _this.getSimplifier(task);
simplifier.simplify(setting, function (newMesh) {
task.mesh.addLODLevel(setting.distance, newMesh);
newMesh.isVisible = true;
//check if it is the last
if (setting.quality === task.settings[task.settings.length - 1].quality && task.successCallback) {
//all done, run the success callback.
task.successCallback();
}
_this.executeNext();
});
});
}
else {
//single simplifier.
var simplifier = this.getSimplifier(task);
var runDecimation = function (setting, callback) {
simplifier.simplify(setting, function (newMesh) {
task.mesh.addLODLevel(setting.distance, newMesh);
newMesh.isVisible = true;
//run the next quality level
callback();
});
};
BABYLON.AsyncLoop.Run(task.settings.length, function (loop) {
runDecimation(task.settings[loop.index], function () {
loop.executeNext();
});
}, function () {
//execution ended, run the success callback.
if (task.successCallback) {
task.successCallback();
}
_this.executeNext();
});
}
};
SimplificationQueue.prototype.getSimplifier = function (task) {
switch (task.simplificationType) {
case SimplificationType.QUADRATIC:
default:
return new QuadraticErrorSimplification(task.mesh);
}
};
return SimplificationQueue;
}());
BABYLON.SimplificationQueue = SimplificationQueue;
/**
* The implemented types of simplification
* At the moment only Quadratic Error Decimation is implemented
*/
var SimplificationType;
(function (SimplificationType) {
/** Quadratic error decimation */
SimplificationType[SimplificationType["QUADRATIC"] = 0] = "QUADRATIC";
})(SimplificationType = BABYLON.SimplificationType || (BABYLON.SimplificationType = {}));
var DecimationTriangle = /** @class */ (function () {
function DecimationTriangle(vertices) {
this.vertices = vertices;
this.error = new Array(4);
this.deleted = false;
this.isDirty = false;
this.deletePending = false;
this.borderFactor = 0;
}
return DecimationTriangle;
}());
BABYLON.DecimationTriangle = DecimationTriangle;
var DecimationVertex = /** @class */ (function () {
function DecimationVertex(position, id) {
this.position = position;
this.id = id;
this.isBorder = true;
this.q = new QuadraticMatrix();
this.triangleCount = 0;
this.triangleStart = 0;
this.originalOffsets = [];
}
DecimationVertex.prototype.updatePosition = function (newPosition) {
this.position.copyFrom(newPosition);
};
return DecimationVertex;
}());
BABYLON.DecimationVertex = DecimationVertex;
var QuadraticMatrix = /** @class */ (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 = /** @class */ (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 = /** @class */ (function () {
function QuadraticErrorSimplification(_mesh) {
this._mesh = _mesh;
this.syncIterations = 5000;
this.aggressiveness = 7;
this.decimationIterations = 100;
this.boundingBoxEpsilon = BABYLON.Epsilon;
}
QuadraticErrorSimplification.prototype.simplify = function (settings, successCallback) {
var _this = this;
this.initDecimatedMesh();
//iterating through the submeshes array, one after the other.
BABYLON.AsyncLoop.Run(this._mesh.subMeshes.length, function (loop) {
_this.initWithMesh(loop.index, function () {
_this.runDecimation(settings, loop.index, function () {
loop.executeNext();
});
}, settings.optimizeMesh);
}, function () {
setTimeout(function () {
successCallback(_this._reconstructedMesh);
}, 0);
});
};
QuadraticErrorSimplification.prototype.runDecimation = function (settings, submeshIndex, 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];
if (!t)
return;
if (t.error[3] > threshold || t.deleted || t.isDirty) {
return;
}
for (var j = 0; j < 3; ++j) {
if (t.error[j] < threshold) {
var deleted0 = [];
var deleted1 = [];
var v0 = t.vertices[j];
var v1 = t.vertices[(j + 1) % 3];
if (v0.isBorder || v1.isBorder)
continue;
var p = BABYLON.Vector3.Zero();
var n = BABYLON.Vector3.Zero();
var uv = BABYLON.Vector2.Zero();
var color = new BABYLON.Color4(0, 0, 0, 1);
_this.calculateError(v0, v1, p, n, uv, color);
var delTr = new Array();
if (_this.isFlipped(v0, v1, p, deleted0, t.borderFactor, delTr))
continue;
if (_this.isFlipped(v1, v0, p, deleted1, t.borderFactor, delTr))
continue;
if (deleted0.indexOf(true) < 0 || deleted1.indexOf(true) < 0)
continue;
var uniqueArray = new Array();
delTr.forEach(function (deletedT) {
if (uniqueArray.indexOf(deletedT) === -1) {
deletedT.deletePending = true;
uniqueArray.push(deletedT);
}
});
if (uniqueArray.length % 2 !== 0) {
continue;
}
v0.q = v1.q.add(v0.q);
v0.updatePosition(p);
var tStart = _this.references.length;
deletedTriangles = _this.updateTriangles(v0, v0, deleted0, deletedTriangles);
deletedTriangles = _this.updateTriangles(v0, 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 () {
//reconstruct this part of the mesh
_this.reconstructMesh(submeshIndex);
successCallback();
}, 0);
});
};
QuadraticErrorSimplification.prototype.initWithMesh = function (submeshIndex, callback, optimizeMesh) {
var _this = this;
this.vertices = [];
this.triangles = [];
var positionData = this._mesh.getVerticesData(BABYLON.VertexBuffer.PositionKind);
var indices = this._mesh.getIndices();
var submesh = this._mesh.subMeshes[submeshIndex];
var findInVertices = function (positionToSearch) {
if (optimizeMesh) {
for (var ii = 0; ii < _this.vertices.length; ++ii) {
if (_this.vertices[ii].position.equals(positionToSearch)) {
return _this.vertices[ii];
}
}
}
return null;
};
var vertexReferences = [];
var vertexInit = function (i) {
if (!positionData) {
return;
}
var offset = i + submesh.verticesStart;
var position = BABYLON.Vector3.FromArray(positionData, offset * 3);
var vertex = findInVertices(position) || new DecimationVertex(position, _this.vertices.length);
vertex.originalOffsets.push(offset);
if (vertex.id === _this.vertices.length) {
_this.vertices.push(vertex);
}
vertexReferences.push(vertex.id);
};
//var totalVertices = mesh.getTotalVertices();
var totalVertices = submesh.verticesCount;
BABYLON.AsyncLoop.SyncAsyncForLoop(totalVertices, (this.syncIterations / 4) >> 0, vertexInit, function () {
var indicesInit = function (i) {
if (!indices) {
return;
}
var offset = (submesh.indexStart / 3) + i;
var pos = (offset * 3);
var i0 = indices[pos + 0];
var i1 = indices[pos + 1];
var i2 = indices[pos + 2];
var v0 = _this.vertices[vertexReferences[i0 - submesh.verticesStart]];
var v1 = _this.vertices[vertexReferences[i1 - submesh.verticesStart]];
var v2 = _this.vertices[vertexReferences[i2 - submesh.verticesStart]];
var triangle = new DecimationTriangle([v0, v1, v2]);
triangle.originalOffset = pos;
_this.triangles.push(triangle);
};
BABYLON.AsyncLoop.SyncAsyncForLoop(submesh.indexCount / 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(t.vertices[1].position.subtract(t.vertices[0].position), t.vertices[2].position.subtract(t.vertices[0].position)).normalize();
for (var j = 0; j < 3; j++) {
t.vertices[j].q.addArrayInPlace(QuadraticMatrix.DataFromNumbers(t.normal.x, t.normal.y, t.normal.z, -(BABYLON.Vector3.Dot(t.normal, 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(t.vertices[j], 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 () {
callback();
});
});
};
QuadraticErrorSimplification.prototype.reconstructMesh = function (submeshIndex) {
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) {
t.vertices[j].triangleCount = 1;
}
newTriangles.push(t);
}
}
var newPositionData = (this._reconstructedMesh.getVerticesData(BABYLON.VertexBuffer.PositionKind) || []);
var newNormalData = (this._reconstructedMesh.getVerticesData(BABYLON.VertexBuffer.NormalKind) || []);
var newUVsData = (this._reconstructedMesh.getVerticesData(BABYLON.VertexBuffer.UVKind) || []);
var newColorsData = (this._reconstructedMesh.getVerticesData(BABYLON.VertexBuffer.ColorKind) || []);
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 vertexCount = 0;
for (i = 0; i < this.vertices.length; ++i) {
var vertex = this.vertices[i];
vertex.id = vertexCount;
if (vertex.triangleCount) {
vertex.originalOffsets.forEach(function (originalOffset) {
if (!normalData) {
return;
}
newPositionData.push(vertex.position.x);
newPositionData.push(vertex.position.y);
newPositionData.push(vertex.position.z);
newNormalData.push(normalData[originalOffset * 3]);
newNormalData.push(normalData[(originalOffset * 3) + 1]);
newNormalData.push(normalData[(originalOffset * 3) + 2]);
if (uvs && uvs.length) {
newUVsData.push(uvs[(originalOffset * 2)]);
newUVsData.push(uvs[(originalOffset * 2) + 1]);
}
else if (colorsData && colorsData.length) {
newColorsData.push(colorsData[(originalOffset * 4)]);
newColorsData.push(colorsData[(originalOffset * 4) + 1]);
newColorsData.push(colorsData[(originalOffset * 4) + 2]);
newColorsData.push(colorsData[(originalOffset * 4) + 3]);
}
++vertexCount;
});
}
}
var startingIndex = this._reconstructedMesh.getTotalIndices();
var startingVertex = this._reconstructedMesh.getTotalVertices();
var submeshesArray = this._reconstructedMesh.subMeshes;
this._reconstructedMesh.subMeshes = [];
var newIndicesArray = this._reconstructedMesh.getIndices(); //[];
var originalIndices = this._mesh.getIndices();
for (i = 0; i < newTriangles.length; ++i) {
t = newTriangles[i]; //now get the new referencing point for each vertex
[0, 1, 2].forEach(function (idx) {
var id = originalIndices[t.originalOffset + idx];
var offset = t.vertices[idx].originalOffsets.indexOf(id);
if (offset < 0)
offset = 0;
newIndicesArray.push(t.vertices[idx].id + offset + startingVertex);
});
}
//overwriting the old vertex buffers and indices.
this._reconstructedMesh.setIndices(newIndicesArray);
this._reconstructedMesh.setVerticesData(BABYLON.VertexBuffer.PositionKind, newPositionData);
this._reconstructedMesh.setVerticesData(BABYLON.VertexBuffer.NormalKind, newNormalData);
if (newUVsData.length > 0)
this._reconstructedMesh.setVerticesData(BABYLON.VertexBuffer.UVKind, newUVsData);
if (newColorsData.length > 0)
this._reconstructedMesh.setVerticesData(BABYLON.VertexBuffer.ColorKind, newColorsData);
//create submesh
var originalSubmesh = this._mesh.subMeshes[submeshIndex];
if (submeshIndex > 0) {
this._reconstructedMesh.subMeshes = [];
submeshesArray.forEach(function (submesh) {
BABYLON.SubMesh.AddToMesh(submesh.materialIndex, submesh.verticesStart, submesh.verticesCount, /* 0, newPositionData.length/3, */ submesh.indexStart, submesh.indexCount, submesh.getMesh());
});
BABYLON.SubMesh.AddToMesh(originalSubmesh.materialIndex, startingVertex, vertexCount, /* 0, newPositionData.length / 3, */ startingIndex, newTriangles.length * 3, this._reconstructedMesh);
}
};
QuadraticErrorSimplification.prototype.initDecimatedMesh = function () {
this._reconstructedMesh = new BABYLON.Mesh(this._mesh.name + "Decimated", this._mesh.getScene());
this._reconstructedMesh.material = this._mesh.material;
this._reconstructedMesh.parent = this._mesh.parent;
this._reconstructedMesh.isVisible = false;
this._reconstructedMesh.renderingGroupId = this._mesh.renderingGroupId;
};
QuadraticErrorSimplification.prototype.isFlipped = function (vertex1, vertex2, point, deletedArray, borderFactor, delTr) {
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 v1 = t.vertices[(s + 1) % 3];
var v2 = t.vertices[(s + 2) % 3];
if ((v1 === vertex2 || v2 === vertex2)) {
deletedArray[i] = true;
delTr.push(t);
continue;
}
var d1 = v1.position.subtract(point);
d1 = d1.normalize();
var d2 = v2.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 (origVertex, 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.deletePending) {
t.deleted = true;
newDeleted++;
continue;
}
t.vertices[ref.vertexId] = origVertex;
t.isDirty = true;
t.error[0] = this.calculateError(t.vertices[0], t.vertices[1]) + (t.borderFactor / 2);
t.error[1] = this.calculateError(t.vertices[1], t.vertices[2]) + (t.borderFactor / 2);
t.error[2] = this.calculateError(t.vertices[2], 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 vv = triangle.vertices[ii];
while (ofs < vCount.length) {
if (vId[ofs] === vv.id)
break;
++ofs;
}
if (ofs === vCount.length) {
vCount.push(1);
vId.push(vv.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 (identifyBorders === void 0) { 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 = 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 = 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, colorResult) {
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);
}
else {
var p3 = (vertex1.position.add(vertex2.position)).divide(new BABYLON.Vector3(2, 2, 2));
//var norm3 = (vertex1.normal.add(vertex2.normal)).divide(new 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);
}
}
else if (error === error2) {
if (pointResult) {
pointResult.copyFrom(vertex2.position);
}
}
else {
if (pointResult) {
pointResult.copyFrom(p3);
}
}
}
return error;
};
return QuadraticErrorSimplification;
}());
BABYLON.QuadraticErrorSimplification = QuadraticErrorSimplification;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.meshSimplification.js.map
var BABYLON;
(function (BABYLON) {
var MeshLODLevel = /** @class */ (function () {
function MeshLODLevel(distance, mesh) {
this.distance = distance;
this.mesh = mesh;
}
return MeshLODLevel;
}());
BABYLON.MeshLODLevel = MeshLODLevel;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.meshLODLevel.js.map
var BABYLON;
(function (BABYLON) {
/**
* Defines the root class used to create scene optimization to use with SceneOptimizer
* @description More details at http://doc.babylonjs.com/how_to/how_to_use_sceneoptimizer
*/
var SceneOptimization = /** @class */ (function () {
/**
* Creates the SceneOptimization object
* @param priority defines the priority of this optimization (0 by default which means first in the list)
* @param desc defines the description associated with the optimization
*/
function SceneOptimization(
/**
* Defines the priority of this optimization (0 by default which means first in the list)
*/
priority) {
if (priority === void 0) { priority = 0; }
this.priority = priority;
}
/**
* Gets a string describing the action executed by the current optimization
* @returns description string
*/
SceneOptimization.prototype.getDescription = function () {
return "";
};
/**
* This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
* @param scene defines the current scene where to apply this optimization
* @param optimizer defines the current optimizer
* @returns true if everything that can be done was applied
*/
SceneOptimization.prototype.apply = function (scene, optimizer) {
return true;
};
;
return SceneOptimization;
}());
BABYLON.SceneOptimization = SceneOptimization;
/**
* Defines an optimization used to reduce the size of render target textures
* @description More details at http://doc.babylonjs.com/how_to/how_to_use_sceneoptimizer
*/
var TextureOptimization = /** @class */ (function (_super) {
__extends(TextureOptimization, _super);
/**
* Creates the TextureOptimization object
* @param priority defines the priority of this optimization (0 by default which means first in the list)
* @param maximumSize defines the maximum sized allowed for textures (1024 is the default value). If a texture is bigger, it will be scaled down using a factor defined by the step parameter
* @param step defines the factor (0.5 by default) used to scale down textures bigger than maximum sized allowed.
*/
function TextureOptimization(
/**
* Defines the priority of this optimization (0 by default which means first in the list)
*/
priority,
/**
* Defines the maximum sized allowed for textures (1024 is the default value). If a texture is bigger, it will be scaled down using a factor defined by the step parameter
*/
maximumSize,
/**
* Defines the factor (0.5 by default) used to scale down textures bigger than maximum sized allowed.
*/
step) {
if (priority === void 0) { priority = 0; }
if (maximumSize === void 0) { maximumSize = 1024; }
if (step === void 0) { step = 0.5; }
var _this = _super.call(this, priority) || this;
_this.priority = priority;
_this.maximumSize = maximumSize;
_this.step = step;
return _this;
}
/**
* Gets a string describing the action executed by the current optimization
* @returns description string
*/
TextureOptimization.prototype.getDescription = function () {
return "Reducing render target texture size to " + this.maximumSize;
};
/**
* This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
* @param scene defines the current scene where to apply this optimization
* @param optimizer defines the current optimizer
* @returns true if everything that can be done was applied
*/
TextureOptimization.prototype.apply = function (scene, optimizer) {
var allDone = true;
for (var index = 0; index < scene.textures.length; index++) {
var texture = scene.textures[index];
if (!texture.canRescale || texture.getContext) {
continue;
}
var currentSize = texture.getSize();
var maxDimension = Math.max(currentSize.width, currentSize.height);
if (maxDimension > this.maximumSize) {
texture.scale(this.step);
allDone = false;
}
}
return allDone;
};
return TextureOptimization;
}(SceneOptimization));
BABYLON.TextureOptimization = TextureOptimization;
/**
* Defines an optimization used to increase or decrease the rendering resolution
* @description More details at http://doc.babylonjs.com/how_to/how_to_use_sceneoptimizer
*/
var HardwareScalingOptimization = /** @class */ (function (_super) {
__extends(HardwareScalingOptimization, _super);
/**
* Creates the HardwareScalingOptimization object
* @param priority defines the priority of this optimization (0 by default which means first in the list)
* @param maximumScale defines the maximum scale to use (2 by default)
* @param step defines the step to use between two passes (0.5 by default)
*/
function HardwareScalingOptimization(
/**
* Defines the priority of this optimization (0 by default which means first in the list)
*/
priority,
/**
* Defines the maximum scale to use (2 by default)
*/
maximumScale,
/**
* Defines the step to use between two passes (0.5 by default)
*/
step) {
if (priority === void 0) { priority = 0; }
if (maximumScale === void 0) { maximumScale = 2; }
if (step === void 0) { step = 0.25; }
var _this = _super.call(this, priority) || this;
_this.priority = priority;
_this.maximumScale = maximumScale;
_this.step = step;
_this._currentScale = -1;
_this._directionOffset = 1;
return _this;
}
/**
* Gets a string describing the action executed by the current optimization
* @return description string
*/
HardwareScalingOptimization.prototype.getDescription = function () {
return "Setting hardware scaling level to " + this._currentScale;
};
/**
* This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
* @param scene defines the current scene where to apply this optimization
* @param optimizer defines the current optimizer
* @returns true if everything that can be done was applied
*/
HardwareScalingOptimization.prototype.apply = function (scene, optimizer) {
if (this._currentScale === -1) {
this._currentScale = scene.getEngine().getHardwareScalingLevel();
if (this._currentScale > this.maximumScale) {
this._directionOffset = -1;
}
}
this._currentScale += this._directionOffset * this.step;
scene.getEngine().setHardwareScalingLevel(this._currentScale);
return this._directionOffset === 1 ? this._currentScale >= this.maximumScale : this._currentScale <= this.maximumScale;
};
;
return HardwareScalingOptimization;
}(SceneOptimization));
BABYLON.HardwareScalingOptimization = HardwareScalingOptimization;
/**
* Defines an optimization used to remove shadows
* @description More details at http://doc.babylonjs.com/how_to/how_to_use_sceneoptimizer
*/
var ShadowsOptimization = /** @class */ (function (_super) {
__extends(ShadowsOptimization, _super);
function ShadowsOptimization() {
return _super !== null && _super.apply(this, arguments) || this;
}
/**
* Gets a string describing the action executed by the current optimization
* @return description string
*/
ShadowsOptimization.prototype.getDescription = function () {
return "Turning shadows on/off";
};
/**
* This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
* @param scene defines the current scene where to apply this optimization
* @param optimizer defines the current optimizer
* @returns true if everything that can be done was applied
*/
ShadowsOptimization.prototype.apply = function (scene, optimizer) {
scene.shadowsEnabled = optimizer.isInImprovementMode;
return true;
};
;
return ShadowsOptimization;
}(SceneOptimization));
BABYLON.ShadowsOptimization = ShadowsOptimization;
/**
* Defines an optimization used to turn post-processes off
* @description More details at http://doc.babylonjs.com/how_to/how_to_use_sceneoptimizer
*/
var PostProcessesOptimization = /** @class */ (function (_super) {
__extends(PostProcessesOptimization, _super);
function PostProcessesOptimization() {
return _super !== null && _super.apply(this, arguments) || this;
}
/**
* Gets a string describing the action executed by the current optimization
* @return description string
*/
PostProcessesOptimization.prototype.getDescription = function () {
return "Turning post-processes on/off";
};
/**
* This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
* @param scene defines the current scene where to apply this optimization
* @param optimizer defines the current optimizer
* @returns true if everything that can be done was applied
*/
PostProcessesOptimization.prototype.apply = function (scene, optimizer) {
scene.postProcessesEnabled = optimizer.isInImprovementMode;
return true;
};
;
return PostProcessesOptimization;
}(SceneOptimization));
BABYLON.PostProcessesOptimization = PostProcessesOptimization;
/**
* Defines an optimization used to turn lens flares off
* @description More details at http://doc.babylonjs.com/how_to/how_to_use_sceneoptimizer
*/
var LensFlaresOptimization = /** @class */ (function (_super) {
__extends(LensFlaresOptimization, _super);
function LensFlaresOptimization() {
return _super !== null && _super.apply(this, arguments) || this;
}
/**
* Gets a string describing the action executed by the current optimization
* @return description string
*/
LensFlaresOptimization.prototype.getDescription = function () {
return "Turning lens flares on/off";
};
/**
* This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
* @param scene defines the current scene where to apply this optimization
* @param optimizer defines the current optimizer
* @returns true if everything that can be done was applied
*/
LensFlaresOptimization.prototype.apply = function (scene, optimizer) {
scene.lensFlaresEnabled = optimizer.isInImprovementMode;
return true;
};
;
return LensFlaresOptimization;
}(SceneOptimization));
BABYLON.LensFlaresOptimization = LensFlaresOptimization;
/**
* Defines an optimization based on user defined callback.
* @description More details at http://doc.babylonjs.com/how_to/how_to_use_sceneoptimizer
*/
var CustomOptimization = /** @class */ (function (_super) {
__extends(CustomOptimization, _super);
function CustomOptimization() {
return _super !== null && _super.apply(this, arguments) || this;
}
/**
* Gets a string describing the action executed by the current optimization
* @returns description string
*/
CustomOptimization.prototype.getDescription = function () {
if (this.onGetDescription) {
return this.onGetDescription();
}
return "Running user defined callback";
};
/**
* This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
* @param scene defines the current scene where to apply this optimization
* @param optimizer defines the current optimizer
* @returns true if everything that can be done was applied
*/
CustomOptimization.prototype.apply = function (scene, optimizer) {
if (this.onApply) {
return this.onApply(scene, optimizer);
}
return true;
};
;
return CustomOptimization;
}(SceneOptimization));
BABYLON.CustomOptimization = CustomOptimization;
/**
* Defines an optimization used to turn particles off
* @description More details at http://doc.babylonjs.com/how_to/how_to_use_sceneoptimizer
*/
var ParticlesOptimization = /** @class */ (function (_super) {
__extends(ParticlesOptimization, _super);
function ParticlesOptimization() {
return _super !== null && _super.apply(this, arguments) || this;
}
/**
* Gets a string describing the action executed by the current optimization
* @return description string
*/
ParticlesOptimization.prototype.getDescription = function () {
return "Turning particles on/off";
};
/**
* This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
* @param scene defines the current scene where to apply this optimization
* @param optimizer defines the current optimizer
* @returns true if everything that can be done was applied
*/
ParticlesOptimization.prototype.apply = function (scene, optimizer) {
scene.particlesEnabled = optimizer.isInImprovementMode;
return true;
};
;
return ParticlesOptimization;
}(SceneOptimization));
BABYLON.ParticlesOptimization = ParticlesOptimization;
/**
* Defines an optimization used to turn render targets off
* @description More details at http://doc.babylonjs.com/how_to/how_to_use_sceneoptimizer
*/
var RenderTargetsOptimization = /** @class */ (function (_super) {
__extends(RenderTargetsOptimization, _super);
function RenderTargetsOptimization() {
return _super !== null && _super.apply(this, arguments) || this;
}
/**
* Gets a string describing the action executed by the current optimization
* @return description string
*/
RenderTargetsOptimization.prototype.getDescription = function () {
return "Turning render targets off";
};
/**
* This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
* @param scene defines the current scene where to apply this optimization
* @param optimizer defines the current optimizer
* @returns true if everything that can be done was applied
*/
RenderTargetsOptimization.prototype.apply = function (scene, optimizer) {
scene.renderTargetsEnabled = optimizer.isInImprovementMode;
return true;
};
;
return RenderTargetsOptimization;
}(SceneOptimization));
BABYLON.RenderTargetsOptimization = RenderTargetsOptimization;
/**
* Defines an optimization used to merge meshes with compatible materials
* @description More details at http://doc.babylonjs.com/how_to/how_to_use_sceneoptimizer
*/
var MergeMeshesOptimization = /** @class */ (function (_super) {
__extends(MergeMeshesOptimization, _super);
function MergeMeshesOptimization() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this._canBeMerged = function (abstractMesh) {
if (!(abstractMesh instanceof BABYLON.Mesh)) {
return false;
}
var mesh = abstractMesh;
if (mesh.isDisposed()) {
return false;
}
if (!mesh.isVisible || !mesh.isEnabled()) {
return false;
}
if (mesh.instances.length > 0) {
return false;
}
if (mesh.skeleton || mesh.hasLODLevels) {
return false;
}
return true;
};
return _this;
}
Object.defineProperty(MergeMeshesOptimization, "UpdateSelectionTree", {
/**
* Gets or sets a boolean which defines if optimization octree has to be updated
*/
get: function () {
return MergeMeshesOptimization._UpdateSelectionTree;
},
/**
* Gets or sets a boolean which defines if optimization octree has to be updated
*/
set: function (value) {
MergeMeshesOptimization._UpdateSelectionTree = value;
},
enumerable: true,
configurable: true
});
/**
* Gets a string describing the action executed by the current optimization
* @return description string
*/
MergeMeshesOptimization.prototype.getDescription = function () {
return "Merging similar meshes together";
};
/**
* This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
* @param scene defines the current scene where to apply this optimization
* @param optimizer defines the current optimizer
* @param updateSelectionTree defines that the selection octree has to be updated (false by default)
* @returns true if everything that can be done was applied
*/
MergeMeshesOptimization.prototype.apply = function (scene, optimizer, updateSelectionTree) {
var globalPool = scene.meshes.slice(0);
var globalLength = globalPool.length;
for (var index = 0; index < globalLength; index++) {
var currentPool = new Array();
var current = globalPool[index];
// Checks
if (!this._canBeMerged(current)) {
continue;
}
currentPool.push(current);
// Find compatible meshes
for (var subIndex = index + 1; subIndex < globalLength; subIndex++) {
var otherMesh = globalPool[subIndex];
if (!this._canBeMerged(otherMesh)) {
continue;
}
if (otherMesh.material !== current.material) {
continue;
}
if (otherMesh.checkCollisions !== current.checkCollisions) {
continue;
}
currentPool.push(otherMesh);
globalLength--;
globalPool.splice(subIndex, 1);
subIndex--;
}
if (currentPool.length < 2) {
continue;
}
// Merge meshes
BABYLON.Mesh.MergeMeshes(currentPool, undefined, true);
}
if (updateSelectionTree != undefined) {
if (updateSelectionTree) {
scene.createOrUpdateSelectionOctree();
}
}
else if (MergeMeshesOptimization.UpdateSelectionTree) {
scene.createOrUpdateSelectionOctree();
}
return true;
};
;
MergeMeshesOptimization._UpdateSelectionTree = false;
return MergeMeshesOptimization;
}(SceneOptimization));
BABYLON.MergeMeshesOptimization = MergeMeshesOptimization;
/**
* Defines a list of options used by SceneOptimizer
* @description More details at http://doc.babylonjs.com/how_to/how_to_use_sceneoptimizer
*/
var SceneOptimizerOptions = /** @class */ (function () {
/**
* Creates a new list of options used by SceneOptimizer
* @param targetFrameRate defines the target frame rate to reach (60 by default)
* @param trackerDuration defines the interval between two checkes (2000ms by default)
*/
function SceneOptimizerOptions(
/**
* Defines the target frame rate to reach (60 by default)
*/
targetFrameRate,
/**
* Defines the interval between two checkes (2000ms by default)
*/
trackerDuration) {
if (targetFrameRate === void 0) { targetFrameRate = 60; }
if (trackerDuration === void 0) { trackerDuration = 2000; }
this.targetFrameRate = targetFrameRate;
this.trackerDuration = trackerDuration;
/**
* Gets the list of optimizations to apply
*/
this.optimizations = new Array();
}
/**
* Add a new optimization
* @param optimization defines the SceneOptimization to add to the list of active optimizations
* @returns the current SceneOptimizerOptions
*/
SceneOptimizerOptions.prototype.addOptimization = function (optimization) {
this.optimizations.push(optimization);
return this;
};
/**
* Add a new custom optimization
* @param onApply defines the callback called to apply the custom optimization (true if everything that can be done was applied)
* @param onGetDescription defines the callback called to get the description attached with the optimization.
* @param priority defines the priority of this optimization (0 by default which means first in the list)
* @returns the current SceneOptimizerOptions
*/
SceneOptimizerOptions.prototype.addCustomOptimization = function (onApply, onGetDescription, priority) {
if (priority === void 0) { priority = 0; }
var optimization = new CustomOptimization(priority);
optimization.onApply = onApply;
optimization.onGetDescription = onGetDescription;
this.optimizations.push(optimization);
return this;
};
/**
* Creates a list of pre-defined optimizations aimed to reduce the visual impact on the scene
* @param targetFrameRate defines the target frame rate (60 by default)
* @returns a SceneOptimizerOptions object
*/
SceneOptimizerOptions.LowDegradationAllowed = function (targetFrameRate) {
var result = new SceneOptimizerOptions(targetFrameRate);
var priority = 0;
result.addOptimization(new MergeMeshesOptimization(priority));
result.addOptimization(new ShadowsOptimization(priority));
result.addOptimization(new LensFlaresOptimization(priority));
// Next priority
priority++;
result.addOptimization(new PostProcessesOptimization(priority));
result.addOptimization(new ParticlesOptimization(priority));
// Next priority
priority++;
result.addOptimization(new TextureOptimization(priority, 1024));
return result;
};
/**
* Creates a list of pre-defined optimizations aimed to have a moderate impact on the scene visual
* @param targetFrameRate defines the target frame rate (60 by default)
* @returns a SceneOptimizerOptions object
*/
SceneOptimizerOptions.ModerateDegradationAllowed = function (targetFrameRate) {
var result = new SceneOptimizerOptions(targetFrameRate);
var priority = 0;
result.addOptimization(new MergeMeshesOptimization(priority));
result.addOptimization(new ShadowsOptimization(priority));
result.addOptimization(new LensFlaresOptimization(priority));
// Next priority
priority++;
result.addOptimization(new PostProcessesOptimization(priority));
result.addOptimization(new ParticlesOptimization(priority));
// Next priority
priority++;
result.addOptimization(new TextureOptimization(priority, 512));
// Next priority
priority++;
result.addOptimization(new RenderTargetsOptimization(priority));
// Next priority
priority++;
result.addOptimization(new HardwareScalingOptimization(priority, 2));
return result;
};
/**
* Creates a list of pre-defined optimizations aimed to have a big impact on the scene visual
* @param targetFrameRate defines the target frame rate (60 by default)
* @returns a SceneOptimizerOptions object
*/
SceneOptimizerOptions.HighDegradationAllowed = function (targetFrameRate) {
var result = new SceneOptimizerOptions(targetFrameRate);
var priority = 0;
result.addOptimization(new MergeMeshesOptimization(priority));
result.addOptimization(new ShadowsOptimization(priority));
result.addOptimization(new LensFlaresOptimization(priority));
// Next priority
priority++;
result.addOptimization(new PostProcessesOptimization(priority));
result.addOptimization(new ParticlesOptimization(priority));
// Next priority
priority++;
result.addOptimization(new TextureOptimization(priority, 256));
// Next priority
priority++;
result.addOptimization(new RenderTargetsOptimization(priority));
// Next priority
priority++;
result.addOptimization(new HardwareScalingOptimization(priority, 4));
return result;
};
return SceneOptimizerOptions;
}());
BABYLON.SceneOptimizerOptions = SceneOptimizerOptions;
/**
* Class used to run optimizations in order to reach a target frame rate
* @description More details at http://doc.babylonjs.com/how_to/how_to_use_sceneoptimizer
*/
var SceneOptimizer = /** @class */ (function () {
/**
* Creates a new SceneOptimizer
* @param scene defines the scene to work on
* @param options defines the options to use with the SceneOptimizer
* @param autoGeneratePriorities defines if priorities must be generated and not read from SceneOptimization property (true by default)
* @param improvementMode defines if the scene optimizer must run the maximum optimization while staying over a target frame instead of trying to reach the target framerate (false by default)
*/
function SceneOptimizer(scene, options, autoGeneratePriorities, improvementMode) {
if (autoGeneratePriorities === void 0) { autoGeneratePriorities = true; }
if (improvementMode === void 0) { improvementMode = false; }
var _this = this;
this._isRunning = false;
this._currentPriorityLevel = 0;
this._targetFrameRate = 60;
this._trackerDuration = 2000;
this._currentFrameRate = 0;
this._improvementMode = false;
/**
* Defines an observable called when the optimizer reaches the target frame rate
*/
this.onSuccessObservable = new BABYLON.Observable();
/**
* Defines an observable called when the optimizer enables an optimization
*/
this.onNewOptimizationAppliedObservable = new BABYLON.Observable();
/**
* Defines an observable called when the optimizer is not able to reach the target frame rate
*/
this.onFailureObservable = new BABYLON.Observable();
if (!options) {
this._options = new SceneOptimizerOptions();
}
else {
this._options = options;
}
if (this._options.targetFrameRate) {
this._targetFrameRate = this._options.targetFrameRate;
}
if (this._options.trackerDuration) {
this._trackerDuration = this._options.trackerDuration;
}
if (autoGeneratePriorities) {
var priority = 0;
for (var _i = 0, _a = this._options.optimizations; _i < _a.length; _i++) {
var optim = _a[_i];
optim.priority = priority++;
}
}
this._improvementMode = improvementMode;
this._scene = scene || BABYLON.Engine.LastCreatedScene;
this._sceneDisposeObserver = this._scene.onDisposeObservable.add(function () {
_this._sceneDisposeObserver = null;
_this.dispose();
});
}
Object.defineProperty(SceneOptimizer.prototype, "isInImprovementMode", {
/**
* Gets a boolean indicating if the optimizer is in improvement mode
*/
get: function () {
return this._improvementMode;
},
enumerable: true,
configurable: true
});
Object.defineProperty(SceneOptimizer.prototype, "currentPriorityLevel", {
/**
* Gets the current priority level (0 at start)
*/
get: function () {
return this._currentPriorityLevel;
},
enumerable: true,
configurable: true
});
Object.defineProperty(SceneOptimizer.prototype, "currentFrameRate", {
/**
* Gets the current frame rate checked by the SceneOptimizer
*/
get: function () {
return this._currentFrameRate;
},
enumerable: true,
configurable: true
});
Object.defineProperty(SceneOptimizer.prototype, "targetFrameRate", {
/**
* Gets or sets the current target frame rate (60 by default)
*/
get: function () {
return this._targetFrameRate;
},
/**
* Gets or sets the current target frame rate (60 by default)
*/
set: function (value) {
this._targetFrameRate = value;
},
enumerable: true,
configurable: true
});
Object.defineProperty(SceneOptimizer.prototype, "trackerDuration", {
/**
* Gets or sets the current interval between two checks (every 2000ms by default)
*/
get: function () {
return this._trackerDuration;
},
/**
* Gets or sets the current interval between two checks (every 2000ms by default)
*/
set: function (value) {
this._trackerDuration = value;
},
enumerable: true,
configurable: true
});
Object.defineProperty(SceneOptimizer.prototype, "optimizations", {
/**
* Gets the list of active optimizations
*/
get: function () {
return this._options.optimizations;
},
enumerable: true,
configurable: true
});
/**
* Stops the current optimizer
*/
SceneOptimizer.prototype.stop = function () {
this._isRunning = false;
};
/**
* Reset the optimizer to initial step (current priority level = 0)
*/
SceneOptimizer.prototype.reset = function () {
this._currentPriorityLevel = 0;
};
/**
* Start the optimizer. By default it will try to reach a specific framerate
* but if the optimizer is set with improvementMode === true then it will run all optimiatiation while frame rate is above the target frame rate
*/
SceneOptimizer.prototype.start = function () {
var _this = this;
if (this._isRunning) {
return;
}
this._isRunning = true;
// Let's wait for the scene to be ready before running our check
this._scene.executeWhenReady(function () {
setTimeout(function () {
_this._checkCurrentState();
}, _this._trackerDuration);
});
};
SceneOptimizer.prototype._checkCurrentState = function () {
var _this = this;
if (!this._isRunning) {
return;
}
var scene = this._scene;
var options = this._options;
this._currentFrameRate = Math.round(scene.getEngine().getFps());
if (this._improvementMode && this._currentFrameRate <= this._targetFrameRate ||
!this._improvementMode && this._currentFrameRate >= this._targetFrameRate) {
this._isRunning = false;
this.onSuccessObservable.notifyObservers(this);
return;
}
// Apply current level of optimizations
var allDone = true;
var noOptimizationApplied = true;
for (var index = 0; index < options.optimizations.length; index++) {
var optimization = options.optimizations[index];
if (optimization.priority === this._currentPriorityLevel) {
noOptimizationApplied = false;
allDone = allDone && optimization.apply(scene, this);
this.onNewOptimizationAppliedObservable.notifyObservers(optimization);
}
}
// If no optimization was applied, this is a failure :(
if (noOptimizationApplied) {
this._isRunning = false;
this.onFailureObservable.notifyObservers(this);
return;
}
// If all optimizations were done, move to next level
if (allDone) {
this._currentPriorityLevel++;
}
// Let's the system running for a specific amount of time before checking FPS
scene.executeWhenReady(function () {
setTimeout(function () {
_this._checkCurrentState();
}, _this._trackerDuration);
});
};
/**
* Release all resources
*/
SceneOptimizer.prototype.dispose = function () {
this.stop();
this.onSuccessObservable.clear();
this.onFailureObservable.clear();
this.onNewOptimizationAppliedObservable.clear();
if (this._sceneDisposeObserver) {
this._scene.onDisposeObservable.remove(this._sceneDisposeObserver);
}
};
/**
* Helper function to create a SceneOptimizer with one single line of code
* @param scene defines the scene to work on
* @param options defines the options to use with the SceneOptimizer
* @param onSuccess defines a callback to call on success
* @param onFailure defines a callback to call on failure
* @returns the new SceneOptimizer object
*/
SceneOptimizer.OptimizeAsync = function (scene, options, onSuccess, onFailure) {
var optimizer = new SceneOptimizer(scene, options || SceneOptimizerOptions.ModerateDegradationAllowed(), false);
if (onSuccess) {
optimizer.onSuccessObservable.add(function () {
onSuccess();
});
}
if (onFailure) {
optimizer.onFailureObservable.add(function () {
onFailure();
});
}
optimizer.start();
return optimizer;
};
return SceneOptimizer;
}());
BABYLON.SceneOptimizer = SceneOptimizer;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.sceneOptimizer.js.map
var BABYLON;
(function (BABYLON) {
var OutlineRenderer = /** @class */ (function () {
function OutlineRenderer(scene) {
this.zOffset = 1;
this._scene = scene;
}
OutlineRenderer.prototype.render = function (subMesh, batch, useOverlay) {
var _this = this;
if (useOverlay === void 0) { useOverlay = false; }
var scene = this._scene;
var engine = this._scene.getEngine();
var hardwareInstancedRendering = (engine.getCaps().instancedArrays) && (batch.visibleInstances[subMesh._id] !== null) && (batch.visibleInstances[subMesh._id] !== undefined);
if (!this.isReady(subMesh, hardwareInstancedRendering)) {
return;
}
var mesh = subMesh.getRenderingMesh();
var material = subMesh.getMaterial();
if (!material || !scene.activeCamera) {
return;
}
engine.enableEffect(this._effect);
// Logarithmic depth
if (material.useLogarithmicDepth) {
this._effect.setFloat("logarithmicDepthConstant", 2.0 / (Math.log(scene.activeCamera.maxZ + 1.0) / Math.LN2));
}
this._effect.setFloat("offset", useOverlay ? 0 : mesh.outlineWidth);
this._effect.setColor4("color", useOverlay ? mesh.overlayColor : mesh.outlineColor, useOverlay ? mesh.overlayAlpha : material.alpha);
this._effect.setMatrix("viewProjection", scene.getTransformMatrix());
// Bones
if (mesh.useBones && mesh.computeBonesUsingShaders && mesh.skeleton) {
this._effect.setMatrices("mBones", mesh.skeleton.getTransformMatrices(mesh));
}
mesh._bind(subMesh, this._effect, BABYLON.Material.TriangleFillMode);
// Alpha test
if (material && material.needAlphaTesting()) {
var alphaTexture = material.getAlphaTestTexture();
if (alphaTexture) {
this._effect.setTexture("diffuseSampler", alphaTexture);
this._effect.setMatrix("diffuseMatrix", alphaTexture.getTextureMatrix());
}
}
engine.setZOffset(-this.zOffset);
mesh._processRendering(subMesh, this._effect, BABYLON.Material.TriangleFillMode, batch, hardwareInstancedRendering, function (isInstance, world) { _this._effect.setMatrix("world", world); });
engine.setZOffset(0);
};
OutlineRenderer.prototype.isReady = function (subMesh, useInstances) {
var defines = [];
var attribs = [BABYLON.VertexBuffer.PositionKind, BABYLON.VertexBuffer.NormalKind];
var mesh = subMesh.getMesh();
var material = subMesh.getMaterial();
if (material) {
// Alpha test
if (material.needAlphaTesting()) {
defines.push("#define ALPHATEST");
if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) {
attribs.push(BABYLON.VertexBuffer.UVKind);
defines.push("#define UV1");
}
if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.UV2Kind)) {
attribs.push(BABYLON.VertexBuffer.UV2Kind);
defines.push("#define UV2");
}
}
//Logarithmic depth
if (material.useLogarithmicDepth) {
defines.push("#define LOGARITHMICDEPTH");
}
}
// Bones
if (mesh.useBones && mesh.computeBonesUsingShaders) {
attribs.push(BABYLON.VertexBuffer.MatricesIndicesKind);
attribs.push(BABYLON.VertexBuffer.MatricesWeightsKind);
if (mesh.numBoneInfluencers > 4) {
attribs.push(BABYLON.VertexBuffer.MatricesIndicesExtraKind);
attribs.push(BABYLON.VertexBuffer.MatricesWeightsExtraKind);
}
defines.push("#define NUM_BONE_INFLUENCERS " + mesh.numBoneInfluencers);
defines.push("#define BonesPerMesh " + (mesh.skeleton ? mesh.skeleton.bones.length + 1 : 0));
}
else {
defines.push("#define NUM_BONE_INFLUENCERS 0");
}
// Instances
if (useInstances) {
defines.push("#define INSTANCES");
attribs.push("world0");
attribs.push("world1");
attribs.push("world2");
attribs.push("world3");
}
// Get correct effect
var join = defines.join("\n");
if (this._cachedDefines !== join) {
this._cachedDefines = join;
this._effect = this._scene.getEngine().createEffect("outline", attribs, ["world", "mBones", "viewProjection", "diffuseMatrix", "offset", "color", "logarithmicDepthConstant"], ["diffuseSampler"], join);
}
return this._effect.isReady();
};
return OutlineRenderer;
}());
BABYLON.OutlineRenderer = OutlineRenderer;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.outlineRenderer.js.map
var BABYLON;
(function (BABYLON) {
var FaceAdjacencies = /** @class */ (function () {
function FaceAdjacencies() {
this.edges = new Array();
this.edgesConnectedCount = 0;
}
return FaceAdjacencies;
}());
var EdgesRenderer = /** @class */ (function () {
// Beware when you use this class with complex objects as the adjacencies computation can be really long
function EdgesRenderer(source, epsilon, checkVerticesInsteadOfIndices) {
if (epsilon === void 0) { epsilon = 0.95; }
if (checkVerticesInsteadOfIndices === void 0) { checkVerticesInsteadOfIndices = false; }
this.edgesWidthScalerForOrthographic = 1000.0;
this.edgesWidthScalerForPerspective = 50.0;
this._linesPositions = new Array();
this._linesNormals = new Array();
this._linesIndices = new Array();
this._buffers = {};
this._checkVerticesInsteadOfIndices = false;
/** Gets or sets a boolean indicating if the edgesRenderer is active */
this.isEnabled = true;
this._source = source;
this._checkVerticesInsteadOfIndices = checkVerticesInsteadOfIndices;
this._epsilon = epsilon;
this._prepareRessources();
this._generateEdgesLines();
}
EdgesRenderer.prototype._prepareRessources = function () {
if (this._lineShader) {
return;
}
this._lineShader = new BABYLON.ShaderMaterial("lineShader", this._source.getScene(), "line", {
attributes: ["position", "normal"],
uniforms: ["worldViewProjection", "color", "width", "aspectRatio"]
});
this._lineShader.disableDepthWrite = true;
this._lineShader.backFaceCulling = false;
};
EdgesRenderer.prototype._rebuild = function () {
var buffer = this._buffers[BABYLON.VertexBuffer.PositionKind];
if (buffer) {
buffer._rebuild();
}
buffer = this._buffers[BABYLON.VertexBuffer.NormalKind];
if (buffer) {
buffer._rebuild();
}
var scene = this._source.getScene();
var engine = scene.getEngine();
this._ib = engine.createIndexBuffer(this._linesIndices);
};
EdgesRenderer.prototype.dispose = function () {
var buffer = this._buffers[BABYLON.VertexBuffer.PositionKind];
if (buffer) {
buffer.dispose();
this._buffers[BABYLON.VertexBuffer.PositionKind] = null;
}
buffer = this._buffers[BABYLON.VertexBuffer.NormalKind];
if (buffer) {
buffer.dispose();
this._buffers[BABYLON.VertexBuffer.NormalKind] = null;
}
this._source.getScene().getEngine()._releaseBuffer(this._ib);
this._lineShader.dispose();
};
EdgesRenderer.prototype._processEdgeForAdjacencies = function (pa, pb, p0, p1, p2) {
if (pa === p0 && pb === p1 || pa === p1 && pb === p0) {
return 0;
}
if (pa === p1 && pb === p2 || pa === p2 && pb === p1) {
return 1;
}
if (pa === p2 && pb === p0 || pa === p0 && pb === p2) {
return 2;
}
return -1;
};
EdgesRenderer.prototype._processEdgeForAdjacenciesWithVertices = function (pa, pb, p0, p1, p2) {
if (pa.equalsWithEpsilon(p0) && pb.equalsWithEpsilon(p1) || pa.equalsWithEpsilon(p1) && pb.equalsWithEpsilon(p0)) {
return 0;
}
if (pa.equalsWithEpsilon(p1) && pb.equalsWithEpsilon(p2) || pa.equalsWithEpsilon(p2) && pb.equalsWithEpsilon(p1)) {
return 1;
}
if (pa.equalsWithEpsilon(p2) && pb.equalsWithEpsilon(p0) || pa.equalsWithEpsilon(p0) && pb.equalsWithEpsilon(p2)) {
return 2;
}
return -1;
};
EdgesRenderer.prototype._checkEdge = function (faceIndex, edge, faceNormals, p0, p1) {
var needToCreateLine;
if (edge === undefined) {
needToCreateLine = true;
}
else {
var dotProduct = BABYLON.Vector3.Dot(faceNormals[faceIndex], faceNormals[edge]);
needToCreateLine = dotProduct < this._epsilon;
}
if (needToCreateLine) {
var offset = this._linesPositions.length / 3;
var normal = p0.subtract(p1);
normal.normalize();
// Positions
this._linesPositions.push(p0.x);
this._linesPositions.push(p0.y);
this._linesPositions.push(p0.z);
this._linesPositions.push(p0.x);
this._linesPositions.push(p0.y);
this._linesPositions.push(p0.z);
this._linesPositions.push(p1.x);
this._linesPositions.push(p1.y);
this._linesPositions.push(p1.z);
this._linesPositions.push(p1.x);
this._linesPositions.push(p1.y);
this._linesPositions.push(p1.z);
// Normals
this._linesNormals.push(p1.x);
this._linesNormals.push(p1.y);
this._linesNormals.push(p1.z);
this._linesNormals.push(-1);
this._linesNormals.push(p1.x);
this._linesNormals.push(p1.y);
this._linesNormals.push(p1.z);
this._linesNormals.push(1);
this._linesNormals.push(p0.x);
this._linesNormals.push(p0.y);
this._linesNormals.push(p0.z);
this._linesNormals.push(-1);
this._linesNormals.push(p0.x);
this._linesNormals.push(p0.y);
this._linesNormals.push(p0.z);
this._linesNormals.push(1);
// Indices
this._linesIndices.push(offset);
this._linesIndices.push(offset + 1);
this._linesIndices.push(offset + 2);
this._linesIndices.push(offset);
this._linesIndices.push(offset + 2);
this._linesIndices.push(offset + 3);
}
};
EdgesRenderer.prototype._generateEdgesLines = function () {
var positions = this._source.getVerticesData(BABYLON.VertexBuffer.PositionKind);
var indices = this._source.getIndices();
if (!indices || !positions) {
return;
}
// First let's find adjacencies
var adjacencies = new Array();
var faceNormals = new Array();
var index;
var faceAdjacencies;
// Prepare faces
for (index = 0; index < indices.length; index += 3) {
faceAdjacencies = new FaceAdjacencies();
var p0Index = indices[index];
var p1Index = indices[index + 1];
var p2Index = indices[index + 2];
faceAdjacencies.p0 = new BABYLON.Vector3(positions[p0Index * 3], positions[p0Index * 3 + 1], positions[p0Index * 3 + 2]);
faceAdjacencies.p1 = new BABYLON.Vector3(positions[p1Index * 3], positions[p1Index * 3 + 1], positions[p1Index * 3 + 2]);
faceAdjacencies.p2 = new BABYLON.Vector3(positions[p2Index * 3], positions[p2Index * 3 + 1], positions[p2Index * 3 + 2]);
var faceNormal = BABYLON.Vector3.Cross(faceAdjacencies.p1.subtract(faceAdjacencies.p0), faceAdjacencies.p2.subtract(faceAdjacencies.p1));
faceNormal.normalize();
faceNormals.push(faceNormal);
adjacencies.push(faceAdjacencies);
}
// Scan
for (index = 0; index < adjacencies.length; index++) {
faceAdjacencies = adjacencies[index];
for (var otherIndex = index + 1; otherIndex < adjacencies.length; otherIndex++) {
var otherFaceAdjacencies = adjacencies[otherIndex];
if (faceAdjacencies.edgesConnectedCount === 3) { // Full
break;
}
if (otherFaceAdjacencies.edgesConnectedCount === 3) { // Full
continue;
}
var otherP0 = indices[otherIndex * 3];
var otherP1 = indices[otherIndex * 3 + 1];
var otherP2 = indices[otherIndex * 3 + 2];
for (var edgeIndex = 0; edgeIndex < 3; edgeIndex++) {
var otherEdgeIndex = 0;
if (faceAdjacencies.edges[edgeIndex] !== undefined) {
continue;
}
switch (edgeIndex) {
case 0:
if (this._checkVerticesInsteadOfIndices) {
otherEdgeIndex = this._processEdgeForAdjacenciesWithVertices(faceAdjacencies.p0, faceAdjacencies.p1, otherFaceAdjacencies.p0, otherFaceAdjacencies.p1, otherFaceAdjacencies.p2);
}
else {
otherEdgeIndex = this._processEdgeForAdjacencies(indices[index * 3], indices[index * 3 + 1], otherP0, otherP1, otherP2);
}
break;
case 1:
if (this._checkVerticesInsteadOfIndices) {
otherEdgeIndex = this._processEdgeForAdjacenciesWithVertices(faceAdjacencies.p1, faceAdjacencies.p2, otherFaceAdjacencies.p0, otherFaceAdjacencies.p1, otherFaceAdjacencies.p2);
}
else {
otherEdgeIndex = this._processEdgeForAdjacencies(indices[index * 3 + 1], indices[index * 3 + 2], otherP0, otherP1, otherP2);
}
break;
case 2:
if (this._checkVerticesInsteadOfIndices) {
otherEdgeIndex = this._processEdgeForAdjacenciesWithVertices(faceAdjacencies.p2, faceAdjacencies.p0, otherFaceAdjacencies.p0, otherFaceAdjacencies.p1, otherFaceAdjacencies.p2);
}
else {
otherEdgeIndex = this._processEdgeForAdjacencies(indices[index * 3 + 2], indices[index * 3], otherP0, otherP1, otherP2);
}
break;
}
if (otherEdgeIndex === -1) {
continue;
}
faceAdjacencies.edges[edgeIndex] = otherIndex;
otherFaceAdjacencies.edges[otherEdgeIndex] = index;
faceAdjacencies.edgesConnectedCount++;
otherFaceAdjacencies.edgesConnectedCount++;
if (faceAdjacencies.edgesConnectedCount === 3) {
break;
}
}
}
}
// Create lines
for (index = 0; index < adjacencies.length; index++) {
// We need a line when a face has no adjacency on a specific edge or if all the adjacencies has an angle greater than epsilon
var current = adjacencies[index];
this._checkEdge(index, current.edges[0], faceNormals, current.p0, current.p1);
this._checkEdge(index, current.edges[1], faceNormals, current.p1, current.p2);
this._checkEdge(index, current.edges[2], faceNormals, current.p2, current.p0);
}
// Merge into a single mesh
var engine = this._source.getScene().getEngine();
this._buffers[BABYLON.VertexBuffer.PositionKind] = new BABYLON.VertexBuffer(engine, this._linesPositions, BABYLON.VertexBuffer.PositionKind, false);
this._buffers[BABYLON.VertexBuffer.NormalKind] = new BABYLON.VertexBuffer(engine, this._linesNormals, BABYLON.VertexBuffer.NormalKind, false, false, 4);
this._ib = engine.createIndexBuffer(this._linesIndices);
this._indicesCount = this._linesIndices.length;
};
EdgesRenderer.prototype.render = function () {
var scene = this._source.getScene();
if (!this._lineShader.isReady() || !scene.activeCamera) {
return;
}
var engine = scene.getEngine();
this._lineShader._preBind();
// VBOs
engine.bindBuffers(this._buffers, this._ib, this._lineShader.getEffect());
scene.resetCachedMaterial();
this._lineShader.setColor4("color", this._source.edgesColor);
if (scene.activeCamera.mode === BABYLON.Camera.ORTHOGRAPHIC_CAMERA) {
this._lineShader.setFloat("width", this._source.edgesWidth / this.edgesWidthScalerForOrthographic);
}
else {
this._lineShader.setFloat("width", this._source.edgesWidth / this.edgesWidthScalerForPerspective);
}
this._lineShader.setFloat("aspectRatio", engine.getAspectRatio(scene.activeCamera));
this._lineShader.bind(this._source.getWorldMatrix());
// Draw order
engine.drawElementsType(BABYLON.Material.TriangleFillMode, 0, this._indicesCount);
this._lineShader.unbind();
engine.setDepthWrite(true);
};
return EdgesRenderer;
}());
BABYLON.EdgesRenderer = EdgesRenderer;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.edgesRenderer.js.map
var BABYLON;
(function (BABYLON) {
// Adds the parser to the scene parsers.
BABYLON.AbstractScene.AddParser(BABYLON.SceneComponentConstants.NAME_EFFECTLAYER, function (parsedData, scene, container, rootUrl) {
if (parsedData.effectLayers) {
for (var index = 0; index < parsedData.effectLayers.length; index++) {
var effectLayer = BABYLON.EffectLayer.Parse(parsedData.effectLayers[index], scene, rootUrl);
container.effectLayers.push(effectLayer);
}
}
});
BABYLON.AbstractScene.prototype.removeEffectLayer = function (toRemove) {
var index = this.effectLayers.indexOf(toRemove);
if (index !== -1) {
this.effectLayers.splice(index, 1);
}
return index;
};
BABYLON.AbstractScene.prototype.addEffectLayer = function (newEffectLayer) {
this.effectLayers.push(newEffectLayer);
};
/**
* Defines the layer scene component responsible to manage any effect layers
* in a given scene.
*/
var EffectLayerSceneComponent = /** @class */ (function () {
/**
* Creates a new instance of the component for the given scene
* @param scene Defines the scene to register the component in
*/
function EffectLayerSceneComponent(scene) {
/**
* The component name helpfull to identify the component in the list of scene components.
*/
this.name = BABYLON.SceneComponentConstants.NAME_EFFECTLAYER;
this._renderEffects = false;
this._needStencil = false;
this._previousStencilState = false;
this.scene = scene;
this._engine = scene.getEngine();
scene.effectLayers = new Array();
}
/**
* Registers the component in a given scene
*/
EffectLayerSceneComponent.prototype.register = function () {
this.scene._isReadyForMeshStage.registerStep(BABYLON.SceneComponentConstants.STEP_ISREADYFORMESH_EFFECTLAYER, this, this._isReadyForMesh);
this.scene._cameraDrawRenderTargetStage.registerStep(BABYLON.SceneComponentConstants.STEP_CAMERADRAWRENDERTARGET_EFFECTLAYER, this, this._renderMainTexture);
this.scene._beforeCameraDrawStage.registerStep(BABYLON.SceneComponentConstants.STEP_BEFORECAMERADRAW_EFFECTLAYER, this, this._setStencil);
this.scene._afterRenderingGroupDrawStage.registerStep(BABYLON.SceneComponentConstants.STEP_AFTERRENDERINGGROUPDRAW_EFFECTLAYER_DRAW, this, this._drawRenderingGroup);
this.scene._afterCameraDrawStage.registerStep(BABYLON.SceneComponentConstants.STEP_AFTERCAMERADRAW_EFFECTLAYER, this, this._setStencilBack);
this.scene._afterCameraDrawStage.registerStep(BABYLON.SceneComponentConstants.STEP_AFTERCAMERADRAW_EFFECTLAYER_DRAW, this, this._drawCamera);
};
/**
* Rebuilds the elements related to this component in case of
* context lost for instance.
*/
EffectLayerSceneComponent.prototype.rebuild = function () {
var layers = this.scene.effectLayers;
for (var _i = 0, layers_1 = layers; _i < layers_1.length; _i++) {
var effectLayer = layers_1[_i];
effectLayer._rebuild();
}
};
/**
* Serializes the component data to the specified json object
* @param serializationObject The object to serialize to
*/
EffectLayerSceneComponent.prototype.serialize = function (serializationObject) {
// Effect layers
serializationObject.effectLayers = [];
var layers = this.scene.effectLayers;
for (var _i = 0, layers_2 = layers; _i < layers_2.length; _i++) {
var effectLayer = layers_2[_i];
if (effectLayer.serialize) {
serializationObject.effectLayers.push(effectLayer.serialize());
}
}
};
/**
* Adds all the element from the container to the scene
* @param container the container holding the elements
*/
EffectLayerSceneComponent.prototype.addFromContainer = function (container) {
var _this = this;
if (!container.effectLayers) {
return;
}
container.effectLayers.forEach(function (o) {
_this.scene.addEffectLayer(o);
});
};
/**
* Removes all the elements in the container from the scene
* @param container contains the elements to remove
*/
EffectLayerSceneComponent.prototype.removeFromContainer = function (container) {
var _this = this;
if (!container.effectLayers) {
return;
}
container.effectLayers.forEach(function (o) {
_this.scene.removeEffectLayer(o);
});
};
/**
* Disposes the component and the associated ressources.
*/
EffectLayerSceneComponent.prototype.dispose = function () {
var layers = this.scene.effectLayers;
while (layers.length) {
layers[0].dispose();
}
};
EffectLayerSceneComponent.prototype._isReadyForMesh = function (mesh, hardwareInstancedRendering) {
var layers = this.scene.effectLayers;
for (var _i = 0, layers_3 = layers; _i < layers_3.length; _i++) {
var layer = layers_3[_i];
if (!layer.hasMesh(mesh)) {
continue;
}
for (var _a = 0, _b = mesh.subMeshes; _a < _b.length; _a++) {
var subMesh = _b[_a];
if (!layer.isReady(subMesh, hardwareInstancedRendering)) {
return false;
}
}
}
return true;
};
EffectLayerSceneComponent.prototype._renderMainTexture = function (camera) {
this._renderEffects = false;
this._needStencil = false;
var layers = this.scene.effectLayers;
if (layers && layers.length > 0) {
this._previousStencilState = this._engine.getStencilBuffer();
for (var _i = 0, layers_4 = layers; _i < layers_4.length; _i++) {
var effectLayer = layers_4[_i];
if (effectLayer.shouldRender() &&
(!effectLayer.camera ||
(effectLayer.camera.cameraRigMode === BABYLON.Camera.RIG_MODE_NONE && camera === effectLayer.camera) ||
(effectLayer.camera.cameraRigMode !== BABYLON.Camera.RIG_MODE_NONE && effectLayer.camera._rigCameras.indexOf(camera) > -1))) {
this._renderEffects = true;
this._needStencil = this._needStencil || effectLayer.needStencil();
var renderTarget = effectLayer._mainTexture;
if (renderTarget._shouldRender()) {
this.scene.incrementRenderId();
renderTarget.render(false, false);
}
}
}
this.scene.incrementRenderId();
}
};
EffectLayerSceneComponent.prototype._setStencil = function (camera) {
// Activate effect Layer stencil
if (this._needStencil) {
this._engine.setStencilBuffer(true);
}
};
EffectLayerSceneComponent.prototype._setStencilBack = function (camera) {
// Restore effect Layer stencil
if (this._needStencil) {
this._engine.setStencilBuffer(this._previousStencilState);
}
};
EffectLayerSceneComponent.prototype._draw = function (renderingGroupId) {
if (this._renderEffects) {
this._engine.setDepthBuffer(false);
var layers = this.scene.effectLayers;
for (var i = 0; i < layers.length; i++) {
var effectLayer = layers[i];
if (effectLayer.renderingGroupId === renderingGroupId) {
if (effectLayer.shouldRender()) {
effectLayer.render();
}
}
}
this._engine.setDepthBuffer(true);
}
};
EffectLayerSceneComponent.prototype._drawCamera = function (camera) {
if (this._renderEffects) {
this._draw(-1);
}
};
EffectLayerSceneComponent.prototype._drawRenderingGroup = function (index) {
if (!this.scene._isInIntermediateRendering() && this._renderEffects) {
this._draw(index);
}
};
return EffectLayerSceneComponent;
}());
BABYLON.EffectLayerSceneComponent = EffectLayerSceneComponent;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.effectLayerSceneComponent.js.map
var __assign = (this && this.__assign) || Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
var BABYLON;
(function (BABYLON) {
/**
* The effect layer Helps adding post process effect blended with the main pass.
*
* This can be for instance use to generate glow or higlight effects on the scene.
*
* The effect layer class can not be used directly and is intented to inherited from to be
* customized per effects.
*/
var EffectLayer = /** @class */ (function () {
/**
* Instantiates a new effect Layer and references it in the scene.
* @param name The name of the layer
* @param scene The scene to use the layer in
*/
function EffectLayer(
/** The Friendly of the effect in the scene */
name, scene) {
this._vertexBuffers = {};
this._maxSize = 0;
this._mainTextureDesiredSize = { width: 0, height: 0 };
this._shouldRender = true;
this._postProcesses = [];
this._textures = [];
this._emissiveTextureAndColor = { texture: null, color: new BABYLON.Color4() };
/**
* The clear color of the texture used to generate the glow map.
*/
this.neutralColor = new BABYLON.Color4();
/**
* Specifies wether the highlight layer is enabled or not.
*/
this.isEnabled = true;
/**
* An event triggered when the effect layer has been disposed.
*/
this.onDisposeObservable = new BABYLON.Observable();
/**
* An event triggered when the effect layer is about rendering the main texture with the glowy parts.
*/
this.onBeforeRenderMainTextureObservable = new BABYLON.Observable();
/**
* An event triggered when the generated texture is being merged in the scene.
*/
this.onBeforeComposeObservable = new BABYLON.Observable();
/**
* An event triggered when the generated texture has been merged in the scene.
*/
this.onAfterComposeObservable = new BABYLON.Observable();
/**
* An event triggered when the efffect layer changes its size.
*/
this.onSizeChangedObservable = new BABYLON.Observable();
this.name = name;
this._scene = scene || BABYLON.Engine.LastCreatedScene;
var component = this._scene._getComponent(BABYLON.SceneComponentConstants.NAME_EFFECTLAYER);
if (!component) {
component = new BABYLON.EffectLayerSceneComponent(this._scene);
this._scene._addComponent(component);
}
this._engine = this._scene.getEngine();
this._maxSize = this._engine.getCaps().maxTextureSize;
this._scene.effectLayers.push(this);
// Generate Buffers
this._generateIndexBuffer();
this._genrateVertexBuffer();
}
Object.defineProperty(EffectLayer.prototype, "camera", {
/**
* Gets the camera attached to the layer.
*/
get: function () {
return this._effectLayerOptions.camera;
},
enumerable: true,
configurable: true
});
Object.defineProperty(EffectLayer.prototype, "renderingGroupId", {
/**
* Gets the rendering group id the layer should render in.
*/
get: function () {
return this._effectLayerOptions.renderingGroupId;
},
enumerable: true,
configurable: true
});
/**
* Initializes the effect layer with the required options.
* @param options Sets of none mandatory options to use with the layer (see IEffectLayerOptions for more information)
*/
EffectLayer.prototype._init = function (options) {
// Adapt options
this._effectLayerOptions = __assign({ mainTextureRatio: 0.5, alphaBlendingMode: BABYLON.Engine.ALPHA_COMBINE, camera: null, renderingGroupId: -1 }, options);
this._setMainTextureSize();
this._createMainTexture();
this._createTextureAndPostProcesses();
this._mergeEffect = this._createMergeEffect();
};
/**
* Generates the index buffer of the full screen quad blending to the main canvas.
*/
EffectLayer.prototype._generateIndexBuffer = function () {
// Indices
var indices = [];
indices.push(0);
indices.push(1);
indices.push(2);
indices.push(0);
indices.push(2);
indices.push(3);
this._indexBuffer = this._engine.createIndexBuffer(indices);
};
/**
* Generates the vertex buffer of the full screen quad blending to the main canvas.
*/
EffectLayer.prototype._genrateVertexBuffer = function () {
// VBO
var vertices = [];
vertices.push(1, 1);
vertices.push(-1, 1);
vertices.push(-1, -1);
vertices.push(1, -1);
var vertexBuffer = new BABYLON.VertexBuffer(this._engine, vertices, BABYLON.VertexBuffer.PositionKind, false, false, 2);
this._vertexBuffers[BABYLON.VertexBuffer.PositionKind] = vertexBuffer;
};
/**
* Sets the main texture desired size which is the closest power of two
* of the engine canvas size.
*/
EffectLayer.prototype._setMainTextureSize = function () {
if (this._effectLayerOptions.mainTextureFixedSize) {
this._mainTextureDesiredSize.width = this._effectLayerOptions.mainTextureFixedSize;
this._mainTextureDesiredSize.height = this._effectLayerOptions.mainTextureFixedSize;
}
else {
this._mainTextureDesiredSize.width = this._engine.getRenderWidth() * this._effectLayerOptions.mainTextureRatio;
this._mainTextureDesiredSize.height = this._engine.getRenderHeight() * this._effectLayerOptions.mainTextureRatio;
this._mainTextureDesiredSize.width = this._engine.needPOTTextures ? BABYLON.Tools.GetExponentOfTwo(this._mainTextureDesiredSize.width, this._maxSize) : this._mainTextureDesiredSize.width;
this._mainTextureDesiredSize.height = this._engine.needPOTTextures ? BABYLON.Tools.GetExponentOfTwo(this._mainTextureDesiredSize.height, this._maxSize) : this._mainTextureDesiredSize.height;
}
this._mainTextureDesiredSize.width = Math.floor(this._mainTextureDesiredSize.width);
this._mainTextureDesiredSize.height = Math.floor(this._mainTextureDesiredSize.height);
};
/**
* Creates the main texture for the effect layer.
*/
EffectLayer.prototype._createMainTexture = function () {
var _this = this;
this._mainTexture = new BABYLON.RenderTargetTexture("HighlightLayerMainRTT", {
width: this._mainTextureDesiredSize.width,
height: this._mainTextureDesiredSize.height
}, this._scene, false, true, BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT);
this._mainTexture.activeCamera = this._effectLayerOptions.camera;
this._mainTexture.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE;
this._mainTexture.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
this._mainTexture.anisotropicFilteringLevel = 1;
this._mainTexture.updateSamplingMode(BABYLON.Texture.BILINEAR_SAMPLINGMODE);
this._mainTexture.renderParticles = false;
this._mainTexture.renderList = null;
this._mainTexture.ignoreCameraViewport = true;
// Custom render function
this._mainTexture.customRenderFunction = function (opaqueSubMeshes, alphaTestSubMeshes, transparentSubMeshes, depthOnlySubMeshes) {
_this.onBeforeRenderMainTextureObservable.notifyObservers(_this);
var index;
var engine = _this._scene.getEngine();
if (depthOnlySubMeshes.length) {
engine.setColorWrite(false);
for (index = 0; index < depthOnlySubMeshes.length; index++) {
_this._renderSubMesh(depthOnlySubMeshes.data[index]);
}
engine.setColorWrite(true);
}
for (index = 0; index < opaqueSubMeshes.length; index++) {
_this._renderSubMesh(opaqueSubMeshes.data[index]);
}
for (index = 0; index < alphaTestSubMeshes.length; index++) {
_this._renderSubMesh(alphaTestSubMeshes.data[index]);
}
for (index = 0; index < transparentSubMeshes.length; index++) {
_this._renderSubMesh(transparentSubMeshes.data[index]);
}
};
this._mainTexture.onClearObservable.add(function (engine) {
engine.clear(_this.neutralColor, true, true, true);
});
};
/**
* Checks for the readiness of the element composing the layer.
* @param subMesh the mesh to check for
* @param useInstances specify wether or not to use instances to render the mesh
* @param emissiveTexture the associated emissive texture used to generate the glow
* @return true if ready otherwise, false
*/
EffectLayer.prototype._isReady = function (subMesh, useInstances, emissiveTexture) {
var material = subMesh.getMaterial();
if (!material) {
return false;
}
if (!material.isReady(subMesh.getMesh(), useInstances)) {
return false;
}
var defines = [];
var attribs = [BABYLON.VertexBuffer.PositionKind];
var mesh = subMesh.getMesh();
var uv1 = false;
var uv2 = false;
// Alpha test
if (material && material.needAlphaTesting()) {
var alphaTexture = material.getAlphaTestTexture();
if (alphaTexture) {
defines.push("#define ALPHATEST");
if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.UV2Kind) &&
alphaTexture.coordinatesIndex === 1) {
defines.push("#define DIFFUSEUV2");
uv2 = true;
}
else if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) {
defines.push("#define DIFFUSEUV1");
uv1 = true;
}
}
}
// Emissive
if (emissiveTexture) {
defines.push("#define EMISSIVE");
if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.UV2Kind) &&
emissiveTexture.coordinatesIndex === 1) {
defines.push("#define EMISSIVEUV2");
uv2 = true;
}
else if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) {
defines.push("#define EMISSIVEUV1");
uv1 = true;
}
}
if (uv1) {
attribs.push(BABYLON.VertexBuffer.UVKind);
defines.push("#define UV1");
}
if (uv2) {
attribs.push(BABYLON.VertexBuffer.UV2Kind);
defines.push("#define UV2");
}
// Bones
if (mesh.useBones && mesh.computeBonesUsingShaders) {
attribs.push(BABYLON.VertexBuffer.MatricesIndicesKind);
attribs.push(BABYLON.VertexBuffer.MatricesWeightsKind);
if (mesh.numBoneInfluencers > 4) {
attribs.push(BABYLON.VertexBuffer.MatricesIndicesExtraKind);
attribs.push(BABYLON.VertexBuffer.MatricesWeightsExtraKind);
}
defines.push("#define NUM_BONE_INFLUENCERS " + mesh.numBoneInfluencers);
defines.push("#define BonesPerMesh " + (mesh.skeleton ? (mesh.skeleton.bones.length + 1) : 0));
}
else {
defines.push("#define NUM_BONE_INFLUENCERS 0");
}
// Morph targets
var manager = mesh.morphTargetManager;
var morphInfluencers = 0;
if (manager) {
if (manager.numInfluencers > 0) {
defines.push("#define MORPHTARGETS");
morphInfluencers = manager.numInfluencers;
defines.push("#define NUM_MORPH_INFLUENCERS " + morphInfluencers);
BABYLON.MaterialHelper.PrepareAttributesForMorphTargets(attribs, mesh, { "NUM_MORPH_INFLUENCERS": morphInfluencers });
}
}
// Instances
if (useInstances) {
defines.push("#define INSTANCES");
attribs.push("world0");
attribs.push("world1");
attribs.push("world2");
attribs.push("world3");
}
// Get correct effect
var join = defines.join("\n");
if (this._cachedDefines !== join) {
this._cachedDefines = join;
this._effectLayerMapGenerationEffect = this._scene.getEngine().createEffect("glowMapGeneration", attribs, ["world", "mBones", "viewProjection", "diffuseMatrix", "color", "emissiveMatrix", "morphTargetInfluences"], ["diffuseSampler", "emissiveSampler"], join, undefined, undefined, undefined, { maxSimultaneousMorphTargets: morphInfluencers });
}
return this._effectLayerMapGenerationEffect.isReady();
};
/**
* Renders the glowing part of the scene by blending the blurred glowing meshes on top of the rendered scene.
*/
EffectLayer.prototype.render = function () {
var currentEffect = this._mergeEffect;
// Check
if (!currentEffect.isReady())
return;
for (var i = 0; i < this._postProcesses.length; i++) {
if (!this._postProcesses[i].isReady()) {
return;
}
}
var engine = this._scene.getEngine();
this.onBeforeComposeObservable.notifyObservers(this);
// Render
engine.enableEffect(currentEffect);
engine.setState(false);
// VBOs
engine.bindBuffers(this._vertexBuffers, this._indexBuffer, currentEffect);
// Cache
var previousAlphaMode = engine.getAlphaMode();
// Go Blend.
engine.setAlphaMode(this._effectLayerOptions.alphaBlendingMode);
// Blends the map on the main canvas.
this._internalRender(currentEffect);
// Restore Alpha
engine.setAlphaMode(previousAlphaMode);
this.onAfterComposeObservable.notifyObservers(this);
// Handle size changes.
var size = this._mainTexture.getSize();
this._setMainTextureSize();
if (size.width !== this._mainTextureDesiredSize.width || size.height !== this._mainTextureDesiredSize.height) {
// Recreate RTT and post processes on size change.
this.onSizeChangedObservable.notifyObservers(this);
this._disposeTextureAndPostProcesses();
this._createMainTexture();
this._createTextureAndPostProcesses();
}
};
/**
* Determine if a given mesh will be used in the current effect.
* @param mesh mesh to test
* @returns true if the mesh will be used
*/
EffectLayer.prototype.hasMesh = function (mesh) {
if (this.renderingGroupId === -1 || mesh.renderingGroupId === this.renderingGroupId) {
return true;
}
return false;
};
/**
* Returns true if the layer contains information to display, otherwise false.
* @returns true if the glow layer should be rendered
*/
EffectLayer.prototype.shouldRender = function () {
return this.isEnabled && this._shouldRender;
};
/**
* Returns true if the mesh should render, otherwise false.
* @param mesh The mesh to render
* @returns true if it should render otherwise false
*/
EffectLayer.prototype._shouldRenderMesh = function (mesh) {
return true;
};
/**
* Returns true if the mesh should render, otherwise false.
* @param mesh The mesh to render
* @returns true if it should render otherwise false
*/
EffectLayer.prototype._shouldRenderEmissiveTextureForMesh = function (mesh) {
return true;
};
/**
* Renders the submesh passed in parameter to the generation map.
*/
EffectLayer.prototype._renderSubMesh = function (subMesh) {
var _this = this;
if (!this.shouldRender()) {
return;
}
var material = subMesh.getMaterial();
var mesh = subMesh.getRenderingMesh();
var scene = this._scene;
var engine = scene.getEngine();
if (!material) {
return;
}
// Do not block in blend mode.
if (material.needAlphaBlendingForMesh(mesh)) {
return;
}
// Culling
engine.setState(material.backFaceCulling);
// Managing instances
var batch = mesh._getInstancesRenderList(subMesh._id);
if (batch.mustReturn) {
return;
}
// Early Exit per mesh
if (!this._shouldRenderMesh(mesh)) {
return;
}
var hardwareInstancedRendering = (engine.getCaps().instancedArrays) && (batch.visibleInstances[subMesh._id] !== null) && (batch.visibleInstances[subMesh._id] !== undefined);
this._setEmissiveTextureAndColor(mesh, subMesh, material);
if (this._isReady(subMesh, hardwareInstancedRendering, this._emissiveTextureAndColor.texture)) {
engine.enableEffect(this._effectLayerMapGenerationEffect);
mesh._bind(subMesh, this._effectLayerMapGenerationEffect, BABYLON.Material.TriangleFillMode);
this._effectLayerMapGenerationEffect.setMatrix("viewProjection", scene.getTransformMatrix());
this._effectLayerMapGenerationEffect.setFloat4("color", this._emissiveTextureAndColor.color.r, this._emissiveTextureAndColor.color.g, this._emissiveTextureAndColor.color.b, this._emissiveTextureAndColor.color.a);
// Alpha test
if (material && material.needAlphaTesting()) {
var alphaTexture = material.getAlphaTestTexture();
if (alphaTexture) {
this._effectLayerMapGenerationEffect.setTexture("diffuseSampler", alphaTexture);
var textureMatrix = alphaTexture.getTextureMatrix();
if (textureMatrix) {
this._effectLayerMapGenerationEffect.setMatrix("diffuseMatrix", textureMatrix);
}
}
}
// Glow emissive only
if (this._emissiveTextureAndColor.texture) {
this._effectLayerMapGenerationEffect.setTexture("emissiveSampler", this._emissiveTextureAndColor.texture);
this._effectLayerMapGenerationEffect.setMatrix("emissiveMatrix", this._emissiveTextureAndColor.texture.getTextureMatrix());
}
// Bones
if (mesh.useBones && mesh.computeBonesUsingShaders && mesh.skeleton) {
this._effectLayerMapGenerationEffect.setMatrices("mBones", mesh.skeleton.getTransformMatrices(mesh));
}
// Morph targets
BABYLON.MaterialHelper.BindMorphTargetParameters(mesh, this._effectLayerMapGenerationEffect);
// Draw
mesh._processRendering(subMesh, this._effectLayerMapGenerationEffect, BABYLON.Material.TriangleFillMode, batch, hardwareInstancedRendering, function (isInstance, world) { return _this._effectLayerMapGenerationEffect.setMatrix("world", world); });
}
else {
// Need to reset refresh rate of the main map
this._mainTexture.resetRefreshCounter();
}
};
/**
* Rebuild the required buffers.
* @hidden Internal use only.
*/
EffectLayer.prototype._rebuild = function () {
var vb = this._vertexBuffers[BABYLON.VertexBuffer.PositionKind];
if (vb) {
vb._rebuild();
}
this._generateIndexBuffer();
};
/**
* Dispose only the render target textures and post process.
*/
EffectLayer.prototype._disposeTextureAndPostProcesses = function () {
this._mainTexture.dispose();
for (var i = 0; i < this._postProcesses.length; i++) {
if (this._postProcesses[i]) {
this._postProcesses[i].dispose();
}
}
this._postProcesses = [];
for (var i = 0; i < this._textures.length; i++) {
if (this._textures[i]) {
this._textures[i].dispose();
}
}
this._textures = [];
};
/**
* Dispose the highlight layer and free resources.
*/
EffectLayer.prototype.dispose = function () {
var vertexBuffer = this._vertexBuffers[BABYLON.VertexBuffer.PositionKind];
if (vertexBuffer) {
vertexBuffer.dispose();
this._vertexBuffers[BABYLON.VertexBuffer.PositionKind] = null;
}
if (this._indexBuffer) {
this._scene.getEngine()._releaseBuffer(this._indexBuffer);
this._indexBuffer = null;
}
// Clean textures and post processes
this._disposeTextureAndPostProcesses();
// Remove from scene
var index = this._scene.effectLayers.indexOf(this, 0);
if (index > -1) {
this._scene.effectLayers.splice(index, 1);
}
// Callback
this.onDisposeObservable.notifyObservers(this);
this.onDisposeObservable.clear();
this.onBeforeRenderMainTextureObservable.clear();
this.onBeforeComposeObservable.clear();
this.onAfterComposeObservable.clear();
this.onSizeChangedObservable.clear();
};
/**
* Gets the class name of the effect layer
* @returns the string with the class name of the effect layer
*/
EffectLayer.prototype.getClassName = function () {
return "EffectLayer";
};
/**
* Creates an effect layer from parsed effect layer data
* @param parsedEffectLayer defines effect layer data
* @param scene defines the current scene
* @param rootUrl defines the root URL containing the effect layer information
* @returns a parsed effect Layer
*/
EffectLayer.Parse = function (parsedEffectLayer, scene, rootUrl) {
var effectLayerType = BABYLON.Tools.Instantiate(parsedEffectLayer.customType);
return effectLayerType.Parse(parsedEffectLayer, scene, rootUrl);
};
__decorate([
BABYLON.serialize()
], EffectLayer.prototype, "name", void 0);
__decorate([
BABYLON.serializeAsColor4()
], EffectLayer.prototype, "neutralColor", void 0);
__decorate([
BABYLON.serialize()
], EffectLayer.prototype, "isEnabled", void 0);
__decorate([
BABYLON.serializeAsCameraReference()
], EffectLayer.prototype, "camera", null);
__decorate([
BABYLON.serialize()
], EffectLayer.prototype, "renderingGroupId", null);
return EffectLayer;
}());
BABYLON.EffectLayer = EffectLayer;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.effectLayer.js.map
var BABYLON;
(function (BABYLON) {
BABYLON.AbstractScene.prototype.getHighlightLayerByName = function (name) {
for (var index = 0; index < this.effectLayers.length; index++) {
if (this.effectLayers[index].name === name && this.effectLayers[index].getEffectName() === HighlightLayer.EffectName) {
return this.effectLayers[index];
}
}
return null;
};
/**
* Special Glow Blur post process only blurring the alpha channel
* It enforces keeping the most luminous color in the color channel.
*/
var GlowBlurPostProcess = /** @class */ (function (_super) {
__extends(GlowBlurPostProcess, _super);
function GlowBlurPostProcess(name, direction, kernel, options, camera, samplingMode, engine, reusable) {
if (samplingMode === void 0) { samplingMode = BABYLON.Texture.BILINEAR_SAMPLINGMODE; }
var _this = _super.call(this, name, "glowBlurPostProcess", ["screenSize", "direction", "blurWidth"], null, options, camera, samplingMode, engine, reusable) || this;
_this.direction = direction;
_this.kernel = kernel;
_this.onApplyObservable.add(function (effect) {
effect.setFloat2("screenSize", _this.width, _this.height);
effect.setVector2("direction", _this.direction);
effect.setFloat("blurWidth", _this.kernel);
});
return _this;
}
return GlowBlurPostProcess;
}(BABYLON.PostProcess));
/**
* The highlight layer Helps adding a glow effect around a mesh.
*
* Once instantiated in a scene, simply use the pushMesh or removeMesh method to add or remove
* glowy meshes to your scene.
*
* !!! THIS REQUIRES AN ACTIVE STENCIL BUFFER ON THE CANVAS !!!
*/
var HighlightLayer = /** @class */ (function (_super) {
__extends(HighlightLayer, _super);
/**
* Instantiates a new highlight Layer and references it to the scene..
* @param name The name of the layer
* @param scene The scene to use the layer in
* @param options Sets of none mandatory options to use with the layer (see IHighlightLayerOptions for more information)
*/
function HighlightLayer(name, scene, options) {
var _this = _super.call(this, name, scene) || this;
_this.name = name;
/**
* Specifies whether or not the inner glow is ACTIVE in the layer.
*/
_this.innerGlow = true;
/**
* Specifies whether or not the outer glow is ACTIVE in the layer.
*/
_this.outerGlow = true;
/**
* An event triggered when the highlight layer is being blurred.
*/
_this.onBeforeBlurObservable = new BABYLON.Observable();
/**
* An event triggered when the highlight layer has been blurred.
*/
_this.onAfterBlurObservable = new BABYLON.Observable();
_this._instanceGlowingMeshStencilReference = HighlightLayer.GlowingMeshStencilReference++;
_this._meshes = {};
_this._excludedMeshes = {};
_this.neutralColor = HighlightLayer.NeutralColor;
// Warn on stencil
if (!_this._engine.isStencilEnable) {
BABYLON.Tools.Warn("Rendering the Highlight Layer requires the stencil to be active on the canvas. var engine = new BABYLON.Engine(canvas, antialias, { stencil: true }");
}
// Adapt options
_this._options = __assign({ mainTextureRatio: 0.5, blurTextureSizeRatio: 0.5, blurHorizontalSize: 1.0, blurVerticalSize: 1.0, alphaBlendingMode: BABYLON.Engine.ALPHA_COMBINE, camera: null, renderingGroupId: -1 }, options);
// Initialize the layer
_this._init({
alphaBlendingMode: _this._options.alphaBlendingMode,
camera: _this._options.camera,
mainTextureFixedSize: _this._options.mainTextureFixedSize,
mainTextureRatio: _this._options.mainTextureRatio,
renderingGroupId: _this._options.renderingGroupId
});
// Do not render as long as no meshes have been added
_this._shouldRender = false;
return _this;
}
Object.defineProperty(HighlightLayer.prototype, "blurHorizontalSize", {
/**
* Gets the horizontal size of the blur.
*/
get: function () {
return this._horizontalBlurPostprocess.kernel;
},
/**
* Specifies the horizontal size of the blur.
*/
set: function (value) {
this._horizontalBlurPostprocess.kernel = value;
},
enumerable: true,
configurable: true
});
Object.defineProperty(HighlightLayer.prototype, "blurVerticalSize", {
/**
* Gets the vertical size of the blur.
*/
get: function () {
return this._verticalBlurPostprocess.kernel;
},
/**
* Specifies the vertical size of the blur.
*/
set: function (value) {
this._verticalBlurPostprocess.kernel = value;
},
enumerable: true,
configurable: true
});
/**
* Get the effect name of the layer.
* @return The effect name
*/
HighlightLayer.prototype.getEffectName = function () {
return HighlightLayer.EffectName;
};
/**
* Create the merge effect. This is the shader use to blit the information back
* to the main canvas at the end of the scene rendering.
*/
HighlightLayer.prototype._createMergeEffect = function () {
// Effect
return this._engine.createEffect("glowMapMerge", [BABYLON.VertexBuffer.PositionKind], ["offset"], ["textureSampler"], this._options.isStroke ? "#define STROKE \n" : undefined);
};
/**
* Creates the render target textures and post processes used in the highlight layer.
*/
HighlightLayer.prototype._createTextureAndPostProcesses = function () {
var _this = this;
var blurTextureWidth = this._mainTextureDesiredSize.width * this._options.blurTextureSizeRatio;
var blurTextureHeight = this._mainTextureDesiredSize.height * this._options.blurTextureSizeRatio;
blurTextureWidth = this._engine.needPOTTextures ? BABYLON.Tools.GetExponentOfTwo(blurTextureWidth, this._maxSize) : blurTextureWidth;
blurTextureHeight = this._engine.needPOTTextures ? BABYLON.Tools.GetExponentOfTwo(blurTextureHeight, this._maxSize) : blurTextureHeight;
var textureType = 0;
if (this._engine.getCaps().textureHalfFloatRender) {
textureType = BABYLON.Engine.TEXTURETYPE_HALF_FLOAT;
}
else {
textureType = BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT;
}
this._blurTexture = new BABYLON.RenderTargetTexture("HighlightLayerBlurRTT", {
width: blurTextureWidth,
height: blurTextureHeight
}, this._scene, false, true, textureType);
this._blurTexture.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE;
this._blurTexture.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
this._blurTexture.anisotropicFilteringLevel = 16;
this._blurTexture.updateSamplingMode(BABYLON.Texture.TRILINEAR_SAMPLINGMODE);
this._blurTexture.renderParticles = false;
this._blurTexture.ignoreCameraViewport = true;
this._textures = [this._blurTexture];
if (this._options.alphaBlendingMode === BABYLON.Engine.ALPHA_COMBINE) {
this._downSamplePostprocess = new BABYLON.PassPostProcess("HighlightLayerPPP", this._options.blurTextureSizeRatio, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, this._scene.getEngine());
this._downSamplePostprocess.onApplyObservable.add(function (effect) {
effect.setTexture("textureSampler", _this._mainTexture);
});
this._horizontalBlurPostprocess = new GlowBlurPostProcess("HighlightLayerHBP", new BABYLON.Vector2(1.0, 0), this._options.blurHorizontalSize, 1, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, this._scene.getEngine());
this._horizontalBlurPostprocess.onApplyObservable.add(function (effect) {
effect.setFloat2("screenSize", blurTextureWidth, blurTextureHeight);
});
this._verticalBlurPostprocess = new GlowBlurPostProcess("HighlightLayerVBP", new BABYLON.Vector2(0, 1.0), this._options.blurVerticalSize, 1, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, this._scene.getEngine());
this._verticalBlurPostprocess.onApplyObservable.add(function (effect) {
effect.setFloat2("screenSize", blurTextureWidth, blurTextureHeight);
});
this._postProcesses = [this._downSamplePostprocess, this._horizontalBlurPostprocess, this._verticalBlurPostprocess];
}
else {
this._horizontalBlurPostprocess = new BABYLON.BlurPostProcess("HighlightLayerHBP", new BABYLON.Vector2(1.0, 0), this._options.blurHorizontalSize / 2, {
width: blurTextureWidth,
height: blurTextureHeight
}, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, this._scene.getEngine(), false, textureType);
this._horizontalBlurPostprocess.width = blurTextureWidth;
this._horizontalBlurPostprocess.height = blurTextureHeight;
this._horizontalBlurPostprocess.onApplyObservable.add(function (effect) {
effect.setTexture("textureSampler", _this._mainTexture);
});
this._verticalBlurPostprocess = new BABYLON.BlurPostProcess("HighlightLayerVBP", new BABYLON.Vector2(0, 1.0), this._options.blurVerticalSize / 2, {
width: blurTextureWidth,
height: blurTextureHeight
}, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, this._scene.getEngine(), false, textureType);
this._postProcesses = [this._horizontalBlurPostprocess, this._verticalBlurPostprocess];
}
this._mainTexture.onAfterUnbindObservable.add(function () {
_this.onBeforeBlurObservable.notifyObservers(_this);
var internalTexture = _this._blurTexture.getInternalTexture();
if (internalTexture) {
_this._scene.postProcessManager.directRender(_this._postProcesses, internalTexture, true);
}
_this.onAfterBlurObservable.notifyObservers(_this);
});
// Prevent autoClear.
this._postProcesses.map(function (pp) { pp.autoClear = false; });
};
/**
* Returns wether or nood the layer needs stencil enabled during the mesh rendering.
*/
HighlightLayer.prototype.needStencil = function () {
return true;
};
/**
* Checks for the readiness of the element composing the layer.
* @param subMesh the mesh to check for
* @param useInstances specify wether or not to use instances to render the mesh
* @param emissiveTexture the associated emissive texture used to generate the glow
* @return true if ready otherwise, false
*/
HighlightLayer.prototype.isReady = function (subMesh, useInstances) {
var material = subMesh.getMaterial();
var mesh = subMesh.getRenderingMesh();
if (!material || !mesh || !this._meshes) {
return false;
}
var emissiveTexture = null;
var highlightLayerMesh = this._meshes[mesh.uniqueId];
if (highlightLayerMesh && highlightLayerMesh.glowEmissiveOnly && material) {
emissiveTexture = material.emissiveTexture;
}
return _super.prototype._isReady.call(this, subMesh, useInstances, emissiveTexture);
};
/**
* Implementation specific of rendering the generating effect on the main canvas.
* @param effect The effect used to render through
*/
HighlightLayer.prototype._internalRender = function (effect) {
// Texture
effect.setTexture("textureSampler", this._blurTexture);
// Cache
var engine = this._engine;
var previousStencilBuffer = engine.getStencilBuffer();
var previousStencilFunction = engine.getStencilFunction();
var previousStencilMask = engine.getStencilMask();
var previousStencilOperationPass = engine.getStencilOperationPass();
var previousStencilOperationFail = engine.getStencilOperationFail();
var previousStencilOperationDepthFail = engine.getStencilOperationDepthFail();
var previousStencilReference = engine.getStencilFunctionReference();
// Stencil operations
engine.setStencilOperationPass(BABYLON.Engine.REPLACE);
engine.setStencilOperationFail(BABYLON.Engine.KEEP);
engine.setStencilOperationDepthFail(BABYLON.Engine.KEEP);
// Draw order
engine.setStencilMask(0x00);
engine.setStencilBuffer(true);
engine.setStencilFunctionReference(this._instanceGlowingMeshStencilReference);
// 2 passes inner outer
if (this.outerGlow) {
effect.setFloat("offset", 0);
engine.setStencilFunction(BABYLON.Engine.NOTEQUAL);
engine.drawElementsType(BABYLON.Material.TriangleFillMode, 0, 6);
}
if (this.innerGlow) {
effect.setFloat("offset", 1);
engine.setStencilFunction(BABYLON.Engine.EQUAL);
engine.drawElementsType(BABYLON.Material.TriangleFillMode, 0, 6);
}
// Restore Cache
engine.setStencilFunction(previousStencilFunction);
engine.setStencilMask(previousStencilMask);
engine.setStencilBuffer(previousStencilBuffer);
engine.setStencilOperationPass(previousStencilOperationPass);
engine.setStencilOperationFail(previousStencilOperationFail);
engine.setStencilOperationDepthFail(previousStencilOperationDepthFail);
engine.setStencilFunctionReference(previousStencilReference);
};
/**
* Returns true if the layer contains information to display, otherwise false.
*/
HighlightLayer.prototype.shouldRender = function () {
if (_super.prototype.shouldRender.call(this)) {
return this._meshes ? true : false;
}
return false;
};
/**
* Returns true if the mesh should render, otherwise false.
* @param mesh The mesh to render
* @returns true if it should render otherwise false
*/
HighlightLayer.prototype._shouldRenderMesh = function (mesh) {
// Excluded Mesh
if (this._excludedMeshes && this._excludedMeshes[mesh.uniqueId]) {
return false;
}
;
if (!_super.prototype.hasMesh.call(this, mesh)) {
return false;
}
return true;
};
/**
* Sets the required values for both the emissive texture and and the main color.
*/
HighlightLayer.prototype._setEmissiveTextureAndColor = function (mesh, subMesh, material) {
var highlightLayerMesh = this._meshes[mesh.uniqueId];
if (highlightLayerMesh) {
this._emissiveTextureAndColor.color.set(highlightLayerMesh.color.r, highlightLayerMesh.color.g, highlightLayerMesh.color.b, 1.0);
}
else {
this._emissiveTextureAndColor.color.set(this.neutralColor.r, this.neutralColor.g, this.neutralColor.b, this.neutralColor.a);
}
if (highlightLayerMesh && highlightLayerMesh.glowEmissiveOnly && material) {
this._emissiveTextureAndColor.texture = material.emissiveTexture;
this._emissiveTextureAndColor.color.set(1.0, 1.0, 1.0, 1.0);
}
else {
this._emissiveTextureAndColor.texture = null;
}
};
/**
* Add a mesh in the exclusion list to prevent it to impact or being impacted by the highlight layer.
* @param mesh The mesh to exclude from the highlight layer
*/
HighlightLayer.prototype.addExcludedMesh = function (mesh) {
if (!this._excludedMeshes) {
return;
}
var meshExcluded = this._excludedMeshes[mesh.uniqueId];
if (!meshExcluded) {
this._excludedMeshes[mesh.uniqueId] = {
mesh: mesh,
beforeRender: mesh.onBeforeRenderObservable.add(function (mesh) {
mesh.getEngine().setStencilBuffer(false);
}),
afterRender: mesh.onAfterRenderObservable.add(function (mesh) {
mesh.getEngine().setStencilBuffer(true);
}),
};
}
};
/**
* Remove a mesh from the exclusion list to let it impact or being impacted by the highlight layer.
* @param mesh The mesh to highlight
*/
HighlightLayer.prototype.removeExcludedMesh = function (mesh) {
if (!this._excludedMeshes) {
return;
}
var meshExcluded = this._excludedMeshes[mesh.uniqueId];
if (meshExcluded) {
if (meshExcluded.beforeRender) {
mesh.onBeforeRenderObservable.remove(meshExcluded.beforeRender);
}
if (meshExcluded.afterRender) {
mesh.onAfterRenderObservable.remove(meshExcluded.afterRender);
}
}
this._excludedMeshes[mesh.uniqueId] = null;
};
/**
* Determine if a given mesh will be highlighted by the current HighlightLayer
* @param mesh mesh to test
* @returns true if the mesh will be highlighted by the current HighlightLayer
*/
HighlightLayer.prototype.hasMesh = function (mesh) {
if (!this._meshes) {
return false;
}
if (!_super.prototype.hasMesh.call(this, mesh)) {
return false;
}
return this._meshes[mesh.uniqueId] !== undefined && this._meshes[mesh.uniqueId] !== null;
};
/**
* Add a mesh in the highlight layer in order to make it glow with the chosen color.
* @param mesh The mesh to highlight
* @param color The color of the highlight
* @param glowEmissiveOnly Extract the glow from the emissive texture
*/
HighlightLayer.prototype.addMesh = function (mesh, color, glowEmissiveOnly) {
var _this = this;
if (glowEmissiveOnly === void 0) { glowEmissiveOnly = false; }
if (!this._meshes) {
return;
}
var meshHighlight = this._meshes[mesh.uniqueId];
if (meshHighlight) {
meshHighlight.color = color;
}
else {
this._meshes[mesh.uniqueId] = {
mesh: mesh,
color: color,
// Lambda required for capture due to Observable this context
observerHighlight: mesh.onBeforeRenderObservable.add(function (mesh) {
if (_this._excludedMeshes && _this._excludedMeshes[mesh.uniqueId]) {
_this._defaultStencilReference(mesh);
}
else {
mesh.getScene().getEngine().setStencilFunctionReference(_this._instanceGlowingMeshStencilReference);
}
}),
observerDefault: mesh.onAfterRenderObservable.add(this._defaultStencilReference),
glowEmissiveOnly: glowEmissiveOnly
};
mesh.onDisposeObservable.add(function () {
_this._disposeMesh(mesh);
});
}
this._shouldRender = true;
};
/**
* Remove a mesh from the highlight layer in order to make it stop glowing.
* @param mesh The mesh to highlight
*/
HighlightLayer.prototype.removeMesh = function (mesh) {
if (!this._meshes) {
return;
}
var meshHighlight = this._meshes[mesh.uniqueId];
if (meshHighlight) {
if (meshHighlight.observerHighlight) {
mesh.onBeforeRenderObservable.remove(meshHighlight.observerHighlight);
}
if (meshHighlight.observerDefault) {
mesh.onAfterRenderObservable.remove(meshHighlight.observerDefault);
}
delete this._meshes[mesh.uniqueId];
}
this._shouldRender = false;
for (var meshHighlightToCheck in this._meshes) {
if (this._meshes[meshHighlightToCheck]) {
this._shouldRender = true;
break;
}
}
};
/**
* Force the stencil to the normal expected value for none glowing parts
*/
HighlightLayer.prototype._defaultStencilReference = function (mesh) {
mesh.getScene().getEngine().setStencilFunctionReference(HighlightLayer.NormalMeshStencilReference);
};
/**
* Free any resources and references associated to a mesh.
* Internal use
* @param mesh The mesh to free.
*/
HighlightLayer.prototype._disposeMesh = function (mesh) {
this.removeMesh(mesh);
this.removeExcludedMesh(mesh);
};
/**
* Dispose the highlight layer and free resources.
*/
HighlightLayer.prototype.dispose = function () {
if (this._meshes) {
// Clean mesh references
for (var id in this._meshes) {
var meshHighlight = this._meshes[id];
if (meshHighlight && meshHighlight.mesh) {
if (meshHighlight.observerHighlight) {
meshHighlight.mesh.onBeforeRenderObservable.remove(meshHighlight.observerHighlight);
}
if (meshHighlight.observerDefault) {
meshHighlight.mesh.onAfterRenderObservable.remove(meshHighlight.observerDefault);
}
}
}
this._meshes = null;
}
if (this._excludedMeshes) {
for (var id in this._excludedMeshes) {
var meshHighlight = this._excludedMeshes[id];
if (meshHighlight) {
if (meshHighlight.beforeRender) {
meshHighlight.mesh.onBeforeRenderObservable.remove(meshHighlight.beforeRender);
}
if (meshHighlight.afterRender) {
meshHighlight.mesh.onAfterRenderObservable.remove(meshHighlight.afterRender);
}
}
}
this._excludedMeshes = null;
}
_super.prototype.dispose.call(this);
};
/**
* Gets the class name of the effect layer
* @returns the string with the class name of the effect layer
*/
HighlightLayer.prototype.getClassName = function () {
return "HighlightLayer";
};
/**
* Serializes this Highlight layer
* @returns a serialized Highlight layer object
*/
HighlightLayer.prototype.serialize = function () {
var serializationObject = BABYLON.SerializationHelper.Serialize(this);
serializationObject.customType = "BABYLON.HighlightLayer";
// Highlighted meshes
serializationObject.meshes = [];
if (this._meshes) {
for (var m in this._meshes) {
var mesh = this._meshes[m];
if (mesh) {
serializationObject.meshes.push({
glowEmissiveOnly: mesh.glowEmissiveOnly,
color: mesh.color.asArray(),
meshId: mesh.mesh.id
});
}
}
}
// Excluded meshes
serializationObject.excludedMeshes = [];
if (this._excludedMeshes) {
for (var e in this._excludedMeshes) {
var excludedMesh = this._excludedMeshes[e];
if (excludedMesh) {
serializationObject.excludedMeshes.push(excludedMesh.mesh.id);
}
}
}
return serializationObject;
};
/**
* Creates a Highlight layer from parsed Highlight layer data
* @param parsedHightlightLayer defines the Highlight layer data
* @param scene defines the current scene
* @param rootUrl defines the root URL containing the Highlight layer information
* @returns a parsed Highlight layer
*/
HighlightLayer.Parse = function (parsedHightlightLayer, scene, rootUrl) {
var hl = BABYLON.SerializationHelper.Parse(function () { return new HighlightLayer(parsedHightlightLayer.name, scene, parsedHightlightLayer.options); }, parsedHightlightLayer, scene, rootUrl);
var index;
// Excluded meshes
for (index = 0; index < parsedHightlightLayer.excludedMeshes.length; index++) {
var mesh = scene.getMeshByID(parsedHightlightLayer.excludedMeshes[index]);
if (mesh) {
hl.addExcludedMesh(mesh);
}
}
// Included meshes
for (index = 0; index < parsedHightlightLayer.meshes.length; index++) {
var highlightedMesh = parsedHightlightLayer.meshes[index];
var mesh = scene.getMeshByID(highlightedMesh.meshId);
if (mesh) {
hl.addMesh(mesh, BABYLON.Color3.FromArray(highlightedMesh.color), highlightedMesh.glowEmissiveOnly);
}
}
return hl;
};
/**
* Effect Name of the highlight layer.
*/
HighlightLayer.EffectName = "HighlightLayer";
/**
* The neutral color used during the preparation of the glow effect.
* This is black by default as the blend operation is a blend operation.
*/
HighlightLayer.NeutralColor = new BABYLON.Color4(0, 0, 0, 0);
/**
* Stencil value used for glowing meshes.
*/
HighlightLayer.GlowingMeshStencilReference = 0x02;
/**
* Stencil value used for the other meshes in the scene.
*/
HighlightLayer.NormalMeshStencilReference = 0x01;
__decorate([
BABYLON.serialize()
], HighlightLayer.prototype, "innerGlow", void 0);
__decorate([
BABYLON.serialize()
], HighlightLayer.prototype, "outerGlow", void 0);
__decorate([
BABYLON.serialize()
], HighlightLayer.prototype, "blurHorizontalSize", null);
__decorate([
BABYLON.serialize()
], HighlightLayer.prototype, "blurVerticalSize", null);
__decorate([
BABYLON.serialize("options")
], HighlightLayer.prototype, "_options", void 0);
return HighlightLayer;
}(BABYLON.EffectLayer));
BABYLON.HighlightLayer = HighlightLayer;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.highlightLayer.js.map
var BABYLON;
(function (BABYLON) {
BABYLON.AbstractScene.prototype.getGlowLayerByName = function (name) {
for (var index = 0; index < this.effectLayers.length; index++) {
if (this.effectLayers[index].name === name && this.effectLayers[index].getEffectName() === GlowLayer.EffectName) {
return this.effectLayers[index];
}
}
return null;
};
/**
* The glow layer Helps adding a glow effect around the emissive parts of a mesh.
*
* Once instantiated in a scene, simply use the pushMesh or removeMesh method to add or remove
* glowy meshes to your scene.
*
* Documentation: https://doc.babylonjs.com/how_to/glow_layer
*/
var GlowLayer = /** @class */ (function (_super) {
__extends(GlowLayer, _super);
/**
* Instantiates a new glow Layer and references it to the scene.
* @param name The name of the layer
* @param scene The scene to use the layer in
* @param options Sets of none mandatory options to use with the layer (see IGlowLayerOptions for more information)
*/
function GlowLayer(name, scene, options) {
var _this = _super.call(this, name, scene) || this;
_this._intensity = 1.0;
_this._includedOnlyMeshes = [];
_this._excludedMeshes = [];
_this.neutralColor = new BABYLON.Color4(0, 0, 0, 1);
// Adapt options
_this._options = __assign({ mainTextureRatio: GlowLayer.DefaultTextureRatio, blurKernelSize: 32, mainTextureFixedSize: undefined, camera: null, mainTextureSamples: 1, renderingGroupId: -1 }, options);
// Initialize the layer
_this._init({
alphaBlendingMode: BABYLON.Engine.ALPHA_ADD,
camera: _this._options.camera,
mainTextureFixedSize: _this._options.mainTextureFixedSize,
mainTextureRatio: _this._options.mainTextureRatio,
renderingGroupId: _this._options.renderingGroupId
});
return _this;
}
Object.defineProperty(GlowLayer.prototype, "blurKernelSize", {
/**
* Gets the kernel size of the blur.
*/
get: function () {
return this._horizontalBlurPostprocess1.kernel;
},
/**
* Sets the kernel size of the blur.
*/
set: function (value) {
this._horizontalBlurPostprocess1.kernel = value;
this._verticalBlurPostprocess1.kernel = value;
this._horizontalBlurPostprocess2.kernel = value;
this._verticalBlurPostprocess2.kernel = value;
},
enumerable: true,
configurable: true
});
Object.defineProperty(GlowLayer.prototype, "intensity", {
/**
* Gets the glow intensity.
*/
get: function () {
return this._intensity;
},
/**
* Sets the glow intensity.
*/
set: function (value) {
this._intensity = value;
},
enumerable: true,
configurable: true
});
/**
* Get the effect name of the layer.
* @return The effect name
*/
GlowLayer.prototype.getEffectName = function () {
return GlowLayer.EffectName;
};
/**
* Create the merge effect. This is the shader use to blit the information back
* to the main canvas at the end of the scene rendering.
*/
GlowLayer.prototype._createMergeEffect = function () {
// Effect
return this._engine.createEffect("glowMapMerge", [BABYLON.VertexBuffer.PositionKind], ["offset"], ["textureSampler", "textureSampler2"], "#define EMISSIVE \n");
};
/**
* Creates the render target textures and post processes used in the glow layer.
*/
GlowLayer.prototype._createTextureAndPostProcesses = function () {
var _this = this;
var blurTextureWidth = this._mainTextureDesiredSize.width;
var blurTextureHeight = this._mainTextureDesiredSize.height;
blurTextureWidth = this._engine.needPOTTextures ? BABYLON.Tools.GetExponentOfTwo(blurTextureWidth, this._maxSize) : blurTextureWidth;
blurTextureHeight = this._engine.needPOTTextures ? BABYLON.Tools.GetExponentOfTwo(blurTextureHeight, this._maxSize) : blurTextureHeight;
var textureType = 0;
if (this._engine.getCaps().textureHalfFloatRender) {
textureType = BABYLON.Engine.TEXTURETYPE_HALF_FLOAT;
}
else {
textureType = BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT;
}
this._blurTexture1 = new BABYLON.RenderTargetTexture("GlowLayerBlurRTT", {
width: blurTextureWidth,
height: blurTextureHeight
}, this._scene, false, true, textureType);
this._blurTexture1.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE;
this._blurTexture1.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
this._blurTexture1.updateSamplingMode(BABYLON.Texture.BILINEAR_SAMPLINGMODE);
this._blurTexture1.renderParticles = false;
this._blurTexture1.ignoreCameraViewport = true;
var blurTextureWidth2 = Math.floor(blurTextureWidth / 2);
var blurTextureHeight2 = Math.floor(blurTextureHeight / 2);
this._blurTexture2 = new BABYLON.RenderTargetTexture("GlowLayerBlurRTT2", {
width: blurTextureWidth2,
height: blurTextureHeight2
}, this._scene, false, true, textureType);
this._blurTexture2.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE;
this._blurTexture2.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
this._blurTexture2.updateSamplingMode(BABYLON.Texture.BILINEAR_SAMPLINGMODE);
this._blurTexture2.renderParticles = false;
this._blurTexture2.ignoreCameraViewport = true;
this._textures = [this._blurTexture1, this._blurTexture2];
this._horizontalBlurPostprocess1 = new BABYLON.BlurPostProcess("GlowLayerHBP1", new BABYLON.Vector2(1.0, 0), this._options.blurKernelSize / 2, {
width: blurTextureWidth,
height: blurTextureHeight
}, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, this._scene.getEngine(), false, textureType);
this._horizontalBlurPostprocess1.width = blurTextureWidth;
this._horizontalBlurPostprocess1.height = blurTextureHeight;
this._horizontalBlurPostprocess1.onApplyObservable.add(function (effect) {
effect.setTexture("textureSampler", _this._mainTexture);
});
this._verticalBlurPostprocess1 = new BABYLON.BlurPostProcess("GlowLayerVBP1", new BABYLON.Vector2(0, 1.0), this._options.blurKernelSize / 2, {
width: blurTextureWidth,
height: blurTextureHeight
}, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, this._scene.getEngine(), false, textureType);
this._horizontalBlurPostprocess2 = new BABYLON.BlurPostProcess("GlowLayerHBP2", new BABYLON.Vector2(1.0, 0), this._options.blurKernelSize / 2, {
width: blurTextureWidth2,
height: blurTextureHeight2
}, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, this._scene.getEngine(), false, textureType);
this._horizontalBlurPostprocess2.width = blurTextureWidth2;
this._horizontalBlurPostprocess2.height = blurTextureHeight2;
this._horizontalBlurPostprocess2.onApplyObservable.add(function (effect) {
effect.setTexture("textureSampler", _this._blurTexture1);
});
this._verticalBlurPostprocess2 = new BABYLON.BlurPostProcess("GlowLayerVBP2", new BABYLON.Vector2(0, 1.0), this._options.blurKernelSize / 2, {
width: blurTextureWidth2,
height: blurTextureHeight2
}, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, this._scene.getEngine(), false, textureType);
this._postProcesses = [this._horizontalBlurPostprocess1, this._verticalBlurPostprocess1, this._horizontalBlurPostprocess2, this._verticalBlurPostprocess2];
this._postProcesses1 = [this._horizontalBlurPostprocess1, this._verticalBlurPostprocess1];
this._postProcesses2 = [this._horizontalBlurPostprocess2, this._verticalBlurPostprocess2];
this._mainTexture.samples = this._options.mainTextureSamples;
this._mainTexture.onAfterUnbindObservable.add(function () {
var internalTexture = _this._blurTexture1.getInternalTexture();
if (internalTexture) {
_this._scene.postProcessManager.directRender(_this._postProcesses1, internalTexture, true);
internalTexture = _this._blurTexture2.getInternalTexture();
if (internalTexture) {
_this._scene.postProcessManager.directRender(_this._postProcesses2, internalTexture, true);
}
}
});
// Prevent autoClear.
this._postProcesses.map(function (pp) { pp.autoClear = false; });
};
/**
* Checks for the readiness of the element composing the layer.
* @param subMesh the mesh to check for
* @param useInstances specify wether or not to use instances to render the mesh
* @param emissiveTexture the associated emissive texture used to generate the glow
* @return true if ready otherwise, false
*/
GlowLayer.prototype.isReady = function (subMesh, useInstances) {
var material = subMesh.getMaterial();
var mesh = subMesh.getRenderingMesh();
if (!material || !mesh) {
return false;
}
var emissiveTexture = material.emissiveTexture;
return _super.prototype._isReady.call(this, subMesh, useInstances, emissiveTexture);
};
/**
* Returns wether or nood the layer needs stencil enabled during the mesh rendering.
*/
GlowLayer.prototype.needStencil = function () {
return false;
};
/**
* Implementation specific of rendering the generating effect on the main canvas.
* @param effect The effect used to render through
*/
GlowLayer.prototype._internalRender = function (effect) {
// Texture
effect.setTexture("textureSampler", this._blurTexture1);
effect.setTexture("textureSampler2", this._blurTexture2);
effect.setFloat("offset", this._intensity);
// Cache
var engine = this._engine;
var previousStencilBuffer = engine.getStencilBuffer();
// Draw order
engine.setStencilBuffer(false);
engine.drawElementsType(BABYLON.Material.TriangleFillMode, 0, 6);
// Draw order
engine.setStencilBuffer(previousStencilBuffer);
};
/**
* Sets the required values for both the emissive texture and and the main color.
*/
GlowLayer.prototype._setEmissiveTextureAndColor = function (mesh, subMesh, material) {
var textureLevel = 1.0;
if (this.customEmissiveTextureSelector) {
this._emissiveTextureAndColor.texture = this.customEmissiveTextureSelector(mesh, subMesh, material);
}
else {
if (material) {
this._emissiveTextureAndColor.texture = material.emissiveTexture;
if (this._emissiveTextureAndColor.texture) {
textureLevel = this._emissiveTextureAndColor.texture.level;
}
}
else {
this._emissiveTextureAndColor.texture = null;
}
}
if (this.customEmissiveColorSelector) {
this.customEmissiveColorSelector(mesh, subMesh, material, this._emissiveTextureAndColor.color);
}
else {
if (material.emissiveColor) {
this._emissiveTextureAndColor.color.set(material.emissiveColor.r * textureLevel, material.emissiveColor.g * textureLevel, material.emissiveColor.b * textureLevel, 1.0);
}
else {
this._emissiveTextureAndColor.color.set(this.neutralColor.r, this.neutralColor.g, this.neutralColor.b, this.neutralColor.a);
}
}
};
/**
* Returns true if the mesh should render, otherwise false.
* @param mesh The mesh to render
* @returns true if it should render otherwise false
*/
GlowLayer.prototype._shouldRenderMesh = function (mesh) {
return this.hasMesh(mesh);
};
/**
* Add a mesh in the exclusion list to prevent it to impact or being impacted by the glow layer.
* @param mesh The mesh to exclude from the glow layer
*/
GlowLayer.prototype.addExcludedMesh = function (mesh) {
if (this._excludedMeshes.indexOf(mesh.uniqueId) === -1) {
this._excludedMeshes.push(mesh.uniqueId);
}
};
/**
* Remove a mesh from the exclusion list to let it impact or being impacted by the glow layer.
* @param mesh The mesh to remove
*/
GlowLayer.prototype.removeExcludedMesh = function (mesh) {
var index = this._excludedMeshes.indexOf(mesh.uniqueId);
if (index !== -1) {
this._excludedMeshes.splice(index, 1);
}
};
/**
* Add a mesh in the inclusion list to impact or being impacted by the glow layer.
* @param mesh The mesh to include in the glow layer
*/
GlowLayer.prototype.addIncludedOnlyMesh = function (mesh) {
if (this._includedOnlyMeshes.indexOf(mesh.uniqueId) === -1) {
this._includedOnlyMeshes.push(mesh.uniqueId);
}
};
/**
* Remove a mesh from the Inclusion list to prevent it to impact or being impacted by the glow layer.
* @param mesh The mesh to remove
*/
GlowLayer.prototype.removeIncludedOnlyMesh = function (mesh) {
var index = this._includedOnlyMeshes.indexOf(mesh.uniqueId);
if (index !== -1) {
this._includedOnlyMeshes.splice(index, 1);
}
};
/**
* Determine if a given mesh will be used in the glow layer
* @param mesh The mesh to test
* @returns true if the mesh will be highlighted by the current glow layer
*/
GlowLayer.prototype.hasMesh = function (mesh) {
if (!_super.prototype.hasMesh.call(this, mesh)) {
return false;
}
// Included Mesh
if (this._includedOnlyMeshes.length) {
return this._includedOnlyMeshes.indexOf(mesh.uniqueId) !== -1;
}
;
// Excluded Mesh
if (this._excludedMeshes.length) {
return this._excludedMeshes.indexOf(mesh.uniqueId) === -1;
}
;
return true;
};
/**
* Free any resources and references associated to a mesh.
* Internal use
* @param mesh The mesh to free.
*/
GlowLayer.prototype._disposeMesh = function (mesh) {
this.removeIncludedOnlyMesh(mesh);
this.removeExcludedMesh(mesh);
};
/**
* Gets the class name of the effect layer
* @returns the string with the class name of the effect layer
*/
GlowLayer.prototype.getClassName = function () {
return "GlowLayer";
};
/**
* Serializes this glow layer
* @returns a serialized glow layer object
*/
GlowLayer.prototype.serialize = function () {
var serializationObject = BABYLON.SerializationHelper.Serialize(this);
serializationObject.customType = "BABYLON.GlowLayer";
var index;
// Included meshes
serializationObject.includedMeshes = [];
if (this._includedOnlyMeshes.length) {
for (index = 0; index < this._includedOnlyMeshes.length; index++) {
var mesh = this._scene.getMeshByUniqueID(this._includedOnlyMeshes[index]);
if (mesh) {
serializationObject.includedMeshes.push(mesh.id);
}
}
}
// Excluded meshes
serializationObject.excludedMeshes = [];
if (this._excludedMeshes.length) {
for (index = 0; index < this._excludedMeshes.length; index++) {
var mesh = this._scene.getMeshByUniqueID(this._excludedMeshes[index]);
if (mesh) {
serializationObject.excludedMeshes.push(mesh.id);
}
}
}
return serializationObject;
};
/**
* Creates a Glow Layer from parsed glow layer data
* @param parsedGlowLayer defines glow layer data
* @param scene defines the current scene
* @param rootUrl defines the root URL containing the glow layer information
* @returns a parsed Glow Layer
*/
GlowLayer.Parse = function (parsedGlowLayer, scene, rootUrl) {
var gl = BABYLON.SerializationHelper.Parse(function () { return new GlowLayer(parsedGlowLayer.name, scene, parsedGlowLayer.options); }, parsedGlowLayer, scene, rootUrl);
var index;
// Excluded meshes
for (index = 0; index < parsedGlowLayer.excludedMeshes.length; index++) {
var mesh = scene.getMeshByID(parsedGlowLayer.excludedMeshes[index]);
if (mesh) {
gl.addExcludedMesh(mesh);
}
}
// Included meshes
for (index = 0; index < parsedGlowLayer.includedMeshes.length; index++) {
var mesh = scene.getMeshByID(parsedGlowLayer.includedMeshes[index]);
if (mesh) {
gl.addIncludedOnlyMesh(mesh);
}
}
return gl;
};
/**
* Effect Name of the layer.
*/
GlowLayer.EffectName = "GlowLayer";
/**
* The default blur kernel size used for the glow.
*/
GlowLayer.DefaultBlurKernelSize = 32;
/**
* The default texture size ratio used for the glow.
*/
GlowLayer.DefaultTextureRatio = 0.5;
__decorate([
BABYLON.serialize()
], GlowLayer.prototype, "blurKernelSize", null);
__decorate([
BABYLON.serialize()
], GlowLayer.prototype, "intensity", null);
__decorate([
BABYLON.serialize("options")
], GlowLayer.prototype, "_options", void 0);
return GlowLayer;
}(BABYLON.EffectLayer));
BABYLON.GlowLayer = GlowLayer;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.glowLayer.js.map
var BABYLON;
(function (BABYLON) {
/**
* Defines the list of states available for a task inside a {BABYLON.AssetsManager}
*/
var AssetTaskState;
(function (AssetTaskState) {
/**
* Initialization
*/
AssetTaskState[AssetTaskState["INIT"] = 0] = "INIT";
/**
* Running
*/
AssetTaskState[AssetTaskState["RUNNING"] = 1] = "RUNNING";
/**
* Done
*/
AssetTaskState[AssetTaskState["DONE"] = 2] = "DONE";
/**
* Error
*/
AssetTaskState[AssetTaskState["ERROR"] = 3] = "ERROR";
})(AssetTaskState = BABYLON.AssetTaskState || (BABYLON.AssetTaskState = {}));
/**
* Define an abstract asset task used with a {BABYLON.AssetsManager} class to load assets into a scene
*/
var AbstractAssetTask = /** @class */ (function () {
/**
* Creates a new {BABYLON.AssetsManager}
* @param name defines the name of the task
*/
function AbstractAssetTask(
/**
* Task name
*/ name) {
this.name = name;
this._isCompleted = false;
this._taskState = AssetTaskState.INIT;
}
Object.defineProperty(AbstractAssetTask.prototype, "isCompleted", {
/**
* Get if the task is completed
*/
get: function () {
return this._isCompleted;
},
enumerable: true,
configurable: true
});
Object.defineProperty(AbstractAssetTask.prototype, "taskState", {
/**
* Gets the current state of the task
*/
get: function () {
return this._taskState;
},
enumerable: true,
configurable: true
});
Object.defineProperty(AbstractAssetTask.prototype, "errorObject", {
/**
* Gets the current error object (if task is in error)
*/
get: function () {
return this._errorObject;
},
enumerable: true,
configurable: true
});
/**
* Internal only
* @hidden
*/
AbstractAssetTask.prototype._setErrorObject = function (message, exception) {
if (this._errorObject) {
return;
}
this._errorObject = {
message: message,
exception: exception
};
};
/**
* Execute the current task
* @param scene defines the scene where you want your assets to be loaded
* @param onSuccess is a callback called when the task is successfully executed
* @param onError is a callback called if an error occurs
*/
AbstractAssetTask.prototype.run = function (scene, onSuccess, onError) {
var _this = this;
this._taskState = AssetTaskState.RUNNING;
this.runTask(scene, function () {
_this.onDoneCallback(onSuccess, onError);
}, function (msg, exception) {
_this.onErrorCallback(onError, msg, exception);
});
};
/**
* Execute the current task
* @param scene defines the scene where you want your assets to be loaded
* @param onSuccess is a callback called when the task is successfully executed
* @param onError is a callback called if an error occurs
*/
AbstractAssetTask.prototype.runTask = function (scene, onSuccess, onError) {
throw new Error("runTask is not implemented");
};
/**
* Reset will set the task state back to INIT, so the next load call of the assets manager will execute this task again.
* This can be used with failed tasks that have the reason for failure fixed.
*/
AbstractAssetTask.prototype.reset = function () {
this._taskState = AssetTaskState.INIT;
};
AbstractAssetTask.prototype.onErrorCallback = function (onError, message, exception) {
this._taskState = AssetTaskState.ERROR;
this._errorObject = {
message: message,
exception: exception
};
if (this.onError) {
this.onError(this, message, exception);
}
onError();
};
AbstractAssetTask.prototype.onDoneCallback = function (onSuccess, onError) {
try {
this._taskState = AssetTaskState.DONE;
this._isCompleted = true;
if (this.onSuccess) {
this.onSuccess(this);
}
onSuccess();
}
catch (e) {
this.onErrorCallback(onError, "Task is done, error executing success callback(s)", e);
}
};
return AbstractAssetTask;
}());
BABYLON.AbstractAssetTask = AbstractAssetTask;
/**
* Class used to share progress information about assets loading
*/
var AssetsProgressEvent = /** @class */ (function () {
/**
* Creates a {BABYLON.AssetsProgressEvent}
* @param remainingCount defines the number of remaining tasks to process
* @param totalCount defines the total number of tasks
* @param task defines the task that was just processed
*/
function AssetsProgressEvent(remainingCount, totalCount, task) {
this.remainingCount = remainingCount;
this.totalCount = totalCount;
this.task = task;
}
return AssetsProgressEvent;
}());
BABYLON.AssetsProgressEvent = AssetsProgressEvent;
/**
* Define a task used by {BABYLON.AssetsManager} to load meshes
*/
var MeshAssetTask = /** @class */ (function (_super) {
__extends(MeshAssetTask, _super);
/**
* Creates a new {BABYLON.MeshAssetTask}
* @param name defines the name of the task
* @param meshesNames defines the list of mesh's names you want to load
* @param rootUrl defines the root url to use as a base to load your meshes and associated resources
* @param sceneFilename defines the filename of the scene to load from
*/
function MeshAssetTask(
/**
* Defines the name of the task
*/
name,
/**
* Defines the list of mesh's names you want to load
*/
meshesNames,
/**
* Defines the root url to use as a base to load your meshes and associated resources
*/
rootUrl,
/**
* Defines the filename of the scene to load from
*/
sceneFilename) {
var _this = _super.call(this, name) || this;
_this.name = name;
_this.meshesNames = meshesNames;
_this.rootUrl = rootUrl;
_this.sceneFilename = sceneFilename;
return _this;
}
/**
* Execute the current task
* @param scene defines the scene where you want your assets to be loaded
* @param onSuccess is a callback called when the task is successfully executed
* @param onError is a callback called if an error occurs
*/
MeshAssetTask.prototype.runTask = function (scene, onSuccess, onError) {
var _this = this;
BABYLON.SceneLoader.ImportMesh(this.meshesNames, this.rootUrl, this.sceneFilename, scene, function (meshes, particleSystems, skeletons) {
_this.loadedMeshes = meshes;
_this.loadedParticleSystems = particleSystems;
_this.loadedSkeletons = skeletons;
onSuccess();
}, null, function (scene, message, exception) {
onError(message, exception);
});
};
return MeshAssetTask;
}(AbstractAssetTask));
BABYLON.MeshAssetTask = MeshAssetTask;
/**
* Define a task used by {BABYLON.AssetsManager} to load text content
*/
var TextFileAssetTask = /** @class */ (function (_super) {
__extends(TextFileAssetTask, _super);
/**
* Creates a new TextFileAssetTask object
* @param name defines the name of the task
* @param url defines the location of the file to load
*/
function TextFileAssetTask(
/**
* Defines the name of the task
*/
name,
/**
* Defines the location of the file to load
*/
url) {
var _this = _super.call(this, name) || this;
_this.name = name;
_this.url = url;
return _this;
}
/**
* Execute the current task
* @param scene defines the scene where you want your assets to be loaded
* @param onSuccess is a callback called when the task is successfully executed
* @param onError is a callback called if an error occurs
*/
TextFileAssetTask.prototype.runTask = function (scene, onSuccess, onError) {
var _this = this;
scene._loadFile(this.url, function (data) {
_this.text = data;
onSuccess();
}, undefined, false, false, function (request, exception) {
if (request) {
onError(request.status + " " + request.statusText, exception);
}
});
};
return TextFileAssetTask;
}(AbstractAssetTask));
BABYLON.TextFileAssetTask = TextFileAssetTask;
/**
* Define a task used by {BABYLON.AssetsManager} to load binary data
*/
var BinaryFileAssetTask = /** @class */ (function (_super) {
__extends(BinaryFileAssetTask, _super);
/**
* Creates a new BinaryFileAssetTask object
* @param name defines the name of the new task
* @param url defines the location of the file to load
*/
function BinaryFileAssetTask(
/**
* Defines the name of the task
*/
name,
/**
* Defines the location of the file to load
*/
url) {
var _this = _super.call(this, name) || this;
_this.name = name;
_this.url = url;
return _this;
}
/**
* Execute the current task
* @param scene defines the scene where you want your assets to be loaded
* @param onSuccess is a callback called when the task is successfully executed
* @param onError is a callback called if an error occurs
*/
BinaryFileAssetTask.prototype.runTask = function (scene, onSuccess, onError) {
var _this = this;
scene._loadFile(this.url, function (data) {
_this.data = data;
onSuccess();
}, undefined, true, true, function (request, exception) {
if (request) {
onError(request.status + " " + request.statusText, exception);
}
});
};
return BinaryFileAssetTask;
}(AbstractAssetTask));
BABYLON.BinaryFileAssetTask = BinaryFileAssetTask;
/**
* Define a task used by {BABYLON.AssetsManager} to load images
*/
var ImageAssetTask = /** @class */ (function (_super) {
__extends(ImageAssetTask, _super);
/**
* Creates a new ImageAssetTask
* @param name defines the name of the task
* @param url defines the location of the image to load
*/
function ImageAssetTask(
/**
* Defines the name of the task
*/
name,
/**
* Defines the location of the image to load
*/
url) {
var _this = _super.call(this, name) || this;
_this.name = name;
_this.url = url;
return _this;
}
/**
* Execute the current task
* @param scene defines the scene where you want your assets to be loaded
* @param onSuccess is a callback called when the task is successfully executed
* @param onError is a callback called if an error occurs
*/
ImageAssetTask.prototype.runTask = function (scene, onSuccess, onError) {
var _this = this;
var img = new Image();
BABYLON.Tools.SetCorsBehavior(this.url, img);
img.onload = function () {
_this.image = img;
onSuccess();
};
img.onerror = function (err) {
onError("Error loading image", err);
};
img.src = this.url;
};
return ImageAssetTask;
}(AbstractAssetTask));
BABYLON.ImageAssetTask = ImageAssetTask;
/**
* Define a task used by {BABYLON.AssetsManager} to load 2D textures
*/
var TextureAssetTask = /** @class */ (function (_super) {
__extends(TextureAssetTask, _super);
/**
* Creates a new TextureAssetTask object
* @param name defines the name of the task
* @param url defines the location of the file to load
* @param noMipmap defines if mipmap should not be generated (default is false)
* @param invertY defines if texture must be inverted on Y axis (default is false)
* @param samplingMode defines the sampling mode to use (default is BABYLON.Texture.TRILINEAR_SAMPLINGMODE)
*/
function TextureAssetTask(
/**
* Defines the name of the task
*/
name,
/**
* Defines the location of the file to load
*/
url,
/**
* Defines if mipmap should not be generated (default is false)
*/
noMipmap,
/**
* Defines if texture must be inverted on Y axis (default is false)
*/
invertY,
/**
* Defines the sampling mode to use (default is BABYLON.Texture.TRILINEAR_SAMPLINGMODE)
*/
samplingMode) {
if (samplingMode === void 0) { samplingMode = BABYLON.Texture.TRILINEAR_SAMPLINGMODE; }
var _this = _super.call(this, name) || this;
_this.name = name;
_this.url = url;
_this.noMipmap = noMipmap;
_this.invertY = invertY;
_this.samplingMode = samplingMode;
return _this;
}
/**
* Execute the current task
* @param scene defines the scene where you want your assets to be loaded
* @param onSuccess is a callback called when the task is successfully executed
* @param onError is a callback called if an error occurs
*/
TextureAssetTask.prototype.runTask = function (scene, onSuccess, onError) {
var onload = function () {
onSuccess();
};
var onerror = function (message, exception) {
onError(message, exception);
};
this.texture = new BABYLON.Texture(this.url, scene, this.noMipmap, this.invertY, this.samplingMode, onload, onerror);
};
return TextureAssetTask;
}(AbstractAssetTask));
BABYLON.TextureAssetTask = TextureAssetTask;
/**
* Define a task used by {BABYLON.AssetsManager} to load cube textures
*/
var CubeTextureAssetTask = /** @class */ (function (_super) {
__extends(CubeTextureAssetTask, _super);
/**
* Creates a new CubeTextureAssetTask
* @param name defines the name of the task
* @param url defines the location of the files to load (You have to specify the folder where the files are + filename with no extension)
* @param extensions defines the extensions to use to load files (["_px", "_py", "_pz", "_nx", "_ny", "_nz"] by default)
* @param noMipmap defines if mipmaps should not be generated (default is false)
* @param files defines the explicit list of files (undefined by default)
*/
function CubeTextureAssetTask(
/**
* Defines the name of the task
*/
name,
/**
* Defines the location of the files to load (You have to specify the folder where the files are + filename with no extension)
*/
url,
/**
* Defines the extensions to use to load files (["_px", "_py", "_pz", "_nx", "_ny", "_nz"] by default)
*/
extensions,
/**
* Defines if mipmaps should not be generated (default is false)
*/
noMipmap,
/**
* Defines the explicit list of files (undefined by default)
*/
files) {
var _this = _super.call(this, name) || this;
_this.name = name;
_this.url = url;
_this.extensions = extensions;
_this.noMipmap = noMipmap;
_this.files = files;
return _this;
}
/**
* Execute the current task
* @param scene defines the scene where you want your assets to be loaded
* @param onSuccess is a callback called when the task is successfully executed
* @param onError is a callback called if an error occurs
*/
CubeTextureAssetTask.prototype.runTask = function (scene, onSuccess, onError) {
var onload = function () {
onSuccess();
};
var onerror = function (message, exception) {
onError(message, exception);
};
this.texture = new BABYLON.CubeTexture(this.url, scene, this.extensions, this.noMipmap, this.files, onload, onerror);
};
return CubeTextureAssetTask;
}(AbstractAssetTask));
BABYLON.CubeTextureAssetTask = CubeTextureAssetTask;
/**
* Define a task used by {BABYLON.AssetsManager} to load HDR cube textures
*/
var HDRCubeTextureAssetTask = /** @class */ (function (_super) {
__extends(HDRCubeTextureAssetTask, _super);
/**
* Creates a new HDRCubeTextureAssetTask object
* @param name defines the name of the task
* @param url defines the location of the file to load
* @param size defines the desired size (the more it increases the longer the generation will be) If the size is omitted this implies you are using a preprocessed cubemap.
* @param noMipmap defines if mipmaps should not be generated (default is false)
* @param generateHarmonics specifies whether you want to extract the polynomial harmonics during the generation process (default is true)
* @param gammaSpace specifies if the texture will be use in gamma or linear space (the PBR material requires those texture in linear space, but the standard material would require them in Gamma space) (default is false)
* @param reserved Internal use only
*/
function HDRCubeTextureAssetTask(
/**
* Defines the name of the task
*/
name,
/**
* Defines the location of the file to load
*/
url,
/**
* Defines the desired size (the more it increases the longer the generation will be)
*/
size,
/**
* Defines if mipmaps should not be generated (default is false)
*/
noMipmap,
/**
* Specifies whether you want to extract the polynomial harmonics during the generation process (default is true)
*/
generateHarmonics,
/**
* Specifies if the texture will be use in gamma or linear space (the PBR material requires those texture in linear space, but the standard material would require them in Gamma space) (default is false)
*/
gammaSpace,
/**
* Internal Use Only
*/
reserved) {
if (noMipmap === void 0) { noMipmap = false; }
if (generateHarmonics === void 0) { generateHarmonics = true; }
if (gammaSpace === void 0) { gammaSpace = false; }
if (reserved === void 0) { reserved = false; }
var _this = _super.call(this, name) || this;
_this.name = name;
_this.url = url;
_this.size = size;
_this.noMipmap = noMipmap;
_this.generateHarmonics = generateHarmonics;
_this.gammaSpace = gammaSpace;
_this.reserved = reserved;
return _this;
}
/**
* Execute the current task
* @param scene defines the scene where you want your assets to be loaded
* @param onSuccess is a callback called when the task is successfully executed
* @param onError is a callback called if an error occurs
*/
HDRCubeTextureAssetTask.prototype.run = function (scene, onSuccess, onError) {
var onload = function () {
onSuccess();
};
var onerror = function (message, exception) {
onError(message, exception);
};
this.texture = new BABYLON.HDRCubeTexture(this.url, scene, this.size, this.noMipmap, this.generateHarmonics, this.gammaSpace, this.reserved, onload, onerror);
};
return HDRCubeTextureAssetTask;
}(AbstractAssetTask));
BABYLON.HDRCubeTextureAssetTask = HDRCubeTextureAssetTask;
/**
* This class can be used to easily import assets into a scene
* @see http://doc.babylonjs.com/how_to/how_to_use_assetsmanager
*/
var AssetsManager = /** @class */ (function () {
/**
* Creates a new AssetsManager
* @param scene defines the scene to work on
*/
function AssetsManager(scene) {
this._isLoading = false;
this._tasks = new Array();
this._waitingTasksCount = 0;
this._totalTasksCount = 0;
/**
* Observable called when all tasks are processed
*/
this.onTaskSuccessObservable = new BABYLON.Observable();
/**
* Observable called when a task had an error
*/
this.onTaskErrorObservable = new BABYLON.Observable();
/**
* Observable called when a task is successful
*/
this.onTasksDoneObservable = new BABYLON.Observable();
/**
* Observable called when a task is done (whatever the result is)
*/
this.onProgressObservable = new BABYLON.Observable();
/**
* Gets or sets a boolean defining if the {BABYLON.AssetsManager} should use the default loading screen
* @see http://doc.babylonjs.com/how_to/creating_a_custom_loading_screen
*/
this.useDefaultLoadingScreen = true;
this._scene = scene;
}
/**
* Add a {BABYLON.MeshAssetTask} to the list of active tasks
* @param taskName defines the name of the new task
* @param meshesNames defines the name of meshes to load
* @param rootUrl defines the root url to use to locate files
* @param sceneFilename defines the filename of the scene file
* @returns a new {BABYLON.MeshAssetTask} object
*/
AssetsManager.prototype.addMeshTask = function (taskName, meshesNames, rootUrl, sceneFilename) {
var task = new MeshAssetTask(taskName, meshesNames, rootUrl, sceneFilename);
this._tasks.push(task);
return task;
};
/**
* Add a {BABYLON.TextFileAssetTask} to the list of active tasks
* @param taskName defines the name of the new task
* @param url defines the url of the file to load
* @returns a new {BABYLON.TextFileAssetTask} object
*/
AssetsManager.prototype.addTextFileTask = function (taskName, url) {
var task = new TextFileAssetTask(taskName, url);
this._tasks.push(task);
return task;
};
/**
* Add a {BABYLON.BinaryFileAssetTask} to the list of active tasks
* @param taskName defines the name of the new task
* @param url defines the url of the file to load
* @returns a new {BABYLON.BinaryFileAssetTask} object
*/
AssetsManager.prototype.addBinaryFileTask = function (taskName, url) {
var task = new BinaryFileAssetTask(taskName, url);
this._tasks.push(task);
return task;
};
/**
* Add a {BABYLON.ImageAssetTask} to the list of active tasks
* @param taskName defines the name of the new task
* @param url defines the url of the file to load
* @returns a new {BABYLON.ImageAssetTask} object
*/
AssetsManager.prototype.addImageTask = function (taskName, url) {
var task = new ImageAssetTask(taskName, url);
this._tasks.push(task);
return task;
};
/**
* Add a {BABYLON.TextureAssetTask} to the list of active tasks
* @param taskName defines the name of the new task
* @param url defines the url of the file to load
* @param noMipmap defines if the texture must not receive mipmaps (false by default)
* @param invertY defines if you want to invert Y axis of the loaded texture (false by default)
* @param samplingMode defines the sampling mode to use (BABYLON.Texture.TRILINEAR_SAMPLINGMODE by default)
* @returns a new {BABYLON.TextureAssetTask} object
*/
AssetsManager.prototype.addTextureTask = function (taskName, url, noMipmap, invertY, samplingMode) {
if (samplingMode === void 0) { samplingMode = BABYLON.Texture.TRILINEAR_SAMPLINGMODE; }
var task = new TextureAssetTask(taskName, url, noMipmap, invertY, samplingMode);
this._tasks.push(task);
return task;
};
/**
* Add a {BABYLON.CubeTextureAssetTask} to the list of active tasks
* @param taskName defines the name of the new task
* @param url defines the url of the file to load
* @param extensions defines the extension to use to load the cube map (can be null)
* @param noMipmap defines if the texture must not receive mipmaps (false by default)
* @param files defines the list of files to load (can be null)
* @returns a new {BABYLON.CubeTextureAssetTask} object
*/
AssetsManager.prototype.addCubeTextureTask = function (taskName, url, extensions, noMipmap, files) {
var task = new CubeTextureAssetTask(taskName, url, extensions, noMipmap, files);
this._tasks.push(task);
return task;
};
/**
*
* Add a {BABYLON.HDRCubeTextureAssetTask} to the list of active tasks
* @param taskName defines the name of the new task
* @param url defines the url of the file to load
* @param size defines the size you want for the cubemap (can be null)
* @param noMipmap defines if the texture must not receive mipmaps (false by default)
* @param generateHarmonics defines if you want to automatically generate (true by default)
* @param gammaSpace specifies if the texture will be use in gamma or linear space (the PBR material requires those texture in linear space, but the standard material would require them in Gamma space) (default is false)
* @param reserved Internal use only
* @returns a new {BABYLON.HDRCubeTextureAssetTask} object
*/
AssetsManager.prototype.addHDRCubeTextureTask = function (taskName, url, size, noMipmap, generateHarmonics, gammaSpace, reserved) {
if (noMipmap === void 0) { noMipmap = false; }
if (generateHarmonics === void 0) { generateHarmonics = true; }
if (gammaSpace === void 0) { gammaSpace = false; }
if (reserved === void 0) { reserved = false; }
var task = new HDRCubeTextureAssetTask(taskName, url, size, noMipmap, generateHarmonics, gammaSpace, reserved);
this._tasks.push(task);
return task;
};
/**
* Remove a task from the assets manager.
* @param task the task to remove
*/
AssetsManager.prototype.removeTask = function (task) {
var index = this._tasks.indexOf(task);
if (index > -1) {
this._tasks.splice(index, 1);
}
};
AssetsManager.prototype._decreaseWaitingTasksCount = function (task) {
this._waitingTasksCount--;
try {
if (this.onProgress) {
this.onProgress(this._waitingTasksCount, this._totalTasksCount, task);
}
this.onProgressObservable.notifyObservers(new AssetsProgressEvent(this._waitingTasksCount, this._totalTasksCount, task));
}
catch (e) {
BABYLON.Tools.Error("Error running progress callbacks.");
console.log(e);
}
if (this._waitingTasksCount === 0) {
try {
if (this.onFinish) {
this.onFinish(this._tasks);
}
// Let's remove successfull tasks
var currentTasks = this._tasks.slice();
for (var _i = 0, currentTasks_1 = currentTasks; _i < currentTasks_1.length; _i++) {
var task = currentTasks_1[_i];
if (task.taskState === AssetTaskState.DONE) {
var index = this._tasks.indexOf(task);
if (index > -1) {
this._tasks.splice(index, 1);
}
}
}
this.onTasksDoneObservable.notifyObservers(this._tasks);
}
catch (e) {
BABYLON.Tools.Error("Error running tasks-done callbacks.");
console.log(e);
}
this._isLoading = false;
this._scene.getEngine().hideLoadingUI();
}
};
AssetsManager.prototype._runTask = function (task) {
var _this = this;
var done = function () {
try {
if (_this.onTaskSuccess) {
_this.onTaskSuccess(task);
}
_this.onTaskSuccessObservable.notifyObservers(task);
_this._decreaseWaitingTasksCount(task);
}
catch (e) {
error("Error executing task success callbacks", e);
}
};
var error = function (message, exception) {
task._setErrorObject(message, exception);
if (_this.onTaskError) {
_this.onTaskError(task);
}
_this.onTaskErrorObservable.notifyObservers(task);
_this._decreaseWaitingTasksCount(task);
};
task.run(this._scene, done, error);
};
/**
* Reset the {BABYLON.AssetsManager} and remove all tasks
* @return the current instance of the {BABYLON.AssetsManager}
*/
AssetsManager.prototype.reset = function () {
this._isLoading = false;
this._tasks = new Array();
return this;
};
/**
* Start the loading process
* @return the current instance of the {BABYLON.AssetsManager}
*/
AssetsManager.prototype.load = function () {
if (this._isLoading) {
return this;
}
this._isLoading = true;
this._waitingTasksCount = this._tasks.length;
this._totalTasksCount = this._tasks.length;
if (this._waitingTasksCount === 0) {
this._isLoading = false;
if (this.onFinish) {
this.onFinish(this._tasks);
}
this.onTasksDoneObservable.notifyObservers(this._tasks);
return this;
}
if (this.useDefaultLoadingScreen) {
this._scene.getEngine().displayLoadingUI();
}
for (var index = 0; index < this._tasks.length; index++) {
var task = this._tasks[index];
if (task.taskState === AssetTaskState.INIT) {
this._runTask(task);
}
}
return this;
};
return AssetsManager;
}());
BABYLON.AssetsManager = AssetsManager;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.assetsManager.js.map
var BABYLON;
(function (BABYLON) {
var serializedGeometries = [];
var serializeGeometry = function (geometry, serializationGeometries) {
if (serializedGeometries[geometry.id]) {
return;
}
if (geometry.doNotSerialize) {
return;
}
if (geometry instanceof BABYLON.BoxGeometry) {
serializationGeometries.boxes.push(geometry.serialize());
}
else if (geometry instanceof BABYLON.SphereGeometry) {
serializationGeometries.spheres.push(geometry.serialize());
}
else if (geometry instanceof BABYLON.CylinderGeometry) {
serializationGeometries.cylinders.push(geometry.serialize());
}
else if (geometry instanceof BABYLON.TorusGeometry) {
serializationGeometries.toruses.push(geometry.serialize());
}
else if (geometry instanceof BABYLON.GroundGeometry) {
serializationGeometries.grounds.push(geometry.serialize());
}
else if (geometry instanceof BABYLON.Plane) {
serializationGeometries.planes.push(geometry.serialize());
}
else if (geometry instanceof BABYLON.TorusKnotGeometry) {
serializationGeometries.torusKnots.push(geometry.serialize());
}
else if (geometry instanceof BABYLON._PrimitiveGeometry) {
throw new Error("Unknown primitive type");
}
else {
serializationGeometries.vertexData.push(geometry.serializeVerticeData());
}
serializedGeometries[geometry.id] = true;
};
var serializeMesh = function (mesh, serializationScene) {
var serializationObject = {};
// Geometry
var geometry = mesh._geometry;
if (geometry) {
if (!mesh.getScene().getGeometryByID(geometry.id)) {
// Geometry was in the memory but not added to the scene, nevertheless it's better to serialize to be able to reload the mesh with its geometry
serializeGeometry(geometry, serializationScene.geometries);
}
}
// Custom
if (mesh.serialize) {
mesh.serialize(serializationObject);
}
return serializationObject;
};
var finalizeSingleMesh = function (mesh, serializationObject) {
//only works if the mesh is already loaded
if (mesh.delayLoadState === BABYLON.Engine.DELAYLOADSTATE_LOADED || mesh.delayLoadState === BABYLON.Engine.DELAYLOADSTATE_NONE) {
//serialize material
if (mesh.material) {
if (mesh.material instanceof BABYLON.MultiMaterial) {
serializationObject.multiMaterials = serializationObject.multiMaterials || [];
serializationObject.materials = serializationObject.materials || [];
if (!serializationObject.multiMaterials.some(function (mat) { return (mat.id === mesh.material.id); })) {
serializationObject.multiMaterials.push(mesh.material.serialize());
var _loop_1 = function (submaterial) {
if (submaterial) {
if (!serializationObject.materials.some(function (mat) { return (mat.id === submaterial.id); })) {
serializationObject.materials.push(submaterial.serialize());
}
}
};
for (var _i = 0, _a = mesh.material.subMaterials; _i < _a.length; _i++) {
var submaterial = _a[_i];
_loop_1(submaterial);
}
}
}
else {
serializationObject.materials = serializationObject.materials || [];
if (!serializationObject.materials.some(function (mat) { return (mat.id === mesh.material.id); })) {
serializationObject.materials.push(mesh.material.serialize());
}
}
}
//serialize geometry
var geometry = mesh._geometry;
if (geometry) {
if (!serializationObject.geometries) {
serializationObject.geometries = {};
serializationObject.geometries.boxes = [];
serializationObject.geometries.spheres = [];
serializationObject.geometries.cylinders = [];
serializationObject.geometries.toruses = [];
serializationObject.geometries.grounds = [];
serializationObject.geometries.planes = [];
serializationObject.geometries.torusKnots = [];
serializationObject.geometries.vertexData = [];
}
serializeGeometry(geometry, serializationObject.geometries);
}
// Skeletons
if (mesh.skeleton) {
serializationObject.skeletons = serializationObject.skeletons || [];
serializationObject.skeletons.push(mesh.skeleton.serialize());
}
//serialize the actual mesh
serializationObject.meshes = serializationObject.meshes || [];
serializationObject.meshes.push(serializeMesh(mesh, serializationObject));
}
};
var SceneSerializer = /** @class */ (function () {
function SceneSerializer() {
}
SceneSerializer.ClearCache = function () {
serializedGeometries = [];
};
SceneSerializer.Serialize = function (scene) {
var serializationObject = {};
SceneSerializer.ClearCache();
// Scene
serializationObject.useDelayedTextureLoading = scene.useDelayedTextureLoading;
serializationObject.autoClear = scene.autoClear;
serializationObject.clearColor = scene.clearColor.asArray();
serializationObject.ambientColor = scene.ambientColor.asArray();
serializationObject.gravity = scene.gravity.asArray();
serializationObject.collisionsEnabled = scene.collisionsEnabled;
serializationObject.workerCollisions = scene.workerCollisions;
// Fog
if (scene.fogMode && scene.fogMode !== 0) {
serializationObject.fogMode = scene.fogMode;
serializationObject.fogColor = scene.fogColor.asArray();
serializationObject.fogStart = scene.fogStart;
serializationObject.fogEnd = scene.fogEnd;
serializationObject.fogDensity = scene.fogDensity;
}
//Physics
if (scene.isPhysicsEnabled()) {
var physicEngine = scene.getPhysicsEngine();
if (physicEngine) {
serializationObject.physicsEnabled = true;
serializationObject.physicsGravity = physicEngine.gravity.asArray();
serializationObject.physicsEngine = physicEngine.getPhysicsPluginName();
}
}
// Metadata
if (scene.metadata) {
serializationObject.metadata = scene.metadata;
}
// Morph targets
serializationObject.morphTargetManagers = [];
for (var _i = 0, _a = scene.meshes; _i < _a.length; _i++) {
var abstractMesh = _a[_i];
var manager = abstractMesh.morphTargetManager;
if (manager) {
serializationObject.morphTargetManagers.push(manager.serialize());
}
}
// Lights
serializationObject.lights = [];
var index;
var light;
for (index = 0; index < scene.lights.length; index++) {
light = scene.lights[index];
if (!light.doNotSerialize) {
serializationObject.lights.push(light.serialize());
}
}
// Cameras
serializationObject.cameras = [];
for (index = 0; index < scene.cameras.length; index++) {
var camera = scene.cameras[index];
if (!camera.doNotSerialize) {
serializationObject.cameras.push(camera.serialize());
}
}
if (scene.activeCamera) {
serializationObject.activeCameraID = scene.activeCamera.id;
}
// Animations
BABYLON.Animation.AppendSerializedAnimations(scene, serializationObject);
// Materials
serializationObject.materials = [];
serializationObject.multiMaterials = [];
var material;
for (index = 0; index < scene.materials.length; index++) {
material = scene.materials[index];
if (!material.doNotSerialize) {
serializationObject.materials.push(material.serialize());
}
}
// MultiMaterials
serializationObject.multiMaterials = [];
for (index = 0; index < scene.multiMaterials.length; index++) {
var multiMaterial = scene.multiMaterials[index];
serializationObject.multiMaterials.push(multiMaterial.serialize());
}
// Environment texture
if (scene.environmentTexture) {
serializationObject.environmentTexture = scene.environmentTexture.name;
}
// Skeletons
serializationObject.skeletons = [];
for (index = 0; index < scene.skeletons.length; index++) {
var skeleton = scene.skeletons[index];
if (!skeleton.doNotSerialize) {
serializationObject.skeletons.push(skeleton.serialize());
}
}
// Transform nodes
serializationObject.transformNodes = [];
for (index = 0; index < scene.transformNodes.length; index++) {
serializationObject.transformNodes.push(scene.transformNodes[index].serialize());
}
// Geometries
serializationObject.geometries = {};
serializationObject.geometries.boxes = [];
serializationObject.geometries.spheres = [];
serializationObject.geometries.cylinders = [];
serializationObject.geometries.toruses = [];
serializationObject.geometries.grounds = [];
serializationObject.geometries.planes = [];
serializationObject.geometries.torusKnots = [];
serializationObject.geometries.vertexData = [];
serializedGeometries = [];
var geometries = scene.getGeometries();
for (index = 0; index < geometries.length; index++) {
var geometry = geometries[index];
if (geometry.isReady()) {
serializeGeometry(geometry, serializationObject.geometries);
}
}
// Meshes
serializationObject.meshes = [];
for (index = 0; index < scene.meshes.length; index++) {
var abstractMesh = scene.meshes[index];
if (abstractMesh instanceof BABYLON.Mesh) {
var mesh = abstractMesh;
if (!mesh.doNotSerialize) {
if (mesh.delayLoadState === BABYLON.Engine.DELAYLOADSTATE_LOADED || mesh.delayLoadState === BABYLON.Engine.DELAYLOADSTATE_NONE) {
serializationObject.meshes.push(serializeMesh(mesh, serializationObject));
}
}
}
}
// Particles Systems
serializationObject.particleSystems = [];
for (index = 0; index < scene.particleSystems.length; index++) {
serializationObject.particleSystems.push(scene.particleSystems[index].serialize());
}
// Shadows
serializationObject.shadowGenerators = [];
for (index = 0; index < scene.lights.length; index++) {
light = scene.lights[index];
var shadowGenerator = light.getShadowGenerator();
if (shadowGenerator) {
serializationObject.shadowGenerators.push(shadowGenerator.serialize());
}
}
// Action Manager
if (scene.actionManager) {
serializationObject.actions = scene.actionManager.serialize("scene");
}
// Audio
serializationObject.sounds = [];
for (index = 0; index < scene.soundTracks.length; index++) {
var soundtrack = scene.soundTracks[index];
for (var soundId = 0; soundId < soundtrack.soundCollection.length; soundId++) {
serializationObject.sounds.push(soundtrack.soundCollection[soundId].serialize());
}
}
// Components
for (var _b = 0, _c = scene._serializableComponents; _b < _c.length; _b++) {
var component = _c[_b];
component.serialize(serializationObject);
}
return serializationObject;
};
SceneSerializer.SerializeMesh = function (toSerialize /* Mesh || Mesh[] */, withParents, withChildren) {
if (withParents === void 0) { withParents = false; }
if (withChildren === void 0) { withChildren = false; }
var serializationObject = {};
SceneSerializer.ClearCache();
toSerialize = (toSerialize instanceof Array) ? toSerialize : [toSerialize];
if (withParents || withChildren) {
//deliberate for loop! not for each, appended should be processed as well.
for (var i = 0; i < toSerialize.length; ++i) {
if (withChildren) {
toSerialize[i].getDescendants().forEach(function (node) {
if (node instanceof BABYLON.Mesh && (toSerialize.indexOf(node) < 0)) {
toSerialize.push(node);
}
});
}
//make sure the array doesn't contain the object already
if (withParents && toSerialize[i].parent && (toSerialize.indexOf(toSerialize[i].parent) < 0)) {
toSerialize.push(toSerialize[i].parent);
}
}
}
toSerialize.forEach(function (mesh) {
finalizeSingleMesh(mesh, serializationObject);
});
return serializationObject;
};
return SceneSerializer;
}());
BABYLON.SceneSerializer = SceneSerializer;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.sceneSerializer.js.map
var BABYLON;
(function (BABYLON) {
var ReflectionProbe = /** @class */ (function () {
function ReflectionProbe(name, size, scene, generateMipMaps) {
if (generateMipMaps === void 0) { generateMipMaps = true; }
var _this = this;
this.name = name;
this._viewMatrix = BABYLON.Matrix.Identity();
this._target = BABYLON.Vector3.Zero();
this._add = BABYLON.Vector3.Zero();
this._invertYAxis = false;
this.position = BABYLON.Vector3.Zero();
this._scene = scene;
this._scene.reflectionProbes.push(this);
this._renderTargetTexture = new BABYLON.RenderTargetTexture(name, size, scene, generateMipMaps, true, BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT, true);
this._renderTargetTexture.onBeforeRenderObservable.add(function (faceIndex) {
switch (faceIndex) {
case 0:
_this._add.copyFromFloats(1, 0, 0);
break;
case 1:
_this._add.copyFromFloats(-1, 0, 0);
break;
case 2:
_this._add.copyFromFloats(0, _this._invertYAxis ? 1 : -1, 0);
break;
case 3:
_this._add.copyFromFloats(0, _this._invertYAxis ? -1 : 1, 0);
break;
case 4:
_this._add.copyFromFloats(0, 0, 1);
break;
case 5:
_this._add.copyFromFloats(0, 0, -1);
break;
}
if (_this._attachedMesh) {
_this.position.copyFrom(_this._attachedMesh.getAbsolutePosition());
}
_this.position.addToRef(_this._add, _this._target);
BABYLON.Matrix.LookAtLHToRef(_this.position, _this._target, BABYLON.Vector3.Up(), _this._viewMatrix);
scene.setTransformMatrix(_this._viewMatrix, _this._projectionMatrix);
scene._forcedViewPosition = _this.position;
});
this._renderTargetTexture.onAfterUnbindObservable.add(function () {
scene._forcedViewPosition = null;
scene.updateTransformMatrix(true);
});
if (scene.activeCamera) {
this._projectionMatrix = BABYLON.Matrix.PerspectiveFovLH(Math.PI / 2, 1, scene.activeCamera.minZ, scene.activeCamera.maxZ);
}
}
Object.defineProperty(ReflectionProbe.prototype, "samples", {
get: function () {
return this._renderTargetTexture.samples;
},
set: function (value) {
this._renderTargetTexture.samples = value;
},
enumerable: true,
configurable: true
});
Object.defineProperty(ReflectionProbe.prototype, "refreshRate", {
get: function () {
return this._renderTargetTexture.refreshRate;
},
set: function (value) {
this._renderTargetTexture.refreshRate = value;
},
enumerable: true,
configurable: true
});
ReflectionProbe.prototype.getScene = function () {
return this._scene;
};
Object.defineProperty(ReflectionProbe.prototype, "cubeTexture", {
get: function () {
return this._renderTargetTexture;
},
enumerable: true,
configurable: true
});
Object.defineProperty(ReflectionProbe.prototype, "renderList", {
get: function () {
return this._renderTargetTexture.renderList;
},
enumerable: true,
configurable: true
});
ReflectionProbe.prototype.attachToMesh = function (mesh) {
this._attachedMesh = mesh;
};
/**
* Specifies whether or not the stencil and depth buffer are cleared between two rendering groups.
*
* @param renderingGroupId The rendering group id corresponding to its index
* @param autoClearDepthStencil Automatically clears depth and stencil between groups if true.
*/
ReflectionProbe.prototype.setRenderingAutoClearDepthStencil = function (renderingGroupId, autoClearDepthStencil) {
this._renderTargetTexture.setRenderingAutoClearDepthStencil(renderingGroupId, autoClearDepthStencil);
};
ReflectionProbe.prototype.dispose = function () {
var index = this._scene.reflectionProbes.indexOf(this);
if (index !== -1) {
// Remove from the scene if found
this._scene.reflectionProbes.splice(index, 1);
}
if (this._renderTargetTexture) {
this._renderTargetTexture.dispose();
this._renderTargetTexture = null;
}
};
return ReflectionProbe;
}());
BABYLON.ReflectionProbe = ReflectionProbe;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.reflectionProbe.js.map
var BABYLON;
(function (BABYLON) {
/**
* Defines the layer scene component responsible to manage any layers
* in a given scene.
*/
var LayerSceneComponent = /** @class */ (function () {
/**
* Creates a new instance of the component for the given scene
* @param scene Defines the scene to register the component in
*/
function LayerSceneComponent(scene) {
/**
* The component name helpfull to identify the component in the list of scene components.
*/
this.name = BABYLON.SceneComponentConstants.NAME_LAYER;
this.scene = scene;
this._engine = scene.getEngine();
scene.layers = new Array();
}
/**
* Registers the component in a given scene
*/
LayerSceneComponent.prototype.register = function () {
this.scene._beforeCameraDrawStage.registerStep(BABYLON.SceneComponentConstants.STEP_BEFORECAMERADRAW_LAYER, this, this._drawBackground);
this.scene._afterCameraDrawStage.registerStep(BABYLON.SceneComponentConstants.STEP_AFTERCAMERADRAW_LAYER, this, this._drawForeground);
};
/**
* Rebuilds the elements related to this component in case of
* context lost for instance.
*/
LayerSceneComponent.prototype.rebuild = function () {
var layers = this.scene.layers;
for (var _i = 0, layers_1 = layers; _i < layers_1.length; _i++) {
var layer = layers_1[_i];
layer._rebuild();
}
};
/**
* Disposes the component and the associated ressources.
*/
LayerSceneComponent.prototype.dispose = function () {
var layers = this.scene.layers;
while (layers.length) {
layers[0].dispose();
}
};
LayerSceneComponent.prototype._draw = function (camera, isBackground) {
var layers = this.scene.layers;
if (layers.length) {
this._engine.setDepthBuffer(false);
var cameraLayerMask = camera.layerMask;
for (var _i = 0, layers_2 = layers; _i < layers_2.length; _i++) {
var layer = layers_2[_i];
if (layer.isBackground === isBackground && ((layer.layerMask & cameraLayerMask) !== 0)) {
layer.render();
}
}
this._engine.setDepthBuffer(true);
}
};
LayerSceneComponent.prototype._drawBackground = function (camera) {
this._draw(camera, true);
};
LayerSceneComponent.prototype._drawForeground = function (camera) {
this._draw(camera, false);
};
return LayerSceneComponent;
}());
BABYLON.LayerSceneComponent = LayerSceneComponent;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.layerSceneComponent.js.map
var BABYLON;
(function (BABYLON) {
var Layer = /** @class */ (function () {
function Layer(name, imgUrl, scene, isBackground, color) {
this.name = name;
this.scale = new BABYLON.Vector2(1, 1);
this.offset = new BABYLON.Vector2(0, 0);
this.alphaBlendingMode = BABYLON.Engine.ALPHA_COMBINE;
this.layerMask = 0x0FFFFFFF;
this._vertexBuffers = {};
// Events
/**
* An event triggered when the layer is disposed.
*/
this.onDisposeObservable = new BABYLON.Observable();
/**
* An event triggered before rendering the scene
*/
this.onBeforeRenderObservable = new BABYLON.Observable();
/**
* An event triggered after rendering the scene
*/
this.onAfterRenderObservable = new BABYLON.Observable();
this.texture = imgUrl ? new BABYLON.Texture(imgUrl, scene, true) : null;
this.isBackground = isBackground === undefined ? true : isBackground;
this.color = color === undefined ? new BABYLON.Color4(1, 1, 1, 1) : color;
this._scene = (scene || BABYLON.Engine.LastCreatedScene);
var layerComponent = this._scene._getComponent(BABYLON.SceneComponentConstants.NAME_LAYER);
if (!layerComponent) {
layerComponent = new BABYLON.LayerSceneComponent(this._scene);
this._scene._addComponent(layerComponent);
}
this._scene.layers.push(this);
var engine = this._scene.getEngine();
// VBO
var vertices = [];
vertices.push(1, 1);
vertices.push(-1, 1);
vertices.push(-1, -1);
vertices.push(1, -1);
var vertexBuffer = new BABYLON.VertexBuffer(engine, vertices, BABYLON.VertexBuffer.PositionKind, false, false, 2);
this._vertexBuffers[BABYLON.VertexBuffer.PositionKind] = vertexBuffer;
this._createIndexBuffer();
// Effects
this._effect = engine.createEffect("layer", [BABYLON.VertexBuffer.PositionKind], ["textureMatrix", "color", "scale", "offset"], ["textureSampler"], "");
this._alphaTestEffect = engine.createEffect("layer", [BABYLON.VertexBuffer.PositionKind], ["textureMatrix", "color", "scale", "offset"], ["textureSampler"], "#define ALPHATEST");
}
Object.defineProperty(Layer.prototype, "onDispose", {
set: function (callback) {
if (this._onDisposeObserver) {
this.onDisposeObservable.remove(this._onDisposeObserver);
}
this._onDisposeObserver = this.onDisposeObservable.add(callback);
},
enumerable: true,
configurable: true
});
Object.defineProperty(Layer.prototype, "onBeforeRender", {
set: function (callback) {
if (this._onBeforeRenderObserver) {
this.onBeforeRenderObservable.remove(this._onBeforeRenderObserver);
}
this._onBeforeRenderObserver = this.onBeforeRenderObservable.add(callback);
},
enumerable: true,
configurable: true
});
Object.defineProperty(Layer.prototype, "onAfterRender", {
set: function (callback) {
if (this._onAfterRenderObserver) {
this.onAfterRenderObservable.remove(this._onAfterRenderObserver);
}
this._onAfterRenderObserver = this.onAfterRenderObservable.add(callback);
},
enumerable: true,
configurable: true
});
Layer.prototype._createIndexBuffer = function () {
var engine = this._scene.getEngine();
// Indices
var indices = [];
indices.push(0);
indices.push(1);
indices.push(2);
indices.push(0);
indices.push(2);
indices.push(3);
this._indexBuffer = engine.createIndexBuffer(indices);
};
Layer.prototype._rebuild = function () {
var vb = this._vertexBuffers[BABYLON.VertexBuffer.PositionKind];
if (vb) {
vb._rebuild();
}
this._createIndexBuffer();
};
Layer.prototype.render = function () {
var currentEffect = this.alphaTest ? this._alphaTestEffect : this._effect;
// Check
if (!currentEffect.isReady() || !this.texture || !this.texture.isReady())
return;
var engine = this._scene.getEngine();
this.onBeforeRenderObservable.notifyObservers(this);
// Render
engine.enableEffect(currentEffect);
engine.setState(false);
// Texture
currentEffect.setTexture("textureSampler", this.texture);
currentEffect.setMatrix("textureMatrix", this.texture.getTextureMatrix());
// Color
currentEffect.setFloat4("color", this.color.r, this.color.g, this.color.b, this.color.a);
// Scale / offset
currentEffect.setVector2("offset", this.offset);
currentEffect.setVector2("scale", this.scale);
// VBOs
engine.bindBuffers(this._vertexBuffers, this._indexBuffer, currentEffect);
// Draw order
if (!this.alphaTest) {
engine.setAlphaMode(this.alphaBlendingMode);
engine.drawElementsType(BABYLON.Material.TriangleFillMode, 0, 6);
engine.setAlphaMode(BABYLON.Engine.ALPHA_DISABLE);
}
else {
engine.drawElementsType(BABYLON.Material.TriangleFillMode, 0, 6);
}
this.onAfterRenderObservable.notifyObservers(this);
};
Layer.prototype.dispose = function () {
var vertexBuffer = this._vertexBuffers[BABYLON.VertexBuffer.PositionKind];
if (vertexBuffer) {
vertexBuffer.dispose();
this._vertexBuffers[BABYLON.VertexBuffer.PositionKind] = null;
}
if (this._indexBuffer) {
this._scene.getEngine()._releaseBuffer(this._indexBuffer);
this._indexBuffer = null;
}
if (this.texture) {
this.texture.dispose();
this.texture = null;
}
// Remove from scene
var index = this._scene.layers.indexOf(this);
this._scene.layers.splice(index, 1);
// Callback
this.onDisposeObservable.notifyObservers(this);
this.onDisposeObservable.clear();
this.onAfterRenderObservable.clear();
this.onBeforeRenderObservable.clear();
};
return Layer;
}());
BABYLON.Layer = Layer;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.layer.js.map
var BABYLON;
(function (BABYLON) {
var TextureTools = /** @class */ (function () {
function TextureTools() {
}
/**
* Uses the GPU to create a copy texture rescaled at a given size
* @param texture Texture to copy from
* @param width Desired width
* @param height Desired height
* @return Generated texture
*/
TextureTools.CreateResizedCopy = function (texture, width, height, useBilinearMode) {
if (useBilinearMode === void 0) { useBilinearMode = true; }
var scene = texture.getScene();
var engine = scene.getEngine();
var rtt = new BABYLON.RenderTargetTexture('resized' + texture.name, { width: width, height: height }, scene, !texture.noMipmap, true, texture._texture.type, false, texture._samplingMode, false);
rtt.wrapU = texture.wrapU;
rtt.wrapV = texture.wrapV;
rtt.uOffset = texture.uOffset;
rtt.vOffset = texture.vOffset;
rtt.uScale = texture.uScale;
rtt.vScale = texture.vScale;
rtt.uAng = texture.uAng;
rtt.vAng = texture.vAng;
rtt.wAng = texture.wAng;
rtt.coordinatesIndex = texture.coordinatesIndex;
rtt.level = texture.level;
rtt.anisotropicFilteringLevel = texture.anisotropicFilteringLevel;
rtt._texture.isReady = false;
texture.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE;
texture.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
var passPostProcess = new BABYLON.PassPostProcess("pass", 1, null, useBilinearMode ? BABYLON.Texture.BILINEAR_SAMPLINGMODE : BABYLON.Texture.NEAREST_SAMPLINGMODE, engine, false, BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT);
passPostProcess.getEffect().executeWhenCompiled(function () {
passPostProcess.onApply = function (effect) {
effect.setTexture("textureSampler", texture);
};
var internalTexture = rtt.getInternalTexture();
if (internalTexture) {
scene.postProcessManager.directRender([passPostProcess], internalTexture);
engine.unBindFramebuffer(internalTexture);
rtt.disposeFramebufferObjects();
passPostProcess.dispose();
internalTexture.isReady = true;
}
});
return rtt;
};
TextureTools.GetEnvironmentBRDFTexture = function (scene) {
if (!scene._environmentBRDFTexture) {
var texture = BABYLON.Texture.CreateFromBase64String(this._environmentBRDFBase64Texture, "EnvironmentBRDFTexture", scene, true, false, BABYLON.Texture.BILINEAR_SAMPLINGMODE);
texture.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE;
texture.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
scene._environmentBRDFTexture = texture;
}
return scene._environmentBRDFTexture;
};
TextureTools._environmentBRDFBase64Texture = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAYAAABccqhmAAAgAElEQVR4Xu19Z7PtTHbW1g3jMMbGmGDAZAMm5xxMLDAU0WSKWOQcCoqccw6eGdtgk4yNbZxnvvAL+Af8Af6AsQl+06ako9X36dXPSi3pnPu+cz/cOntL3S1pq5+w1mrpLs/eud9fvn27rf9evPPwFz+v22S7fGZ/n7/70G79J5/Xv/qzbLP+Pnvvoc/6Tz7jX/15/c62LfeH7fofbpfP3l/ct36Wf+u4+D37+XYb++G26LPsr/zFttnPuh37bm1bt0f7MvtlnOx4uv0H4fty8UUsz77rfn/57u32cgXvDv72eQf0tl0+G38b0Nf9K4Dl704MEfA16KsE8Gw9JgD+DQE8EA0DT2b7GwK4GHnF4a8iguXZt9/vL5/dbisJbEq/uwD5vIK/fbbAv4N9U/8nJIDNCazKvBLBGwdwu62OhajxmQSAx6gqNp5HCg9wPan2nwSNjhLD8ux/3u8vP3y7vbwDAYjtR8AzFyDqLu1Q+YEINnew23rPCYiKb+q/K7o4AVT4tg0t/h4ydJZfkQASQ/d5b9fZ/Z1ENmuPn/cwYCYEELBguKC3nRkCnE0AFOwOKCOAR/sH/L4hgFMpbSWP5dn/uN9ffs7t9mJ5cAHoBLTyszBAFJ/F/xIKdASw5wgaEWDMLySxAk4svf6L+4QAGPiJCziNAPb4f3UZ2dh/m+z7BK4SAPYrxf5FB6ABPgCUAfANAZwKyscc7IEA/vv9/uLzbreXzx9cQCMACAl00m8jAlF7ov6SCMQ8gJsMFFBnCECSg5H6TxJAU3vPAbwhgFfz9AABeOEDBcIbB3AqPzwQwH+731/8sNvt5Ydut5e3B2C/fG9P+jESgGz/RgxG9r9VAwTUUh0goQDafUz+DYnAnSha5l99Z1l/yQVswAZSGIAugNd/9xBgCw9E8aECkHUB22QPHIAVDlQdQAMWAibhBgZAasAVHUAI8Cqg96Tm0bj3VBS9jwd7IIBvuN9ffMHt9vLTbreXy+32QlwAhgMIeuNzKwOqCoB2Aa00KHE+EsIeDuj4H2N+Hf/TfAC6A4nhgQCQDDwiaKDXiq9KgBEJNPArAtCk0AEd2mpAizW3/lYIoANpBPg3BPA+hjs/9eXZV+0E8Bm32wsJA9aEoBCAuAABPiEAC/yDC4gSgRgKRHkAlgsI6v7iEFqJEMgBwb4BGkEfEEDnDlReoAP/SQRgOYIB+IYDMEE/SQBbXoLNr0jhq4qOZc0PHBSf5oKW519xvz//kbfby8+83V68ABfwniIBgwgQ/HoRUMv8w5qAoQqgk4DWQiCw+63eD8k/XAPQgK5s/5a5xzAAqgR6wY9k+ZEMtCOoJABb230hEHMFWQdgAl0Ap/+uc6tKBrrP/n0AuwfiNwTwNKguHHV5/qX3+/M1B/Ddb7cXax7g2e324vaQB3hhkMAW92tHoFb96cVAbimwkgQ0Vv7R+D8iACfuxzKfLvnNlAAjAsBwwP2MwLQAD9sbYJME0AFcg5uBPSAA0x0AobhtcDKDA0j3KYDhk7Hp8uKj9/vzH3C7vfget9uLT9nDgDUZuOYCLBJA8MNKPyGGIftPrL+4gy3eh5p/lwRUYYAs9Fn7tM/E9lvJwCH2DxJ/mPTr4nyyLiDtBgTAGCrgNuPzNuETgN+suEEAFhng9lkCoICMLH7V0isCeEMCxylrefkl9/uzz90J4NNUGLDmAnYXINUBrf5dCCAuQCcCvYVAYPk3G++VAveVfkIAFRLolgbr2F9ifP33pAqAV/fHRF4HcAS7AKlAAEIYFNwITOszs/wMsB6II4BXFZ0QwBsSOEYCDwTw2TsBfPrt9uLlqzCgcwFABI0EVCiANl8Uvq0JWNsi2JPZ/0YKsOiHxftsW4v51ZqAaBWgZf91PsBL/jFHwEqBR1cCiuJ3gAfCmCEA3cf8rmz8AMZHIoA3JDBPAsuHVgL4jNvt+UoCH34ggK0asIYBGArsAB7AD+reQgCl+GwZ8LaNlP3MEEDaSg4ACMGr/+ulwV4JsAEfLH42/vdKgWElAJ4QpBl+LAlKErHwt+oGMgTA2ngE4IUIOH3dGr/hAKT/m/UBdSJYPuVL7vflU26352sScCWAD+0EsCcDVxewKjfmAzAsENVn4EfgdySgnYB81yEAgL4RA8T8mTUASAAYBgylQAkL8K/+zL6rsl8qF6ArAeS7WRGoAB8Sf7isN/VZqTs6jQ5wXlweWfyqpQ8I4I0TmCCAT/3I/b48u92ef9bt9nwNAdZE4FoOFALYXcAGegkDMByAzzQEgJh+cAIs/legH0IA5QTCPADE+7ISkD0TgA/8sBIgLQfOgF/F9kPcr+J8fIYguyCILQRKgV4DNviOzoKqeJS0u4AA3pBAjQSWT//I/b5OmC0MWB3ASgBrGLA+IryvDNxCgRXo+wKhjgwk8bcTwUACsJ09ANRVAALwCxmEoFcrAUsuAJ4M1E8BDuHABAHomJ8RgACrZfQLyT9dBWi2OOEG9NJd/TDQ8HAQuBE97ZhjGKy6o+imnU+4gDckkCeB5cMfud/v6zr9Dz84gOdCAM/3JwQhF9CAD25gBWWz/8wNgMpj3K9Lfy0foMMBVffXyT4r+cceC9bvCcDFP0311QrATPkvWgosYQFLAuoqQEcQuw3v2si25F+M1RkZXLUU+CgBmCBOEsCbvECOBJbP+Oj9fv+u2+3Zp91uz9cy4Kfebs/3ROD6iPD2b10YJCXB+0PyrgsHdtBuRACfBeTN+uM+suJPSEDbfh3/oxPoHgwiC3/06j8Eutj69sAQqj++I0CUfvIpwCEvYCT90O4Pn1XsT5Ve1/+dcp9FBh3woqXBSEJkvjHHEOUPqJPAjUUCeOMGfCJYPvOj9/t7//d2e7YmAlcS2B3A8xcPYcBm/7ULEDIQew+5gS0EIEA31R8Uf6gAoBsgKwBd9ddvBBJAs6XARgLQXQ2o7T8+IETe+9eRACg7rhCMVgCiE8D4O9wOCb2ubOht1/vYd2ubzLlgKbBHEDSnAMfL6durVm8qBPwXWz7rY/f7/X/fbsvL2+3Zqv4QAjzfw4COAMAJbEC3wC8koBJ9lAhgxZ+4hi3Oh/f8dU8EqtV/JhHgWn9cC4CJQZXZp6GAk/1nawMkrrcqAiwPIIA2FwOB2oaAF5UkcX+GADBs0I5gsNbBQqCorJcFJjqWKvhNMjky0Aek7/LZH7vf3/vO2215vruAD91uz/dSYCOAPQzYkoD7vw34sFIQw4LNymNSUKk8Wv0hCYhkoJ74Q6BboO9eDKoWAHXvBiCvAdPZf4nt3QqA924AbfXV8t8uN4Bt2We029WkoErWpSoCSm11TM8AOYA5uRS4RAITIQDDavaYHxCcm5exfM7H7vd3v2N9McDt9uxDD//WKsAG/ue32/M1DEACuO3g1jkBsf57fqCL/7UbIISAio85AAG0VQEYiIC9DJTYfy/+Dx8HlpeDRK8G90IBHQbgWgD2WT8LoOJ7NyeA5JEkAwwxmuqzur5X6y+sBEwDMggrqoBNH7c68Puk/fI9Vwfwvx4e6H724oEA1iSg5AAaAewlweeyLmAnAHQCTfU1CTAH4GyTMt+QDMRFQFEYQB71lXUAOjHYlvTqh4N2xe5yASoh2PpaJUGDBDrLr9cGIDlY1l+vDlQOAQHckYMiA68KMFsGtOy65RCGsMIDT+QqJoD3yUwCy/f+6P3+7koAt50AXrwigM0FrIuEoBrwHMMAUhmQUKAlAwHo7VmAPURo9h/r//ozLv1V7/5v6wGMV4B3rwYPXEBqIZAQwp4TYDE+LQlqtQfw6my/LgsyZaeLg7wVgmDnWQ5AA5ZWCDRx7ECzyn3udgFptFCIgTlyFRMEUCKgA+O/jl2Xz/3o/f7Otz88QvpszQOsLmAPARoBSDVgud02AthdwPZ5BSxUBVr8L3kAVHrvs076KSLQi3/M9QCJ7H/G/rf4n8X41XIgcwHecuBMDgAe+BHA6uQgqnvbF5DB5hwUQM3vQgIWkKOVftH+gAC6cz0RXZ9MjmD5fh/ZCWCd1CsB7CSwhgArAUgIIC5AQoDOCewJwab+CH79WR4C0mQAZT4hEQS9DgfEztNkoEECDfi6FAhZflb6Q1XXqwHDEECpvZX4a0qP1l7bfAS98cQfzQUo9a4mASMC0CsIm6JGK/2i/QkCuFK9PxmIYPm8nQDu795uy3K7LTvwVyJAB7ARwJoAVLkA7QIkJ9A5AQS95Ad2YmgvAJWwQFcBpB38pUuB9wVKbAWgCXwV86Mz2ICKTwUWFgOxMEBicr0eoBwCGBUADfxsDsAiA+zflNay31ZcfnAdAAXgDGkcdAcfZCJYfuCX3O9vf/vtthHAmgcQF7ATwOoAtn9IACsRSDkQ/wqIIUGoXYEQQ/sL5IDJP539776DwodVAGlr5QBgP8sDdApP3gSUXQa8/rZsRaBeHmy+HwDyCI1MUNlZzX9iJSBO9igJGJYCo4RdIqMfJQ4Ztq8C7FXjHuSnQ92XH/yvdwJ4Z68ErOXAlQRW0O9/JRG42v9GBHsuAImAqv+uzDo30C3yAfVHoHeg9xyAp/7wlp+WFCSWv1sOTBb+0EoAZP5DImBrApAUMFHolQG19c+EAkbpjyUEdQ6gm/QEsCzZFxKDlWNwprJVWfBm/1WAvWrcQ0ie7Lz80H91v7/9v263+9sPI2zrAZAEdvXvXMBKBJIIFDcgyUAEvHICg/o7wA/Bvyt35wCc2F9Cg03RvRyAA34N8hD0xsIfXP7bQgDMFSgyYO8GsF4N/hQ5ALak1yUGRQDZZJ5VWXgKEsie8yQuH63b8vn/8oEA3lsJYJ2EQgD73xX4z9bs/74gaHMBQgA7+DsXAJWBBniHCLTtNx2AUnkG/LYNiUCpvX7wp6sIOHF/lwgkNf8UGagwYMgLMBdgLQCyVgOyciCGCs5nz/Jr8EXOQOcQZEbrfjjTU8qaCBseMyx4vxPB8iP+RU8A24Kg9R8Qgaj/av8lDBgcwApQ+QdVgW0bKr3+jsk//AztzBKgtv4K+Kj08rl7JFgt9BnCAIsQcD2AsQAolQj0CAGAqhOFCK5u3cA+84dyIJLCPm6buAgoBa5qDoDF6wzUkZ13iSDKKwTamSKZSf29cuzJUwq7LV/wz18RwH2Nl9dKABLArv6bC5B/+9OBGxmsIIR1AQ3w2gk4RECTfwBulgC0rP96/FYJUOv9SzkAB/xuKTBY/qsTgZ0LILF/s/RW9v81ywEwhbeAwUIH6hRwGp+wEOhqoF49fojqQoPlR/+z+/3t77jd3n3rdru999CzEYAQAYJfXACEAqL8W5lQgA5uoJUK9zxBB3ii9ALiYT2AjvuN72wFILP+XdlP8gLKFeg6f5QM3AC+VlMMZ9ABGuN+VePHWL6tHVD23or3tQPo2iWfBRgShDp0ELcBjmIAbwTWqEzIJvLM6kEDEFcD9erxCzg3my4/9p/e7299x+323lu32+oAtjwAhgE7Cazqv7mAvRLQcgG7A9B5AAwHus87CWBYsIKFfe+eCSBgt2J+7QBQ+VsogOU/9fIPBvLhASEF8AHwlhPQ2wVYFhmo/Wby74QyYLcmQAEbbbue2FcnAb28QTmHQKBwNVCvHv8IESw//h/f7299pyIA7QIE/LsTeIbqL59hPUADvHIBG8jBIWgn0L4rsKMj2Noomz8QgZELsCoAAnh0Caj8lup7ib9tX+ZBoKgUmFkWTGJ8S/UHZa/kAHT+QGaeoeQmMUC/CoAzVYAjYDvSNwPCq8fPnINus/zEfwQE8O7tdt8dwGZjIQQQ9Y9cwAB+RQIC4I4MdvvdLL+O//E7LgLykn6q3Efjf6X8bOUfkoNYcQZ8z/KzBUBYCqT/YQgjBuOBHxPs7JHh7JoAy/IzWz+xEtBKBEYg8fIGw+SeQQQ+CzHZP+oWXWPU/8z9y0/+h/f729/5kAN4791X/6/cpl4SCsDfLRQwHEBLCmJFYH92vssNgBPo7D8qv4CekIHpAjKgx1iffGbKb5UAQwdguIAtz2KsEWj7vIQggNON91lYoIFN2mznYKj9UBmwQgXLLcDstRTdBchEFWAWcLP9MgC9cuzM8aXN8lP//v3+9v/uCUDyAM0FIBFADqAjAsgFiAvYwK3/MfAL8InSd/Yfy37Qpyv3OSTgxf8C5vZXPfF3aB2AA3hJGg5LghMOgCUBo8SgEAyC3Irvh5xAwhW0cT1iQBKYWds/QQLdeVUQcrEjeGoiWH7633sggHfWJOAaAkglYL/wLQyQf3tYsCp9CwmgFIgOgIJ/JwMdBuB3cQTDX4z9wR2whN+WE9idh67761p/F/8bpb8O/OotQCsJDhZfji0qT9p0LsCI83X9H8E9KH8iCSiTrQO29bwAAbvlCipPAw4T/oRKQAVElbaMJ472t7jnqnEjrlt+1t+539/6P4oAxLquawIkF7Bb/40M9hAAHcD2GVzABmBYKSgxfyMGAbROCipl1w6gs/8ZF0Cy/UIOOr7vHAIu9iHP/2v77yX9ROUt29+AHVUCnDJgtvSn8wXsnQGzIUAW3F27qFS4z2CrD07wCogqbR8LtGecUwR4vX/5OX/7FQFsOYC9FCiToBGAEAH83ZwA5AM06BspiPKrNQIt/kcg69iffBegNqVXb/wdQgIMC0DltUuQ+L+Bmz0OrNTdK/91+4JVf15SEPMCYRkwEfc3stBxurMS0AoTMKRocaV8cKw6jpcFsdUn2/8qRT8buGeP55HC8vP+5v3+1v99cADvvfNQBZB4dO24Kv5GAntSUOz/+n1wAis4wAnoMAC/N9svSUKsBABgmwPAbQTwWzsW/2vAI6j14h+1CEjnBYZFQWSxj+sEVFyPjgBBrhf+aOtPY39vRaBVJlQ2vyOGIATQsb6etBguDMSQyAF4IMhUAmZANNNnUNSqBDvtzzif6HSWL/wbuwN4eycA4gDEBQgRYPzfSGC3/BYBdOCHxKBHBAJoAbdWfIz1I9XXsf5g9y0yAJB7iUDPCaC6e2EA2ngMGyIHwAgBldncf4ID0EDXVp1NYmbnrclOtyfDhiPOoCO4CEXB/rOBfOZ4yy/8a7sDAALY1gKAfWMEgOovoNdk0IArKr+7gwH02gWQ2L4t/sEEoLL2IQnoFX96HYC4CIz/jcSgAJSVAtu2RPZ/SPRBHkC7AkYEqceC2fqBfdKaCcHAAeAkpKVBCANcElBVgBQRTC4HngHOTJ+rQo2jhEbP6xf/VU4AmBza7L+EAZgLgGSgxP8dGQDwmQOQbS2xp6oEWAnQn1seIEMCJO4fsv8Q2w/JQU0IJMvPiCCT/NPuQP/noJ0rAFBa23VSr1N/vQhIgxzzB9odMMIAkGvFZPF6JkyIlJeFFl6IcRYYX0ciOOOcll/6l+/3t/7fngPYy4BSCmyT0SGAlgvY4/+BAET10fZjUhAWCg2AV8nBEPQ6D6DJgSUAoQ/G+Dr+T9l/pfg0HxAs/e3WBUhbsihIgHKkHGiGCQHYO/UHomDgdd0BcRkZlYtyAFlgZNtlzqkSJcwc1xr/6FjLL/tLPQG8t+YA3tuXBKPiqISgAB//bjZdkoNE/Rs5EAIYXIAKCwYHYJADlvhalp8RgS4PogNwFN8jgo1A2LoALxRw1gA09TbCAjckQHBZlQEFwEoS0Iv1S3mAYFGPlwOIJn+0v+ocPohEsHzRX9gJYM0BvPvwTyoB2gGsP6iEAowANsBJWAAVgRYeAPCb/WdkAKEAttNJwRbzM+UPQI8K36k9Kf3RagBTe2vhj3o8uAFXLxUGxTdXBrK1AIltTZ2JzUe7Lp/Ralvxvrb5kcWP9nv2fwBzIRF4FRFkx/XcwRljHCGm5Vf++fv9re+63d4xCABVRhOAJoOtRCguQKoCmghwv7L/mBPQwB/KfMQhCEF0ym8RAUkIToUAxrP/gxOwSoDGmn9WCjTzASw3kHQA5poA7Q4g3n+MEMAChiadiopXwHZV26usvB43e/7Lr/pznADakmBdDcB8AFj+5ggcF4AhgAlwwyUM6m+pPgF8U3BS6jOdAAkJ3HUAO5C7ZKBT99/IVDsGhwyY3e8qNfhCERXDa5BrlW/ftaoqe265Ar0U+PIQQCUzqwqYBYfnSK4AcuW8sjmHaMzl1/zZnQDeud3eXRcCrfH/ngNYbyxzAKL8nQNAMiC5gI0gBNz42XIBAnAkBACwqDyWByPlp2BPWP7WD0Crs/5ewq+1JaBnWX8rEajbDiVAlbNpwHRyAJ4D6EqECQcQWfxo/0wI4E3wcPJnUbSLXqH5A26qHaD9kb7ssKaj+nV/ZiSALRG4rwhsJLBfUKt/k3yAJMGwEtCFBGD/PTIY4n6d8ANyaEk/Q/nPUv8h+WeRgXYCVgIwSwbK3osKi4PonEGUC2C2Pngc2LL73Xanlj9bBTg7BIgAFe2vuoxZS14B7wy/DCT8xX/qfn/rrYccwLtrElA7AJkgkrDSJUHJfO/Z/wZ4Kx8g4IXyYKfm0i9QfkoSJK5HghALr51Ce2Jwv0ad9BvAj1WCidKfZf1x3UDnvPQ90HYf7o1WfSQMGbOpU1D3H6oCynpjPE7VfSccpoalMEHNdAxFKkDLgDzTRo5ZaXukz1E34f1Gy2/8kzEB6MUlsjCoCwWMEAAdgOcGTECrnECn+JYTgPyABn0U82vwt7hfJft0rK9DAlHooTSolH94GxBUAnTSL/reAbz6UBADt344SDkIJBIT5E62HgnEAwgFmjq3ChFkAJUFd7Zd9fwsdZ89nnX85Tf/8Z0A1hwAOgDJAxBbuU1usboYCoiCKvWX+L/lAUDlNUG0bD8Bt7dviP9Vf0v9LbV3XQCz/3qbZf2d0h8D+JAPYDb/RAfArL1l92W7Z/OjEICpOZvkw7bES0EisET7M0RxRNkzx78qJGj37rf+MUUA+zoAnQjs1gTAhJNyFy4X7kBtkYHKB0ifDMgrLiADfJMESGa/Cwe0/a+CHsmA5QQ8N6ByAzJZh1IhEobOAegsvwaVDhEKDkCre0cielYbau4SQfIZggyIM0DMtMkc6ywnMHMsduzlt/+R+/2tt2+3d8QBiAtQSUBaEVDxPyYB22cEuiYDQgJtLUFk7539ke1vgAeAR05gC3ekbAclwuaEjEVA3XoAAnLpT6sBCuStrUrIpqsBHhkwcBOVTecFJAteCAFSyk/GzapwBOJofwV0mbEQkNX2p/X9HX9IEcB7eyLw3q8IlPgSbV/LBThEIMreQJkhAeYOIsDrsELV8VmIgHX9ITGo1L+BnxGB5wQY6IvKLzZZCKD7nsj8m+sADjoAVHk9ga19tF1CzSk5GO8T9MCUAdpZbSqEUW17lpNYfucfvN/fBgfwLlQBcEnwdkA9cdGiCjCgGrCpZhACDMSA6wL28dewgKl6GzuI963EXwtf1Nr/wQ0YMb+bCJwAPgKc5gPIPeiImeUC4B5J2zbZnGXBQjI4Mdk2HFNPYqv9MNlJCJByAzPPEezIiUAe7a8ANjPWGYpePc52Db/799/vb7/zKgQQAnhvDwH0cwFWLqBluwkRYJ7AqgoMTiHjApTqR9ZfbLxbCbCUX1wOKQGiO8ASn7XdKgMimL2SoG4nkxGVnqk+OoeBDHR4AN87EmCWnlULBGiBuiNJMFC5RJB8HsACRgYwZ7WpEEY2pNEuYOoYv/f37Q7g3dvtnT3+39YC6BBAv3IK1wVA9p8SAYC5gRDBqz53QDasvag/dQboGMCy0zBA7e/CgoTyszX/VeA35QeH1YGc2Hwr2YchGn5mJNGVd8FdoEOIHEBo9VkeQc3cqFJgEkPhxSBHwoIMCVTAlx1vlggq4y+/7/fe72+tDuDdV2XARgD7isDtd95BpZWjKRUov4Acwa6BT5OEsEjICg1aBUAl8DpwA2kgQeCYbHsjL0zygfKbll9XC5xk3zYGgM1yA0IKERGgI2PJQJ20M13CAQfgWv1kEjBj+Yc2zlqAGdWPgBPtrwI2O16FXMrn8Ad+z04AaxVgTwDiasAtBNgnrK4E6HBgSApichCBBHkBCnQNbmb1iTPoSEXlDXCfTv6x0EAA2OUDtCPA70bMT6sAXjVAlf4sIhieC8BYXy0CYk5gIPKCA8CJGzoAI5QYJqoRzx8NAZ6KCLLgzra7igSWP/i79hzA6gCAAMQFrBMNSUCrFypUm+x78k/cQRffY45AqatOGDJy0CDHkh5dDERielFhWvrTIYHO+icy/jK+qe6sCkCAH70erLsXylXMWv5GFowQrLyACISU6HZ0W+RALX0Qz2ug4NgYUWScRNQ+q6IZ8GbaVMCdHS99jX/4dwIBCAmsoNd5AHAB1sRDArByAV1YgLkBnfRDF6AtPbP4LNY32lkOgMX/tPynSKFzC466Y2JP+mT+mk8BOiVAVP2MA9COgH4nQGcgHxyCAe5uMicqARTcJ+QBIlB5+6O+V4E7c9wMCSx/9HfkCEDyAMPDJiQZ2AABqtZUVwG7s+ZWMlCDO/F9iPFZso9l/IkDaMRgxPqe4g8JQa30yg14pdaM7TddgWHxXcUPVgLqvnqyWw6AqrlT0jPV33AekYJb4IlAdfX+6LwR0BVi8Yhg+WO//X5/e68AyLMAawlwCAEwF2BkpTfgqwlu5QU6G45KrdYNsNi9qwAQMgjBnyEDI77XYGcxfjXut1wAhlfSptsGoNHJPab6XkLwTAeAk1MIidp+mJlRJYCqPxCABwizr0aUDl3I/ogEMsDMjJEZp0oYjECWP/HbSA4ACEDWAbA8gJ6MjADWbYP6i5LqvyRROBBABHgjXEAV14k963s7d0koOkm/s+J+FiaERADqbjkAHKNNrsRCoE7lmYsQ0HjlPm+dgMzKRLmQkkgyBJhR/SPWPwPyTJuriWD5U78FHMB7eyJQ5QDaYiBhXL0mgGWumRNQAO/KbieTASMOL8bvVgUSq2/lAvAaOvDiwiEjs6/BThdZ6bUBJNvfuQN0Z+pzVzI09nXqrT3UMRMAACAASURBVJcKg+J6xKAnLao7Tvruc6ZcyBS6EDpUXUIEvgyAz2oTnQuqe+aYzT386d98v69rALZ1AEIAazVgz/4zBzC8aorlAdS2rkIgC4e8v2TxkOsGMLeA45I6vgZ7ygFg4g8JQhOdl+FPZv+ZnRey0CQhE4PtH1TfCBmkXQd+S+1ZXkCTiQZq0gG4sb6qMHSAKFYQHpsIMoDMtKla/syYy5/9Tb0DWGP/7R8QgOUA2NtnzEw3LhRS6hjlA9CK6/gfS4XU5rOk427p9bg02cfATtS9CwGcSsB6/taTf9Zvx0ItvQ2JgH7WgEYyMMA+5AwmHMBMDsAjAhrPTz5M9H4mggy4M65g+XO/YSeAXf1lLYAsBca/24D7MwKdakBIYOUBxKYyJ0BDAeIOTOW2QI75AgVkXNVH7b+VBFTgDisAQda/gd5LrCrlZpa/WXJrEVBk+cGxNWAkqwDMQWiFNq2/zNKgDOi6A2NFICULRAV8rrSN7HgEzmh/NH4G2MZlDi8qXf78Fz8QgNj/thjIcADtvw9HNcgQwGxIwPIGLHTQVj8BfszWmzkAlZsQwFrlPbcCYOUCjBwKKwl6pUBRWyFhukxY7LmO7414X8f61BVY4YLY9iDBhy6BTX6LPJCoPHtcAXelbQRUD+gZEojGZyCvjrv8hV/fOwArBGBLgnFpcGdJYUJ0gNknxLDNCwm8xKEV6xtqPwt4DWpm92kIQICN7bSNF2Xv/pLfUgNd5wxoCEAA34GbqL0VAmhSuMIBuIqv8wGJRUQWmCzAfNIQwV/8tff7O+9BEhBKgEMiUIUAXjLQinMbAAAcCIruFWMVgBPFX28iLhW2Yvzu+JCo06A21wAQm69XRVJwk+RpaiEQCxeQKEDlaWhgtEWQWEqvt7vhwoQDKAFfjR+5hytdgjf20X1HLH/kIpa//GtUCLATgE4CogOQz628IwzslKx0gosuG1bWnuUGotJhyzUYYUIjBSsnoJKVXZnPCAeYo3EBH1UDDIA38CniiBR/CA1I1r5VEQBUg/1XVt8jjG7iWZUD5WEz5UIK8sRagIhYquQQgfqI/a/aeBYKZMOD5a/86r0MCGsApAqQcQDbgTQBMNuqJ70GE/nuOgMSGjDFj7ZZhNABnxBTIxon459Vfa9yYpUEEfRU5RXounEUkJEgGJlEYNb9O2IQ16hsO07y9nk2ETjzJKG4JIKUSlgQKqyDzgzQM22ic/AcxPLXflXSAew30no8eDsJvBGWyhmJsKojQOAOi3R0yRFtPcvuqxo/tf7qeryYv2T/mZqT0IARgfzmG9Eg6erP8Jvr+4Tk4Sk6IwnWfgA/IxsCPhmfKWuk3ugcqENIgLwC+hl1j4Ac7c+CPDNOd4/++q/ccwCRA1iFHkqAtBrA3ICh/J46Yp7AjM+DHIK27t1aA0YIbKGPIisrw59NAOqSH/0NEKyMCBS4qwnAtNpnk4JGnN8pfKYKoIgiA2R2DEYglW1XE8FZQI6AHu1vv8nf+BUPBNDKgFYOgDkAsHdmQhAnkhP74kNDg72OwgMP0CRuN90GW+CTdCwWoVluQKv3EAYQ1cZjuOpv9JXJNyT49KIgliMwlByVu7kJUFwvPBjcQuaxYSuUOBAGZMjGIxEP1BEQn3z/3/oi4gA0CQD4uxAACMBLCKLNjFSPJd3Q7rtJOWu1oZNcHMgmE+8H5T3P3Xj7OlCzCgEeN+sEVDs8Rpu4Ol9ggd1ScuYWkAQIsDv1lrYqB+BZ/2FfsBqQAe3sbZG6Xwn2aGzr3Ja//cuJA8CnAXfr314SajgBkwBwAs6EAwmwWWFChThY0s8iI297B3DDPYRtCLi3Psb2AdRAHrKvqb9BCEyNtaKXS4OkoqAnomXjKUEo9e/GSjqAs0HvAS8C5WzfaNwKES1/95cZDmAlAbIacPudIRcgi4H0oqBuUirgU6WDSVtJsHnJw8gtZNyGWeJLEJNn61vZzYjzo/3dQ0Ea1DgmUXMWAqTAbil9UOaLynttQj+iAzibCCLQRfstUM+ShJiqqP/y937p7gDuex5gBz5bByD23woDMA9ACeCAG8jkCLTis+8ZUhjCAisZOKvwySw/OoWONFWMrmv4ZsWAqX+wrXMGbLkwnMvgIowEIWuHTsV1CTKz978WeViA88IKDzRnA/Ts8TyCcUng7/+SngC2twFZJLBPljIB4IQ1wgA9waPM+rCfJApN9Tae1beOGZ1LO06CEKj7UbF9A7CVB7AShIa9R3Uf1gOwhF9V6S1iEEQFDqFN3my14IJEYNYRTANNERd+PZMMIsXXp7H8g198v68VgHf2uP9dBX5xAtvbgaUUqEqCg/1HKweAlx9vsLeGIlqxchWojCyqY1RCgXK5jxGHofIsD9B+V92nSAgIxCEkgLEGBU8mAaO4PgoVmEJbOQQG1CzIs+08Msg6kAwRzJBOlgiWf/SLRgewksCq8l0YAKBveQAgBGb/t4vDhJQmAwf4a9dQeZPWnJbiHMfgOYeNlAKlx3BFOxs3L6B+LySS8EUg6rzwuEgQ3luBGugDqx/lCzyCGPbtCBBi05M9Io2OFB4hEXgmGLMgzZDEjIvYruUf/0I7BGgkAJWAbY46SUArGThMyAIZVADH2ppEkiCBir2n5xmpu5ME1I5pUH+LYEnFICKEDpiFEADPSSu0JhQX/MphTBFBIYnI3MRjgLviLs48H9OR/JNf4IcAK9bxPwoV9TerAXgj4T0BOJk9MhAQDZOfACUCNgIy0zbTJpPZpyGAQwTiKug7AYkr0L+N991Vf00gpGyHINbK3yZVMQQwVT2xEMh1BEZ/Nvk1EKsKmgXyGeOeTQQdEf/TL3wggNX2b/H//jqwLRGo1gC0HMCeD9AlQPw+WDqZJEZIoCdaNY6OgOmFAVq5u7ae3Y9AHam7sd8kApUsZHaekclAvrv86eoBcwkZkFvrA1hf1wU4Cu4Btu1T/c8G/hWgrxDEmSFDc0D//OdDCEAqADoPIMnA7a8wrv6LpSEFfJlkoQtAdfKShEmAWlUDN7xgOYYE6DPuBY+Lv0W0HRXdK/cN2X6l0jqcsICubbx2AVeFAK7Sy+zV1YDiasAjgH6MvqZth+vXH6sksfyLn/eKAFaw6yoA5gEE9FYScDsZZfsR8CwhSJNb2Tq5UVLsQO0lE5Pk4bqRiBDU/oEcHFVn9X1T4dFZ6TKhYfWZcltqbm6HsZm6D07QKuGRcqQGgEUKSF5N2QySYPutbZkw4SmJwCIIJIXIYSz/8uf2BEDXAWAosN/w7gUhAHwhge7GY2wGBKFtf5oMGKgcl1Cx/wKwKKQY2hWB3oHbqver7ab6J8t/2L9VbaR6sM8auk4gArlRNbBchQnSaBw5RyV7lRCAgSYCerS/otRZwqiMmSECc7x/9XNUDkCvAyB5AAwDtrlBQgG8KegCOsvolQgrgPKcQKTQSReBhOCquBP3a8LTToXF/vpY8ls2J6AdBFH/rNJfov4YDoL6UzVP5gDc8MBJBFbBnwHrWW08EEcqrvhw+5oNBZZ//bMLBCDqb7kAcAJtUQeyOuQDcGIPnzFeJQClSbJqngBULW3xIzKpkBYe3wGxkISn/u5zASwccLbh5NHhht43ELsFcGeFXwfmA1UAdBsZ9YxU/ej+zDkwJ+RtO5Mkmhh9yc+637cKwJ79lxyAlP/kKcC1IqBzAJgL0K4AQwC0m7hgyAsBrAVEaL0HJU6SQKeiyT6dWictOwsTsqW+9ttosAax/pA3AKJBEqEhQLX+T+J2PG9GEIxEPPC6ag/SNzhOtm/fZo3JABYpfLT/KBFU+leUvxHNR37mSAAC/lYBUDkA76EgIYWOAHASKnXHm4/hwaB8pIxIV8oFFpxlziNws/0diSgF91bwuQQmE7QQ+2fUvwO+pf7KkXRA9db6W6QB1+KCHu1qMgTQE70DoTOG24/Y5qMuIEMOFYBXQ4FM++WjP2MnAFUClGTg5gCEAMhy4M4F7JNou/eZ0qBWELD7qO6D0uNkZXmEwKqb4HXI4wzAa8ejLTYSjb5mfXz8jgCvlP86YrhC/ZH4lfpSFU4SgAfMo88TZFxAlRgyY1aI4Iy2zQF87KfbBLCVAAP199YCaBJAV9AlnAxX0NqwnIBSrHSSziAPa/VeJt/ACMp0AY6l1+CNvofqb6h6NikoJMMUHN2apayZNt3YxRwAPa6Tb2iTXj4cVP2MwkdkUQFz5njsGt1tX/rTHghArwHY7P++DBhdwDanYCWgzgPIfh2TtfUB+6QcJhcBedfGUXoGwAaOyXhdKy4rC1rxPAtlymqfjP0x5h6ArVSdARJdiQa6BWC8t3h8RhQ616AnY+cEigRQdREWUZ1NDBnFz4I5Y+OroMf2y5f9VE4ACH50AS4B7OD28gDtxyEVgW6yOIQwWGlg/Uz8bQLXcBoa/AM56Dq8FcMbCTyx/o3ISF3fsvaMWPRv7JLEPht08nC4TyTDb5UNI1VnwO3coaHQFPBKxa0QwAO/G1LAucwA+2oHkDkny2Vs27/8pygCANUXF9D+h2CdC1CA334rcQf7Z7yxsp8qiFpBOKhPQAiW6jIlN9UdzllAKQBjdtxT9eF8HJLQ5xNae6Lska1nSu+pfyMjb3GOlxwEYrHANwA6sO/abdBxyRiPAf4ZoGf6WOA9y0Es/+YnAwHs4JfsP4v/JSEoTgD/is1veYFZEsB+xAp7gDEX0yRU2asQaHX2wD8QjEEsCDKt0pZqM2LpSqaiiNpteCW7mQSgukc4UTWxsH0Z8EaKT/erRGIW/E/pAo6AOdt35+Pxvwf/t0gA8BKQFfzZMiDmAYakoJ4oUB2gE4UtHDLiYQSa9bnsDEhJj4HfdBYHF/V4Vn8gvh3sh9Rfk60ot7c9Uf+Xc80AkDnCNGng+RrnzCa/RS6Z8zXBJDv0ORnf9bHY96Pbov7LV/ykMQfQrQMgVQABvP67//60BKgXA7UTU9Z/mDgk+TeAndjrBtpCBcEF9Wz23on7j1p9TW74mzaH4jgC/Vtri20uDdakzvIDbTL0y1I9Gx+V8CJHgNeTBfIMEXhjz5LDU5HB8pU/ccwByBOAXQ6AxP9sQVBL5EJGF8uByPYDCehJE1UGAuB7JKD3MadA22iFx9DCiPPpeZAFOZWyH46Jk2cDPiZFRX1IvI7XrMdg2fsOvCRsYGMM25QadgC8KAeQIg5BblAajOL26v5Z4DPrb6m95wKWf/cTxhwAPgJskQAu/aUhAIB5+22J9aelQa0uOuFFQoRBCY2Soc4PNBDBMQVAGJ50amqVI8kYOH4F3FTZsyU9EvuLMs4q/NBP3SNT1Y2FPQyQcs0RYYT7JxYTZQgiAmoE/Ki/8E80DgO+RQYe8Nvx/v2P3wng9updALgAyEoEYrY/ejS4katyBegG2OfOEqpSX7s4K0QohgVUpSft+5VgR7BFsb/nEkxScByD/s31pB2IIOMSIETRE9YLF0wiOGMtwcUu4EoyyIAe79uyEsDwIhAsBSrrT6sAuyJ0i4KU6p9CAkpl9boBNuHT7iCw9vThJBJfe8erKrt2IZZjoWSIcTkLCTwVt6oC6nojwLKYvuoWIsUf1DsZRljn7m3PAPcMBY/GqIK8YU/IHTYs/+HHKQLYAd+tBCQkMIQA7L0AQAxo8bbjI1MXPiOIqMJNOgIEly4HmvsUIaUA7oQ0tD/LuBsAzTqC7XosUnAy/MwBZADtKTl1fjhB2aT19j9RCHAGOWTGyII/Gyos//HHAgEo5c8kAbv4X6m+lRDEmy73EtViSEA5pcFOIVTSMHIEAgTLVuvVceXVeFWwO3F+ByIW5zuxv1ZRRqL6d2TK64E1Y/9dIiDWfVB3veqPEcEThAARcDNgPKtNdC6Dw/lPP+Z+fxcWAOHbgM2FQKDsQ/wP+7TSo+qzsiAqk1apLmGoVUor4kTpcCCDALzZen1EQpbNp+QEjgNdiZWxN8t4pCKQUXeLOChZOFacEoFxTmzsYRIjEZwQAnjjRwCL7Hu0PxofLnVc1IM7gzxGE96vWgkAHwUWF8AWAuGDQOyhIAQ/KwPu+9t5KmVvJwXtMHSgE9BQfU0g7oMy2g4byb9ZMFtkwUCMhNDtJ2VDDVoNLBoSEBLpQBYB18kPpElkv9HM1XRzwFB85gzw2BaArX4uoRRAFYG7up+RQYYgKm5i+aof/RACiPK39wAAEbB3ArSq3v4Bl//qpcAa8Nt3QhAM7N0FE7DTSWc4goEUAAwm8Ky1CNYCG69syWr/BJBWLkArvWflL1H/iDwE2I6dH0hKJkeyYtCRFYCThSdZYLuEwo6hCGwGlE9FBsNx//OP2gkAwwBJBBoVgK4SsE8KyQWwuJ8RAoIdCQJvpMXqVnlQA3z4TpRdjsHA1IEo6hss7JFzQQDQYwaE0AHAUmMrSWgAmJKomuRH7D8DmOVWGMAjgHb7T8oBeORR2XcFOcyMyfps2776C/ocwPr7df8rkEMC23xS/0uQLgVm3IBOAHYni1ldneHVcSMJKdbJEYYOQU7BDR+M8VMZeQZUY1tHVNYxlQJnQgJNKNbk9tzGAFovx0CWDXurDkPF1+MVcgBZhzDbbgaoVWdQsftNaIHcNwLQIYCQgCh9SwaC2jfgQ/lPg92qAnQnokIB6gCUcrlVAqNsZqqco+xMtTM2/FTwVxyBofAsvGGgNe25UxqskgxV+ETIkCaCAgFEzkLmqdXuqZ1ARBam6gMAl6/5kSoEUPYfwa/fBNSeBQBi2MZW7wRox8skBgnYTUfgKLeA11O4KDk3gJ0pWzI00BOYxuhOeU9fhwXWqdg/Io7MfuJKKNhBfRrAJisAFJgH1wF4oPYAF4HxyP6oLwN6xhls/f7Lj7jf5dHf9hdeBNoRgJH5L4UB+2TSpBDmBADsCG5U9izYq+Sg25uKqqsJhnJ64JdrcC13Mfan14tAdDL76MhM0qmOFdh2fRxGJBZQoycKI7BkQZ5tFx0v2h+BPw30BrhXH7bweCOA/eWf+kUgFvjxKcChGqAAbuYADCLQ4N5O14j9I/DjftcGe1UDpn7Ogh2LhCrHfyzw098Hwews/aVkkMzkD8qd7JciggNJQItUjoC0CuAjxMLOMzz3r/3h4ADgLcDM+ktOwKwC4HJg9ZmV/RoXWaGBUv1TiYABO8ofWLHwRDLPBd8JCn8quLMWPeMkiPozK5/dNpBCkAPIgnwWiLP9QqAqBc8of6rN1/3wh4VA8gRg9AxARwI7iFgJUCcAKwlBFg50lQIdDoCbMC1rpYKQrBygW+kUMcjkR+CsxvHus/sReCPQRvsR0A74rPCBnXtK6ZVTsdzgYwK+ovaVthE5zCi/8MnydZ+vQgC1AIiFARveINHnJQMbNlHlAbDbiTj7NBmUiYCoNqsiDBNUT+YjoHaSh3Lz3BDBcivedkaSjvqa8X2ypBe+QEQBVl9vBHrmCCi4H7EKcJban00GFcJYvv6H9UlA+i4AXAuAZT/1WWf/LdXv8G6VAQkxlMHPMsJFJ3CJylugstTaU2FPdT3wZpQ9UZ4LiYvU/TswJ1xDRsWZ88v0a0oIFjtDNt7YEQCPEEc0dnX/AwGQ2P9oDkDCAvld9XdP9dEV4I3tbpaenMZ3V2lIn0yCSlv0wyTh1Nkz9p6ppxVGoFU2VV/UOqn+6NKiMbtzdQgmcgRv1P/hJlXdw/C7/dcfajsAifeFDESU27MB+wa5jzoUaOB3LD4SA4v9NVF4LgAnd3ehgeozAHugHianEx6wCR+FG2YeA294whVQYtjvWQRUMw9BlDIkG7b6j4VmVrusOp9s/y0ncJX6R+POAD4kiI0A4L8BQ+Uf3gfg2H/2MBBTfdP+C7vAzdaPAFfIwLSERHVoIoqUBjNKm3EDGVIwx8kAOFLuaL86hkkkxcU/jDgrSh8CUhG9B6iMzc+0iUB7xO6H4EWszLqBb/ghJARgTwKytwI7OYAhBHBcQDYckOtlTmFYABIA3XILbCEJ3QaE1ampsRItHTbsF+mqqpUryCzZzYA/QzJJN+ICPLFqLwPCI/F/aXy5N4YjiRT6akB7BGmd2/INP/ghBGjJPwL+1QnIfGf2X8CuQ4GGEZXoO9UFEOdwhAxYDiCtXE79ngKh2t7LFWTAHwAbSTEKEby2kaqznEHUJ6XmCUJJjaPUdFbFK4CvtI2IprJ/+caVAHQSkD0ObL0MxCgJbnNNqb7+XlX+KATYLlwdky4NZVaRxY/ZcMGLZwNHkCaXCPwZ1bbOBZXNyS0wkJruSKmll1w9CsrHdACzZOBdYwWwYj7CcAhcijf+8o0/KHYAkgzs/u4Trqm+/g7gKYUDRNG7F4jKhTlAbz+SbgNjdz+g0S5yA0wFO5AQAnHVzwOoZ/vPAn8yMeclKSMlPwOspm1nhO2oeRZEM+0qgH8q9d/O8ZtWAig4AMGQuRDIWQ48JAUBkO3eRcDWuQSi+pETQOBSdpxQ/kjJI7IYljkrVXaBlajpZxbqeGrOQEDzGqA8OoywfvdqHP5+IICznEKFSDJOYhjvm35g0QEkFwIh2Bm4w3AgcAJ6MrV5R+y9BpcmCFQl+oOz8MByE0qNu/EK4UDkJBihWHF7Bvz4m5jAJct+I8Wn+6+I1a8YE0k4+OwBtaLwlbYZwIfjrQQwrP4jK/82+6+2y8q/IQmolR2SiNvvqFUc3x/A9jOwESfAgB6BnxGJFR6E9tWbhJ499ey9FUbIhDT6ejadAjwKMbSVtkgxY7kvAOuZjwFn1fvq0CACeAhucGPycejzzT9gdABYERheCLqDUQhh+0qeC2iYNcBvWf4wMWgQhE7+CdHoC04TAlFy0zkY6+41udAJkyANar8JKVIHEBFEspYfOZLIxofkmSEOr82B+H9WvWcIoALaStuILNj+bdtKAF4JUKu+uQpQx/5AFKj6NBwQeiLOYCCxKEegCELb++GHcCoCA2taYHXU0IrtXTJhjsd5kKcDpziDBEEgQZkkg+MBWVigiYjA/T3gZofjGI4kC+azwTszXgTaqwlgHX/5ls97tRRYVL2tADRCgUH1yYKgDofE4nc4VqDG/EGbE0ZiziMIF/yGYlCHYJEKKzviJLaOEWTbQ5CQpN9AAhcoP5JWGaBA8lmyKYHZI+FgldwMeLNhgncNlX0RWczufyAAWQqcjP2tCgACV+Z+t0RYAUmIpAOxEdtHTmDbTybBsHaAnIMmiuHmatcBk9m8iexcEgrqVgP2c6cxvFL+LMii2HkYJ5Er8H6TaeL4ANj/CKSPofiIowcH8P23COBGnwHQhOBVALxHg1l4kCED0mbIEVjqTIhk+4GT26dJIXAF0yGBQR4U6MR5ZNsNTkIRS0mVsa8ir+o4LnF4ZKvPYXKV3xWK/1o4gG/9/ioJKC8E9dyAAXaM75sDANDp+N8LA7p3CyjF1Y5B3xxKEsZ6AVo5SIDYZHMvGRUlqqLseLCSbzunpBVGMsy6hTA0icAWXf9sIjC45irZyPzKuJUjIH4KxR8cwLd+v50A1PMAmOzTnwXTYvkld7Bth5uM+9uBo3yAodKR8uP4HUEQ5dFtGYEM25QCDwQQqVAEzAgcQdx/JvipC4jICX50Cpxk/wzoorCkAsrM8WbHM0WCEGXU9qr9y0oAWwiglH8LCYz1/w3wqvznqr5BDhqsUwuEqg5BkUwHdgOI2yGsx02tHIHcaGd/pMQIbArMRF7hCGAwFMqAxWwTEdys+sO9zJzfjBuoKPVVba8lgGISsFsApElivyE45wdXADdNhwUdlkm8nnYCCeWXY+l439tecgvG5OxuZqSMjnPoJnwWYJETYUoenWOkaBP9M2C2yDML8my72fg/Am2FLKKxZvZvfb7t+77KAWxOwEj8NXUHp7DNb3QBCvwSAnSCq0MAQhiitugOcCzcbsX71qrAri9OXEY21nMGHUu9GnG4oQVncMg2Z8FPSDEFNMcVHemf6ssIidw3a6wsyM9oVwXhUQLwznkQMVIKbQRAV/45RKDJoAHcIQMhiwjUQwjQscer3hYh0BWBxhhCNCzej/ZZx9FuIsolHLbMFUWfAXIUviAY2ecKOUVjMTIoXH8EmAwhRSA/Cuoj/c255pHot33uQw6A5QFku5cLQGAjMSDmLCcw4BImixUaCDCZkntuwGtPCcABCx6nHBJkVDg7qSuvwEoAcQDIBPi9MTIAKyt59rcKyGWWHCr9IvJ4kv2NAII8gIC1Wwqs1wUAoi0yEABrx82UP+sGziCFDsgkHLDyBN1N80gjqCLg+CkQJOPqdn4BUOhEniENVJtE/2x8TduRa/IAmT1WBMSzxomO8yj7P/65r1YCotIPn0m8j28BFpVvwGdkoCRf2/gOd1k3MNgImIEEyBZZYEKJugVrHYEoi3EsTSzu5HEIZCCFyuQPnMIl4If7kgVMtt0hUkOCMj5XgVex7VM2XU3IlEAQxyPDdP0//n3GlYAh+FWs370OXBbbqWSfblNxAlbbsuUPyMLLBeA9YLafTZruB8+AO2vps+32650Flqem4b4T1d881oyreWICqJLL1e2XjQDkjUDkmX+d5WffEVeWE0CBNJU/qfq6f0eQBdVv/Qw1tdyCBWzGsDJGqBIZgiCAzjqK0kQ6A1hnjOGBNUEwIUmd5AAqxyndB0PFw7nkOAY9R5ePf+9XSUBGBAJudAVt234Ttn37xi4ESGyTE0rnAIBtBqwfAD/+Zl68r8nGdA3RykEsy2TtfJYkKsfWk+wM4GavJwnA2fj/CDCPgqzSPwoLov1HSOUVAeBKwGgtgJH80+AfbL8OC9A66Od0gFy0UiuCa+Sjt0cKboYQRGmHsR0w4vmGE0GRltk+AapuIlTbG9dcDh8mxpkCauL6wt/eUcojfY8AUiv0Wd+tc3ogAA/8xsKfDuykTVP2/YO1GlCLNnUCiii0Cpu7LUfgjUf2WTG/JgXLORwFtbkE2VLQRNKPTgiHjNKASBw7PZZ2J0Vnc+Q4ugsk6gAAG0BJREFUVVKKQH/muZxKCp/4Xv3DQGLn0fI3sEerAPVTghAaaFyllgcDi1Asq43t6yzwI2IIKgHiOFKWjZyjZ3XZBMuAOJqYbTJVwwuDfIb/l8FR2cy5VX6Ts0HmZdunz90i7eClJZnjZdoMv1EjAMcFbLiYAT+x8TpX0DCeAHPXxAA5XTug7YiW7on9NPYPwgLtEEKiSNjcTg2y4YSehCeBv+xUZid98ne5khCmwHaQDGeOGfVZVgKwqgAiiBH4U2XAfTCco1qxNcAZxiOAm+J/kSvwEoYU4Anl325ath0hr5BYNPDYq9Sr4LzY+reJfBZZVa/vhPYRGGf2Z/p4bZZPfM++CmCFAF4YIETR/upnApw3AqUJAQ4ShQPD/ovA3wjdANDwwxvKZbVjN45uSwI427eqnIywpsbIKOT7iAAy4Ix+p5kxMn2kzSsCCKoA+AiwJoOOAJTtF8vPSAK3NSFLhAJdPwLuTKiwHc8jhsx+1YaGBSRxJdeadQgWETBVTJNG0mVEE3TbXww9yg6lmPzL/gapawNSitpXgIdcF40783tlzmUd94EAEiVAuc8m+HWOoCH61fxAy19R/mplAElHicqrryeD3wM1fVkpm1gBkOgxHEV0gZA4VnpiFlQ5MzHNNoXjpM+9APBozKuI59BvpgAwJgE/B0KA6CWgrP7vZP4bWcBJZJYEI1FYQuzlAtw8gTFg2jXs12I+diz7gQA9tu/2GaRkOQvrfYapiZgNR6znyMn1zQCkpG7GOZfG0PenQAAZIM6cS2bcq9osnxAC0C6AgH14+Ie9EIQQwoY5FRo0HAbbKY5In3Yf2QtHEGVWiGEAVhHow1cHPHgeJnAZqAIll3GrSUdKBkdyBmQF41WTsxv3LMK6mAAe5bdwSKt6/AcCMEIAmevrbz88A7Dv1CofVQQ66w9ftAJrMdSuAHD46ucIiEGDeRDcKCwgB43KgZYa47l4biIav0QyybjfOufhWGcRiQHK7nivKQFUATcQ+Ylgnhl7+cT3sEOARgDO038dATjZ/w74AKTM9q05AScjBY8YEHRVy4/Kr4mEKZXbRnaSa/IAvR3HISk3CZkkr3AMOPeM3c2SiTtWAfyzgDyz3+xYZ/6e6XPoCMBZ9tuAboB8cALKIbT5x54H2CeVBrkGOHUFHjFQNlBJ6wnVZ+AWgogA3Fg6cVymuJ1zME/kYQdT0CwgXTUpEFdmUodtCgQQjrVf2NXtMuNn2lTu18x4rxyACgO8sp+n+ts+A+Rs+a+0Z1jFfXS/ASLLGQxjJEAYlgpn1FwdN0UazloDD6wR4aQVH4GTPP+ZCUkn/MmhxtWgsu7H7O9x5fkun/hsFQKw5B+AGsGfjfc9UrDIYjukmmjatlv4taoAFduvyccFWYJIvOSdFvIo7s8Avps0ScBaE606VoVUdFvL9byO4Inc2PvhnEcC2CfL+mf7p+P//ar1dgTsEA7AmJ1gFrZ36k36tXEjV8CshFwT3tEsqBPt2rDQNqX68GNl2kfEUQGmpcQR+VSOkQJIQf2vUMorxkxdd1R+hbl6aLzmAMhCnuEZAKPmrxW+EYAFcGtpsLM9dATgUrSiMvLQbSruYArQCaKIAJxyCjgxnGN6hGLuyy55npicFuEcJZSjAD7aPwvOK46TGfPBAej4nz3959T8B8VXYMR5aK4HIACOLD8DLZvzlp2nZiAB1G1+J9pVbD8jrdR6Awts5PymQL+Pf6j6EBCCNVHN/7iV/lgq6XkWCcn1k2NmwX2UxLLHyQBeLkPGXD7x3cccQGbdP1P9UPmt5CAAqiMLOVvD8re2XkjggHXASALUWfAzl4BzKLT0wblk+kdt0vuNc6lMbBPkhtU9tMpRgfUogGaApfmi8lsdPd9S/44ASLyPQEelZwlATQqIPU/56ctB1MtEGI61slP1NybvU4LfELBXmxMZfzZGxnGkQY8HgB9rxkVM9XkK0imqfYUYqgRYAnHBEelxXzkAJwcg4EOFz9p+5hSasBPlZuGCMgIPIkwmiN50RjWg+22zDsFxHRnwR21cEKtzjADvTUx0OzMgjsY2VbEI/iq4ps+L3JiKslfPszJ2pS2exwMBZHMA+8Re709HAGxxELTtnACgWZNIa5ew/APY9c0xngno+qlBXHxfDP7tBlaOwSZjsn+GFLZJciAMOUQYRQI4dKxHBvWVJDAz9vKJz4rXAYjidiHA/sPRtQDWE4LGOwIt1e+2KxvgEsD7DPyotNPqXwQNO84ApIkxI3IJwXryMcPjnUAAVeCd1f6MaxsJgNX9WXjgKbzlCIwyX7vn3jJhpZCUAGBjRBCKTzjukoraOlfbp04iooTk04mFic4I6QiwvQkvp+XlL44cewYkZwF0uDZ1D2Ztu76VR8ZZPv5ZDxpOwwDr+X9P4ZV9b66B2HodRmgXnHEGrc8Tgz98B4GF4wJp0Bud7B+BqDu9fcxMn6hNaT+5llL/IsnNkMNMn9eZUDYC0M/5I2jXzxqowzaw9l1bZzsCl1p9I1zQJCHkhffeVH+HJBgA9HwysZYE4TA/Z/sZziECi+clPAXOKg62y5xLFHJMjZFU2ciVnA30GRJ4jD7Lxz/zVQ5AwFVa/rt3osAv5gIQ3A+25OFuenbefV6AlBLZeBb4U/hMNSLQC8gonPyzx7Xq7gapyObwfKJx4SfIOJmzjveYQM78VlW7PktU2eseCSCI9wegW5Y/SQwakDpksPYLM1juofVTQHFxE71NKGkJQmyGDTyt9qsFGeCYo8N5ZcfJtnMnsvo9smNm2mWBUHU50bFnjvvYY67H6wiAvvLLyQPgk3xWqKCFRZSdAbdti5KBilws8YrcAd70cgxfJYtAYQPI97uPEog62DbxCmNGE7UKJjx2duwz2kVjXLl/hiAihzEz5isCCFYByhzRCj0A37H92xjE1neuwtmP/V1nQBYKWfMbQ40MCKvtD5EMO6ErgBqMGQGBnWa6z37sdPujoUYUipy4f9a+R0A/c9zl277bXgXYRQABjsDUIK0Anym7DiW0m2CCaS0ZHsggafuzYO6GSwCQNkn0CwnojDESYUwFjDjcTL9osVHZTTwigCMgvu77txCAEkCy7s9IAcHI3IIGNoJwIAV0ppmwYD+4xgn9HoCpAuIQl0aDsF9nH0J6KDWo2v5DKk86zxy/QjCZtq9Tm+hcrtq/EUCn9M4LQIYwYL+x5mpABUgK8H0jgmH47IC/U38Sl1fBnwV+GryzuYILwd+GTl5ENPmyzNONkzx2xg7PklP2ujLtHqtNdJxov3YljQBEibW1t7Y34CVW/Wngt3vv9MXxB4sPd5w5CBY+6PESTvihCUzU7JzF68uCwzrnSnKudCx1MZmJUxo/itWTP+bMeWX7PEW7s46ZGSdq00IA+uYfou4DkEG9vX2W7Weqz8gBccjcAQNPRfnNuUjcCQPB6a7BZIMqBI32SfBVjhZNtm6sxPFL48HglX5XtM2OeWa7zFhWm+VbP6NPAgrYXOX3VH8fwFT9qEqg+rvq76izRxQZfEVlQXcOJ4nDBdgZY6TZKoZ6ZpLFo4iq8JZHj1Htf1X7K8bNjDnTZiCAyPLPxvs4LnUEiaW/HaifCPyReEXEkSGfM22/nO82OaKTTyP4QMOLQo/M5NdnfXWf6viZ9pk263Vm2m0hwOoAUK3NxUCBsrvEkFH9YI1AN3+zFYHki0M6UBog8bCDYcth0SUHOgW3pwxyAPiJ9wvMjp6Z7Gzsx+pXPU62/RntGgFYyt/IQVnS9au3DwHL6vc6RIjWASDIBntvOMvsSkAPwBZuuu0HQBuNUwUFPd+LwZ+diFc4kPSxyQ/52H2rx6u0z7bV7ZZvkRyAEddr694BP3IFmXyAE/NHlt8iAv2fjXju1wJ/Cvhq4AzOzDZO58y4mXxClUxObX/4IvqzyU547xqOjnGkf7VvpX2p7bd8eCIJKIpLXAFTfq322jl0feCOee00qC2HYIHfUt408GFgb26n5v0JawVmiOVUgHuDpX6E+GwqEzseLRcnXz3OzDVV+3jtl5UAEKAIOhO40WO+mZifOA5KBEG7DuCJhUADIcDkZPPUJIQDil21/dP4KXYsNs9g46HNgYGrkz1/UucRwHrMo+c527/abwwBdgLoSIAou1bjSNU98jD/81Ct/t7/IyAuRPocAH9F9be2pEM0x+l+tTEag03u11H55Zy2yTZzURUUH2xbBVDmcEfGfOy+yzfrEMBaCrzfTAbsiBwyYcGg/oSEAOu9sKi2oe2fUP3WJQnacN4XbH84lp6VB9xJZoKn25RPPD3yaQ2PAC5zEkfHP9I/03cjAAbgAegHFv9YBMEsPyqsPgcNbNaWgb+bh4QsNLHgjWV9Q4IxZoZFIubxghmWcRWZSVrgj/xwb8Df/VYZMEY/7hVjPBAAgIIqvKHGkfJ3Y0UEsl99+L4AaQcoxLmm593Z4Gfz2pvrw76kg5giBXIiV+EwHDdsEE336/efAaiZszzzuEfHWr7508k7ARXIEMjMGZhKnnkpKGnDxhu2ESWfAX8K0Jn/ZwBmgjn3E7Y/i5uIWDITM3uszFgdYV01cPVEgvZHwXP0dK46fmXc5Zs+nZcBN8BFqn10v7H8V5NMZ7kTVYHBoicBTMkgqaqhC3AaRHiJ9m8TccJZeBM4dUw2wIHrjABVmdjkJ2nDV8eJzuus/VeelzX2RgCDwnuLghxV74CbedQ3Uy5MvBQkUn53P7odreIJUFnzvdueGKdq+b3xLwF2NqE/zRxnweiDNc6VpLD+Uo0AGnjBWg92f6dVur2yNFhA59h4nEfb5+T6fw2MCPxU9ZV8mG3UXKNzn1yjnqIRZtz9RXIpinaIplkiCgd+08D9Bc4ihuUbMQRQkzXrDBAv4UNBcllR+IDK/Ejgb5MZZnVEIJ7V9J4M9EAdEUI7ZqZhVrkzZJawFslTegPvR/gFMiSxEYBW2PX7oPIROWTe+JsIHzoygS/6fDTwjiq/Bv8s8BmJAOfR2x6BxnMW1dDBIyxrTkbnt/VzGqX6PwIgjhxCX0MGXEeO9xh912t4IIAo5nfAj2o0kAaqeDLb341hHNcDf/QEoAvsI8lCA4nW5D/iAE5558ABxR/O/SDCD3a/DCuZ83q/E8HyDZ/mVAF2pCEoKcizdj5DJEIaVfAnlgJXwT/lApxS3wzoM2DLTNSK8mfHE+UvtS/A9apxM6fwlMeW81vJ5WrnsREAA/W2LQHsVMyfGKez/gr8Q1ignEXm8V8PzFXXYIHJUmY2mWbIwPq/EvWEzkzeTJuQNMgg2XEzIJwJb6rjHgp7zjrYI43D3MryX8EBWHZ+VvUtEmGAbseAGUSPWwT/2apvglntOAv0bRwDWRnAXdYmM/BkEvKpgZm8tEeC7nWH6QhgRvVdkColt9rKcT1ioC4gsP0V8LttjUnMwFkBvjXJhu2EFGcBEk3saL8cN5uHmD3PaMpnzzMax9v/GMc4cn5n9N0IANXXBWnmPQCi0Enwb8AO2mbAXwFw1fJXiKQBxLg7FYJAR8aGiyboZfvVwNFxMhN1ZoyZPplzie5hZYzXve3y9RICEBAOZJAEdQnQxpiuG3DWBWA//RnJhu5TdyskFTIDKwBPtU2qfwQGb3/Ut/utEo0TTUxczPSd6ZMF5pVjZ88hanfkHDcCiAC7HSAqFQJthi4icAlU8YMyImPtAcAOmLBtCHzCHikwR6GEvtMnVxQY6ZFD2vMt8TDTjFN5yj5Xgisa29t/BNSV4y5f/6nj04ADABNZfI8kqJor5XcVPwF+D7RybimSgF/PHDNQ5YhAPCC2vkl3EYF6VvlpP7VxZpJW+lTasntbAYLVduYcKse9evzoXJav+9RX6wBkMnUKfgH4U+VFDcTkcmANCAR/SBIF8M+CPOUUCDnijZwB9UyfDlSJmZpo0s3HTPtMm7McRMkNRcgK9s9e18HDDt03AugArx7qMfftQ0XKP+MmvD4U4HguhDi8PpV9mfUGTJFToJdrMGaGNWHO2u46iYCQjgAwC4RsuyxRZoA0c8xo3CvGjI7p3dvla4kD2Dqom06JIOsOEs8A4A9jOZCzwV9yBKpxBtSZNt01JY5h3cwzicA7p84VZGZech1AFhjZdjPneYTIop+iet7ReGed60YAFuBc9T8R/IPiF2N+Rh6RWtM+xEmIw/EmlEckacA6KnsGuL0JaO5LJv2ykztqF+2fBXV23LNApcc5cnyPCM4Yd/kv6ACyoM62q7wSTD+BaDiQlAuYLBNSIBeAGRGBSQbkTlZAf0bb4dySbqQ62TOTNtPGDVkIarJjnkkCR45Z/V1nHMPa5xUBwEQ/TfnhF3DHJC8TYa7gKPhLqg8Hi4Bd3W9ZbDZhzgB3ZYx2bs7szUzsqM3R/Y/pBqJzPZM0HgP4eD0bAaTi/WxeoBDvD6SQIAzG/K1bslJgEUF3o48+XUhi32EiFev8WYKYAjzOPBCDSFkicHj7o75Zlc+MQy4vurS2vzp+9ryvtveZ81i+5lPGMiBT3zRJ7J3Tig9UHvVxHYC6SxmQm22csVwC2q8lcgTbGGRWHQF4tq83KbYxjNkegWAW6NG4mUk84wYyx50Zt3K+FgFUzu2o+9gIIALeVeBHuxmdQxb8VeAP48IAEZCn9zvHsCZQFuDZdvQ4CeWPJudTE0F0fjNOoDLmEQKoHmfmWjRhLF8dOQA1KVygFpKDrwP4B7IwgDkNdOYIDJBlgXt2O7wPenJEE3IG7DN9qhM9Ou8rx5slgMo5zzoT5hY2AjBBfTL48cfZhs6+OhzOvANtArBpR5AA5mEiIHc5GjPrCLLEcIXyW5O3uj07sTNgybTJgjU7Vna8KtEebe/1X/6z5QAmwT+AnL1g9CD4hTzcsMAiDba9mPCLQEv3G2RlTfoMoDNtvEnZ+quBZlR6Buwzx7lCvTMAz7SZIYDsuFlyZCrvnddGAIMDCMDfgbxCFIkKgUcg2q6m1X3/VWj7yTUD7Ec1iSHhLrJEcAT0dLIVKxHRRKwSQQSAq/dH15PdX2030z76LRj4oz7LV2kHQJRqIAgB1GOD31DRChF0bR3lM8GcKO91fYvuwmJr73y8yeQSRlL5zwL1rOJHk/jo/oxyR8e4GtDZ41fPoyeAQhKvVBk4Q/kD8FdIYLvhCTLxQozIAWzDBwCLQB3tj87BnQwTyl8hgkrbzKSNAHD1/gxJZNtkrhfVPLo2rfyV9hsBlMH8RMpfBjn8MpbyZ8asEEEbT/1GFZWOgB/tD13EBcpfBfwVbiCa+FfvrwA7OpfKWLNksZ7D8p8+lFwI9AS2H1U0A1Rp47YlwLTaTwF/7xSB9Oj+I+pfeX15SCYGyWYm5etGAhlQPmabqxwFjrsRgAaO+f0k5ccTcI+dBGuaHJLjReByCSNQ16PAj/qHgIUBKqrN2h7tH6ncFQQRgSoCeLQ/Gj+65gxxasufPSZrt/zHrAN4jcCfBjyG4RPPCZQdgAOuCLgeqUSEFIIeZt0VQD46pjeBryCBCMRX788CNjqPCplYx9wIIHQAB8GfVvwT3gNAgTQBflflme0l7qJCIDMgzwCvtQmcSZpECi82rTiECBTVsWbHi/pl9kdtzgT20bGW/xA5gNcc/K4bOAh8D8DdD3/kPygplhVLoL9Q+TPnESlUFdTV9rPOIgLw0f1HQRv9rjpE8I63EYDpAF5D8LuAP2j5o7GpSkMn/UNXvlfaZtxCa3Oh8lcAWWk7C9yzjpEFmAes2X3ZY2dIKNNm+feWA3hC8FeASNuS9QxZNbeOTfur38i6edkxI2BnVFc7kyPWPnO8yvhntI0m9WOSwBGQRy7g6P4skWwEMDiASfDjzTFdxX5m3f4CYCNyyCzwicZIkQUBv6fiFYWvtDVB9cjKnyWLqrqfBehZsM4CcbZfFrjR+BFRynGWf6cdwCT4GahSJBCAPwJrtx++6GOnQK3icVO5T3p+oAL0qG13fYScvImVAW/p+CoIzYxfPb8qkUSAuIIgZseMzjWzP9NmPb+NABpYXgPwlwAPE02vZjwT8BHJsMn7ZG6AzLoMAM9qU7H5Z6j7GWNkVLd6nCwAFVe2r5HCn7V/+crVAVSeAUALbyjhrPJ7LsIC9NaHKN4lDsBQVtMpOI7CIyg2ebxjzKr/DOgzfSok8NhtI2CeCfQjID3SN7pG3L985cvEOgAE/ZFXfSceCio7AMO1uIShriflFhySqQL2DMKgx0yofwbAnnupALYCpsx5PUaY8H4ILSoAjxzG8hUvi88C7Ee3VB5PjrZJuA02BgVp4EBSwM7E/cn1BBVV90A2tQ86RQCOCCuz/ygRZAF/lETOBLSnypXz9Igssy8igIp7WP7tTgAhcCfVuyOBE8DfLq4A/shVuERhAGsKpBeFBNH/gmRNqogoov2PRQJHj/MYJDBDDkeAPHs8fcxGAJaiVwHMwLZtS4Df7Kst+8HKgQX44fj7hizYz24XKbH8rmjzItAe3R+dU9WmZ53AB5UEZoE8228ggH+TdQAFADMgpQhGAZ0SAlHkSOGj/VZ4MRNCZPvMtuv6JQgqA9gqKWTBmAV3tl32uGcpvgWy6vZZpT8L5CgQlAA85a2qtwZ6RflDB5AEfwT4aL+21Fb7LIhn+kfAzfzHIhVgR22j8zmq/BVQZc61SgKV41fH9n6bWXI4q9/y5SoJiAMfBb9Xm7ccwXB8cQVE7QayIW8groI0s5KwOmYEHm9Cm/suUP+MEp/V5oiaV8B6VdsZEphR9Jk+FXLYCMAE0oTtb2OpCZoBq+kAjLFMsgDP4x33TOsfugohMnJuEUEM56lmRaSIV+/PnP8RwGfHrxzjyrZnksPlBPBlRhlwxrpnwW8CnWXJC0RymBCS5b4zwV5Wf+hwBNhH+lqW9rHdwVF1P9r/dQZ6ljiWlQC0SjIbPLRRilYFv0cC7Yc9WOrLAFWf94y9n+ljnZurdie8YnzquMS9PAUJHAVshqCs63oMsFeuzzvPaB8eZ/lS7QCU4jJVNckgUGurH1XuiVJfilSYFTdUtUIgR0nA67/tU7OjouBll2GEKVnQZ4EWXUPFps8es3KM15EEskoPt3T7KP02AojUO0UCk+CnoCWAzII7Au2w3yG8o6COzoUBioKCnKPrFBjJqRlQcQLVY2WJIjNuBaCvIwlUVX0G0NVjdATwMXEAAYBdEnhC8Ecgc/efGPNH5xFNdhOQRdt/ptpHCh3tj675CFE8JTFUjv2UriFz7GUlgOp/DNKRwUHwdxPfUeMjDoCCq5BfOOoEZvpr2x+BLavolXEyAM6obnTMzHEqoMuc09HxKv2rbTPAVYZO/ydUbXfkKP4/BnecprBuissAAAAASUVORK5CYII=";
return TextureTools;
}());
BABYLON.TextureTools = TextureTools;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.textureTools.js.map
var BABYLON;
(function (BABYLON) {
var FramingBehavior = /** @class */ (function () {
function FramingBehavior() {
this._mode = FramingBehavior.FitFrustumSidesMode;
this._radiusScale = 1.0;
this._positionScale = 0.5;
this._defaultElevation = 0.3;
this._elevationReturnTime = 1500;
this._elevationReturnWaitTime = 1000;
this._zoomStopsAnimation = false;
this._framingTime = 1500;
this._isPointerDown = false;
this._lastInteractionTime = -Infinity;
// Framing control
this._animatables = new Array();
this._betaIsAnimating = false;
}
Object.defineProperty(FramingBehavior.prototype, "name", {
get: function () {
return "Framing";
},
enumerable: true,
configurable: true
});
Object.defineProperty(FramingBehavior.prototype, "mode", {
/**
* Gets current mode used by the behavior.
*/
get: function () {
return this._mode;
},
/**
* Sets the current mode used by the behavior
*/
set: function (mode) {
this._mode = mode;
},
enumerable: true,
configurable: true
});
Object.defineProperty(FramingBehavior.prototype, "radiusScale", {
/**
* Gets the scale applied to the radius
*/
get: function () {
return this._radiusScale;
},
/**
* Sets the scale applied to the radius (1 by default)
*/
set: function (radius) {
this._radiusScale = radius;
},
enumerable: true,
configurable: true
});
Object.defineProperty(FramingBehavior.prototype, "positionScale", {
/**
* Gets the scale to apply on Y axis to position camera focus. 0.5 by default which means the center of the bounding box.
*/
get: function () {
return this._positionScale;
},
/**
* Sets the scale to apply on Y axis to position camera focus. 0.5 by default which means the center of the bounding box.
*/
set: function (scale) {
this._positionScale = scale;
},
enumerable: true,
configurable: true
});
Object.defineProperty(FramingBehavior.prototype, "defaultElevation", {
/**
* Gets the angle above/below the horizontal plane to return to when the return to default elevation idle
* behaviour is triggered, in radians.
*/
get: function () {
return this._defaultElevation;
},
/**
* Sets the angle above/below the horizontal plane to return to when the return to default elevation idle
* behaviour is triggered, in radians.
*/
set: function (elevation) {
this._defaultElevation = elevation;
},
enumerable: true,
configurable: true
});
Object.defineProperty(FramingBehavior.prototype, "elevationReturnTime", {
/**
* Gets the time (in milliseconds) taken to return to the default beta position.
* Negative value indicates camera should not return to default.
*/
get: function () {
return this._elevationReturnTime;
},
/**
* Sets the time (in milliseconds) taken to return to the default beta position.
* Negative value indicates camera should not return to default.
*/
set: function (speed) {
this._elevationReturnTime = speed;
},
enumerable: true,
configurable: true
});
Object.defineProperty(FramingBehavior.prototype, "elevationReturnWaitTime", {
/**
* Gets the delay (in milliseconds) taken before the camera returns to the default beta position.
*/
get: function () {
return this._elevationReturnWaitTime;
},
/**
* Sets the delay (in milliseconds) taken before the camera returns to the default beta position.
*/
set: function (time) {
this._elevationReturnWaitTime = time;
},
enumerable: true,
configurable: true
});
Object.defineProperty(FramingBehavior.prototype, "zoomStopsAnimation", {
/**
* Gets the flag that indicates if user zooming should stop animation.
*/
get: function () {
return this._zoomStopsAnimation;
},
/**
* Sets the flag that indicates if user zooming should stop animation.
*/
set: function (flag) {
this._zoomStopsAnimation = flag;
},
enumerable: true,
configurable: true
});
Object.defineProperty(FramingBehavior.prototype, "framingTime", {
/**
* Gets the transition time when framing the mesh, in milliseconds
*/
get: function () {
return this._framingTime;
},
/**
* Sets the transition time when framing the mesh, in milliseconds
*/
set: function (time) {
this._framingTime = time;
},
enumerable: true,
configurable: true
});
FramingBehavior.prototype.init = function () {
// Do notihng
};
FramingBehavior.prototype.attach = function (camera) {
var _this = this;
this._attachedCamera = camera;
var scene = this._attachedCamera.getScene();
FramingBehavior.EasingFunction.setEasingMode(FramingBehavior.EasingMode);
this._onPrePointerObservableObserver = scene.onPrePointerObservable.add(function (pointerInfoPre) {
if (pointerInfoPre.type === BABYLON.PointerEventTypes.POINTERDOWN) {
_this._isPointerDown = true;
return;
}
if (pointerInfoPre.type === BABYLON.PointerEventTypes.POINTERUP) {
_this._isPointerDown = false;
}
});
this._onMeshTargetChangedObserver = camera.onMeshTargetChangedObservable.add(function (mesh) {
if (mesh) {
_this.zoomOnMesh(mesh);
}
});
this._onAfterCheckInputsObserver = camera.onAfterCheckInputsObservable.add(function () {
// Stop the animation if there is user interaction and the animation should stop for this interaction
_this._applyUserInteraction();
// Maintain the camera above the ground. If the user pulls the camera beneath the ground plane, lift it
// back to the default position after a given timeout
_this._maintainCameraAboveGround();
});
};
FramingBehavior.prototype.detach = function () {
if (!this._attachedCamera) {
return;
}
var scene = this._attachedCamera.getScene();
if (this._onPrePointerObservableObserver) {
scene.onPrePointerObservable.remove(this._onPrePointerObservableObserver);
}
if (this._onAfterCheckInputsObserver) {
this._attachedCamera.onAfterCheckInputsObservable.remove(this._onAfterCheckInputsObserver);
}
if (this._onMeshTargetChangedObserver) {
this._attachedCamera.onMeshTargetChangedObservable.remove(this._onMeshTargetChangedObserver);
}
this._attachedCamera = null;
};
/**
* Targets the given mesh and updates zoom level accordingly.
* @param mesh The mesh to target.
* @param radius Optional. If a cached radius position already exists, overrides default.
* @param framingPositionY Position on mesh to center camera focus where 0 corresponds bottom of its bounding box and 1, the top
* @param focusOnOriginXZ Determines if the camera should focus on 0 in the X and Z axis instead of the mesh
* @param onAnimationEnd Callback triggered at the end of the framing animation
*/
FramingBehavior.prototype.zoomOnMesh = function (mesh, focusOnOriginXZ, onAnimationEnd) {
if (focusOnOriginXZ === void 0) { focusOnOriginXZ = false; }
if (onAnimationEnd === void 0) { onAnimationEnd = null; }
mesh.computeWorldMatrix(true);
var boundingBox = mesh.getBoundingInfo().boundingBox;
this.zoomOnBoundingInfo(boundingBox.minimumWorld, boundingBox.maximumWorld, focusOnOriginXZ, onAnimationEnd);
};
/**
* Targets the given mesh with its children and updates zoom level accordingly.
* @param mesh The mesh to target.
* @param radius Optional. If a cached radius position already exists, overrides default.
* @param framingPositionY Position on mesh to center camera focus where 0 corresponds bottom of its bounding box and 1, the top
* @param focusOnOriginXZ Determines if the camera should focus on 0 in the X and Z axis instead of the mesh
* @param onAnimationEnd Callback triggered at the end of the framing animation
*/
FramingBehavior.prototype.zoomOnMeshHierarchy = function (mesh, focusOnOriginXZ, onAnimationEnd) {
if (focusOnOriginXZ === void 0) { focusOnOriginXZ = false; }
if (onAnimationEnd === void 0) { onAnimationEnd = null; }
mesh.computeWorldMatrix(true);
var boundingBox = mesh.getHierarchyBoundingVectors(true);
this.zoomOnBoundingInfo(boundingBox.min, boundingBox.max, focusOnOriginXZ, onAnimationEnd);
};
/**
* Targets the given meshes with their children and updates zoom level accordingly.
* @param meshes The mesh to target.
* @param radius Optional. If a cached radius position already exists, overrides default.
* @param framingPositionY Position on mesh to center camera focus where 0 corresponds bottom of its bounding box and 1, the top
* @param focusOnOriginXZ Determines if the camera should focus on 0 in the X and Z axis instead of the mesh
* @param onAnimationEnd Callback triggered at the end of the framing animation
*/
FramingBehavior.prototype.zoomOnMeshesHierarchy = function (meshes, focusOnOriginXZ, onAnimationEnd) {
if (focusOnOriginXZ === void 0) { focusOnOriginXZ = false; }
if (onAnimationEnd === void 0) { onAnimationEnd = null; }
var min = new BABYLON.Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
var max = new BABYLON.Vector3(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE);
for (var i = 0; i < meshes.length; i++) {
var boundingInfo = meshes[i].getHierarchyBoundingVectors(true);
BABYLON.Tools.CheckExtends(boundingInfo.min, min, max);
BABYLON.Tools.CheckExtends(boundingInfo.max, min, max);
}
this.zoomOnBoundingInfo(min, max, focusOnOriginXZ, onAnimationEnd);
};
/**
* Targets the given mesh and updates zoom level accordingly.
* @param mesh The mesh to target.
* @param radius Optional. If a cached radius position already exists, overrides default.
* @param framingPositionY Position on mesh to center camera focus where 0 corresponds bottom of its bounding box and 1, the top
* @param focusOnOriginXZ Determines if the camera should focus on 0 in the X and Z axis instead of the mesh
* @param onAnimationEnd Callback triggered at the end of the framing animation
*/
FramingBehavior.prototype.zoomOnBoundingInfo = function (minimumWorld, maximumWorld, focusOnOriginXZ, onAnimationEnd) {
var _this = this;
if (focusOnOriginXZ === void 0) { focusOnOriginXZ = false; }
if (onAnimationEnd === void 0) { onAnimationEnd = null; }
var zoomTarget;
if (!this._attachedCamera) {
return;
}
// Find target by interpolating from bottom of bounding box in world-space to top via framingPositionY
var bottom = minimumWorld.y;
var top = maximumWorld.y;
var zoomTargetY = bottom + (top - bottom) * this._positionScale;
var radiusWorld = maximumWorld.subtract(minimumWorld).scale(0.5);
if (focusOnOriginXZ) {
zoomTarget = new BABYLON.Vector3(0, zoomTargetY, 0);
}
else {
var centerWorld = minimumWorld.add(radiusWorld);
zoomTarget = new BABYLON.Vector3(centerWorld.x, zoomTargetY, centerWorld.z);
}
if (!this._vectorTransition) {
this._vectorTransition = BABYLON.Animation.CreateAnimation("target", BABYLON.Animation.ANIMATIONTYPE_VECTOR3, 60, FramingBehavior.EasingFunction);
}
this._betaIsAnimating = true;
var animatable = BABYLON.Animation.TransitionTo("target", zoomTarget, this._attachedCamera, this._attachedCamera.getScene(), 60, this._vectorTransition, this._framingTime);
if (animatable) {
this._animatables.push(animatable);
}
// sets the radius and lower radius bounds
// Small delta ensures camera is not always at lower zoom limit.
var radius = 0;
if (this._mode === FramingBehavior.FitFrustumSidesMode) {
var position = this._calculateLowerRadiusFromModelBoundingSphere(minimumWorld, maximumWorld);
this._attachedCamera.lowerRadiusLimit = radiusWorld.length() + this._attachedCamera.minZ;
radius = position;
}
else if (this._mode === FramingBehavior.IgnoreBoundsSizeMode) {
radius = this._calculateLowerRadiusFromModelBoundingSphere(minimumWorld, maximumWorld);
if (this._attachedCamera.lowerRadiusLimit === null) {
this._attachedCamera.lowerRadiusLimit = this._attachedCamera.minZ;
}
}
// Set sensibilities
var extend = maximumWorld.subtract(minimumWorld).length();
this._attachedCamera.panningSensibility = 5000 / extend;
this._attachedCamera.wheelPrecision = 100 / radius;
// transition to new radius
if (!this._radiusTransition) {
this._radiusTransition = BABYLON.Animation.CreateAnimation("radius", BABYLON.Animation.ANIMATIONTYPE_FLOAT, 60, FramingBehavior.EasingFunction);
}
animatable = BABYLON.Animation.TransitionTo("radius", radius, this._attachedCamera, this._attachedCamera.getScene(), 60, this._radiusTransition, this._framingTime, function () {
_this.stopAllAnimations();
if (onAnimationEnd) {
onAnimationEnd();
}
if (_this._attachedCamera) {
_this._attachedCamera.storeState();
}
});
if (animatable) {
this._animatables.push(animatable);
}
};
/**
* Calculates the lowest radius for the camera based on the bounding box of the mesh.
* @param mesh The mesh on which to base the calculation. mesh boundingInfo used to estimate necessary
* frustum width.
* @return The minimum distance from the primary mesh's center point at which the camera must be kept in order
* to fully enclose the mesh in the viewing frustum.
*/
FramingBehavior.prototype._calculateLowerRadiusFromModelBoundingSphere = function (minimumWorld, maximumWorld) {
var size = maximumWorld.subtract(minimumWorld);
var boxVectorGlobalDiagonal = size.length();
var frustumSlope = this._getFrustumSlope();
// Formula for setting distance
// (Good explanation: http://stackoverflow.com/questions/2866350/move-camera-to-fit-3d-scene)
var radiusWithoutFraming = boxVectorGlobalDiagonal * 0.5;
// Horizon distance
var radius = radiusWithoutFraming * this._radiusScale;
var distanceForHorizontalFrustum = radius * Math.sqrt(1.0 + 1.0 / (frustumSlope.x * frustumSlope.x));
var distanceForVerticalFrustum = radius * Math.sqrt(1.0 + 1.0 / (frustumSlope.y * frustumSlope.y));
var distance = Math.max(distanceForHorizontalFrustum, distanceForVerticalFrustum);
var camera = this._attachedCamera;
if (!camera) {
return 0;
}
if (camera.lowerRadiusLimit && this._mode === FramingBehavior.IgnoreBoundsSizeMode) {
// Don't exceed the requested limit
distance = distance < camera.lowerRadiusLimit ? camera.lowerRadiusLimit : distance;
}
// Don't exceed the upper radius limit
if (camera.upperRadiusLimit) {
distance = distance > camera.upperRadiusLimit ? camera.upperRadiusLimit : distance;
}
return distance;
};
/**
* Keeps the camera above the ground plane. If the user pulls the camera below the ground plane, the camera
* is automatically returned to its default position (expected to be above ground plane).
*/
FramingBehavior.prototype._maintainCameraAboveGround = function () {
var _this = this;
if (this._elevationReturnTime < 0) {
return;
}
var timeSinceInteraction = BABYLON.Tools.Now - this._lastInteractionTime;
var defaultBeta = Math.PI * 0.5 - this._defaultElevation;
var limitBeta = Math.PI * 0.5;
// Bring the camera back up if below the ground plane
if (this._attachedCamera && !this._betaIsAnimating && this._attachedCamera.beta > limitBeta && timeSinceInteraction >= this._elevationReturnWaitTime) {
this._betaIsAnimating = true;
//Transition to new position
this.stopAllAnimations();
if (!this._betaTransition) {
this._betaTransition = BABYLON.Animation.CreateAnimation("beta", BABYLON.Animation.ANIMATIONTYPE_FLOAT, 60, FramingBehavior.EasingFunction);
}
var animatabe = BABYLON.Animation.TransitionTo("beta", defaultBeta, this._attachedCamera, this._attachedCamera.getScene(), 60, this._betaTransition, this._elevationReturnTime, function () {
_this._clearAnimationLocks();
_this.stopAllAnimations();
});
if (animatabe) {
this._animatables.push(animatabe);
}
}
};
/**
* Returns the frustum slope based on the canvas ratio and camera FOV
* @returns The frustum slope represented as a Vector2 with X and Y slopes
*/
FramingBehavior.prototype._getFrustumSlope = function () {
// Calculate the viewport ratio
// Aspect Ratio is Height/Width.
var camera = this._attachedCamera;
if (!camera) {
return BABYLON.Vector2.Zero();
}
var engine = camera.getScene().getEngine();
var aspectRatio = engine.getAspectRatio(camera);
// Camera FOV is the vertical field of view (top-bottom) in radians.
// Slope of the frustum top/bottom planes in view space, relative to the forward vector.
var frustumSlopeY = Math.tan(camera.fov / 2);
// Slope of the frustum left/right planes in view space, relative to the forward vector.
// Provides the amount that one side (e.g. left) of the frustum gets wider for every unit
// along the forward vector.
var frustumSlopeX = frustumSlopeY * aspectRatio;
return new BABYLON.Vector2(frustumSlopeX, frustumSlopeY);
};
/**
* Removes all animation locks. Allows new animations to be added to any of the arcCamera properties.
*/
FramingBehavior.prototype._clearAnimationLocks = function () {
this._betaIsAnimating = false;
};
/**
* Applies any current user interaction to the camera. Takes into account maximum alpha rotation.
*/
FramingBehavior.prototype._applyUserInteraction = function () {
if (this.isUserIsMoving) {
this._lastInteractionTime = BABYLON.Tools.Now;
this.stopAllAnimations();
this._clearAnimationLocks();
}
};
/**
* Stops and removes all animations that have been applied to the camera
*/
FramingBehavior.prototype.stopAllAnimations = function () {
if (this._attachedCamera) {
this._attachedCamera.animations = [];
}
while (this._animatables.length) {
if (this._animatables[0]) {
this._animatables[0].onAnimationEnd = null;
this._animatables[0].stop();
}
this._animatables.shift();
}
};
Object.defineProperty(FramingBehavior.prototype, "isUserIsMoving", {
/**
* Gets a value indicating if the user is moving the camera
*/
get: function () {
if (!this._attachedCamera) {
return false;
}
return this._attachedCamera.inertialAlphaOffset !== 0 ||
this._attachedCamera.inertialBetaOffset !== 0 ||
this._attachedCamera.inertialRadiusOffset !== 0 ||
this._attachedCamera.inertialPanningX !== 0 ||
this._attachedCamera.inertialPanningY !== 0 ||
this._isPointerDown;
},
enumerable: true,
configurable: true
});
/**
* The easing function used by animations
*/
FramingBehavior.EasingFunction = new BABYLON.ExponentialEase();
/**
* The easing mode used by animations
*/
FramingBehavior.EasingMode = BABYLON.EasingFunction.EASINGMODE_EASEINOUT;
// Statics
/**
* The camera can move all the way towards the mesh.
*/
FramingBehavior.IgnoreBoundsSizeMode = 0;
/**
* The camera is not allowed to zoom closer to the mesh than the point at which the adjusted bounding sphere touches the frustum sides
*/
FramingBehavior.FitFrustumSidesMode = 1;
return FramingBehavior;
}());
BABYLON.FramingBehavior = FramingBehavior;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.framingBehavior.js.map
var BABYLON;
(function (BABYLON) {
/**
* Add a bouncing effect to an ArcRotateCamera when reaching a specified minimum and maximum radius
*/
var BouncingBehavior = /** @class */ (function () {
function BouncingBehavior() {
/**
* The duration of the animation, in milliseconds
*/
this.transitionDuration = 450;
/**
* Length of the distance animated by the transition when lower radius is reached
*/
this.lowerRadiusTransitionRange = 2;
/**
* Length of the distance animated by the transition when upper radius is reached
*/
this.upperRadiusTransitionRange = -2;
this._autoTransitionRange = false;
// Animations
this._radiusIsAnimating = false;
this._radiusBounceTransition = null;
this._animatables = new Array();
}
Object.defineProperty(BouncingBehavior.prototype, "name", {
get: function () {
return "Bouncing";
},
enumerable: true,
configurable: true
});
Object.defineProperty(BouncingBehavior.prototype, "autoTransitionRange", {
/**
* Gets a value indicating if the lowerRadiusTransitionRange and upperRadiusTransitionRange are defined automatically
*/
get: function () {
return this._autoTransitionRange;
},
/**
* Sets a value indicating if the lowerRadiusTransitionRange and upperRadiusTransitionRange are defined automatically
* Transition ranges will be set to 5% of the bounding box diagonal in world space
*/
set: function (value) {
var _this = this;
if (this._autoTransitionRange === value) {
return;
}
this._autoTransitionRange = value;
var camera = this._attachedCamera;
if (!camera) {
return;
}
if (value) {
this._onMeshTargetChangedObserver = camera.onMeshTargetChangedObservable.add(function (mesh) {
if (!mesh) {
return;
}
mesh.computeWorldMatrix(true);
var diagonal = mesh.getBoundingInfo().diagonalLength;
_this.lowerRadiusTransitionRange = diagonal * 0.05;
_this.upperRadiusTransitionRange = diagonal * 0.05;
});
}
else if (this._onMeshTargetChangedObserver) {
camera.onMeshTargetChangedObservable.remove(this._onMeshTargetChangedObserver);
}
},
enumerable: true,
configurable: true
});
BouncingBehavior.prototype.init = function () {
// Do notihng
};
BouncingBehavior.prototype.attach = function (camera) {
var _this = this;
this._attachedCamera = camera;
this._onAfterCheckInputsObserver = camera.onAfterCheckInputsObservable.add(function () {
if (!_this._attachedCamera) {
return;
}
// Add the bounce animation to the lower radius limit
if (_this._isRadiusAtLimit(_this._attachedCamera.lowerRadiusLimit)) {
_this._applyBoundRadiusAnimation(_this.lowerRadiusTransitionRange);
}
// Add the bounce animation to the upper radius limit
if (_this._isRadiusAtLimit(_this._attachedCamera.upperRadiusLimit)) {
_this._applyBoundRadiusAnimation(_this.upperRadiusTransitionRange);
}
});
};
BouncingBehavior.prototype.detach = function () {
if (!this._attachedCamera) {
return;
}
if (this._onAfterCheckInputsObserver) {
this._attachedCamera.onAfterCheckInputsObservable.remove(this._onAfterCheckInputsObserver);
}
if (this._onMeshTargetChangedObserver) {
this._attachedCamera.onMeshTargetChangedObservable.remove(this._onMeshTargetChangedObserver);
}
this._attachedCamera = null;
};
/**
* Checks if the camera radius is at the specified limit. Takes into account animation locks.
* @param radiusLimit The limit to check against.
* @return Bool to indicate if at limit.
*/
BouncingBehavior.prototype._isRadiusAtLimit = function (radiusLimit) {
if (!this._attachedCamera) {
return false;
}
if (this._attachedCamera.radius === radiusLimit && !this._radiusIsAnimating) {
return true;
}
return false;
};
/**
* Applies an animation to the radius of the camera, extending by the radiusDelta.
* @param radiusDelta The delta by which to animate to. Can be negative.
*/
BouncingBehavior.prototype._applyBoundRadiusAnimation = function (radiusDelta) {
var _this = this;
if (!this._attachedCamera) {
return;
}
if (!this._radiusBounceTransition) {
BouncingBehavior.EasingFunction.setEasingMode(BouncingBehavior.EasingMode);
this._radiusBounceTransition = BABYLON.Animation.CreateAnimation("radius", BABYLON.Animation.ANIMATIONTYPE_FLOAT, 60, BouncingBehavior.EasingFunction);
}
// Prevent zoom until bounce has completed
this._cachedWheelPrecision = this._attachedCamera.wheelPrecision;
this._attachedCamera.wheelPrecision = Infinity;
this._attachedCamera.inertialRadiusOffset = 0;
// Animate to the radius limit
this.stopAllAnimations();
this._radiusIsAnimating = true;
var animatable = BABYLON.Animation.TransitionTo("radius", this._attachedCamera.radius + radiusDelta, this._attachedCamera, this._attachedCamera.getScene(), 60, this._radiusBounceTransition, this.transitionDuration, function () { return _this._clearAnimationLocks(); });
if (animatable) {
this._animatables.push(animatable);
}
};
/**
* Removes all animation locks. Allows new animations to be added to any of the camera properties.
*/
BouncingBehavior.prototype._clearAnimationLocks = function () {
this._radiusIsAnimating = false;
if (this._attachedCamera) {
this._attachedCamera.wheelPrecision = this._cachedWheelPrecision;
}
};
/**
* Stops and removes all animations that have been applied to the camera
*/
BouncingBehavior.prototype.stopAllAnimations = function () {
if (this._attachedCamera) {
this._attachedCamera.animations = [];
}
while (this._animatables.length) {
this._animatables[0].onAnimationEnd = null;
this._animatables[0].stop();
this._animatables.shift();
}
};
/**
* The easing function used by animations
*/
BouncingBehavior.EasingFunction = new BABYLON.BackEase(0.3);
/**
* The easing mode used by animations
*/
BouncingBehavior.EasingMode = BABYLON.EasingFunction.EASINGMODE_EASEOUT;
return BouncingBehavior;
}());
BABYLON.BouncingBehavior = BouncingBehavior;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.bouncingBehavior.js.map
var BABYLON;
(function (BABYLON) {
var AutoRotationBehavior = /** @class */ (function () {
function AutoRotationBehavior() {
this._zoomStopsAnimation = false;
this._idleRotationSpeed = 0.05;
this._idleRotationWaitTime = 2000;
this._idleRotationSpinupTime = 2000;
this._isPointerDown = false;
this._lastFrameTime = null;
this._lastInteractionTime = -Infinity;
this._cameraRotationSpeed = 0;
this._lastFrameRadius = 0;
}
Object.defineProperty(AutoRotationBehavior.prototype, "name", {
get: function () {
return "AutoRotation";
},
enumerable: true,
configurable: true
});
Object.defineProperty(AutoRotationBehavior.prototype, "zoomStopsAnimation", {
/**
* Gets the flag that indicates if user zooming should stop animation.
*/
get: function () {
return this._zoomStopsAnimation;
},
/**
* Sets the flag that indicates if user zooming should stop animation.
*/
set: function (flag) {
this._zoomStopsAnimation = flag;
},
enumerable: true,
configurable: true
});
Object.defineProperty(AutoRotationBehavior.prototype, "idleRotationSpeed", {
/**
* Gets the default speed at which the camera rotates around the model.
*/
get: function () {
return this._idleRotationSpeed;
},
/**
* Sets the default speed at which the camera rotates around the model.
*/
set: function (speed) {
this._idleRotationSpeed = speed;
},
enumerable: true,
configurable: true
});
Object.defineProperty(AutoRotationBehavior.prototype, "idleRotationWaitTime", {
/**
* Gets the time (milliseconds) to wait after user interaction before the camera starts rotating.
*/
get: function () {
return this._idleRotationWaitTime;
},
/**
* Sets the time (in milliseconds) to wait after user interaction before the camera starts rotating.
*/
set: function (time) {
this._idleRotationWaitTime = time;
},
enumerable: true,
configurable: true
});
Object.defineProperty(AutoRotationBehavior.prototype, "idleRotationSpinupTime", {
/**
* Gets the time (milliseconds) to take to spin up to the full idle rotation speed.
*/
get: function () {
return this._idleRotationSpinupTime;
},
/**
* Sets the time (milliseconds) to take to spin up to the full idle rotation speed.
*/
set: function (time) {
this._idleRotationSpinupTime = time;
},
enumerable: true,
configurable: true
});
Object.defineProperty(AutoRotationBehavior.prototype, "rotationInProgress", {
/**
* Gets a value indicating if the camera is currently rotating because of this behavior
*/
get: function () {
return Math.abs(this._cameraRotationSpeed) > 0;
},
enumerable: true,
configurable: true
});
AutoRotationBehavior.prototype.init = function () {
// Do notihng
};
AutoRotationBehavior.prototype.attach = function (camera) {
var _this = this;
this._attachedCamera = camera;
var scene = this._attachedCamera.getScene();
this._onPrePointerObservableObserver = scene.onPrePointerObservable.add(function (pointerInfoPre) {
if (pointerInfoPre.type === BABYLON.PointerEventTypes.POINTERDOWN) {
_this._isPointerDown = true;
return;
}
if (pointerInfoPre.type === BABYLON.PointerEventTypes.POINTERUP) {
_this._isPointerDown = false;
}
});
this._onAfterCheckInputsObserver = camera.onAfterCheckInputsObservable.add(function () {
var now = BABYLON.Tools.Now;
var dt = 0;
if (_this._lastFrameTime != null) {
dt = now - _this._lastFrameTime;
}
_this._lastFrameTime = now;
// Stop the animation if there is user interaction and the animation should stop for this interaction
_this._applyUserInteraction();
var timeToRotation = now - _this._lastInteractionTime - _this._idleRotationWaitTime;
var scale = Math.max(Math.min(timeToRotation / (_this._idleRotationSpinupTime), 1), 0);
_this._cameraRotationSpeed = _this._idleRotationSpeed * scale;
// Step camera rotation by rotation speed
if (_this._attachedCamera) {
_this._attachedCamera.alpha -= _this._cameraRotationSpeed * (dt / 1000);
}
});
};
AutoRotationBehavior.prototype.detach = function () {
if (!this._attachedCamera) {
return;
}
var scene = this._attachedCamera.getScene();
if (this._onPrePointerObservableObserver) {
scene.onPrePointerObservable.remove(this._onPrePointerObservableObserver);
}
this._attachedCamera.onAfterCheckInputsObservable.remove(this._onAfterCheckInputsObserver);
this._attachedCamera = null;
};
/**
* Returns true if user is scrolling.
* @return true if user is scrolling.
*/
AutoRotationBehavior.prototype._userIsZooming = function () {
if (!this._attachedCamera) {
return false;
}
return this._attachedCamera.inertialRadiusOffset !== 0;
};
AutoRotationBehavior.prototype._shouldAnimationStopForInteraction = function () {
if (!this._attachedCamera) {
return false;
}
var zoomHasHitLimit = false;
if (this._lastFrameRadius === this._attachedCamera.radius && this._attachedCamera.inertialRadiusOffset !== 0) {
zoomHasHitLimit = true;
}
// Update the record of previous radius - works as an approx. indicator of hitting radius limits
this._lastFrameRadius = this._attachedCamera.radius;
return this._zoomStopsAnimation ? zoomHasHitLimit : this._userIsZooming();
};
/**
* Applies any current user interaction to the camera. Takes into account maximum alpha rotation.
*/
AutoRotationBehavior.prototype._applyUserInteraction = function () {
if (this._userIsMoving() && !this._shouldAnimationStopForInteraction()) {
this._lastInteractionTime = BABYLON.Tools.Now;
}
};
// Tools
AutoRotationBehavior.prototype._userIsMoving = function () {
if (!this._attachedCamera) {
return false;
}
return this._attachedCamera.inertialAlphaOffset !== 0 ||
this._attachedCamera.inertialBetaOffset !== 0 ||
this._attachedCamera.inertialRadiusOffset !== 0 ||
this._attachedCamera.inertialPanningX !== 0 ||
this._attachedCamera.inertialPanningY !== 0 ||
this._isPointerDown;
};
return AutoRotationBehavior;
}());
BABYLON.AutoRotationBehavior = AutoRotationBehavior;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.autoRotationBehavior.js.map
var BABYLON;
(function (BABYLON) {
var NullEngineOptions = /** @class */ (function () {
function NullEngineOptions() {
this.renderWidth = 512;
this.renderHeight = 256;
this.textureSize = 512;
this.deterministicLockstep = false;
this.lockstepMaxSteps = 4;
}
return NullEngineOptions;
}());
BABYLON.NullEngineOptions = NullEngineOptions;
/**
* The null engine class provides support for headless version of babylon.js.
* This can be used in server side scenario or for testing purposes
*/
var NullEngine = /** @class */ (function (_super) {
__extends(NullEngine, _super);
function NullEngine(options) {
if (options === void 0) { options = new NullEngineOptions(); }
var _this = _super.call(this, null) || this;
if (options.deterministicLockstep === undefined) {
options.deterministicLockstep = false;
}
if (options.lockstepMaxSteps === undefined) {
options.lockstepMaxSteps = 4;
}
_this._options = options;
// Init caps
// We consider we are on a webgl1 capable device
_this._caps = new BABYLON.EngineCapabilities();
_this._caps.maxTexturesImageUnits = 16;
_this._caps.maxVertexTextureImageUnits = 16;
_this._caps.maxTextureSize = 512;
_this._caps.maxCubemapTextureSize = 512;
_this._caps.maxRenderTextureSize = 512;
_this._caps.maxVertexAttribs = 16;
_this._caps.maxVaryingVectors = 16;
_this._caps.maxFragmentUniformVectors = 16;
_this._caps.maxVertexUniformVectors = 16;
// Extensions
_this._caps.standardDerivatives = false;
_this._caps.astc = null;
_this._caps.s3tc = null;
_this._caps.pvrtc = null;
_this._caps.etc1 = null;
_this._caps.etc2 = null;
_this._caps.textureAnisotropicFilterExtension = null;
_this._caps.maxAnisotropy = 0;
_this._caps.uintIndices = false;
_this._caps.fragmentDepthSupported = false;
_this._caps.highPrecisionShaderSupported = true;
_this._caps.colorBufferFloat = false;
_this._caps.textureFloat = false;
_this._caps.textureFloatLinearFiltering = false;
_this._caps.textureFloatRender = false;
_this._caps.textureHalfFloat = false;
_this._caps.textureHalfFloatLinearFiltering = false;
_this._caps.textureHalfFloatRender = false;
_this._caps.textureLOD = false;
_this._caps.drawBuffersExtension = false;
_this._caps.depthTextureExtension = false;
_this._caps.vertexArrayObject = false;
_this._caps.instancedArrays = false;
BABYLON.Tools.Log("Babylon.js null engine (v" + BABYLON.Engine.Version + ") launched");
// Wrappers
if (typeof URL === "undefined") {
URL = {
createObjectURL: function () { },
revokeObjectURL: function () { }
};
}
if (typeof Blob === "undefined") {
Blob = function () { };
}
return _this;
}
NullEngine.prototype.isDeterministicLockStep = function () {
return this._options.deterministicLockstep;
};
NullEngine.prototype.getLockstepMaxSteps = function () {
return this._options.lockstepMaxSteps;
};
NullEngine.prototype.getHardwareScalingLevel = function () {
return 1.0;
};
NullEngine.prototype.createVertexBuffer = function (vertices) {
return {
capacity: 0,
references: 1,
is32Bits: false
};
};
NullEngine.prototype.createIndexBuffer = function (indices) {
return {
capacity: 0,
references: 1,
is32Bits: false
};
};
NullEngine.prototype.clear = function (color, backBuffer, depth, stencil) {
if (stencil === void 0) { stencil = false; }
};
NullEngine.prototype.getRenderWidth = function (useScreen) {
if (useScreen === void 0) { useScreen = false; }
if (!useScreen && this._currentRenderTarget) {
return this._currentRenderTarget.width;
}
return this._options.renderWidth;
};
NullEngine.prototype.getRenderHeight = function (useScreen) {
if (useScreen === void 0) { useScreen = false; }
if (!useScreen && this._currentRenderTarget) {
return this._currentRenderTarget.height;
}
return this._options.renderHeight;
};
NullEngine.prototype.setViewport = function (viewport, requiredWidth, requiredHeight) {
this._cachedViewport = viewport;
};
NullEngine.prototype.createShaderProgram = function (vertexCode, fragmentCode, defines, context) {
return {
transformFeedback: null,
__SPECTOR_rebuildProgram: null
};
};
NullEngine.prototype.getUniforms = function (shaderProgram, uniformsNames) {
return [];
};
NullEngine.prototype.getAttributes = function (shaderProgram, attributesNames) {
return [];
};
NullEngine.prototype.bindSamplers = function (effect) {
this._currentEffect = null;
};
NullEngine.prototype.enableEffect = function (effect) {
this._currentEffect = effect;
if (effect.onBind) {
effect.onBind(effect);
}
effect.onBindObservable.notifyObservers(effect);
};
NullEngine.prototype.setState = function (culling, zOffset, force, reverseSide) {
if (zOffset === void 0) { zOffset = 0; }
if (reverseSide === void 0) { reverseSide = false; }
};
NullEngine.prototype.setIntArray = function (uniform, array) {
};
NullEngine.prototype.setIntArray2 = function (uniform, array) {
};
NullEngine.prototype.setIntArray3 = function (uniform, array) {
};
NullEngine.prototype.setIntArray4 = function (uniform, array) {
};
NullEngine.prototype.setFloatArray = function (uniform, array) {
};
NullEngine.prototype.setFloatArray2 = function (uniform, array) {
};
NullEngine.prototype.setFloatArray3 = function (uniform, array) {
};
NullEngine.prototype.setFloatArray4 = function (uniform, array) {
};
NullEngine.prototype.setArray = function (uniform, array) {
};
NullEngine.prototype.setArray2 = function (uniform, array) {
};
NullEngine.prototype.setArray3 = function (uniform, array) {
};
NullEngine.prototype.setArray4 = function (uniform, array) {
};
NullEngine.prototype.setMatrices = function (uniform, matrices) {
};
NullEngine.prototype.setMatrix = function (uniform, matrix) {
};
NullEngine.prototype.setMatrix3x3 = function (uniform, matrix) {
};
NullEngine.prototype.setMatrix2x2 = function (uniform, matrix) {
};
NullEngine.prototype.setFloat = function (uniform, value) {
};
NullEngine.prototype.setFloat2 = function (uniform, x, y) {
};
NullEngine.prototype.setFloat3 = function (uniform, x, y, z) {
};
NullEngine.prototype.setBool = function (uniform, bool) {
};
NullEngine.prototype.setFloat4 = function (uniform, x, y, z, w) {
};
NullEngine.prototype.setColor3 = function (uniform, color3) {
};
NullEngine.prototype.setColor4 = function (uniform, color3, alpha) {
};
NullEngine.prototype.setAlphaMode = function (mode, noDepthWriteChange) {
if (noDepthWriteChange === void 0) { noDepthWriteChange = false; }
if (this._alphaMode === mode) {
return;
}
this._alphaState.alphaBlend = (mode !== BABYLON.Engine.ALPHA_DISABLE);
if (!noDepthWriteChange) {
this.setDepthWrite(mode === BABYLON.Engine.ALPHA_DISABLE);
}
this._alphaMode = mode;
};
NullEngine.prototype.bindBuffers = function (vertexBuffers, indexBuffer, effect) {
};
NullEngine.prototype.wipeCaches = function (bruteForce) {
if (this.preventCacheWipeBetweenFrames) {
return;
}
this.resetTextureCache();
this._currentEffect = null;
if (bruteForce) {
this._currentProgram = null;
this._stencilState.reset();
this._depthCullingState.reset();
this._alphaState.reset();
}
this._cachedVertexBuffers = null;
this._cachedIndexBuffer = null;
this._cachedEffectForVertexBuffers = null;
};
NullEngine.prototype.draw = function (useTriangles, indexStart, indexCount, instancesCount) {
};
NullEngine.prototype.drawElementsType = function (fillMode, indexStart, indexCount, instancesCount) {
};
NullEngine.prototype.drawArraysType = function (fillMode, verticesStart, verticesCount, instancesCount) {
};
NullEngine.prototype._createTexture = function () {
return {};
};
NullEngine.prototype._releaseTexture = function (texture) {
};
NullEngine.prototype.createTexture = function (urlArg, noMipmap, invertY, scene, samplingMode, onLoad, onError, buffer, fallBack, format) {
if (samplingMode === void 0) { samplingMode = BABYLON.Texture.TRILINEAR_SAMPLINGMODE; }
if (onLoad === void 0) { onLoad = null; }
if (onError === void 0) { onError = null; }
if (buffer === void 0) { buffer = null; }
var texture = new BABYLON.InternalTexture(this, BABYLON.InternalTexture.DATASOURCE_URL);
var url = String(urlArg);
texture.url = url;
texture.generateMipMaps = !noMipmap;
texture.samplingMode = samplingMode;
texture.invertY = invertY;
texture.baseWidth = this._options.textureSize;
texture.baseHeight = this._options.textureSize;
texture.width = this._options.textureSize;
texture.height = this._options.textureSize;
if (format) {
texture.format = format;
}
texture.isReady = true;
if (onLoad) {
onLoad();
}
this._internalTexturesCache.push(texture);
return texture;
};
NullEngine.prototype.createRenderTargetTexture = function (size, options) {
var fullOptions = new BABYLON.RenderTargetCreationOptions();
if (options !== undefined && typeof options === "object") {
fullOptions.generateMipMaps = options.generateMipMaps;
fullOptions.generateDepthBuffer = options.generateDepthBuffer === undefined ? true : options.generateDepthBuffer;
fullOptions.generateStencilBuffer = fullOptions.generateDepthBuffer && options.generateStencilBuffer;
fullOptions.type = options.type === undefined ? BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT : options.type;
fullOptions.samplingMode = options.samplingMode === undefined ? BABYLON.Texture.TRILINEAR_SAMPLINGMODE : options.samplingMode;
}
else {
fullOptions.generateMipMaps = options;
fullOptions.generateDepthBuffer = true;
fullOptions.generateStencilBuffer = false;
fullOptions.type = BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT;
fullOptions.samplingMode = BABYLON.Texture.TRILINEAR_SAMPLINGMODE;
}
var texture = new BABYLON.InternalTexture(this, BABYLON.InternalTexture.DATASOURCE_RENDERTARGET);
var width = size.width || size;
var height = size.height || size;
texture._depthStencilBuffer = {};
texture._framebuffer = {};
texture.baseWidth = width;
texture.baseHeight = height;
texture.width = width;
texture.height = height;
texture.isReady = true;
texture.samples = 1;
texture.generateMipMaps = fullOptions.generateMipMaps ? true : false;
texture.samplingMode = fullOptions.samplingMode;
texture.type = fullOptions.type;
texture._generateDepthBuffer = fullOptions.generateDepthBuffer;
texture._generateStencilBuffer = fullOptions.generateStencilBuffer ? true : false;
this._internalTexturesCache.push(texture);
return texture;
};
NullEngine.prototype.updateTextureSamplingMode = function (samplingMode, texture) {
texture.samplingMode = samplingMode;
};
NullEngine.prototype.bindFramebuffer = function (texture, faceIndex, requiredWidth, requiredHeight, forceFullscreenViewport) {
if (this._currentRenderTarget) {
this.unBindFramebuffer(this._currentRenderTarget);
}
this._currentRenderTarget = texture;
this._currentFramebuffer = texture._MSAAFramebuffer ? texture._MSAAFramebuffer : texture._framebuffer;
if (this._cachedViewport && !forceFullscreenViewport) {
this.setViewport(this._cachedViewport, requiredWidth, requiredHeight);
}
};
NullEngine.prototype.unBindFramebuffer = function (texture, disableGenerateMipMaps, onBeforeUnbind) {
if (disableGenerateMipMaps === void 0) { disableGenerateMipMaps = false; }
this._currentRenderTarget = null;
if (onBeforeUnbind) {
if (texture._MSAAFramebuffer) {
this._currentFramebuffer = texture._framebuffer;
}
onBeforeUnbind();
}
this._currentFramebuffer = null;
};
NullEngine.prototype.createDynamicVertexBuffer = function (vertices) {
var vbo = {
capacity: 1,
references: 1,
is32Bits: false
};
return vbo;
};
NullEngine.prototype.updateDynamicTexture = function (texture, canvas, invertY, premulAlpha, format) {
if (premulAlpha === void 0) { premulAlpha = false; }
};
/**
* Get the current error code of the webGL context
* @returns the error code
* @see https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/getError
*/
NullEngine.prototype.getError = function () {
return 0;
};
/** @hidden */
NullEngine.prototype._getUnpackAlignement = function () {
return 1;
};
/** @hidden */
NullEngine.prototype._unpackFlipY = function (value) {
};
NullEngine.prototype.updateDynamicIndexBuffer = function (indexBuffer, indices, offset) {
if (offset === void 0) { offset = 0; }
};
/**
* Updates a dynamic vertex buffer.
* @param vertexBuffer the vertex buffer to update
* @param data the data used to update the vertex buffer
* @param byteOffset the byte offset of the data (optional)
* @param byteLength the byte length of the data (optional)
*/
NullEngine.prototype.updateDynamicVertexBuffer = function (vertexBuffer, vertices, byteOffset, byteLength) {
};
NullEngine.prototype._bindTextureDirectly = function (target, texture) {
if (this._boundTexturesCache[this._activeChannel] !== texture) {
this._boundTexturesCache[this._activeChannel] = texture;
return true;
}
return false;
};
NullEngine.prototype._bindTexture = function (channel, texture) {
if (channel < 0) {
return;
}
this._bindTextureDirectly(0, texture);
};
NullEngine.prototype._releaseBuffer = function (buffer) {
buffer.references--;
if (buffer.references === 0) {
return true;
}
return false;
};
NullEngine.prototype.releaseEffects = function () {
};
NullEngine.prototype.displayLoadingUI = function () {
};
NullEngine.prototype.hideLoadingUI = function () {
};
/** @hidden */
NullEngine.prototype._uploadCompressedDataToTextureDirectly = function (texture, internalFormat, width, height, data, faceIndex, lod) {
if (faceIndex === void 0) { faceIndex = 0; }
if (lod === void 0) { lod = 0; }
};
/** @hidden */
NullEngine.prototype._uploadDataToTextureDirectly = function (texture, imageData, faceIndex, lod) {
if (faceIndex === void 0) { faceIndex = 0; }
if (lod === void 0) { lod = 0; }
};
/** @hidden */
NullEngine.prototype._uploadArrayBufferViewToTexture = function (texture, imageData, faceIndex, lod) {
if (faceIndex === void 0) { faceIndex = 0; }
if (lod === void 0) { lod = 0; }
};
/** @hidden */
NullEngine.prototype._uploadImageToTexture = function (texture, image, faceIndex, lod) {
if (faceIndex === void 0) { faceIndex = 0; }
if (lod === void 0) { lod = 0; }
};
return NullEngine;
}(BABYLON.Engine));
BABYLON.NullEngine = NullEngine;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.nullEngine.js.map
var BABYLON;
(function (BABYLON) {
/**
* This class can be used to get instrumentation data from a Babylon engine
*/
var EngineInstrumentation = /** @class */ (function () {
function EngineInstrumentation(engine) {
this.engine = engine;
this._captureGPUFrameTime = false;
this._gpuFrameTime = new BABYLON.PerfCounter();
this._captureShaderCompilationTime = false;
this._shaderCompilationTime = new BABYLON.PerfCounter();
// Observers
this._onBeginFrameObserver = null;
this._onEndFrameObserver = null;
this._onBeforeShaderCompilationObserver = null;
this._onAfterShaderCompilationObserver = null;
}
Object.defineProperty(EngineInstrumentation.prototype, "gpuFrameTimeCounter", {
// Properties
/**
* Gets the perf counter used for GPU frame time
*/
get: function () {
return this._gpuFrameTime;
},
enumerable: true,
configurable: true
});
Object.defineProperty(EngineInstrumentation.prototype, "captureGPUFrameTime", {
/**
* Gets the GPU frame time capture status
*/
get: function () {
return this._captureGPUFrameTime;
},
/**
* Enable or disable the GPU frame time capture
*/
set: function (value) {
var _this = this;
if (value === this._captureGPUFrameTime) {
return;
}
this._captureGPUFrameTime = value;
if (value) {
this._onBeginFrameObserver = this.engine.onBeginFrameObservable.add(function () {
if (!_this._gpuFrameTimeToken) {
_this._gpuFrameTimeToken = _this.engine.startTimeQuery();
}
});
this._onEndFrameObserver = this.engine.onEndFrameObservable.add(function () {
if (!_this._gpuFrameTimeToken) {
return;
}
var time = _this.engine.endTimeQuery(_this._gpuFrameTimeToken);
if (time > -1) {
_this._gpuFrameTimeToken = null;
_this._gpuFrameTime.fetchNewFrame();
_this._gpuFrameTime.addCount(time, true);
}
});
}
else {
this.engine.onBeginFrameObservable.remove(this._onBeginFrameObserver);
this._onBeginFrameObserver = null;
this.engine.onEndFrameObservable.remove(this._onEndFrameObserver);
this._onEndFrameObserver = null;
}
},
enumerable: true,
configurable: true
});
Object.defineProperty(EngineInstrumentation.prototype, "shaderCompilationTimeCounter", {
/**
* Gets the perf counter used for shader compilation time
*/
get: function () {
return this._shaderCompilationTime;
},
enumerable: true,
configurable: true
});
Object.defineProperty(EngineInstrumentation.prototype, "captureShaderCompilationTime", {
/**
* Gets the shader compilation time capture status
*/
get: function () {
return this._captureShaderCompilationTime;
},
/**
* Enable or disable the shader compilation time capture
*/
set: function (value) {
var _this = this;
if (value === this._captureShaderCompilationTime) {
return;
}
this._captureShaderCompilationTime = value;
if (value) {
this._onBeforeShaderCompilationObserver = this.engine.onBeforeShaderCompilationObservable.add(function () {
_this._shaderCompilationTime.fetchNewFrame();
_this._shaderCompilationTime.beginMonitoring();
});
this._onAfterShaderCompilationObserver = this.engine.onAfterShaderCompilationObservable.add(function () {
_this._shaderCompilationTime.endMonitoring();
});
}
else {
this.engine.onBeforeShaderCompilationObservable.remove(this._onBeforeShaderCompilationObserver);
this._onBeforeShaderCompilationObserver = null;
this.engine.onAfterShaderCompilationObservable.remove(this._onAfterShaderCompilationObserver);
this._onAfterShaderCompilationObserver = null;
}
},
enumerable: true,
configurable: true
});
EngineInstrumentation.prototype.dispose = function () {
this.engine.onBeginFrameObservable.remove(this._onBeginFrameObserver);
this._onBeginFrameObserver = null;
this.engine.onEndFrameObservable.remove(this._onEndFrameObserver);
this._onEndFrameObserver = null;
this.engine.onBeforeShaderCompilationObservable.remove(this._onBeforeShaderCompilationObserver);
this._onBeforeShaderCompilationObserver = null;
this.engine.onAfterShaderCompilationObservable.remove(this._onAfterShaderCompilationObserver);
this._onAfterShaderCompilationObserver = null;
this.engine = null;
};
return EngineInstrumentation;
}());
BABYLON.EngineInstrumentation = EngineInstrumentation;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.engineInstrumentation.js.map
var BABYLON;
(function (BABYLON) {
/**
* This class can be used to get instrumentation data from a Babylon engine
*/
var SceneInstrumentation = /** @class */ (function () {
function SceneInstrumentation(scene) {
var _this = this;
this.scene = scene;
this._captureActiveMeshesEvaluationTime = false;
this._activeMeshesEvaluationTime = new BABYLON.PerfCounter();
this._captureRenderTargetsRenderTime = false;
this._renderTargetsRenderTime = new BABYLON.PerfCounter();
this._captureFrameTime = false;
this._frameTime = new BABYLON.PerfCounter();
this._captureRenderTime = false;
this._renderTime = new BABYLON.PerfCounter();
this._captureInterFrameTime = false;
this._interFrameTime = new BABYLON.PerfCounter();
this._captureParticlesRenderTime = false;
this._particlesRenderTime = new BABYLON.PerfCounter();
this._captureSpritesRenderTime = false;
this._spritesRenderTime = new BABYLON.PerfCounter();
this._capturePhysicsTime = false;
this._physicsTime = new BABYLON.PerfCounter();
this._captureAnimationsTime = false;
this._animationsTime = new BABYLON.PerfCounter();
this._captureCameraRenderTime = false;
this._cameraRenderTime = new BABYLON.PerfCounter();
// Observers
this._onBeforeActiveMeshesEvaluationObserver = null;
this._onAfterActiveMeshesEvaluationObserver = null;
this._onBeforeRenderTargetsRenderObserver = null;
this._onAfterRenderTargetsRenderObserver = null;
this._onAfterRenderObserver = null;
this._onBeforeDrawPhaseObserver = null;
this._onAfterDrawPhaseObserver = null;
this._onBeforeAnimationsObserver = null;
this._onBeforeParticlesRenderingObserver = null;
this._onAfterParticlesRenderingObserver = null;
this._onBeforeSpritesRenderingObserver = null;
this._onAfterSpritesRenderingObserver = null;
this._onBeforePhysicsObserver = null;
this._onAfterPhysicsObserver = null;
this._onAfterAnimationsObserver = null;
this._onBeforeCameraRenderObserver = null;
this._onAfterCameraRenderObserver = null;
// Before render
this._onBeforeAnimationsObserver = scene.onBeforeAnimationsObservable.add(function () {
if (_this._captureActiveMeshesEvaluationTime) {
_this._activeMeshesEvaluationTime.fetchNewFrame();
}
if (_this._captureRenderTargetsRenderTime) {
_this._renderTargetsRenderTime.fetchNewFrame();
}
if (_this._captureFrameTime) {
BABYLON.Tools.StartPerformanceCounter("Scene rendering");
_this._frameTime.beginMonitoring();
}
if (_this._captureInterFrameTime) {
_this._interFrameTime.endMonitoring();
}
if (_this._captureParticlesRenderTime) {
_this._particlesRenderTime.fetchNewFrame();
}
if (_this._captureSpritesRenderTime) {
_this._spritesRenderTime.fetchNewFrame();
}
if (_this._captureAnimationsTime) {
_this._animationsTime.beginMonitoring();
}
_this.scene.getEngine()._drawCalls.fetchNewFrame();
_this.scene.getEngine()._textureCollisions.fetchNewFrame();
});
// After render
this._onAfterRenderObserver = scene.onAfterRenderObservable.add(function () {
if (_this._captureFrameTime) {
BABYLON.Tools.EndPerformanceCounter("Scene rendering");
_this._frameTime.endMonitoring();
}
if (_this._captureRenderTime) {
_this._renderTime.endMonitoring(false);
}
if (_this._captureInterFrameTime) {
_this._interFrameTime.beginMonitoring();
}
});
}
Object.defineProperty(SceneInstrumentation.prototype, "activeMeshesEvaluationTimeCounter", {
// Properties
/**
* Gets the perf counter used for active meshes evaluation time
*/
get: function () {
return this._activeMeshesEvaluationTime;
},
enumerable: true,
configurable: true
});
Object.defineProperty(SceneInstrumentation.prototype, "captureActiveMeshesEvaluationTime", {
/**
* Gets the active meshes evaluation time capture status
*/
get: function () {
return this._captureActiveMeshesEvaluationTime;
},
/**
* Enable or disable the active meshes evaluation time capture
*/
set: function (value) {
var _this = this;
if (value === this._captureActiveMeshesEvaluationTime) {
return;
}
this._captureActiveMeshesEvaluationTime = value;
if (value) {
this._onBeforeActiveMeshesEvaluationObserver = this.scene.onBeforeActiveMeshesEvaluationObservable.add(function () {
BABYLON.Tools.StartPerformanceCounter("Active meshes evaluation");
_this._activeMeshesEvaluationTime.beginMonitoring();
});
this._onAfterActiveMeshesEvaluationObserver = this.scene.onAfterActiveMeshesEvaluationObservable.add(function () {
BABYLON.Tools.EndPerformanceCounter("Active meshes evaluation");
_this._activeMeshesEvaluationTime.endMonitoring();
});
}
else {
this.scene.onBeforeActiveMeshesEvaluationObservable.remove(this._onBeforeActiveMeshesEvaluationObserver);
this._onBeforeActiveMeshesEvaluationObserver = null;
this.scene.onAfterActiveMeshesEvaluationObservable.remove(this._onAfterActiveMeshesEvaluationObserver);
this._onAfterActiveMeshesEvaluationObserver = null;
}
},
enumerable: true,
configurable: true
});
Object.defineProperty(SceneInstrumentation.prototype, "renderTargetsRenderTimeCounter", {
/**
* Gets the perf counter used for render targets render time
*/
get: function () {
return this._renderTargetsRenderTime;
},
enumerable: true,
configurable: true
});
Object.defineProperty(SceneInstrumentation.prototype, "captureRenderTargetsRenderTime", {
/**
* Gets the render targets render time capture status
*/
get: function () {
return this._captureRenderTargetsRenderTime;
},
/**
* Enable or disable the render targets render time capture
*/
set: function (value) {
var _this = this;
if (value === this._captureRenderTargetsRenderTime) {
return;
}
this._captureRenderTargetsRenderTime = value;
if (value) {
this._onBeforeRenderTargetsRenderObserver = this.scene.onBeforeRenderTargetsRenderObservable.add(function () {
BABYLON.Tools.StartPerformanceCounter("Render targets rendering");
_this._renderTargetsRenderTime.beginMonitoring();
});
this._onAfterRenderTargetsRenderObserver = this.scene.onAfterRenderTargetsRenderObservable.add(function () {
BABYLON.Tools.EndPerformanceCounter("Render targets rendering");
_this._renderTargetsRenderTime.endMonitoring(false);
});
}
else {
this.scene.onBeforeRenderTargetsRenderObservable.remove(this._onBeforeRenderTargetsRenderObserver);
this._onBeforeRenderTargetsRenderObserver = null;
this.scene.onAfterRenderTargetsRenderObservable.remove(this._onAfterRenderTargetsRenderObserver);
this._onAfterRenderTargetsRenderObserver = null;
}
},
enumerable: true,
configurable: true
});
Object.defineProperty(SceneInstrumentation.prototype, "particlesRenderTimeCounter", {
/**
* Gets the perf counter used for particles render time
*/
get: function () {
return this._particlesRenderTime;
},
enumerable: true,
configurable: true
});
Object.defineProperty(SceneInstrumentation.prototype, "captureParticlesRenderTime", {
/**
* Gets the particles render time capture status
*/
get: function () {
return this._captureParticlesRenderTime;
},
/**
* Enable or disable the particles render time capture
*/
set: function (value) {
var _this = this;
if (value === this._captureParticlesRenderTime) {
return;
}
this._captureParticlesRenderTime = value;
if (value) {
this._onBeforeParticlesRenderingObserver = this.scene.onBeforeParticlesRenderingObservable.add(function () {
BABYLON.Tools.StartPerformanceCounter("Particles");
_this._particlesRenderTime.beginMonitoring();
});
this._onAfterParticlesRenderingObserver = this.scene.onAfterParticlesRenderingObservable.add(function () {
BABYLON.Tools.EndPerformanceCounter("Particles");
_this._particlesRenderTime.endMonitoring(false);
});
}
else {
this.scene.onBeforeParticlesRenderingObservable.remove(this._onBeforeParticlesRenderingObserver);
this._onBeforeParticlesRenderingObserver = null;
this.scene.onAfterParticlesRenderingObservable.remove(this._onAfterParticlesRenderingObserver);
this._onAfterParticlesRenderingObserver = null;
}
},
enumerable: true,
configurable: true
});
Object.defineProperty(SceneInstrumentation.prototype, "spritesRenderTimeCounter", {
/**
* Gets the perf counter used for sprites render time
*/
get: function () {
return this._spritesRenderTime;
},
enumerable: true,
configurable: true
});
Object.defineProperty(SceneInstrumentation.prototype, "captureSpritesRenderTime", {
/**
* Gets the sprites render time capture status
*/
get: function () {
return this._captureSpritesRenderTime;
},
/**
* Enable or disable the sprites render time capture
*/
set: function (value) {
var _this = this;
if (value === this._captureSpritesRenderTime) {
return;
}
this._captureSpritesRenderTime = value;
if (value) {
this._onBeforeSpritesRenderingObserver = this.scene.onBeforeSpritesRenderingObservable.add(function () {
BABYLON.Tools.StartPerformanceCounter("Sprites");
_this._spritesRenderTime.beginMonitoring();
});
this._onAfterSpritesRenderingObserver = this.scene.onAfterSpritesRenderingObservable.add(function () {
BABYLON.Tools.EndPerformanceCounter("Sprites");
_this._spritesRenderTime.endMonitoring(false);
});
}
else {
this.scene.onBeforeSpritesRenderingObservable.remove(this._onBeforeSpritesRenderingObserver);
this._onBeforeSpritesRenderingObserver = null;
this.scene.onAfterSpritesRenderingObservable.remove(this._onAfterSpritesRenderingObserver);
this._onAfterSpritesRenderingObserver = null;
}
},
enumerable: true,
configurable: true
});
Object.defineProperty(SceneInstrumentation.prototype, "physicsTimeCounter", {
/**
* Gets the perf counter used for physics time
*/
get: function () {
return this._physicsTime;
},
enumerable: true,
configurable: true
});
Object.defineProperty(SceneInstrumentation.prototype, "capturePhysicsTime", {
/**
* Gets the physics time capture status
*/
get: function () {
return this._capturePhysicsTime;
},
/**
* Enable or disable the physics time capture
*/
set: function (value) {
var _this = this;
if (value === this._capturePhysicsTime) {
return;
}
this._capturePhysicsTime = value;
if (value) {
this._onBeforePhysicsObserver = this.scene.onBeforePhysicsObservable.add(function () {
BABYLON.Tools.StartPerformanceCounter("Physics");
_this._physicsTime.beginMonitoring();
});
this._onAfterPhysicsObserver = this.scene.onAfterPhysicsObservable.add(function () {
BABYLON.Tools.EndPerformanceCounter("Physics");
_this._physicsTime.endMonitoring();
});
}
else {
this.scene.onBeforePhysicsObservable.remove(this._onBeforePhysicsObserver);
this._onBeforePhysicsObserver = null;
this.scene.onAfterPhysicsObservable.remove(this._onAfterPhysicsObserver);
this._onAfterPhysicsObserver = null;
}
},
enumerable: true,
configurable: true
});
Object.defineProperty(SceneInstrumentation.prototype, "animationsTimeCounter", {
/**
* Gets the perf counter used for animations time
*/
get: function () {
return this._animationsTime;
},
enumerable: true,
configurable: true
});
Object.defineProperty(SceneInstrumentation.prototype, "captureAnimationsTime", {
/**
* Gets the animations time capture status
*/
get: function () {
return this._captureAnimationsTime;
},
/**
* Enable or disable the animations time capture
*/
set: function (value) {
var _this = this;
if (value === this._captureAnimationsTime) {
return;
}
this._captureAnimationsTime = value;
if (value) {
this._onAfterAnimationsObserver = this.scene.onAfterAnimationsObservable.add(function () {
_this._animationsTime.endMonitoring();
});
}
else {
this.scene.onAfterAnimationsObservable.remove(this._onAfterAnimationsObserver);
this._onAfterAnimationsObserver = null;
}
},
enumerable: true,
configurable: true
});
Object.defineProperty(SceneInstrumentation.prototype, "frameTimeCounter", {
/**
* Gets the perf counter used for frame time capture
*/
get: function () {
return this._frameTime;
},
enumerable: true,
configurable: true
});
Object.defineProperty(SceneInstrumentation.prototype, "captureFrameTime", {
/**
* Gets the frame time capture status
*/
get: function () {
return this._captureFrameTime;
},
/**
* Enable or disable the frame time capture
*/
set: function (value) {
this._captureFrameTime = value;
},
enumerable: true,
configurable: true
});
Object.defineProperty(SceneInstrumentation.prototype, "interFrameTimeCounter", {
/**
* Gets the perf counter used for inter-frames time capture
*/
get: function () {
return this._interFrameTime;
},
enumerable: true,
configurable: true
});
Object.defineProperty(SceneInstrumentation.prototype, "captureInterFrameTime", {
/**
* Gets the inter-frames time capture status
*/
get: function () {
return this._captureInterFrameTime;
},
/**
* Enable or disable the inter-frames time capture
*/
set: function (value) {
this._captureInterFrameTime = value;
},
enumerable: true,
configurable: true
});
Object.defineProperty(SceneInstrumentation.prototype, "renderTimeCounter", {
/**
* Gets the perf counter used for render time capture
*/
get: function () {
return this._renderTime;
},
enumerable: true,
configurable: true
});
Object.defineProperty(SceneInstrumentation.prototype, "captureRenderTime", {
/**
* Gets the render time capture status
*/
get: function () {
return this._captureRenderTime;
},
/**
* Enable or disable the render time capture
*/
set: function (value) {
var _this = this;
if (value === this._captureRenderTime) {
return;
}
this._captureRenderTime = value;
if (value) {
this._onBeforeDrawPhaseObserver = this.scene.onBeforeDrawPhaseObservable.add(function () {
_this._renderTime.beginMonitoring();
BABYLON.Tools.StartPerformanceCounter("Main render");
});
this._onAfterDrawPhaseObserver = this.scene.onAfterDrawPhaseObservable.add(function () {
_this._renderTime.endMonitoring(false);
BABYLON.Tools.EndPerformanceCounter("Main render");
});
}
else {
this.scene.onBeforeDrawPhaseObservable.remove(this._onBeforeDrawPhaseObserver);
this._onBeforeDrawPhaseObserver = null;
this.scene.onAfterDrawPhaseObservable.remove(this._onAfterDrawPhaseObserver);
this._onAfterDrawPhaseObserver = null;
}
},
enumerable: true,
configurable: true
});
Object.defineProperty(SceneInstrumentation.prototype, "cameraRenderTimeCounter", {
/**
* Gets the perf counter used for camera render time capture
*/
get: function () {
return this._cameraRenderTime;
},
enumerable: true,
configurable: true
});
Object.defineProperty(SceneInstrumentation.prototype, "captureCameraRenderTime", {
/**
* Gets the camera render time capture status
*/
get: function () {
return this._captureCameraRenderTime;
},
/**
* Enable or disable the camera render time capture
*/
set: function (value) {
var _this = this;
if (value === this._captureCameraRenderTime) {
return;
}
this._captureCameraRenderTime = value;
if (value) {
this._onBeforeCameraRenderObserver = this.scene.onBeforeCameraRenderObservable.add(function (camera) {
_this._cameraRenderTime.beginMonitoring();
BABYLON.Tools.StartPerformanceCounter("Rendering camera " + camera.name);
});
this._onAfterCameraRenderObserver = this.scene.onAfterCameraRenderObservable.add(function (camera) {
_this._cameraRenderTime.endMonitoring(false);
BABYLON.Tools.EndPerformanceCounter("Rendering camera " + camera.name);
});
}
else {
this.scene.onBeforeCameraRenderObservable.remove(this._onBeforeCameraRenderObserver);
this._onBeforeCameraRenderObserver = null;
this.scene.onAfterCameraRenderObservable.remove(this._onAfterCameraRenderObserver);
this._onAfterCameraRenderObserver = null;
}
},
enumerable: true,
configurable: true
});
Object.defineProperty(SceneInstrumentation.prototype, "drawCallsCounter", {
/**
* Gets the perf counter used for draw calls
*/
get: function () {
return this.scene.getEngine()._drawCalls;
},
enumerable: true,
configurable: true
});
Object.defineProperty(SceneInstrumentation.prototype, "textureCollisionsCounter", {
/**
* Gets the perf counter used for texture collisions
*/
get: function () {
return this.scene.getEngine()._textureCollisions;
},
enumerable: true,
configurable: true
});
SceneInstrumentation.prototype.dispose = function () {
this.scene.onAfterRenderObservable.remove(this._onAfterRenderObserver);
this._onAfterRenderObserver = null;
this.scene.onBeforeActiveMeshesEvaluationObservable.remove(this._onBeforeActiveMeshesEvaluationObserver);
this._onBeforeActiveMeshesEvaluationObserver = null;
this.scene.onAfterActiveMeshesEvaluationObservable.remove(this._onAfterActiveMeshesEvaluationObserver);
this._onAfterActiveMeshesEvaluationObserver = null;
this.scene.onBeforeRenderTargetsRenderObservable.remove(this._onBeforeRenderTargetsRenderObserver);
this._onBeforeRenderTargetsRenderObserver = null;
this.scene.onAfterRenderTargetsRenderObservable.remove(this._onAfterRenderTargetsRenderObserver);
this._onAfterRenderTargetsRenderObserver = null;
this.scene.onBeforeAnimationsObservable.remove(this._onBeforeAnimationsObserver);
this._onBeforeAnimationsObserver = null;
this.scene.onBeforeParticlesRenderingObservable.remove(this._onBeforeParticlesRenderingObserver);
this._onBeforeParticlesRenderingObserver = null;
this.scene.onAfterParticlesRenderingObservable.remove(this._onAfterParticlesRenderingObserver);
this._onAfterParticlesRenderingObserver = null;
this.scene.onBeforeSpritesRenderingObservable.remove(this._onBeforeSpritesRenderingObserver);
this._onBeforeSpritesRenderingObserver = null;
this.scene.onAfterSpritesRenderingObservable.remove(this._onAfterSpritesRenderingObserver);
this._onAfterSpritesRenderingObserver = null;
this.scene.onBeforeDrawPhaseObservable.remove(this._onBeforeDrawPhaseObserver);
this._onBeforeDrawPhaseObserver = null;
this.scene.onAfterDrawPhaseObservable.remove(this._onAfterDrawPhaseObserver);
this._onAfterDrawPhaseObserver = null;
this.scene.onBeforePhysicsObservable.remove(this._onBeforePhysicsObserver);
this._onBeforePhysicsObserver = null;
this.scene.onAfterPhysicsObservable.remove(this._onAfterPhysicsObserver);
this._onAfterPhysicsObserver = null;
this.scene.onAfterAnimationsObservable.remove(this._onAfterAnimationsObserver);
this._onAfterAnimationsObserver = null;
this.scene.onBeforeCameraRenderObservable.remove(this._onBeforeCameraRenderObserver);
this._onBeforeCameraRenderObserver = null;
this.scene.onAfterCameraRenderObservable.remove(this._onAfterCameraRenderObserver);
this._onAfterCameraRenderObserver = null;
this.scene = null;
};
return SceneInstrumentation;
}());
BABYLON.SceneInstrumentation = SceneInstrumentation;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.sceneInstrumentation.js.map
var BABYLON;
(function (BABYLON) {
/**
* @hidden
**/
var _TimeToken = /** @class */ (function () {
function _TimeToken() {
this._timeElapsedQueryEnded = false;
}
return _TimeToken;
}());
BABYLON._TimeToken = _TimeToken;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.timeToken.js.map
var BABYLON;
(function (BABYLON) {
/**
* Background material defines definition.
* @hidden Mainly internal Use
*/
var BackgroundMaterialDefines = /** @class */ (function (_super) {
__extends(BackgroundMaterialDefines, _super);
/**
* Constructor of the defines.
*/
function BackgroundMaterialDefines() {
var _this = _super.call(this) || this;
/**
* True if the diffuse texture is in use.
*/
_this.DIFFUSE = false;
/**
* The direct UV channel to use.
*/
_this.DIFFUSEDIRECTUV = 0;
/**
* True if the diffuse texture is in gamma space.
*/
_this.GAMMADIFFUSE = false;
/**
* True if the diffuse texture has opacity in the alpha channel.
*/
_this.DIFFUSEHASALPHA = false;
/**
* True if you want the material to fade to transparent at grazing angle.
*/
_this.OPACITYFRESNEL = false;
/**
* True if an extra blur needs to be added in the reflection.
*/
_this.REFLECTIONBLUR = false;
/**
* True if you want the material to fade to reflection at grazing angle.
*/
_this.REFLECTIONFRESNEL = false;
/**
* True if you want the material to falloff as far as you move away from the scene center.
*/
_this.REFLECTIONFALLOFF = false;
/**
* False if the current Webgl implementation does not support the texture lod extension.
*/
_this.TEXTURELODSUPPORT = false;
/**
* True to ensure the data are premultiplied.
*/
_this.PREMULTIPLYALPHA = false;
/**
* True if the texture contains cooked RGB values and not gray scaled multipliers.
*/
_this.USERGBCOLOR = false;
/**
* True if highlight and shadow levels have been specified. It can help ensuring the main perceived color
* stays aligned with the desired configuration.
*/
_this.USEHIGHLIGHTANDSHADOWCOLORS = false;
/**
* True to add noise in order to reduce the banding effect.
*/
_this.NOISE = false;
/**
* is the reflection texture in BGR color scheme?
* Mainly used to solve a bug in ios10 video tag
*/
_this.REFLECTIONBGR = false;
_this.IMAGEPROCESSING = false;
_this.VIGNETTE = false;
_this.VIGNETTEBLENDMODEMULTIPLY = false;
_this.VIGNETTEBLENDMODEOPAQUE = false;
_this.TONEMAPPING = false;
_this.CONTRAST = false;
_this.COLORCURVES = false;
_this.COLORGRADING = false;
_this.COLORGRADING3D = false;
_this.SAMPLER3DGREENDEPTH = false;
_this.SAMPLER3DBGRMAP = false;
_this.IMAGEPROCESSINGPOSTPROCESS = false;
_this.EXPOSURE = false;
// Reflection.
_this.REFLECTION = false;
_this.REFLECTIONMAP_3D = false;
_this.REFLECTIONMAP_SPHERICAL = false;
_this.REFLECTIONMAP_PLANAR = false;
_this.REFLECTIONMAP_CUBIC = false;
_this.REFLECTIONMAP_PROJECTION = false;
_this.REFLECTIONMAP_SKYBOX = false;
_this.REFLECTIONMAP_EXPLICIT = false;
_this.REFLECTIONMAP_EQUIRECTANGULAR = false;
_this.REFLECTIONMAP_EQUIRECTANGULAR_FIXED = false;
_this.REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED = false;
_this.INVERTCUBICMAP = false;
_this.REFLECTIONMAP_OPPOSITEZ = false;
_this.LODINREFLECTIONALPHA = false;
_this.GAMMAREFLECTION = false;
_this.RGBDREFLECTION = false;
_this.EQUIRECTANGULAR_RELFECTION_FOV = false;
// Default BJS.
_this.MAINUV1 = false;
_this.MAINUV2 = false;
_this.UV1 = false;
_this.UV2 = false;
_this.CLIPPLANE = false;
_this.POINTSIZE = false;
_this.FOG = false;
_this.NORMAL = false;
_this.NUM_BONE_INFLUENCERS = 0;
_this.BonesPerMesh = 0;
_this.INSTANCES = false;
_this.SHADOWFLOAT = false;
_this.rebuild();
return _this;
}
return BackgroundMaterialDefines;
}(BABYLON.MaterialDefines));
/**
* Background material used to create an efficient environement around your scene.
*/
var BackgroundMaterial = /** @class */ (function (_super) {
__extends(BackgroundMaterial, _super);
/**
* Instantiates a Background Material in the given scene
* @param name The friendly name of the material
* @param scene The scene to add the material to
*/
function BackgroundMaterial(name, scene) {
var _this = _super.call(this, name, scene) || this;
/**
* Key light Color (multiply against the environement texture)
*/
_this.primaryColor = BABYLON.Color3.White();
_this._primaryColorShadowLevel = 0;
_this._primaryColorHighlightLevel = 0;
/**
* Reflection Texture used in the material.
* Should be author in a specific way for the best result (refer to the documentation).
*/
_this.reflectionTexture = null;
/**
* Reflection Texture level of blur.
*
* Can be use to reuse an existing HDR Texture and target a specific LOD to prevent authoring the
* texture twice.
*/
_this.reflectionBlur = 0;
/**
* Diffuse Texture used in the material.
* Should be author in a specific way for the best result (refer to the documentation).
*/
_this.diffuseTexture = null;
_this._shadowLights = null;
/**
* Specify the list of lights casting shadow on the material.
* All scene shadow lights will be included if null.
*/
_this.shadowLights = null;
/**
* Helps adjusting the shadow to a softer level if required.
* 0 means black shadows and 1 means no shadows.
*/
_this.shadowLevel = 0;
/**
* In case of opacity Fresnel or reflection falloff, this is use as a scene center.
* It is usually zero but might be interesting to modify according to your setup.
*/
_this.sceneCenter = BABYLON.Vector3.Zero();
/**
* This helps specifying that the material is falling off to the sky box at grazing angle.
* This helps ensuring a nice transition when the camera goes under the ground.
*/
_this.opacityFresnel = true;
/**
* This helps specifying that the material is falling off from diffuse to the reflection texture at grazing angle.
* This helps adding a mirror texture on the ground.
*/
_this.reflectionFresnel = false;
/**
* This helps specifying the falloff radius off the reflection texture from the sceneCenter.
* This helps adding a nice falloff effect to the reflection if used as a mirror for instance.
*/
_this.reflectionFalloffDistance = 0.0;
/**
* This specifies the weight of the reflection against the background in case of reflection Fresnel.
*/
_this.reflectionAmount = 1.0;
/**
* This specifies the weight of the reflection at grazing angle.
*/
_this.reflectionReflectance0 = 0.05;
/**
* This specifies the weight of the reflection at a perpendicular point of view.
*/
_this.reflectionReflectance90 = 0.5;
/**
* Helps to directly use the maps channels instead of their level.
*/
_this.useRGBColor = true;
/**
* This helps reducing the banding effect that could occur on the background.
*/
_this.enableNoise = false;
_this._fovMultiplier = 1.0;
/**
* Enable the FOV adjustment feature controlled by fovMultiplier.
*/
_this.useEquirectangularFOV = false;
_this._maxSimultaneousLights = 4;
/**
* Number of Simultaneous lights allowed on the material.
*/
_this.maxSimultaneousLights = 4;
/**
* Keep track of the image processing observer to allow dispose and replace.
*/
_this._imageProcessingObserver = null;
/**
* Due to a bug in iOS10, video tags (which are using the background material) are in BGR and not RGB.
* Setting this flag to true (not done automatically!) will convert it back to RGB.
*/
_this.switchToBGR = false;
// Temp values kept as cache in the material.
_this._renderTargets = new BABYLON.SmartArray(16);
_this._reflectionControls = BABYLON.Vector4.Zero();
_this._white = BABYLON.Color3.White();
_this._primaryShadowColor = BABYLON.Color3.Black();
_this._primaryHighlightColor = BABYLON.Color3.Black();
// Setup the default processing configuration to the scene.
_this._attachImageProcessingConfiguration(null);
_this.getRenderTargetTextures = function () {
_this._renderTargets.reset();
if (_this._diffuseTexture && _this._diffuseTexture.isRenderTarget) {
_this._renderTargets.push(_this._diffuseTexture);
}
if (_this._reflectionTexture && _this._reflectionTexture.isRenderTarget) {
_this._renderTargets.push(_this._reflectionTexture);
}
return _this._renderTargets;
};
return _this;
}
Object.defineProperty(BackgroundMaterial.prototype, "_perceptualColor", {
/**
* Experimental Internal Use Only.
*
* Key light Color in "perceptual value" meaning the color you would like to see on screen.
* This acts as a helper to set the primary color to a more "human friendly" value.
* Conversion to linear space as well as exposure and tone mapping correction will be applied to keep the
* output color as close as possible from the chosen value.
* (This does not account for contrast color grading and color curves as they are considered post effect and not directly
* part of lighting setup.)
*/
get: function () {
return this.__perceptualColor;
},
set: function (value) {
this.__perceptualColor = value;
this._computePrimaryColorFromPerceptualColor();
this._markAllSubMeshesAsLightsDirty();
},
enumerable: true,
configurable: true
});
Object.defineProperty(BackgroundMaterial.prototype, "primaryColorShadowLevel", {
/**
* Defines the level of the shadows (dark area of the reflection map) in order to help scaling the colors.
* The color opposite to the primary color is used at the level chosen to define what the black area would look.
*/
get: function () {
return this._primaryColorShadowLevel;
},
set: function (value) {
this._primaryColorShadowLevel = value;
this._computePrimaryColors();
this._markAllSubMeshesAsLightsDirty();
},
enumerable: true,
configurable: true
});
Object.defineProperty(BackgroundMaterial.prototype, "primaryColorHighlightLevel", {
/**
* Defines the level of the highliights (highlight area of the reflection map) in order to help scaling the colors.
* The primary color is used at the level chosen to define what the white area would look.
*/
get: function () {
return this._primaryColorHighlightLevel;
},
set: function (value) {
this._primaryColorHighlightLevel = value;
this._computePrimaryColors();
this._markAllSubMeshesAsLightsDirty();
},
enumerable: true,
configurable: true
});
Object.defineProperty(BackgroundMaterial.prototype, "reflectionStandardFresnelWeight", {
/**
* Sets the reflection reflectance fresnel values according to the default standard
* empirically know to work well :-)
*/
set: function (value) {
var reflectionWeight = value;
if (reflectionWeight < 0.5) {
reflectionWeight = reflectionWeight * 2.0;
this.reflectionReflectance0 = BackgroundMaterial.StandardReflectance0 * reflectionWeight;
this.reflectionReflectance90 = BackgroundMaterial.StandardReflectance90 * reflectionWeight;
}
else {
reflectionWeight = reflectionWeight * 2.0 - 1.0;
this.reflectionReflectance0 = BackgroundMaterial.StandardReflectance0 + (1.0 - BackgroundMaterial.StandardReflectance0) * reflectionWeight;
this.reflectionReflectance90 = BackgroundMaterial.StandardReflectance90 + (1.0 - BackgroundMaterial.StandardReflectance90) * reflectionWeight;
}
},
enumerable: true,
configurable: true
});
Object.defineProperty(BackgroundMaterial.prototype, "fovMultiplier", {
/**
* The current fov(field of view) multiplier, 0.0 - 2.0. Defaults to 1.0. Lower values "zoom in" and higher values "zoom out".
* Best used when trying to implement visual zoom effects like fish-eye or binoculars while not adjusting camera fov.
* Recommended to be keep at 1.0 except for special cases.
*/
get: function () {
return this._fovMultiplier;
},
set: function (value) {
if (isNaN(value)) {
value = 1.0;
}
this._fovMultiplier = Math.max(0.0, Math.min(2.0, value));
},
enumerable: true,
configurable: true
});
/**
* Attaches a new image processing configuration to the PBR Material.
* @param configuration (if null the scene configuration will be use)
*/
BackgroundMaterial.prototype._attachImageProcessingConfiguration = function (configuration) {
var _this = this;
if (configuration === this._imageProcessingConfiguration) {
return;
}
// Detaches observer.
if (this._imageProcessingConfiguration && this._imageProcessingObserver) {
this._imageProcessingConfiguration.onUpdateParameters.remove(this._imageProcessingObserver);
}
// Pick the scene configuration if needed.
if (!configuration) {
this._imageProcessingConfiguration = this.getScene().imageProcessingConfiguration;
}
else {
this._imageProcessingConfiguration = configuration;
}
// Attaches observer.
if (this._imageProcessingConfiguration) {
this._imageProcessingObserver = this._imageProcessingConfiguration.onUpdateParameters.add(function (conf) {
_this._computePrimaryColorFromPerceptualColor();
_this._markAllSubMeshesAsImageProcessingDirty();
});
}
};
Object.defineProperty(BackgroundMaterial.prototype, "imageProcessingConfiguration", {
/**
* Gets the image processing configuration used either in this material.
*/
get: function () {
return this._imageProcessingConfiguration;
},
/**
* Sets the Default image processing configuration used either in the this material.
*
* If sets to null, the scene one is in use.
*/
set: function (value) {
this._attachImageProcessingConfiguration(value);
// Ensure the effect will be rebuilt.
this._markAllSubMeshesAsTexturesDirty();
},
enumerable: true,
configurable: true
});
Object.defineProperty(BackgroundMaterial.prototype, "cameraColorCurvesEnabled", {
/**
* Gets wether the color curves effect is enabled.
*/
get: function () {
return this.imageProcessingConfiguration.colorCurvesEnabled;
},
/**
* Sets wether the color curves effect is enabled.
*/
set: function (value) {
this.imageProcessingConfiguration.colorCurvesEnabled = value;
},
enumerable: true,
configurable: true
});
Object.defineProperty(BackgroundMaterial.prototype, "cameraColorGradingEnabled", {
/**
* Gets wether the color grading effect is enabled.
*/
get: function () {
return this.imageProcessingConfiguration.colorGradingEnabled;
},
/**
* Gets wether the color grading effect is enabled.
*/
set: function (value) {
this.imageProcessingConfiguration.colorGradingEnabled = value;
},
enumerable: true,
configurable: true
});
Object.defineProperty(BackgroundMaterial.prototype, "cameraToneMappingEnabled", {
/**
* Gets wether tonemapping is enabled or not.
*/
get: function () {
return this._imageProcessingConfiguration.toneMappingEnabled;
},
/**
* Sets wether tonemapping is enabled or not
*/
set: function (value) {
this._imageProcessingConfiguration.toneMappingEnabled = value;
},
enumerable: true,
configurable: true
});
;
;
Object.defineProperty(BackgroundMaterial.prototype, "cameraExposure", {
/**
* The camera exposure used on this material.
* This property is here and not in the camera to allow controlling exposure without full screen post process.
* This corresponds to a photographic exposure.
*/
get: function () {
return this._imageProcessingConfiguration.exposure;
},
/**
* The camera exposure used on this material.
* This property is here and not in the camera to allow controlling exposure without full screen post process.
* This corresponds to a photographic exposure.
*/
set: function (value) {
this._imageProcessingConfiguration.exposure = value;
},
enumerable: true,
configurable: true
});
;
;
Object.defineProperty(BackgroundMaterial.prototype, "cameraContrast", {
/**
* Gets The camera contrast used on this material.
*/
get: function () {
return this._imageProcessingConfiguration.contrast;
},
/**
* Sets The camera contrast used on this material.
*/
set: function (value) {
this._imageProcessingConfiguration.contrast = value;
},
enumerable: true,
configurable: true
});
Object.defineProperty(BackgroundMaterial.prototype, "cameraColorGradingTexture", {
/**
* Gets the Color Grading 2D Lookup Texture.
*/
get: function () {
return this._imageProcessingConfiguration.colorGradingTexture;
},
/**
* Sets the Color Grading 2D Lookup Texture.
*/
set: function (value) {
this.imageProcessingConfiguration.colorGradingTexture = value;
},
enumerable: true,
configurable: true
});
Object.defineProperty(BackgroundMaterial.prototype, "cameraColorCurves", {
/**
* The color grading curves provide additional color adjustmnent that is applied after any color grading transform (3D LUT).
* They allow basic adjustment of saturation and small exposure adjustments, along with color filter tinting to provide white balance adjustment or more stylistic effects.
* These are similar to controls found in many professional imaging or colorist software. The global controls are applied to the entire image. For advanced tuning, extra controls are provided to adjust the shadow, midtone and highlight areas of the image;
* corresponding to low luminance, medium luminance, and high luminance areas respectively.
*/
get: function () {
return this.imageProcessingConfiguration.colorCurves;
},
/**
* The color grading curves provide additional color adjustmnent that is applied after any color grading transform (3D LUT).
* They allow basic adjustment of saturation and small exposure adjustments, along with color filter tinting to provide white balance adjustment or more stylistic effects.
* These are similar to controls found in many professional imaging or colorist software. The global controls are applied to the entire image. For advanced tuning, extra controls are provided to adjust the shadow, midtone and highlight areas of the image;
* corresponding to low luminance, medium luminance, and high luminance areas respectively.
*/
set: function (value) {
this.imageProcessingConfiguration.colorCurves = value;
},
enumerable: true,
configurable: true
});
/**
* The entire material has been created in order to prevent overdraw.
* @returns false
*/
BackgroundMaterial.prototype.needAlphaTesting = function () {
return true;
};
/**
* The entire material has been created in order to prevent overdraw.
* @returns true if blending is enable
*/
BackgroundMaterial.prototype.needAlphaBlending = function () {
return ((this.alpha < 0) || (this._diffuseTexture != null && this._diffuseTexture.hasAlpha));
};
/**
* Checks wether the material is ready to be rendered for a given mesh.
* @param mesh The mesh to render
* @param subMesh The submesh to check against
* @param useInstances Specify wether or not the material is used with instances
* @returns true if all the dependencies are ready (Textures, Effects...)
*/
BackgroundMaterial.prototype.isReadyForSubMesh = function (mesh, subMesh, useInstances) {
var _this = this;
if (useInstances === void 0) { useInstances = false; }
if (subMesh.effect && this.isFrozen) {
if (this._wasPreviouslyReady) {
return true;
}
}
if (!subMesh._materialDefines) {
subMesh._materialDefines = new BackgroundMaterialDefines();
}
var scene = this.getScene();
var defines = subMesh._materialDefines;
if (!this.checkReadyOnEveryCall && subMesh.effect) {
if (defines._renderId === scene.getRenderId()) {
return true;
}
}
var engine = scene.getEngine();
// Lights
BABYLON.MaterialHelper.PrepareDefinesForLights(scene, mesh, defines, false, this._maxSimultaneousLights);
defines._needNormals = true;
// Textures
if (defines._areTexturesDirty) {
defines._needUVs = false;
if (scene.texturesEnabled) {
if (scene.getEngine().getCaps().textureLOD) {
defines.TEXTURELODSUPPORT = true;
}
if (this._diffuseTexture && BABYLON.StandardMaterial.DiffuseTextureEnabled) {
if (!this._diffuseTexture.isReadyOrNotBlocking()) {
return false;
}
BABYLON.MaterialHelper.PrepareDefinesForMergedUV(this._diffuseTexture, defines, "DIFFUSE");
defines.DIFFUSEHASALPHA = this._diffuseTexture.hasAlpha;
defines.GAMMADIFFUSE = this._diffuseTexture.gammaSpace;
defines.OPACITYFRESNEL = this._opacityFresnel;
}
else {
defines.DIFFUSE = false;
defines.DIFFUSEHASALPHA = false;
defines.GAMMADIFFUSE = false;
defines.OPACITYFRESNEL = false;
}
var reflectionTexture = this._reflectionTexture;
if (reflectionTexture && BABYLON.StandardMaterial.ReflectionTextureEnabled) {
if (!reflectionTexture.isReadyOrNotBlocking()) {
return false;
}
defines.REFLECTION = true;
defines.GAMMAREFLECTION = reflectionTexture.gammaSpace;
defines.RGBDREFLECTION = reflectionTexture.isRGBD;
defines.REFLECTIONBLUR = this._reflectionBlur > 0;
defines.REFLECTIONMAP_OPPOSITEZ = this.getScene().useRightHandedSystem ? !reflectionTexture.invertZ : reflectionTexture.invertZ;
defines.LODINREFLECTIONALPHA = reflectionTexture.lodLevelInAlpha;
defines.EQUIRECTANGULAR_RELFECTION_FOV = this.useEquirectangularFOV;
defines.REFLECTIONBGR = this.switchToBGR;
if (reflectionTexture.coordinatesMode === BABYLON.Texture.INVCUBIC_MODE) {
defines.INVERTCUBICMAP = true;
}
defines.REFLECTIONMAP_3D = reflectionTexture.isCube;
switch (reflectionTexture.coordinatesMode) {
case BABYLON.Texture.EXPLICIT_MODE:
defines.REFLECTIONMAP_EXPLICIT = true;
break;
case BABYLON.Texture.PLANAR_MODE:
defines.REFLECTIONMAP_PLANAR = true;
break;
case BABYLON.Texture.PROJECTION_MODE:
defines.REFLECTIONMAP_PROJECTION = true;
break;
case BABYLON.Texture.SKYBOX_MODE:
defines.REFLECTIONMAP_SKYBOX = true;
break;
case BABYLON.Texture.SPHERICAL_MODE:
defines.REFLECTIONMAP_SPHERICAL = true;
break;
case BABYLON.Texture.EQUIRECTANGULAR_MODE:
defines.REFLECTIONMAP_EQUIRECTANGULAR = true;
break;
case BABYLON.Texture.FIXED_EQUIRECTANGULAR_MODE:
defines.REFLECTIONMAP_EQUIRECTANGULAR_FIXED = true;
break;
case BABYLON.Texture.FIXED_EQUIRECTANGULAR_MIRRORED_MODE:
defines.REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED = true;
break;
case BABYLON.Texture.CUBIC_MODE:
case BABYLON.Texture.INVCUBIC_MODE:
default:
defines.REFLECTIONMAP_CUBIC = true;
break;
}
if (this.reflectionFresnel) {
defines.REFLECTIONFRESNEL = true;
defines.REFLECTIONFALLOFF = this.reflectionFalloffDistance > 0;
this._reflectionControls.x = this.reflectionAmount;
this._reflectionControls.y = this.reflectionReflectance0;
this._reflectionControls.z = this.reflectionReflectance90;
this._reflectionControls.w = 1 / this.reflectionFalloffDistance;
}
else {
defines.REFLECTIONFRESNEL = false;
defines.REFLECTIONFALLOFF = false;
}
}
else {
defines.REFLECTION = false;
defines.REFLECTIONFRESNEL = false;
defines.REFLECTIONFALLOFF = false;
defines.REFLECTIONBLUR = false;
defines.REFLECTIONMAP_3D = false;
defines.REFLECTIONMAP_SPHERICAL = false;
defines.REFLECTIONMAP_PLANAR = false;
defines.REFLECTIONMAP_CUBIC = false;
defines.REFLECTIONMAP_PROJECTION = false;
defines.REFLECTIONMAP_SKYBOX = false;
defines.REFLECTIONMAP_EXPLICIT = false;
defines.REFLECTIONMAP_EQUIRECTANGULAR = false;
defines.REFLECTIONMAP_EQUIRECTANGULAR_FIXED = false;
defines.REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED = false;
defines.INVERTCUBICMAP = false;
defines.REFLECTIONMAP_OPPOSITEZ = false;
defines.LODINREFLECTIONALPHA = false;
defines.GAMMAREFLECTION = false;
defines.RGBDREFLECTION = false;
}
}
defines.PREMULTIPLYALPHA = (this.alphaMode === BABYLON.Engine.ALPHA_PREMULTIPLIED || this.alphaMode === BABYLON.Engine.ALPHA_PREMULTIPLIED_PORTERDUFF);
defines.USERGBCOLOR = this._useRGBColor;
defines.NOISE = this._enableNoise;
}
if (defines._areLightsDirty) {
defines.USEHIGHLIGHTANDSHADOWCOLORS = !this._useRGBColor && (this._primaryColorShadowLevel !== 0 || this._primaryColorHighlightLevel !== 0);
}
if (defines._areImageProcessingDirty && this._imageProcessingConfiguration) {
if (!this._imageProcessingConfiguration.isReady()) {
return false;
}
this._imageProcessingConfiguration.prepareDefines(defines);
}
// Misc.
BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, this._shouldTurnAlphaTestOn(mesh), defines);
// Values that need to be evaluated on every frame
BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances);
// Attribs
if (BABYLON.MaterialHelper.PrepareDefinesForAttributes(mesh, defines, false, true, false)) {
if (mesh) {
if (!scene.getEngine().getCaps().standardDerivatives && !mesh.isVerticesDataPresent(BABYLON.VertexBuffer.NormalKind)) {
mesh.createNormals(true);
BABYLON.Tools.Warn("BackgroundMaterial: Normals have been created for the mesh: " + mesh.name);
}
}
}
// Get correct effect
if (defines.isDirty) {
defines.markAsProcessed();
scene.resetCachedMaterial();
// Fallbacks
var fallbacks = new BABYLON.EffectFallbacks();
if (defines.FOG) {
fallbacks.addFallback(0, "FOG");
}
if (defines.POINTSIZE) {
fallbacks.addFallback(1, "POINTSIZE");
}
BABYLON.MaterialHelper.HandleFallbacksForShadows(defines, fallbacks, this._maxSimultaneousLights);
if (defines.NUM_BONE_INFLUENCERS > 0) {
fallbacks.addCPUSkinningFallback(0, mesh);
}
//Attributes
var attribs = [BABYLON.VertexBuffer.PositionKind];
if (defines.NORMAL) {
attribs.push(BABYLON.VertexBuffer.NormalKind);
}
if (defines.UV1) {
attribs.push(BABYLON.VertexBuffer.UVKind);
}
if (defines.UV2) {
attribs.push(BABYLON.VertexBuffer.UV2Kind);
}
BABYLON.MaterialHelper.PrepareAttributesForBones(attribs, mesh, defines, fallbacks);
BABYLON.MaterialHelper.PrepareAttributesForInstances(attribs, defines);
var uniforms = ["world", "view", "viewProjection", "vEyePosition", "vLightsType",
"vFogInfos", "vFogColor", "pointSize",
"vClipPlane", "mBones",
"vPrimaryColor", "vPrimaryColorShadow",
"vReflectionInfos", "reflectionMatrix", "vReflectionMicrosurfaceInfos", "fFovMultiplier",
"shadowLevel", "alpha",
"vBackgroundCenter", "vReflectionControl",
"vDiffuseInfos", "diffuseMatrix",
];
var samplers = ["diffuseSampler", "reflectionSampler", "reflectionSamplerLow", "reflectionSamplerHigh"];
var uniformBuffers = ["Material", "Scene"];
if (BABYLON.ImageProcessingConfiguration) {
BABYLON.ImageProcessingConfiguration.PrepareUniforms(uniforms, defines);
BABYLON.ImageProcessingConfiguration.PrepareSamplers(samplers, defines);
}
BABYLON.MaterialHelper.PrepareUniformsAndSamplersList({
uniformsNames: uniforms,
uniformBuffersNames: uniformBuffers,
samplers: samplers,
defines: defines,
maxSimultaneousLights: this._maxSimultaneousLights
});
var onCompiled = function (effect) {
if (_this.onCompiled) {
_this.onCompiled(effect);
}
_this.bindSceneUniformBuffer(effect, scene.getSceneUniformBuffer());
};
var join = defines.toString();
subMesh.setEffect(scene.getEngine().createEffect("background", {
attributes: attribs,
uniformsNames: uniforms,
uniformBuffersNames: uniformBuffers,
samplers: samplers,
defines: join,
fallbacks: fallbacks,
onCompiled: onCompiled,
onError: this.onError,
indexParameters: { maxSimultaneousLights: this._maxSimultaneousLights }
}, engine), defines);
this.buildUniformLayout();
}
if (!subMesh.effect || !subMesh.effect.isReady()) {
return false;
}
defines._renderId = scene.getRenderId();
this._wasPreviouslyReady = true;
return true;
};
/**
* Compute the primary color according to the chosen perceptual color.
*/
BackgroundMaterial.prototype._computePrimaryColorFromPerceptualColor = function () {
if (!this.__perceptualColor) {
return;
}
this._primaryColor.copyFrom(this.__perceptualColor);
// Revert gamma space.
this._primaryColor.toLinearSpaceToRef(this._primaryColor);
// Revert image processing configuration.
if (this._imageProcessingConfiguration) {
// Revert Exposure.
this._primaryColor.scaleToRef(1 / this._imageProcessingConfiguration.exposure, this._primaryColor);
}
this._computePrimaryColors();
};
/**
* Compute the highlights and shadow colors according to their chosen levels.
*/
BackgroundMaterial.prototype._computePrimaryColors = function () {
if (this._primaryColorShadowLevel === 0 && this._primaryColorHighlightLevel === 0) {
return;
}
// Find the highlight color based on the configuration.
this._primaryColor.scaleToRef(this._primaryColorShadowLevel, this._primaryShadowColor);
this._primaryColor.subtractToRef(this._primaryShadowColor, this._primaryShadowColor);
// Find the shadow color based on the configuration.
this._white.subtractToRef(this._primaryColor, this._primaryHighlightColor);
this._primaryHighlightColor.scaleToRef(this._primaryColorHighlightLevel, this._primaryHighlightColor);
this._primaryColor.addToRef(this._primaryHighlightColor, this._primaryHighlightColor);
};
/**
* Build the uniform buffer used in the material.
*/
BackgroundMaterial.prototype.buildUniformLayout = function () {
// Order is important !
this._uniformBuffer.addUniform("vPrimaryColor", 4);
this._uniformBuffer.addUniform("vPrimaryColorShadow", 4);
this._uniformBuffer.addUniform("vDiffuseInfos", 2);
this._uniformBuffer.addUniform("vReflectionInfos", 2);
this._uniformBuffer.addUniform("diffuseMatrix", 16);
this._uniformBuffer.addUniform("reflectionMatrix", 16);
this._uniformBuffer.addUniform("vReflectionMicrosurfaceInfos", 3);
this._uniformBuffer.addUniform("fFovMultiplier", 1);
this._uniformBuffer.addUniform("pointSize", 1);
this._uniformBuffer.addUniform("shadowLevel", 1);
this._uniformBuffer.addUniform("alpha", 1);
this._uniformBuffer.addUniform("vBackgroundCenter", 3);
this._uniformBuffer.addUniform("vReflectionControl", 4);
this._uniformBuffer.create();
};
/**
* Unbind the material.
*/
BackgroundMaterial.prototype.unbind = function () {
if (this._diffuseTexture && this._diffuseTexture.isRenderTarget) {
this._uniformBuffer.setTexture("diffuseSampler", null);
}
if (this._reflectionTexture && this._reflectionTexture.isRenderTarget) {
this._uniformBuffer.setTexture("reflectionSampler", null);
}
_super.prototype.unbind.call(this);
};
/**
* Bind only the world matrix to the material.
* @param world The world matrix to bind.
*/
BackgroundMaterial.prototype.bindOnlyWorldMatrix = function (world) {
this._activeEffect.setMatrix("world", world);
};
/**
* Bind the material for a dedicated submeh (every used meshes will be considered opaque).
* @param world The world matrix to bind.
* @param subMesh The submesh to bind for.
*/
BackgroundMaterial.prototype.bindForSubMesh = function (world, mesh, subMesh) {
var scene = this.getScene();
var defines = subMesh._materialDefines;
if (!defines) {
return;
}
var effect = subMesh.effect;
if (!effect) {
return;
}
this._activeEffect = effect;
// Matrices
this.bindOnlyWorldMatrix(world);
// Bones
BABYLON.MaterialHelper.BindBonesParameters(mesh, this._activeEffect);
var mustRebind = this._mustRebind(scene, effect, mesh.visibility);
if (mustRebind) {
this._uniformBuffer.bindToEffect(effect, "Material");
this.bindViewProjection(effect);
var reflectionTexture = this._reflectionTexture;
if (!this._uniformBuffer.useUbo || !this.isFrozen || !this._uniformBuffer.isSync) {
// Texture uniforms
if (scene.texturesEnabled) {
if (this._diffuseTexture && BABYLON.StandardMaterial.DiffuseTextureEnabled) {
this._uniformBuffer.updateFloat2("vDiffuseInfos", this._diffuseTexture.coordinatesIndex, this._diffuseTexture.level);
BABYLON.MaterialHelper.BindTextureMatrix(this._diffuseTexture, this._uniformBuffer, "diffuse");
}
if (reflectionTexture && BABYLON.StandardMaterial.ReflectionTextureEnabled) {
this._uniformBuffer.updateMatrix("reflectionMatrix", reflectionTexture.getReflectionTextureMatrix());
this._uniformBuffer.updateFloat2("vReflectionInfos", reflectionTexture.level, this._reflectionBlur);
this._uniformBuffer.updateFloat3("vReflectionMicrosurfaceInfos", reflectionTexture.getSize().width, reflectionTexture.lodGenerationScale, reflectionTexture.lodGenerationOffset);
}
}
if (this.shadowLevel > 0) {
this._uniformBuffer.updateFloat("shadowLevel", this.shadowLevel);
}
this._uniformBuffer.updateFloat("alpha", this.alpha);
// Point size
if (this.pointsCloud) {
this._uniformBuffer.updateFloat("pointSize", this.pointSize);
}
if (defines.USEHIGHLIGHTANDSHADOWCOLORS) {
this._uniformBuffer.updateColor4("vPrimaryColor", this._primaryHighlightColor, 1.0);
this._uniformBuffer.updateColor4("vPrimaryColorShadow", this._primaryShadowColor, 1.0);
}
else {
this._uniformBuffer.updateColor4("vPrimaryColor", this._primaryColor, 1.0);
}
}
this._uniformBuffer.updateFloat("fFovMultiplier", this._fovMultiplier);
// Textures
if (scene.texturesEnabled) {
if (this._diffuseTexture && BABYLON.StandardMaterial.DiffuseTextureEnabled) {
this._uniformBuffer.setTexture("diffuseSampler", this._diffuseTexture);
}
if (reflectionTexture && BABYLON.StandardMaterial.ReflectionTextureEnabled) {
if (defines.REFLECTIONBLUR && defines.TEXTURELODSUPPORT) {
this._uniformBuffer.setTexture("reflectionSampler", reflectionTexture);
}
else if (!defines.REFLECTIONBLUR) {
this._uniformBuffer.setTexture("reflectionSampler", reflectionTexture);
}
else {
this._uniformBuffer.setTexture("reflectionSampler", reflectionTexture._lodTextureMid || reflectionTexture);
this._uniformBuffer.setTexture("reflectionSamplerLow", reflectionTexture._lodTextureLow || reflectionTexture);
this._uniformBuffer.setTexture("reflectionSamplerHigh", reflectionTexture._lodTextureHigh || reflectionTexture);
}
if (defines.REFLECTIONFRESNEL) {
this._uniformBuffer.updateFloat3("vBackgroundCenter", this.sceneCenter.x, this.sceneCenter.y, this.sceneCenter.z);
this._uniformBuffer.updateFloat4("vReflectionControl", this._reflectionControls.x, this._reflectionControls.y, this._reflectionControls.z, this._reflectionControls.w);
}
}
}
// Clip plane
BABYLON.MaterialHelper.BindClipPlane(this._activeEffect, scene);
BABYLON.MaterialHelper.BindEyePosition(effect, scene);
}
if (mustRebind || !this.isFrozen) {
if (scene.lightsEnabled) {
BABYLON.MaterialHelper.BindLights(scene, mesh, this._activeEffect, defines, this._maxSimultaneousLights, false);
}
// View
this.bindView(effect);
// Fog
BABYLON.MaterialHelper.BindFogParameters(scene, mesh, this._activeEffect);
// image processing
if (this._imageProcessingConfiguration) {
this._imageProcessingConfiguration.bind(this._activeEffect);
}
}
this._uniformBuffer.update();
this._afterBind(mesh, this._activeEffect);
};
/**
* Dispose the material.
* @param forceDisposeEffect Force disposal of the associated effect.
* @param forceDisposeTextures Force disposal of the associated textures.
*/
BackgroundMaterial.prototype.dispose = function (forceDisposeEffect, forceDisposeTextures) {
if (forceDisposeEffect === void 0) { forceDisposeEffect = false; }
if (forceDisposeTextures === void 0) { forceDisposeTextures = false; }
if (forceDisposeTextures) {
if (this.diffuseTexture) {
this.diffuseTexture.dispose();
}
if (this.reflectionTexture) {
this.reflectionTexture.dispose();
}
}
this._renderTargets.dispose();
if (this._imageProcessingConfiguration && this._imageProcessingObserver) {
this._imageProcessingConfiguration.onUpdateParameters.remove(this._imageProcessingObserver);
}
_super.prototype.dispose.call(this, forceDisposeEffect);
};
/**
* Clones the material.
* @param name The cloned name.
* @returns The cloned material.
*/
BackgroundMaterial.prototype.clone = function (name) {
var _this = this;
return BABYLON.SerializationHelper.Clone(function () { return new BackgroundMaterial(name, _this.getScene()); }, this);
};
/**
* Serializes the current material to its JSON representation.
* @returns The JSON representation.
*/
BackgroundMaterial.prototype.serialize = function () {
var serializationObject = BABYLON.SerializationHelper.Serialize(this);
serializationObject.customType = "BABYLON.BackgroundMaterial";
return serializationObject;
};
/**
* Gets the class name of the material
* @returns "BackgroundMaterial"
*/
BackgroundMaterial.prototype.getClassName = function () {
return "BackgroundMaterial";
};
/**
* Parse a JSON input to create back a background material.
* @param source The JSON data to parse
* @param scene The scene to create the parsed material in
* @param rootUrl The root url of the assets the material depends upon
* @returns the instantiated BackgroundMaterial.
*/
BackgroundMaterial.Parse = function (source, scene, rootUrl) {
return BABYLON.SerializationHelper.Parse(function () { return new BackgroundMaterial(source.name, scene); }, source, scene, rootUrl);
};
/**
* Standard reflectance value at parallel view angle.
*/
BackgroundMaterial.StandardReflectance0 = 0.05;
/**
* Standard reflectance value at grazing angle.
*/
BackgroundMaterial.StandardReflectance90 = 0.5;
__decorate([
BABYLON.serializeAsColor3()
], BackgroundMaterial.prototype, "_primaryColor", void 0);
__decorate([
BABYLON.expandToProperty("_markAllSubMeshesAsLightsDirty")
], BackgroundMaterial.prototype, "primaryColor", void 0);
__decorate([
BABYLON.serializeAsColor3()
], BackgroundMaterial.prototype, "__perceptualColor", void 0);
__decorate([
BABYLON.serialize()
], BackgroundMaterial.prototype, "_primaryColorShadowLevel", void 0);
__decorate([
BABYLON.serialize()
], BackgroundMaterial.prototype, "_primaryColorHighlightLevel", void 0);
__decorate([
BABYLON.expandToProperty("_markAllSubMeshesAsLightsDirty")
], BackgroundMaterial.prototype, "primaryColorHighlightLevel", null);
__decorate([
BABYLON.serializeAsTexture()
], BackgroundMaterial.prototype, "_reflectionTexture", void 0);
__decorate([
BABYLON.expandToProperty("_markAllSubMeshesAsTexturesDirty")
], BackgroundMaterial.prototype, "reflectionTexture", void 0);
__decorate([
BABYLON.serialize()
], BackgroundMaterial.prototype, "_reflectionBlur", void 0);
__decorate([
BABYLON.expandToProperty("_markAllSubMeshesAsTexturesDirty")
], BackgroundMaterial.prototype, "reflectionBlur", void 0);
__decorate([
BABYLON.serializeAsTexture()
], BackgroundMaterial.prototype, "_diffuseTexture", void 0);
__decorate([
BABYLON.expandToProperty("_markAllSubMeshesAsTexturesDirty")
], BackgroundMaterial.prototype, "diffuseTexture", void 0);
__decorate([
BABYLON.expandToProperty("_markAllSubMeshesAsTexturesDirty")
], BackgroundMaterial.prototype, "shadowLights", void 0);
__decorate([
BABYLON.serialize()
], BackgroundMaterial.prototype, "_shadowLevel", void 0);
__decorate([
BABYLON.expandToProperty("_markAllSubMeshesAsTexturesDirty")
], BackgroundMaterial.prototype, "shadowLevel", void 0);
__decorate([
BABYLON.serializeAsVector3()
], BackgroundMaterial.prototype, "_sceneCenter", void 0);
__decorate([
BABYLON.expandToProperty("_markAllSubMeshesAsTexturesDirty")
], BackgroundMaterial.prototype, "sceneCenter", void 0);
__decorate([
BABYLON.serialize()
], BackgroundMaterial.prototype, "_opacityFresnel", void 0);
__decorate([
BABYLON.expandToProperty("_markAllSubMeshesAsTexturesDirty")
], BackgroundMaterial.prototype, "opacityFresnel", void 0);
__decorate([
BABYLON.serialize()
], BackgroundMaterial.prototype, "_reflectionFresnel", void 0);
__decorate([
BABYLON.expandToProperty("_markAllSubMeshesAsTexturesDirty")
], BackgroundMaterial.prototype, "reflectionFresnel", void 0);
__decorate([
BABYLON.serialize()
], BackgroundMaterial.prototype, "_reflectionFalloffDistance", void 0);
__decorate([
BABYLON.expandToProperty("_markAllSubMeshesAsTexturesDirty")
], BackgroundMaterial.prototype, "reflectionFalloffDistance", void 0);
__decorate([
BABYLON.serialize()
], BackgroundMaterial.prototype, "_reflectionAmount", void 0);
__decorate([
BABYLON.expandToProperty("_markAllSubMeshesAsTexturesDirty")
], BackgroundMaterial.prototype, "reflectionAmount", void 0);
__decorate([
BABYLON.serialize()
], BackgroundMaterial.prototype, "_reflectionReflectance0", void 0);
__decorate([
BABYLON.expandToProperty("_markAllSubMeshesAsTexturesDirty")
], BackgroundMaterial.prototype, "reflectionReflectance0", void 0);
__decorate([
BABYLON.serialize()
], BackgroundMaterial.prototype, "_reflectionReflectance90", void 0);
__decorate([
BABYLON.expandToProperty("_markAllSubMeshesAsTexturesDirty")
], BackgroundMaterial.prototype, "reflectionReflectance90", void 0);
__decorate([
BABYLON.serialize()
], BackgroundMaterial.prototype, "_useRGBColor", void 0);
__decorate([
BABYLON.expandToProperty("_markAllSubMeshesAsTexturesDirty")
], BackgroundMaterial.prototype, "useRGBColor", void 0);
__decorate([
BABYLON.serialize()
], BackgroundMaterial.prototype, "_enableNoise", void 0);
__decorate([
BABYLON.expandToProperty("_markAllSubMeshesAsTexturesDirty")
], BackgroundMaterial.prototype, "enableNoise", void 0);
__decorate([
BABYLON.serialize()
], BackgroundMaterial.prototype, "_maxSimultaneousLights", void 0);
__decorate([
BABYLON.expandToProperty("_markAllSubMeshesAsTexturesDirty")
], BackgroundMaterial.prototype, "maxSimultaneousLights", void 0);
__decorate([
BABYLON.serializeAsImageProcessingConfiguration()
], BackgroundMaterial.prototype, "_imageProcessingConfiguration", void 0);
return BackgroundMaterial;
}(BABYLON.PushMaterial));
BABYLON.BackgroundMaterial = BackgroundMaterial;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.backgroundMaterial.js.map
var __assign = (this && this.__assign) || Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
var BABYLON;
(function (BABYLON) {
/**
* The Environment helper class can be used to add a fully featuread none expensive background to your scene.
* It includes by default a skybox and a ground relying on the BackgroundMaterial.
* It also helps with the default setup of your imageProcessing configuration.
*/
var EnvironmentHelper = /** @class */ (function () {
/**
* constructor
* @param options
* @param scene The scene to add the material to
*/
function EnvironmentHelper(options, scene) {
var _this = this;
this._errorHandler = function (message, exception) {
_this.onErrorObservable.notifyObservers({ message: message, exception: exception });
};
this._options = __assign({}, EnvironmentHelper._getDefaultOptions(), options);
this._scene = scene;
this.onErrorObservable = new BABYLON.Observable();
this._setupBackground();
this._setupImageProcessing();
}
/**
* Creates the default options for the helper.
*/
EnvironmentHelper._getDefaultOptions = function () {
return {
createGround: true,
groundSize: 15,
groundTexture: this._groundTextureCDNUrl,
groundColor: new BABYLON.Color3(0.2, 0.2, 0.3).toLinearSpace().scale(3),
groundOpacity: 0.9,
enableGroundShadow: true,
groundShadowLevel: 0.5,
enableGroundMirror: false,
groundMirrorSizeRatio: 0.3,
groundMirrorBlurKernel: 64,
groundMirrorAmount: 1,
groundMirrorFresnelWeight: 1,
groundMirrorFallOffDistance: 0,
groundMirrorTextureType: BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT,
groundYBias: 0.00001,
createSkybox: true,
skyboxSize: 20,
skyboxTexture: this._skyboxTextureCDNUrl,
skyboxColor: new BABYLON.Color3(0.2, 0.2, 0.3).toLinearSpace().scale(3),
backgroundYRotation: 0,
sizeAuto: true,
rootPosition: BABYLON.Vector3.Zero(),
setupImageProcessing: true,
environmentTexture: this._environmentTextureCDNUrl,
cameraExposure: 0.8,
cameraContrast: 1.2,
toneMappingEnabled: true,
};
};
Object.defineProperty(EnvironmentHelper.prototype, "rootMesh", {
/**
* Gets the root mesh created by the helper.
*/
get: function () {
return this._rootMesh;
},
enumerable: true,
configurable: true
});
Object.defineProperty(EnvironmentHelper.prototype, "skybox", {
/**
* Gets the skybox created by the helper.
*/
get: function () {
return this._skybox;
},
enumerable: true,
configurable: true
});
Object.defineProperty(EnvironmentHelper.prototype, "skyboxTexture", {
/**
* Gets the skybox texture created by the helper.
*/
get: function () {
return this._skyboxTexture;
},
enumerable: true,
configurable: true
});
Object.defineProperty(EnvironmentHelper.prototype, "skyboxMaterial", {
/**
* Gets the skybox material created by the helper.
*/
get: function () {
return this._skyboxMaterial;
},
enumerable: true,
configurable: true
});
Object.defineProperty(EnvironmentHelper.prototype, "ground", {
/**
* Gets the ground mesh created by the helper.
*/
get: function () {
return this._ground;
},
enumerable: true,
configurable: true
});
Object.defineProperty(EnvironmentHelper.prototype, "groundTexture", {
/**
* Gets the ground texture created by the helper.
*/
get: function () {
return this._groundTexture;
},
enumerable: true,
configurable: true
});
Object.defineProperty(EnvironmentHelper.prototype, "groundMirror", {
/**
* Gets the ground mirror created by the helper.
*/
get: function () {
return this._groundMirror;
},
enumerable: true,
configurable: true
});
Object.defineProperty(EnvironmentHelper.prototype, "groundMirrorRenderList", {
/**
* Gets the ground mirror render list to helps pushing the meshes
* you wish in the ground reflection.
*/
get: function () {
if (this._groundMirror) {
return this._groundMirror.renderList;
}
return null;
},
enumerable: true,
configurable: true
});
Object.defineProperty(EnvironmentHelper.prototype, "groundMaterial", {
/**
* Gets the ground material created by the helper.
*/
get: function () {
return this._groundMaterial;
},
enumerable: true,
configurable: true
});
/**
* Updates the background according to the new options
* @param options
*/
EnvironmentHelper.prototype.updateOptions = function (options) {
var newOptions = __assign({}, this._options, options);
if (this._ground && !newOptions.createGround) {
this._ground.dispose();
this._ground = null;
}
if (this._groundMaterial && !newOptions.createGround) {
this._groundMaterial.dispose();
this._groundMaterial = null;
}
if (this._groundTexture) {
if (this._options.groundTexture != newOptions.groundTexture) {
this._groundTexture.dispose();
this._groundTexture = null;
}
}
if (this._skybox && !newOptions.createSkybox) {
this._skybox.dispose();
this._skybox = null;
}
if (this._skyboxMaterial && !newOptions.createSkybox) {
this._skyboxMaterial.dispose();
this._skyboxMaterial = null;
}
if (this._skyboxTexture) {
if (this._options.skyboxTexture != newOptions.skyboxTexture) {
this._skyboxTexture.dispose();
this._skyboxTexture = null;
}
}
if (this._groundMirror && !newOptions.enableGroundMirror) {
this._groundMirror.dispose();
this._groundMirror = null;
}
if (this._scene.environmentTexture) {
if (this._options.environmentTexture != newOptions.environmentTexture) {
this._scene.environmentTexture.dispose();
}
}
this._options = newOptions;
this._setupBackground();
this._setupImageProcessing();
};
/**
* Sets the primary color of all the available elements.
* @param color the main color to affect to the ground and the background
*/
EnvironmentHelper.prototype.setMainColor = function (color) {
if (this.groundMaterial) {
this.groundMaterial.primaryColor = color;
}
if (this.skyboxMaterial) {
this.skyboxMaterial.primaryColor = color;
}
if (this.groundMirror) {
this.groundMirror.clearColor = new BABYLON.Color4(color.r, color.g, color.b, 1.0);
}
};
/**
* Setup the image processing according to the specified options.
*/
EnvironmentHelper.prototype._setupImageProcessing = function () {
if (this._options.setupImageProcessing) {
this._scene.imageProcessingConfiguration.contrast = this._options.cameraContrast;
this._scene.imageProcessingConfiguration.exposure = this._options.cameraExposure;
this._scene.imageProcessingConfiguration.toneMappingEnabled = this._options.toneMappingEnabled;
this._setupEnvironmentTexture();
}
};
/**
* Setup the environment texture according to the specified options.
*/
EnvironmentHelper.prototype._setupEnvironmentTexture = function () {
if (this._scene.environmentTexture) {
return;
}
if (this._options.environmentTexture instanceof BABYLON.BaseTexture) {
this._scene.environmentTexture = this._options.environmentTexture;
return;
}
var environmentTexture = BABYLON.CubeTexture.CreateFromPrefilteredData(this._options.environmentTexture, this._scene);
this._scene.environmentTexture = environmentTexture;
};
/**
* Setup the background according to the specified options.
*/
EnvironmentHelper.prototype._setupBackground = function () {
if (!this._rootMesh) {
this._rootMesh = new BABYLON.Mesh("BackgroundHelper", this._scene);
}
this._rootMesh.rotation.y = this._options.backgroundYRotation;
var sceneSize = this._getSceneSize();
if (this._options.createGround) {
this._setupGround(sceneSize);
this._setupGroundMaterial();
this._setupGroundDiffuseTexture();
if (this._options.enableGroundMirror) {
this._setupGroundMirrorTexture(sceneSize);
}
this._setupMirrorInGroundMaterial();
}
if (this._options.createSkybox) {
this._setupSkybox(sceneSize);
this._setupSkyboxMaterial();
this._setupSkyboxReflectionTexture();
}
this._rootMesh.position.x = sceneSize.rootPosition.x;
this._rootMesh.position.z = sceneSize.rootPosition.z;
this._rootMesh.position.y = sceneSize.rootPosition.y;
};
/**
* Get the scene sizes according to the setup.
*/
EnvironmentHelper.prototype._getSceneSize = function () {
var _this = this;
var groundSize = this._options.groundSize;
var skyboxSize = this._options.skyboxSize;
var rootPosition = this._options.rootPosition;
if (!this._scene.meshes || this._scene.meshes.length === 1) { // 1 only means the root of the helper.
return { groundSize: groundSize, skyboxSize: skyboxSize, rootPosition: rootPosition };
}
var sceneExtends = this._scene.getWorldExtends(function (mesh) {
return (mesh !== _this._ground && mesh !== _this._rootMesh && mesh !== _this._skybox);
});
var sceneDiagonal = sceneExtends.max.subtract(sceneExtends.min);
if (this._options.sizeAuto) {
if (this._scene.activeCamera instanceof BABYLON.ArcRotateCamera &&
this._scene.activeCamera.upperRadiusLimit) {
groundSize = this._scene.activeCamera.upperRadiusLimit * 2;
skyboxSize = groundSize;
}
var sceneDiagonalLenght = sceneDiagonal.length();
if (sceneDiagonalLenght > groundSize) {
groundSize = sceneDiagonalLenght * 2;
skyboxSize = groundSize;
}
// 10 % bigger.
groundSize *= 1.1;
skyboxSize *= 1.5;
rootPosition = sceneExtends.min.add(sceneDiagonal.scale(0.5));
rootPosition.y = sceneExtends.min.y - this._options.groundYBias;
}
return { groundSize: groundSize, skyboxSize: skyboxSize, rootPosition: rootPosition };
};
/**
* Setup the ground according to the specified options.
*/
EnvironmentHelper.prototype._setupGround = function (sceneSize) {
var _this = this;
if (!this._ground || this._ground.isDisposed()) {
this._ground = BABYLON.Mesh.CreatePlane("BackgroundPlane", sceneSize.groundSize, this._scene);
this._ground.rotation.x = Math.PI / 2; // Face up by default.
this._ground.parent = this._rootMesh;
this._ground.onDisposeObservable.add(function () { _this._ground = null; });
}
this._ground.receiveShadows = this._options.enableGroundShadow;
};
/**
* Setup the ground material according to the specified options.
*/
EnvironmentHelper.prototype._setupGroundMaterial = function () {
if (!this._groundMaterial) {
this._groundMaterial = new BABYLON.BackgroundMaterial("BackgroundPlaneMaterial", this._scene);
}
this._groundMaterial.alpha = this._options.groundOpacity;
this._groundMaterial.alphaMode = BABYLON.Engine.ALPHA_PREMULTIPLIED_PORTERDUFF;
this._groundMaterial.shadowLevel = this._options.groundShadowLevel;
this._groundMaterial.primaryColor = this._options.groundColor;
this._groundMaterial.useRGBColor = false;
this._groundMaterial.enableNoise = true;
if (this._ground) {
this._ground.material = this._groundMaterial;
}
};
/**
* Setup the ground diffuse texture according to the specified options.
*/
EnvironmentHelper.prototype._setupGroundDiffuseTexture = function () {
if (!this._groundMaterial) {
return;
}
if (this._groundTexture) {
return;
}
if (this._options.groundTexture instanceof BABYLON.BaseTexture) {
this._groundMaterial.diffuseTexture = this._options.groundTexture;
return;
}
var diffuseTexture = new BABYLON.Texture(this._options.groundTexture, this._scene, undefined, undefined, undefined, undefined, this._errorHandler);
diffuseTexture.gammaSpace = false;
diffuseTexture.hasAlpha = true;
this._groundMaterial.diffuseTexture = diffuseTexture;
};
/**
* Setup the ground mirror texture according to the specified options.
*/
EnvironmentHelper.prototype._setupGroundMirrorTexture = function (sceneSize) {
var wrapping = BABYLON.Texture.CLAMP_ADDRESSMODE;
if (!this._groundMirror) {
this._groundMirror = new BABYLON.MirrorTexture("BackgroundPlaneMirrorTexture", { ratio: this._options.groundMirrorSizeRatio }, this._scene, false, this._options.groundMirrorTextureType, BABYLON.Texture.BILINEAR_SAMPLINGMODE, true);
this._groundMirror.mirrorPlane = new BABYLON.Plane(0, -1, 0, sceneSize.rootPosition.y);
this._groundMirror.anisotropicFilteringLevel = 1;
this._groundMirror.wrapU = wrapping;
this._groundMirror.wrapV = wrapping;
this._groundMirror.gammaSpace = false;
if (this._groundMirror.renderList) {
for (var i = 0; i < this._scene.meshes.length; i++) {
var mesh = this._scene.meshes[i];
if (mesh !== this._ground &&
mesh !== this._skybox &&
mesh !== this._rootMesh) {
this._groundMirror.renderList.push(mesh);
}
}
}
}
this._groundMirror.clearColor = new BABYLON.Color4(this._options.groundColor.r, this._options.groundColor.g, this._options.groundColor.b, 1);
this._groundMirror.adaptiveBlurKernel = this._options.groundMirrorBlurKernel;
};
/**
* Setup the ground to receive the mirror texture.
*/
EnvironmentHelper.prototype._setupMirrorInGroundMaterial = function () {
if (this._groundMaterial) {
this._groundMaterial.reflectionTexture = this._groundMirror;
this._groundMaterial.reflectionFresnel = true;
this._groundMaterial.reflectionAmount = this._options.groundMirrorAmount;
this._groundMaterial.reflectionStandardFresnelWeight = this._options.groundMirrorFresnelWeight;
this._groundMaterial.reflectionFalloffDistance = this._options.groundMirrorFallOffDistance;
}
};
/**
* Setup the skybox according to the specified options.
*/
EnvironmentHelper.prototype._setupSkybox = function (sceneSize) {
var _this = this;
if (!this._skybox || this._skybox.isDisposed()) {
this._skybox = BABYLON.Mesh.CreateBox("BackgroundSkybox", sceneSize.skyboxSize, this._scene, undefined, BABYLON.Mesh.BACKSIDE);
this._skybox.onDisposeObservable.add(function () { _this._skybox = null; });
}
this._skybox.parent = this._rootMesh;
};
/**
* Setup the skybox material according to the specified options.
*/
EnvironmentHelper.prototype._setupSkyboxMaterial = function () {
if (!this._skybox) {
return;
}
if (!this._skyboxMaterial) {
this._skyboxMaterial = new BABYLON.BackgroundMaterial("BackgroundSkyboxMaterial", this._scene);
}
this._skyboxMaterial.useRGBColor = false;
this._skyboxMaterial.primaryColor = this._options.skyboxColor;
this._skyboxMaterial.enableNoise = true;
this._skybox.material = this._skyboxMaterial;
};
/**
* Setup the skybox reflection texture according to the specified options.
*/
EnvironmentHelper.prototype._setupSkyboxReflectionTexture = function () {
if (!this._skyboxMaterial) {
return;
}
if (this._skyboxTexture) {
return;
}
if (this._options.skyboxTexture instanceof BABYLON.BaseTexture) {
this._skyboxMaterial.reflectionTexture = this._options.skyboxTexture;
return;
}
this._skyboxTexture = new BABYLON.CubeTexture(this._options.skyboxTexture, this._scene, undefined, undefined, undefined, undefined, this._errorHandler);
this._skyboxTexture.coordinatesMode = BABYLON.Texture.SKYBOX_MODE;
this._skyboxTexture.gammaSpace = false;
this._skyboxMaterial.reflectionTexture = this._skyboxTexture;
};
/**
* Dispose all the elements created by the Helper.
*/
EnvironmentHelper.prototype.dispose = function () {
if (this._groundMaterial) {
this._groundMaterial.dispose(true, true);
}
if (this._skyboxMaterial) {
this._skyboxMaterial.dispose(true, true);
}
this._rootMesh.dispose(false);
};
/**
* Default ground texture URL.
*/
EnvironmentHelper._groundTextureCDNUrl = "https://assets.babylonjs.com/environments/backgroundGround.png";
/**
* Default skybox texture URL.
*/
EnvironmentHelper._skyboxTextureCDNUrl = "https://assets.babylonjs.com/environments/backgroundSkybox.dds";
/**
* Default environment texture URL.
*/
EnvironmentHelper._environmentTextureCDNUrl = "https://assets.babylonjs.com/environments/environmentSpecular.env";
return EnvironmentHelper;
}());
BABYLON.EnvironmentHelper = EnvironmentHelper;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.environmentHelper.js.map
var BABYLON;
(function (BABYLON) {
/** Internal class used to store shapes for emitters */
var ParticleSystemSetEmitterCreationOptions = /** @class */ (function () {
function ParticleSystemSetEmitterCreationOptions() {
}
return ParticleSystemSetEmitterCreationOptions;
}());
/**
* Represents a set of particle systems working together to create a specific effect
*/
var ParticleSystemSet = /** @class */ (function () {
function ParticleSystemSet() {
/**
* Gets the particle system list
*/
this.systems = new Array();
}
Object.defineProperty(ParticleSystemSet.prototype, "emitterNode", {
/**
* Gets the emitter node used with this set
*/
get: function () {
return this._emitterNode;
},
enumerable: true,
configurable: true
});
/**
* Creates a new emitter mesh as a sphere
* @param options defines the options used to create the sphere
* @param renderingGroupId defines the renderingGroupId to use for the sphere
* @param scene defines the hosting scene
*/
ParticleSystemSet.prototype.setEmitterAsSphere = function (options, renderingGroupId, scene) {
if (this._emitterNode) {
this._emitterNode.dispose();
}
this._emitterCreationOptions = {
kind: "Sphere",
options: options,
renderingGroupId: renderingGroupId
};
var emitterMesh = BABYLON.MeshBuilder.CreateSphere("emitterSphere", { diameter: options.diameter, segments: options.segments }, scene);
emitterMesh.renderingGroupId = renderingGroupId;
var material = new BABYLON.StandardMaterial("emitterSphereMaterial", scene);
material.emissiveColor = options.color;
emitterMesh.material = material;
for (var _i = 0, _a = this.systems; _i < _a.length; _i++) {
var system = _a[_i];
system.emitter = emitterMesh;
}
this._emitterNode = emitterMesh;
};
/**
* Starts all particle systems of the set
* @param emitter defines an optional mesh to use as emitter for the particle systems
*/
ParticleSystemSet.prototype.start = function (emitter) {
for (var _i = 0, _a = this.systems; _i < _a.length; _i++) {
var system = _a[_i];
if (emitter) {
system.emitter = emitter;
}
system.start();
}
};
/**
* Release all associated resources
*/
ParticleSystemSet.prototype.dispose = function () {
for (var _i = 0, _a = this.systems; _i < _a.length; _i++) {
var system = _a[_i];
system.dispose();
}
this.systems = [];
if (this._emitterNode) {
this._emitterNode.dispose();
this._emitterNode = null;
}
};
/**
* Serialize the set into a JSON compatible object
* @returns a JSON compatible representation of the set
*/
ParticleSystemSet.prototype.serialize = function () {
var result = {};
result.systems = [];
for (var _i = 0, _a = this.systems; _i < _a.length; _i++) {
var system = _a[_i];
result.systems.push(system.serialize());
}
if (this._emitterNode) {
result.emitter = this._emitterCreationOptions;
}
return result;
};
/**
* Parse a new ParticleSystemSet from a serialized source
* @param data defines a JSON compatible representation of the set
* @param scene defines the hosting scene
* @param gpu defines if we want GPU particles or CPU particles
* @returns a new ParticleSystemSet
*/
ParticleSystemSet.Parse = function (data, scene, gpu) {
if (gpu === void 0) { gpu = false; }
var result = new ParticleSystemSet();
var rootUrl = BABYLON.ParticleHelper.BaseAssetsUrl + "/textures/";
scene = scene || BABYLON.Engine.LastCreatedScene;
for (var _i = 0, _a = data.systems; _i < _a.length; _i++) {
var system = _a[_i];
result.systems.push(gpu ? BABYLON.GPUParticleSystem.Parse(system, scene, rootUrl) : BABYLON.ParticleSystem.Parse(system, scene, rootUrl));
}
if (data.emitter) {
var options = data.emitter.options;
switch (data.emitter.kind) {
case "Sphere":
result.setEmitterAsSphere({
diameter: options.diameter,
segments: options.segments,
color: BABYLON.Color3.FromArray(options.color)
}, data.emitter.renderingGroupId, scene);
break;
}
}
return result;
};
return ParticleSystemSet;
}());
BABYLON.ParticleSystemSet = ParticleSystemSet;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.particleSystemSet.js.map
var BABYLON;
(function (BABYLON) {
/**
* This class is made for on one-liner static method to help creating particle system set.
*/
var ParticleHelper = /** @class */ (function () {
function ParticleHelper() {
}
/**
* This is the main static method (one-liner) of this helper to create different particle systems
* @param type This string represents the type to the particle system to create
* @param scene The scene where the particle system should live
* @param gpu If the system will use gpu
* @returns the ParticleSystemSet created
*/
ParticleHelper.CreateAsync = function (type, scene, gpu) {
if (gpu === void 0) { gpu = false; }
if (!scene) {
scene = BABYLON.Engine.LastCreatedScene;
;
}
var token = {};
scene._addPendingData(token);
return new Promise(function (resolve, reject) {
if (gpu && !BABYLON.GPUParticleSystem.IsSupported) {
scene._removePendingData(token);
return reject("Particle system with GPU is not supported.");
}
BABYLON.Tools.LoadFile(ParticleHelper.BaseAssetsUrl + "/systems/" + type + ".json", function (data, response) {
scene._removePendingData(token);
var newData = JSON.parse(data.toString());
return resolve(BABYLON.ParticleSystemSet.Parse(newData, scene, gpu));
}, undefined, undefined, undefined, function (req, exception) {
scene._removePendingData(token);
return reject("An error occured while the creation of your particle system. Check if your type '" + type + "' exists.");
});
});
};
/**
* Static function used to export a particle system to a ParticleSystemSet variable.
* Please note that the emitter shape is not exported
* @param system defines the particle systems to export
*/
ParticleHelper.ExportSet = function (systems) {
var set = new BABYLON.ParticleSystemSet();
for (var _i = 0, systems_1 = systems; _i < systems_1.length; _i++) {
var system = systems_1[_i];
set.systems.push(system);
}
return set;
};
/**
* Gets or sets base Assets URL
*/
ParticleHelper.BaseAssetsUrl = "https://assets.babylonjs.com/particles";
return ParticleHelper;
}());
BABYLON.ParticleHelper = ParticleHelper;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.particleHelper.js.map
var BABYLON;
(function (BABYLON) {
/**
* Display a 360 degree video on an approximately spherical surface, useful for VR applications or skyboxes.
* As a subclass of Node, this allow parenting to the camera or multiple videos with different locations in the scene.
* This class achieves its effect with a VideoTexture and a correctly configured BackgroundMaterial on an inverted sphere.
* Potential additions to this helper include zoom and and non-infinite distance rendering effects.
*/
var VideoDome = /** @class */ (function (_super) {
__extends(VideoDome, _super);
/**
* Create an instance of this class and pass through the parameters to the relevant classes, VideoTexture, StandardMaterial, and Mesh.
* @param name Element's name, child elements will append suffixes for their own names.
* @param urlsOrVideo defines the url(s) or the video element to use
* @param options An object containing optional or exposed sub element properties
*/
function VideoDome(name, urlsOrVideo, options, scene) {
var _this = _super.call(this, name, scene) || this;
_this._useDirectMapping = false;
// set defaults and manage values
name = name || "videoDome";
options.resolution = (Math.abs(options.resolution) | 0) || 32;
options.clickToPlay = Boolean(options.clickToPlay);
options.autoPlay = options.autoPlay === undefined ? true : Boolean(options.autoPlay);
options.loop = options.loop === undefined ? true : Boolean(options.loop);
options.size = Math.abs(options.size) || (scene.activeCamera ? scene.activeCamera.maxZ * 0.48 : 1000);
if (options.useDirectMapping === undefined) {
_this._useDirectMapping = true;
}
else {
_this._useDirectMapping = options.useDirectMapping;
}
_this._setReady(false);
// create
var tempOptions = { loop: options.loop, autoPlay: options.autoPlay, autoUpdateTexture: true, poster: options.poster };
var material = _this._material = new BABYLON.BackgroundMaterial(name + "_material", scene);
var texture = _this._videoTexture = new BABYLON.VideoTexture(name + "_texture", urlsOrVideo, scene, false, _this._useDirectMapping, BABYLON.Texture.TRILINEAR_SAMPLINGMODE, tempOptions);
_this._mesh = BABYLON.Mesh.CreateSphere(name + "_mesh", options.resolution, options.size, scene, false, BABYLON.Mesh.BACKSIDE);
texture.onLoadObservable.addOnce(function () {
_this._setReady(true);
});
// configure material
material.useEquirectangularFOV = true;
material.fovMultiplier = 1.0;
material.opacityFresnel = false;
if (_this._useDirectMapping) {
texture.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE;
texture.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
material.diffuseTexture = texture;
}
else {
texture.coordinatesMode = BABYLON.Texture.FIXED_EQUIRECTANGULAR_MIRRORED_MODE; // matches orientation
texture.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
material.reflectionTexture = texture;
}
// configure mesh
_this._mesh.material = material;
_this._mesh.parent = _this;
// optional configuration
if (options.clickToPlay) {
scene.onPointerUp = function () {
_this._videoTexture.video.play();
};
}
return _this;
}
Object.defineProperty(VideoDome.prototype, "videoTexture", {
/**
* Gets the video texture being displayed on the sphere
*/
get: function () {
return this._videoTexture;
},
enumerable: true,
configurable: true
});
Object.defineProperty(VideoDome.prototype, "fovMultiplier", {
/**
* The current fov(field of view) multiplier, 0.0 - 2.0. Defaults to 1.0. Lower values "zoom in" and higher values "zoom out".
* Also see the options.resolution property.
*/
get: function () {
return this._material.fovMultiplier;
},
set: function (value) {
this._material.fovMultiplier = value;
},
enumerable: true,
configurable: true
});
/**
* Releases resources associated with this node.
* @param doNotRecurse Set to true to not recurse into each children (recurse into each children by default)
* @param disposeMaterialAndTextures Set to true to also dispose referenced materials and textures (false by default)
*/
VideoDome.prototype.dispose = function (doNotRecurse, disposeMaterialAndTextures) {
if (disposeMaterialAndTextures === void 0) { disposeMaterialAndTextures = false; }
this._videoTexture.dispose();
this._mesh.dispose();
this._material.dispose();
_super.prototype.dispose.call(this, doNotRecurse, disposeMaterialAndTextures);
};
return VideoDome;
}(BABYLON.Node));
BABYLON.VideoDome = VideoDome;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.videoDome.js.map
var BABYLON;
(function (BABYLON) {
/**
* Display a 360 degree photo on an approximately spherical surface, useful for VR applications or skyboxes.
* As a subclass of Node, this allow parenting to the camera with different locations in the scene.
* This class achieves its effect with a Texture and a correctly configured BackgroundMaterial on an inverted sphere.
* Potential additions to this helper include zoom and and non-infinite distance rendering effects.
*/
var PhotoDome = /** @class */ (function (_super) {
__extends(PhotoDome, _super);
/**
* Create an instance of this class and pass through the parameters to the relevant classes, Texture, StandardMaterial, and Mesh.
* @param name Element's name, child elements will append suffixes for their own names.
* @param urlsOfPhoto define the url of the photo to display
* @param options An object containing optional or exposed sub element properties
*/
function PhotoDome(name, urlOfPhoto, options, scene) {
var _this = _super.call(this, name, scene) || this;
_this._useDirectMapping = false;
// set defaults and manage values
name = name || "photoDome";
options.resolution = (Math.abs(options.resolution) | 0) || 32;
options.size = Math.abs(options.size) || (scene.activeCamera ? scene.activeCamera.maxZ * 0.48 : 1000);
if (options.useDirectMapping === undefined) {
_this._useDirectMapping = true;
}
else {
_this._useDirectMapping = options.useDirectMapping;
}
_this._setReady(false);
// create
var material = _this._material = new BABYLON.BackgroundMaterial(name + "_material", scene);
_this._mesh = BABYLON.Mesh.CreateSphere(name + "_mesh", options.resolution, options.size, scene, false, BABYLON.Mesh.BACKSIDE);
// configure material
material.opacityFresnel = false;
material.useEquirectangularFOV = true;
material.fovMultiplier = 1.0;
_this.photoTexture = new BABYLON.Texture(urlOfPhoto, scene, true, !_this._useDirectMapping);
_this.photoTexture.onLoadObservable.addOnce(function () {
_this._setReady(true);
});
// configure mesh
_this._mesh.material = material;
_this._mesh.parent = _this;
return _this;
}
Object.defineProperty(PhotoDome.prototype, "photoTexture", {
/**
* Gets or sets the texture being displayed on the sphere
*/
get: function () {
return this._photoTexture;
},
set: function (value) {
if (this._photoTexture === value) {
return;
}
this._photoTexture = value;
if (this._useDirectMapping) {
this._photoTexture.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE;
this._photoTexture.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
this._material.diffuseTexture = this._photoTexture;
}
else {
this._photoTexture.coordinatesMode = BABYLON.Texture.FIXED_EQUIRECTANGULAR_MIRRORED_MODE; // matches orientation
this._photoTexture.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
this._material.reflectionTexture = this._photoTexture;
}
},
enumerable: true,
configurable: true
});
Object.defineProperty(PhotoDome.prototype, "fovMultiplier", {
/**
* The current fov(field of view) multiplier, 0.0 - 2.0. Defaults to 1.0. Lower values "zoom in" and higher values "zoom out".
* Also see the options.resolution property.
*/
get: function () {
return this._material.fovMultiplier;
},
set: function (value) {
this._material.fovMultiplier = value;
},
enumerable: true,
configurable: true
});
/**
* Releases resources associated with this node.
* @param doNotRecurse Set to true to not recurse into each children (recurse into each children by default)
* @param disposeMaterialAndTextures Set to true to also dispose referenced materials and textures (false by default)
*/
PhotoDome.prototype.dispose = function (doNotRecurse, disposeMaterialAndTextures) {
if (disposeMaterialAndTextures === void 0) { disposeMaterialAndTextures = false; }
this._photoTexture.dispose();
this._mesh.dispose();
this._material.dispose();
_super.prototype.dispose.call(this, doNotRecurse, disposeMaterialAndTextures);
};
return PhotoDome;
}(BABYLON.Node));
BABYLON.PhotoDome = PhotoDome;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.photoDome.js.map
var BABYLON;
(function (BABYLON) {
BABYLON.Engine.prototype.createQuery = function () {
return this._gl.createQuery();
};
BABYLON.Engine.prototype.deleteQuery = function (query) {
this._gl.deleteQuery(query);
return this;
};
BABYLON.Engine.prototype.isQueryResultAvailable = function (query) {
return this._gl.getQueryParameter(query, this._gl.QUERY_RESULT_AVAILABLE);
};
BABYLON.Engine.prototype.getQueryResult = function (query) {
return this._gl.getQueryParameter(query, this._gl.QUERY_RESULT);
};
BABYLON.Engine.prototype.beginOcclusionQuery = function (algorithmType, query) {
var glAlgorithm = this._getGlAlgorithmType(algorithmType);
this._gl.beginQuery(glAlgorithm, query);
return this;
};
BABYLON.Engine.prototype.endOcclusionQuery = function (algorithmType) {
var glAlgorithm = this._getGlAlgorithmType(algorithmType);
this._gl.endQuery(glAlgorithm);
return this;
};
BABYLON.Engine.prototype._createTimeQuery = function () {
var timerQuery = this.getCaps().timerQuery;
if (timerQuery.createQueryEXT) {
return timerQuery.createQueryEXT();
}
return this.createQuery();
};
BABYLON.Engine.prototype._deleteTimeQuery = function (query) {
var timerQuery = this.getCaps().timerQuery;
if (timerQuery.deleteQueryEXT) {
timerQuery.deleteQueryEXT(query);
return;
}
this.deleteQuery(query);
};
BABYLON.Engine.prototype._getTimeQueryResult = function (query) {
var timerQuery = this.getCaps().timerQuery;
if (timerQuery.getQueryObjectEXT) {
return timerQuery.getQueryObjectEXT(query, timerQuery.QUERY_RESULT_EXT);
}
return this.getQueryResult(query);
};
BABYLON.Engine.prototype._getTimeQueryAvailability = function (query) {
var timerQuery = this.getCaps().timerQuery;
if (timerQuery.getQueryObjectEXT) {
return timerQuery.getQueryObjectEXT(query, timerQuery.QUERY_RESULT_AVAILABLE_EXT);
}
return this.isQueryResultAvailable(query);
};
BABYLON.Engine.prototype.startTimeQuery = function () {
var caps = this.getCaps();
var timerQuery = caps.timerQuery;
if (!timerQuery) {
return null;
}
var token = new BABYLON._TimeToken();
this._gl.getParameter(timerQuery.GPU_DISJOINT_EXT);
if (caps.canUseTimestampForTimerQuery) {
token._startTimeQuery = this._createTimeQuery();
timerQuery.queryCounterEXT(token._startTimeQuery, timerQuery.TIMESTAMP_EXT);
}
else {
if (this._currentNonTimestampToken) {
return this._currentNonTimestampToken;
}
token._timeElapsedQuery = this._createTimeQuery();
if (timerQuery.beginQueryEXT) {
timerQuery.beginQueryEXT(timerQuery.TIME_ELAPSED_EXT, token._timeElapsedQuery);
}
else {
this._gl.beginQuery(timerQuery.TIME_ELAPSED_EXT, token._timeElapsedQuery);
}
this._currentNonTimestampToken = token;
}
return token;
};
BABYLON.Engine.prototype.endTimeQuery = function (token) {
var caps = this.getCaps();
var timerQuery = caps.timerQuery;
if (!timerQuery || !token) {
return -1;
}
if (caps.canUseTimestampForTimerQuery) {
if (!token._startTimeQuery) {
return -1;
}
if (!token._endTimeQuery) {
token._endTimeQuery = this._createTimeQuery();
timerQuery.queryCounterEXT(token._endTimeQuery, timerQuery.TIMESTAMP_EXT);
}
}
else if (!token._timeElapsedQueryEnded) {
if (!token._timeElapsedQuery) {
return -1;
}
if (timerQuery.endQueryEXT) {
timerQuery.endQueryEXT(timerQuery.TIME_ELAPSED_EXT);
}
else {
this._gl.endQuery(timerQuery.TIME_ELAPSED_EXT);
}
token._timeElapsedQueryEnded = true;
}
var disjoint = this._gl.getParameter(timerQuery.GPU_DISJOINT_EXT);
var available = false;
if (token._endTimeQuery) {
available = this._getTimeQueryAvailability(token._endTimeQuery);
}
else if (token._timeElapsedQuery) {
available = this._getTimeQueryAvailability(token._timeElapsedQuery);
}
if (available && !disjoint) {
var result = 0;
if (caps.canUseTimestampForTimerQuery) {
if (!token._startTimeQuery || !token._endTimeQuery) {
return -1;
}
var timeStart = this._getTimeQueryResult(token._startTimeQuery);
var timeEnd = this._getTimeQueryResult(token._endTimeQuery);
result = timeEnd - timeStart;
this._deleteTimeQuery(token._startTimeQuery);
this._deleteTimeQuery(token._endTimeQuery);
token._startTimeQuery = null;
token._endTimeQuery = null;
}
else {
if (!token._timeElapsedQuery) {
return -1;
}
result = this._getTimeQueryResult(token._timeElapsedQuery);
this._deleteTimeQuery(token._timeElapsedQuery);
token._timeElapsedQuery = null;
token._timeElapsedQueryEnded = false;
this._currentNonTimestampToken = null;
}
return result;
}
return -1;
};
BABYLON.Engine.prototype._getGlAlgorithmType = function (algorithmType) {
return algorithmType === BABYLON.AbstractMesh.OCCLUSION_ALGORITHM_TYPE_CONSERVATIVE ? this._gl.ANY_SAMPLES_PASSED_CONSERVATIVE : this._gl.ANY_SAMPLES_PASSED;
};
// We also need to update AbstractMesh as there is a portion of the code there
BABYLON.AbstractMesh.prototype._checkOcclusionQuery = function () {
var engine = this.getEngine();
if (!engine.isQueryResultAvailable) { // Occlusion query where not referenced
this._isOccluded = false;
return;
}
if (engine.webGLVersion < 2 || this.occlusionType === BABYLON.AbstractMesh.OCCLUSION_TYPE_NONE) {
this._isOccluded = false;
return;
}
if (this.isOcclusionQueryInProgress && this._occlusionQuery) {
var isOcclusionQueryAvailable = engine.isQueryResultAvailable(this._occlusionQuery);
if (isOcclusionQueryAvailable) {
var occlusionQueryResult = engine.getQueryResult(this._occlusionQuery);
this._isOcclusionQueryInProgress = false;
this._occlusionInternalRetryCounter = 0;
this._isOccluded = occlusionQueryResult === 1 ? false : true;
}
else {
this._occlusionInternalRetryCounter++;
if (this.occlusionRetryCount !== -1 && this._occlusionInternalRetryCounter > this.occlusionRetryCount) {
this._isOcclusionQueryInProgress = false;
this._occlusionInternalRetryCounter = 0;
// if optimistic set isOccluded to false regardless of the status of isOccluded. (Render in the current render loop)
// if strict continue the last state of the object.
this._isOccluded = this.occlusionType === BABYLON.AbstractMesh.OCCLUSION_TYPE_OPTIMISTIC ? false : this._isOccluded;
}
else {
return;
}
}
}
var scene = this.getScene();
if (scene.getBoundingBoxRenderer) {
var occlusionBoundingBoxRenderer = scene.getBoundingBoxRenderer();
if (!this._occlusionQuery) {
this._occlusionQuery = engine.createQuery();
}
engine.beginOcclusionQuery(this.occlusionQueryAlgorithmType, this._occlusionQuery);
occlusionBoundingBoxRenderer.renderOcclusionBoundingBox(this);
engine.endOcclusionQuery(this.occlusionQueryAlgorithmType);
this._isOcclusionQueryInProgress = true;
}
};
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.engine.occlusionQuery.js.map
var BABYLON;
(function (BABYLON) {
/**
* Class used to generate noise procedural textures
*/
var NoiseProceduralTexture = /** @class */ (function (_super) {
__extends(NoiseProceduralTexture, _super);
/**
* Creates a new NoiseProceduralTexture
* @param name defines the name fo the texture
* @param size defines the size of the texture (default is 256)
* @param scene defines the hosting scene
* @param fallbackTexture defines the texture to use if the NoiseProceduralTexture can't be created
* @param generateMipMaps defines if mipmaps must be generated (true by default)
*/
function NoiseProceduralTexture(name, size, scene, fallbackTexture, generateMipMaps) {
if (size === void 0) { size = 256; }
if (scene === void 0) { scene = BABYLON.Engine.LastCreatedScene; }
var _this = _super.call(this, name, size, "noise", scene, fallbackTexture, generateMipMaps) || this;
_this._time = 0;
/** Gets or sets a value between 0 and 1 indicating the overall brightness of the texture (default is 0.2) */
_this.brightness = 0.2;
/** Defines the number of octaves to process */
_this.octaves = 3;
/** Defines the level of persistence (0.8 by default) */
_this.persistence = 0.8;
/** Gets or sets animation speed factor (default is 1) */
_this.animationSpeedFactor = 1;
_this._updateShaderUniforms();
return _this;
}
NoiseProceduralTexture.prototype._updateShaderUniforms = function () {
var scene = this.getScene();
if (!scene) {
return;
}
this._time += scene.getAnimationRatio() * this.animationSpeedFactor * 0.01;
this.setFloat("brightness", this.brightness);
this.setInt("octaves", this.octaves);
this.setFloat("persistence", this.persistence);
this.setFloat("timeScale", this._time);
};
/** Generate the current state of the procedural texture */
NoiseProceduralTexture.prototype.render = function (useCameraPostProcess) {
this._updateShaderUniforms();
_super.prototype.render.call(this, useCameraPostProcess);
};
/**
* Serializes this noise procedural texture
* @returns a serialized noise procedural texture object
*/
NoiseProceduralTexture.prototype.serialize = function () {
var serializationObject = BABYLON.SerializationHelper.Serialize(this, _super.prototype.serialize.call(this));
serializationObject.customType = "BABYLON.NoiseProceduralTexture";
return serializationObject;
};
/**
* Creates a NoiseProceduralTexture from parsed noise procedural texture data
* @param parsedTexture defines parsed texture data
* @param scene defines the current scene
* @param rootUrl defines the root URL containing noise procedural texture information
* @returns a parsed NoiseProceduralTexture
*/
NoiseProceduralTexture.Parse = function (parsedTexture, scene, rootUrl) {
var texture = BABYLON.SerializationHelper.Parse(function () { return new NoiseProceduralTexture(parsedTexture.name, parsedTexture._size, scene, undefined, parsedTexture._generateMipMaps); }, parsedTexture, scene, rootUrl);
return texture;
};
return NoiseProceduralTexture;
}(BABYLON.ProceduralTexture));
BABYLON.NoiseProceduralTexture = NoiseProceduralTexture;
})(BABYLON || (BABYLON = {}));
//# sourceMappingURL=babylon.noiseProceduralTexture.js.map
BABYLON.Effect.ShadersStore={"defaultVertexShader":"#include<__decl__defaultVertex>\n\n#define CUSTOM_VERTEX_BEGIN\nattribute vec3 position;\n#ifdef NORMAL\nattribute vec3 normal;\n#endif\n#ifdef TANGENT\nattribute vec4 tangent;\n#endif\n#ifdef UV1\nattribute vec2 uv;\n#endif\n#ifdef UV2\nattribute vec2 uv2;\n#endif\n#ifdef VERTEXCOLOR\nattribute vec4 color;\n#endif\n#include\n#include\n\n#include\n#ifdef MAINUV1\nvarying vec2 vMainUV1;\n#endif\n#ifdef MAINUV2\nvarying vec2 vMainUV2;\n#endif\n#if defined(DIFFUSE) && DIFFUSEDIRECTUV == 0\nvarying vec2 vDiffuseUV;\n#endif\n#if defined(AMBIENT) && AMBIENTDIRECTUV == 0\nvarying vec2 vAmbientUV;\n#endif\n#if defined(OPACITY) && OPACITYDIRECTUV == 0\nvarying vec2 vOpacityUV;\n#endif\n#if defined(EMISSIVE) && EMISSIVEDIRECTUV == 0\nvarying vec2 vEmissiveUV;\n#endif\n#if defined(LIGHTMAP) && LIGHTMAPDIRECTUV == 0\nvarying vec2 vLightmapUV;\n#endif\n#if defined(SPECULAR) && defined(SPECULARTERM) && SPECULARDIRECTUV == 0\nvarying vec2 vSpecularUV;\n#endif\n#if defined(BUMP) && BUMPDIRECTUV == 0\nvarying vec2 vBumpUV;\n#endif\n\nvarying vec3 vPositionW;\n#ifdef NORMAL\nvarying vec3 vNormalW;\n#endif\n#ifdef VERTEXCOLOR\nvarying vec4 vColor;\n#endif\n#include\n#include\n#include\n#include<__decl__lightFragment>[0..maxSimultaneousLights]\n#include\n#include[0..maxSimultaneousMorphTargets]\n#ifdef REFLECTIONMAP_SKYBOX\nvarying vec3 vPositionUVW;\n#endif\n#if defined(REFLECTIONMAP_EQUIRECTANGULAR_FIXED) || defined(REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED)\nvarying vec3 vDirectionW;\n#endif\n#include\n#define CUSTOM_VERTEX_DEFINITIONS\nvoid main(void) {\n#define CUSTOM_VERTEX_MAIN_BEGIN\nvec3 positionUpdated=position;\n#ifdef NORMAL \nvec3 normalUpdated=normal;\n#endif\n#ifdef TANGENT\nvec4 tangentUpdated=tangent;\n#endif\n#include[0..maxSimultaneousMorphTargets]\n#ifdef REFLECTIONMAP_SKYBOX\nvPositionUVW=positionUpdated;\n#endif \n#define CUSTOM_VERTEX_UPDATE_POSITION\n#define CUSTOM_VERTEX_UPDATE_NORMAL\n#include\n#include\ngl_Position=viewProjection*finalWorld*vec4(positionUpdated,1.0);\nvec4 worldPos=finalWorld*vec4(positionUpdated,1.0);\nvPositionW=vec3(worldPos);\n#ifdef NORMAL\nmat3 normalWorld=mat3(finalWorld);\n#ifdef NONUNIFORMSCALING\nnormalWorld=transposeMat3(inverseMat3(normalWorld));\n#endif\nvNormalW=normalize(normalWorld*normalUpdated);\n#endif\n#if defined(REFLECTIONMAP_EQUIRECTANGULAR_FIXED) || defined(REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED)\nvDirectionW=normalize(vec3(finalWorld*vec4(positionUpdated,0.0)));\n#endif\n\n#ifndef UV1\nvec2 uv=vec2(0.,0.);\n#endif\n#ifndef UV2\nvec2 uv2=vec2(0.,0.);\n#endif\n#ifdef MAINUV1\nvMainUV1=uv;\n#endif\n#ifdef MAINUV2\nvMainUV2=uv2;\n#endif\n#if defined(DIFFUSE) && DIFFUSEDIRECTUV == 0\nif (vDiffuseInfos.x == 0.)\n{\nvDiffuseUV=vec2(diffuseMatrix*vec4(uv,1.0,0.0));\n}\nelse\n{\nvDiffuseUV=vec2(diffuseMatrix*vec4(uv2,1.0,0.0));\n}\n#endif\n#if defined(AMBIENT) && AMBIENTDIRECTUV == 0\nif (vAmbientInfos.x == 0.)\n{\nvAmbientUV=vec2(ambientMatrix*vec4(uv,1.0,0.0));\n}\nelse\n{\nvAmbientUV=vec2(ambientMatrix*vec4(uv2,1.0,0.0));\n}\n#endif\n#if defined(OPACITY) && OPACITYDIRECTUV == 0\nif (vOpacityInfos.x == 0.)\n{\nvOpacityUV=vec2(opacityMatrix*vec4(uv,1.0,0.0));\n}\nelse\n{\nvOpacityUV=vec2(opacityMatrix*vec4(uv2,1.0,0.0));\n}\n#endif\n#if defined(EMISSIVE) && EMISSIVEDIRECTUV == 0\nif (vEmissiveInfos.x == 0.)\n{\nvEmissiveUV=vec2(emissiveMatrix*vec4(uv,1.0,0.0));\n}\nelse\n{\nvEmissiveUV=vec2(emissiveMatrix*vec4(uv2,1.0,0.0));\n}\n#endif\n#if defined(LIGHTMAP) && LIGHTMAPDIRECTUV == 0\nif (vLightmapInfos.x == 0.)\n{\nvLightmapUV=vec2(lightmapMatrix*vec4(uv,1.0,0.0));\n}\nelse\n{\nvLightmapUV=vec2(lightmapMatrix*vec4(uv2,1.0,0.0));\n}\n#endif\n#if defined(SPECULAR) && defined(SPECULARTERM) && SPECULARDIRECTUV == 0\nif (vSpecularInfos.x == 0.)\n{\nvSpecularUV=vec2(specularMatrix*vec4(uv,1.0,0.0));\n}\nelse\n{\nvSpecularUV=vec2(specularMatrix*vec4(uv2,1.0,0.0));\n}\n#endif\n#if defined(BUMP) && BUMPDIRECTUV == 0\nif (vBumpInfos.x == 0.)\n{\nvBumpUV=vec2(bumpMatrix*vec4(uv,1.0,0.0));\n}\nelse\n{\nvBumpUV=vec2(bumpMatrix*vec4(uv2,1.0,0.0));\n}\n#endif\n#include\n#include\n#include\n#include[0..maxSimultaneousLights]\n#ifdef VERTEXCOLOR\n\nvColor=color;\n#endif\n#include\n#include\n#define CUSTOM_VERTEX_MAIN_END\n}\n","defaultPixelShader":"#include<__decl__defaultFragment>\n#if defined(BUMP) || !defined(NORMAL)\n#extension GL_OES_standard_derivatives : enable\n#endif\n#define CUSTOM_FRAGMENT_BEGIN\n#ifdef LOGARITHMICDEPTH\n#extension GL_EXT_frag_depth : enable\n#endif\n\n#define RECIPROCAL_PI2 0.15915494\nuniform vec3 vEyePosition;\nuniform vec3 vAmbientColor;\n\nvarying vec3 vPositionW;\n#ifdef NORMAL\nvarying vec3 vNormalW;\n#endif\n#ifdef VERTEXCOLOR\nvarying vec4 vColor;\n#endif\n#ifdef MAINUV1\nvarying vec2 vMainUV1;\n#endif\n#ifdef MAINUV2\nvarying vec2 vMainUV2;\n#endif\n\n#include\n\n#include<__decl__lightFragment>[0..maxSimultaneousLights]\n#include\n#include\n\n#ifdef DIFFUSE\n#if DIFFUSEDIRECTUV == 1\n#define vDiffuseUV vMainUV1\n#elif DIFFUSEDIRECTUV == 2\n#define vDiffuseUV vMainUV2\n#else\nvarying vec2 vDiffuseUV;\n#endif\nuniform sampler2D diffuseSampler;\n#endif\n#ifdef AMBIENT\n#if AMBIENTDIRECTUV == 1\n#define vAmbientUV vMainUV1\n#elif AMBIENTDIRECTUV == 2\n#define vAmbientUV vMainUV2\n#else\nvarying vec2 vAmbientUV;\n#endif\nuniform sampler2D ambientSampler;\n#endif\n#ifdef OPACITY \n#if OPACITYDIRECTUV == 1\n#define vOpacityUV vMainUV1\n#elif OPACITYDIRECTUV == 2\n#define vOpacityUV vMainUV2\n#else\nvarying vec2 vOpacityUV;\n#endif\nuniform sampler2D opacitySampler;\n#endif\n#ifdef EMISSIVE\n#if EMISSIVEDIRECTUV == 1\n#define vEmissiveUV vMainUV1\n#elif EMISSIVEDIRECTUV == 2\n#define vEmissiveUV vMainUV2\n#else\nvarying vec2 vEmissiveUV;\n#endif\nuniform sampler2D emissiveSampler;\n#endif\n#ifdef LIGHTMAP\n#if LIGHTMAPDIRECTUV == 1\n#define vLightmapUV vMainUV1\n#elif LIGHTMAPDIRECTUV == 2\n#define vLightmapUV vMainUV2\n#else\nvarying vec2 vLightmapUV;\n#endif\nuniform sampler2D lightmapSampler;\n#endif\n#ifdef REFRACTION\n#ifdef REFRACTIONMAP_3D\nuniform samplerCube refractionCubeSampler;\n#else\nuniform sampler2D refraction2DSampler;\n#endif\n#endif\n#if defined(SPECULAR) && defined(SPECULARTERM)\n#if SPECULARDIRECTUV == 1\n#define vSpecularUV vMainUV1\n#elif SPECULARDIRECTUV == 2\n#define vSpecularUV vMainUV2\n#else\nvarying vec2 vSpecularUV;\n#endif\nuniform sampler2D specularSampler;\n#endif\n#ifdef ALPHATEST\nuniform float alphaCutOff;\n#endif\n\n#include\n\n#ifdef REFLECTION\n#ifdef REFLECTIONMAP_3D\nuniform samplerCube reflectionCubeSampler;\n#else\nuniform sampler2D reflection2DSampler;\n#endif\n#ifdef REFLECTIONMAP_SKYBOX\nvarying vec3 vPositionUVW;\n#else\n#if defined(REFLECTIONMAP_EQUIRECTANGULAR_FIXED) || defined(REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED)\nvarying vec3 vDirectionW;\n#endif\n#endif\n#include\n#endif\n#include\n#include\n#include\n#include\n#include\n#include\n#define CUSTOM_FRAGMENT_DEFINITIONS\nvoid main(void) {\n#define CUSTOM_FRAGMENT_MAIN_BEGIN\n#include\nvec3 viewDirectionW=normalize(vEyePosition-vPositionW);\n\nvec4 baseColor=vec4(1.,1.,1.,1.);\nvec3 diffuseColor=vDiffuseColor.rgb;\n\nfloat alpha=vDiffuseColor.a;\n\n#ifdef NORMAL\nvec3 normalW=normalize(vNormalW);\n#else\nvec3 normalW=normalize(-cross(dFdx(vPositionW),dFdy(vPositionW)));\n#endif\n#include\n#ifdef TWOSIDEDLIGHTING\nnormalW=gl_FrontFacing ? normalW : -normalW;\n#endif\n#ifdef DIFFUSE\nbaseColor=texture2D(diffuseSampler,vDiffuseUV+uvOffset);\n#ifdef ALPHATEST\nif (baseColor.a\n#ifdef VERTEXCOLOR\nbaseColor.rgb*=vColor.rgb;\n#endif\n#define CUSTOM_FRAGMENT_UPDATE_DIFFUSE\n\nvec3 baseAmbientColor=vec3(1.,1.,1.);\n#ifdef AMBIENT\nbaseAmbientColor=texture2D(ambientSampler,vAmbientUV+uvOffset).rgb*vAmbientInfos.y;\n#endif\n#define CUSTOM_FRAGMENT_BEFORE_LIGHTS\n\n#ifdef SPECULARTERM\nfloat glossiness=vSpecularColor.a;\nvec3 specularColor=vSpecularColor.rgb;\n#ifdef SPECULAR\nvec4 specularMapColor=texture2D(specularSampler,vSpecularUV+uvOffset);\nspecularColor=specularMapColor.rgb;\n#ifdef GLOSSINESS\nglossiness=glossiness*specularMapColor.a;\n#endif\n#endif\n#else\nfloat glossiness=0.;\n#endif\n\nvec3 diffuseBase=vec3(0.,0.,0.);\nlightingInfo info;\n#ifdef SPECULARTERM\nvec3 specularBase=vec3(0.,0.,0.);\n#endif\nfloat shadow=1.;\n#ifdef LIGHTMAP\nvec3 lightmapColor=texture2D(lightmapSampler,vLightmapUV+uvOffset).rgb*vLightmapInfos.y;\n#endif\n#include[0..maxSimultaneousLights]\n\nvec3 refractionColor=vec3(0.,0.,0.);\n#ifdef REFRACTION\nvec3 refractionVector=normalize(refract(-viewDirectionW,normalW,vRefractionInfos.y));\n#ifdef REFRACTIONMAP_3D\nrefractionVector.y=refractionVector.y*vRefractionInfos.w;\nif (dot(refractionVector,viewDirectionW)<1.0) {\nrefractionColor=textureCube(refractionCubeSampler,refractionVector).rgb;\n}\n#else\nvec3 vRefractionUVW=vec3(refractionMatrix*(view*vec4(vPositionW+refractionVector*vRefractionInfos.z,1.0)));\nvec2 refractionCoords=vRefractionUVW.xy/vRefractionUVW.z;\nrefractionCoords.y=1.0-refractionCoords.y;\nrefractionColor=texture2D(refraction2DSampler,refractionCoords).rgb;\n#endif\n#ifdef IS_REFRACTION_LINEAR\nrefractionColor=toGammaSpace(refractionColor);\n#endif\nrefractionColor*=vRefractionInfos.x;\n#endif\n\nvec3 reflectionColor=vec3(0.,0.,0.);\n#ifdef REFLECTION\nvec3 vReflectionUVW=computeReflectionCoords(vec4(vPositionW,1.0),normalW);\n#ifdef REFLECTIONMAP_3D\n#ifdef ROUGHNESS\nfloat bias=vReflectionInfos.y;\n#ifdef SPECULARTERM\n#ifdef SPECULAR\n#ifdef GLOSSINESS\nbias*=(1.0-specularMapColor.a);\n#endif\n#endif\n#endif\nreflectionColor=textureCube(reflectionCubeSampler,vReflectionUVW,bias).rgb;\n#else\nreflectionColor=textureCube(reflectionCubeSampler,vReflectionUVW).rgb;\n#endif\n#else\nvec2 coords=vReflectionUVW.xy;\n#ifdef REFLECTIONMAP_PROJECTION\ncoords/=vReflectionUVW.z;\n#endif\ncoords.y=1.0-coords.y;\nreflectionColor=texture2D(reflection2DSampler,coords).rgb;\n#endif\n#ifdef IS_REFLECTION_LINEAR\nreflectionColor=toGammaSpace(reflectionColor);\n#endif\nreflectionColor*=vReflectionInfos.x;\n#ifdef REFLECTIONFRESNEL\nfloat reflectionFresnelTerm=computeFresnelTerm(viewDirectionW,normalW,reflectionRightColor.a,reflectionLeftColor.a);\n#ifdef REFLECTIONFRESNELFROMSPECULAR\n#ifdef SPECULARTERM\nreflectionColor*=specularColor.rgb*(1.0-reflectionFresnelTerm)+reflectionFresnelTerm*reflectionRightColor.rgb;\n#else\nreflectionColor*=reflectionLeftColor.rgb*(1.0-reflectionFresnelTerm)+reflectionFresnelTerm*reflectionRightColor.rgb;\n#endif\n#else\nreflectionColor*=reflectionLeftColor.rgb*(1.0-reflectionFresnelTerm)+reflectionFresnelTerm*reflectionRightColor.rgb;\n#endif\n#endif\n#endif\n#ifdef REFRACTIONFRESNEL\nfloat refractionFresnelTerm=computeFresnelTerm(viewDirectionW,normalW,refractionRightColor.a,refractionLeftColor.a);\nrefractionColor*=refractionLeftColor.rgb*(1.0-refractionFresnelTerm)+refractionFresnelTerm*refractionRightColor.rgb;\n#endif\n#ifdef OPACITY\nvec4 opacityMap=texture2D(opacitySampler,vOpacityUV+uvOffset);\n#ifdef OPACITYRGB\nopacityMap.rgb=opacityMap.rgb*vec3(0.3,0.59,0.11);\nalpha*=(opacityMap.x+opacityMap.y+opacityMap.z)* vOpacityInfos.y;\n#else\nalpha*=opacityMap.a*vOpacityInfos.y;\n#endif\n#endif\n#ifdef VERTEXALPHA\nalpha*=vColor.a;\n#endif\n#ifdef OPACITYFRESNEL\nfloat opacityFresnelTerm=computeFresnelTerm(viewDirectionW,normalW,opacityParts.z,opacityParts.w);\nalpha+=opacityParts.x*(1.0-opacityFresnelTerm)+opacityFresnelTerm*opacityParts.y;\n#endif\n\nvec3 emissiveColor=vEmissiveColor;\n#ifdef EMISSIVE\nemissiveColor+=texture2D(emissiveSampler,vEmissiveUV+uvOffset).rgb*vEmissiveInfos.y;\n#endif\n#ifdef EMISSIVEFRESNEL\nfloat emissiveFresnelTerm=computeFresnelTerm(viewDirectionW,normalW,emissiveRightColor.a,emissiveLeftColor.a);\nemissiveColor*=emissiveLeftColor.rgb*(1.0-emissiveFresnelTerm)+emissiveFresnelTerm*emissiveRightColor.rgb;\n#endif\n\n#ifdef DIFFUSEFRESNEL\nfloat diffuseFresnelTerm=computeFresnelTerm(viewDirectionW,normalW,diffuseRightColor.a,diffuseLeftColor.a);\ndiffuseBase*=diffuseLeftColor.rgb*(1.0-diffuseFresnelTerm)+diffuseFresnelTerm*diffuseRightColor.rgb;\n#endif\n\n#ifdef EMISSIVEASILLUMINATION\nvec3 finalDiffuse=clamp(diffuseBase*diffuseColor+vAmbientColor,0.0,1.0)*baseColor.rgb;\n#else\n#ifdef LINKEMISSIVEWITHDIFFUSE\nvec3 finalDiffuse=clamp((diffuseBase+emissiveColor)*diffuseColor+vAmbientColor,0.0,1.0)*baseColor.rgb;\n#else\nvec3 finalDiffuse=clamp(diffuseBase*diffuseColor+emissiveColor+vAmbientColor,0.0,1.0)*baseColor.rgb;\n#endif\n#endif\n#ifdef SPECULARTERM\nvec3 finalSpecular=specularBase*specularColor;\n#ifdef SPECULAROVERALPHA\nalpha=clamp(alpha+dot(finalSpecular,vec3(0.3,0.59,0.11)),0.,1.);\n#endif\n#else\nvec3 finalSpecular=vec3(0.0);\n#endif\n#ifdef REFLECTIONOVERALPHA\nalpha=clamp(alpha+dot(reflectionColor,vec3(0.3,0.59,0.11)),0.,1.);\n#endif\n\n#ifdef EMISSIVEASILLUMINATION\nvec4 color=vec4(clamp(finalDiffuse*baseAmbientColor+finalSpecular+reflectionColor+emissiveColor+refractionColor,0.0,1.0),alpha);\n#else\nvec4 color=vec4(finalDiffuse*baseAmbientColor+finalSpecular+reflectionColor+refractionColor,alpha);\n#endif\n\n#ifdef LIGHTMAP\n#ifndef LIGHTMAPEXCLUDED\n#ifdef USELIGHTMAPASSHADOWMAP\ncolor.rgb*=lightmapColor;\n#else\ncolor.rgb+=lightmapColor;\n#endif\n#endif\n#endif\n#define CUSTOM_FRAGMENT_BEFORE_FOG\ncolor.rgb=max(color.rgb,0.);\n#include\n#include\n\n\n#ifdef IMAGEPROCESSINGPOSTPROCESS\ncolor.rgb=toLinearSpace(color.rgb);\n#else\n#ifdef IMAGEPROCESSING\ncolor.rgb=toLinearSpace(color.rgb);\ncolor=applyImageProcessing(color);\n#endif\n#endif\n#ifdef PREMULTIPLYALPHA\n\ncolor.rgb*=color.a;\n#endif\n#define CUSTOM_FRAGMENT_BEFORE_FRAGCOLOR\ngl_FragColor=color;\n}\n","pbrVertexShader":"precision highp float;\n#include<__decl__pbrVertex>\n\nattribute vec3 position;\n#ifdef NORMAL\nattribute vec3 normal;\n#endif\n#ifdef TANGENT\nattribute vec4 tangent;\n#endif\n#ifdef UV1\nattribute vec2 uv;\n#endif\n#ifdef UV2\nattribute vec2 uv2;\n#endif\n#ifdef MAINUV1\nvarying vec2 vMainUV1;\n#endif\n#ifdef MAINUV2\nvarying vec2 vMainUV2; \n#endif \n#ifdef VERTEXCOLOR\nattribute vec4 color;\n#endif\n#include\n#include\n\n#include\n#if defined(ALBEDO) && ALBEDODIRECTUV == 0\nvarying vec2 vAlbedoUV;\n#endif\n#if defined(AMBIENT) && AMBIENTDIRECTUV == 0\nvarying vec2 vAmbientUV;\n#endif\n#if defined(OPACITY) && OPACITYDIRECTUV == 0\nvarying vec2 vOpacityUV;\n#endif\n#if defined(EMISSIVE) && EMISSIVEDIRECTUV == 0\nvarying vec2 vEmissiveUV;\n#endif\n#if defined(LIGHTMAP) && LIGHTMAPDIRECTUV == 0\nvarying vec2 vLightmapUV;\n#endif\n#if defined(REFLECTIVITY) && REFLECTIVITYDIRECTUV == 0\nvarying vec2 vReflectivityUV;\n#endif\n#if defined(MICROSURFACEMAP) && MICROSURFACEMAPDIRECTUV == 0\nvarying vec2 vMicroSurfaceSamplerUV;\n#endif\n#if defined(BUMP) && BUMPDIRECTUV == 0\nvarying vec2 vBumpUV;\n#endif\n\nvarying vec3 vPositionW;\n#ifdef NORMAL\nvarying vec3 vNormalW;\n#if defined(USESPHERICALFROMREFLECTIONMAP) && defined(USESPHERICALINVERTEX)\nvarying vec3 vEnvironmentIrradiance;\n#include\n#endif\n#endif\n#ifdef VERTEXCOLOR\nvarying vec4 vColor;\n#endif\n#include\n#include\n#include\n#include<__decl__lightFragment>[0..maxSimultaneousLights]\n#include\n#include[0..maxSimultaneousMorphTargets]\n#ifdef REFLECTIONMAP_SKYBOX\nvarying vec3 vPositionUVW;\n#endif\n#if defined(REFLECTIONMAP_EQUIRECTANGULAR_FIXED) || defined(REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED)\nvarying vec3 vDirectionW;\n#endif\n#include\nvoid main(void) {\nvec3 positionUpdated=position;\n#ifdef NORMAL\nvec3 normalUpdated=normal;\n#endif\n#ifdef TANGENT\nvec4 tangentUpdated=tangent;\n#endif\n#include[0..maxSimultaneousMorphTargets]\n#ifdef REFLECTIONMAP_SKYBOX\nvPositionUVW=positionUpdated;\n#endif \n#include\n#include\ngl_Position=viewProjection*finalWorld*vec4(positionUpdated,1.0);\nvec4 worldPos=finalWorld*vec4(positionUpdated,1.0);\nvPositionW=vec3(worldPos);\n#ifdef NORMAL\nmat3 normalWorld=mat3(finalWorld);\n#ifdef NONUNIFORMSCALING\nnormalWorld=transposeMat3(inverseMat3(normalWorld));\n#endif\nvNormalW=normalize(normalWorld*normalUpdated);\n#if defined(USESPHERICALFROMREFLECTIONMAP) && defined(USESPHERICALINVERTEX)\nvec3 reflectionVector=vec3(reflectionMatrix*vec4(vNormalW,0)).xyz;\n#ifdef REFLECTIONMAP_OPPOSITEZ\nreflectionVector.z*=-1.0;\n#endif\nvEnvironmentIrradiance=environmentIrradianceJones(reflectionVector);\n#endif\n#endif\n#if defined(REFLECTIONMAP_EQUIRECTANGULAR_FIXED) || defined(REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED)\nvDirectionW=normalize(vec3(finalWorld*vec4(positionUpdated,0.0)));\n#endif\n\n#ifndef UV1\nvec2 uv=vec2(0.,0.);\n#endif\n#ifndef UV2\nvec2 uv2=vec2(0.,0.);\n#endif\n#ifdef MAINUV1\nvMainUV1=uv;\n#endif \n#ifdef MAINUV2\nvMainUV2=uv2;\n#endif \n#if defined(ALBEDO) && ALBEDODIRECTUV == 0 \nif (vAlbedoInfos.x == 0.)\n{\nvAlbedoUV=vec2(albedoMatrix*vec4(uv,1.0,0.0));\n}\nelse\n{\nvAlbedoUV=vec2(albedoMatrix*vec4(uv2,1.0,0.0));\n}\n#endif\n#if defined(AMBIENT) && AMBIENTDIRECTUV == 0 \nif (vAmbientInfos.x == 0.)\n{\nvAmbientUV=vec2(ambientMatrix*vec4(uv,1.0,0.0));\n}\nelse\n{\nvAmbientUV=vec2(ambientMatrix*vec4(uv2,1.0,0.0));\n}\n#endif\n#if defined(OPACITY) && OPACITYDIRECTUV == 0 \nif (vOpacityInfos.x == 0.)\n{\nvOpacityUV=vec2(opacityMatrix*vec4(uv,1.0,0.0));\n}\nelse\n{\nvOpacityUV=vec2(opacityMatrix*vec4(uv2,1.0,0.0));\n}\n#endif\n#if defined(EMISSIVE) && EMISSIVEDIRECTUV == 0 \nif (vEmissiveInfos.x == 0.)\n{\nvEmissiveUV=vec2(emissiveMatrix*vec4(uv,1.0,0.0));\n}\nelse\n{\nvEmissiveUV=vec2(emissiveMatrix*vec4(uv2,1.0,0.0));\n}\n#endif\n#if defined(LIGHTMAP) && LIGHTMAPDIRECTUV == 0 \nif (vLightmapInfos.x == 0.)\n{\nvLightmapUV=vec2(lightmapMatrix*vec4(uv,1.0,0.0));\n}\nelse\n{\nvLightmapUV=vec2(lightmapMatrix*vec4(uv2,1.0,0.0));\n}\n#endif\n#if defined(REFLECTIVITY) && REFLECTIVITYDIRECTUV == 0 \nif (vReflectivityInfos.x == 0.)\n{\nvReflectivityUV=vec2(reflectivityMatrix*vec4(uv,1.0,0.0));\n}\nelse\n{\nvReflectivityUV=vec2(reflectivityMatrix*vec4(uv2,1.0,0.0));\n}\n#endif\n#if defined(MICROSURFACEMAP) && MICROSURFACEMAPDIRECTUV == 0 \nif (vMicroSurfaceSamplerInfos.x == 0.)\n{\nvMicroSurfaceSamplerUV=vec2(microSurfaceSamplerMatrix*vec4(uv,1.0,0.0));\n}\nelse\n{\nvMicroSurfaceSamplerUV=vec2(microSurfaceSamplerMatrix*vec4(uv2,1.0,0.0));\n}\n#endif\n#if defined(BUMP) && BUMPDIRECTUV == 0 \nif (vBumpInfos.x == 0.)\n{\nvBumpUV=vec2(bumpMatrix*vec4(uv,1.0,0.0));\n}\nelse\n{\nvBumpUV=vec2(bumpMatrix*vec4(uv2,1.0,0.0));\n}\n#endif\n\n#include\n\n#include\n\n#include\n\n#include[0..maxSimultaneousLights]\n\n#ifdef VERTEXCOLOR\nvColor=color;\n#endif\n\n#ifdef POINTSIZE\ngl_PointSize=pointSize;\n#endif\n\n#include\n}","pbrPixelShader":"#if defined(BUMP) || !defined(NORMAL) || defined(FORCENORMALFORWARD) || defined(SPECULARAA)\n#extension GL_OES_standard_derivatives : enable\n#endif\n#ifdef LODBASEDMICROSFURACE\n#extension GL_EXT_shader_texture_lod : enable\n#endif\n#ifdef LOGARITHMICDEPTH\n#extension GL_EXT_frag_depth : enable\n#endif\nprecision highp float;\n#include<__decl__pbrFragment>\nuniform vec4 vEyePosition;\nuniform vec3 vAmbientColor;\nuniform vec4 vCameraInfos;\n\nvarying vec3 vPositionW;\n#ifdef MAINUV1\nvarying vec2 vMainUV1;\n#endif \n#ifdef MAINUV2 \nvarying vec2 vMainUV2;\n#endif \n#ifdef NORMAL\nvarying vec3 vNormalW;\n#if defined(USESPHERICALFROMREFLECTIONMAP) && defined(USESPHERICALINVERTEX)\nvarying vec3 vEnvironmentIrradiance;\n#endif\n#endif\n#ifdef VERTEXCOLOR\nvarying vec4 vColor;\n#endif\n\n#include<__decl__lightFragment>[0..maxSimultaneousLights]\n\n#ifdef ALBEDO\n#if ALBEDODIRECTUV == 1\n#define vAlbedoUV vMainUV1\n#elif ALBEDODIRECTUV == 2\n#define vAlbedoUV vMainUV2\n#else\nvarying vec2 vAlbedoUV;\n#endif\nuniform sampler2D albedoSampler;\n#endif\n#ifdef AMBIENT\n#if AMBIENTDIRECTUV == 1\n#define vAmbientUV vMainUV1\n#elif AMBIENTDIRECTUV == 2\n#define vAmbientUV vMainUV2\n#else\nvarying vec2 vAmbientUV;\n#endif\nuniform sampler2D ambientSampler;\n#endif\n#ifdef OPACITY\n#if OPACITYDIRECTUV == 1\n#define vOpacityUV vMainUV1\n#elif OPACITYDIRECTUV == 2\n#define vOpacityUV vMainUV2\n#else\nvarying vec2 vOpacityUV;\n#endif\nuniform sampler2D opacitySampler;\n#endif\n#ifdef EMISSIVE\n#if EMISSIVEDIRECTUV == 1\n#define vEmissiveUV vMainUV1\n#elif EMISSIVEDIRECTUV == 2\n#define vEmissiveUV vMainUV2\n#else\nvarying vec2 vEmissiveUV;\n#endif\nuniform sampler2D emissiveSampler;\n#endif\n#ifdef LIGHTMAP\n#if LIGHTMAPDIRECTUV == 1\n#define vLightmapUV vMainUV1\n#elif LIGHTMAPDIRECTUV == 2\n#define vLightmapUV vMainUV2\n#else\nvarying vec2 vLightmapUV;\n#endif\nuniform sampler2D lightmapSampler;\n#endif\n#ifdef REFLECTIVITY\n#if REFLECTIVITYDIRECTUV == 1\n#define vReflectivityUV vMainUV1\n#elif REFLECTIVITYDIRECTUV == 2\n#define vReflectivityUV vMainUV2\n#else\nvarying vec2 vReflectivityUV;\n#endif\nuniform sampler2D reflectivitySampler;\n#endif\n#ifdef MICROSURFACEMAP\n#if MICROSURFACEMAPDIRECTUV == 1\n#define vMicroSurfaceSamplerUV vMainUV1\n#elif MICROSURFACEMAPDIRECTUV == 2\n#define vMicroSurfaceSamplerUV vMainUV2\n#else\nvarying vec2 vMicroSurfaceSamplerUV;\n#endif\nuniform sampler2D microSurfaceSampler;\n#endif\n\n#ifdef REFRACTION\n#ifdef REFRACTIONMAP_3D\n#define sampleRefraction(s,c) textureCube(s,c)\nuniform samplerCube refractionSampler;\n#ifdef LODBASEDMICROSFURACE\n#define sampleRefractionLod(s,c,l) textureCubeLodEXT(s,c,l)\n#else\nuniform samplerCube refractionSamplerLow;\nuniform samplerCube refractionSamplerHigh;\n#endif\n#else\n#define sampleRefraction(s,c) texture2D(s,c)\nuniform sampler2D refractionSampler;\n#ifdef LODBASEDMICROSFURACE\n#define sampleRefractionLod(s,c,l) texture2DLodEXT(s,c,l)\n#else\nuniform samplerCube refractionSamplerLow;\nuniform samplerCube refractionSamplerHigh;\n#endif\n#endif\n#endif\n\n#ifdef REFLECTION\n#ifdef REFLECTIONMAP_3D\n#define sampleReflection(s,c) textureCube(s,c)\nuniform samplerCube reflectionSampler;\n#ifdef LODBASEDMICROSFURACE\n#define sampleReflectionLod(s,c,l) textureCubeLodEXT(s,c,l)\n#else\nuniform samplerCube reflectionSamplerLow;\nuniform samplerCube reflectionSamplerHigh;\n#endif\n#else\n#define sampleReflection(s,c) texture2D(s,c)\nuniform sampler2D reflectionSampler;\n#ifdef LODBASEDMICROSFURACE\n#define sampleReflectionLod(s,c,l) texture2DLodEXT(s,c,l)\n#else\nuniform samplerCube reflectionSamplerLow;\nuniform samplerCube reflectionSamplerHigh;\n#endif\n#endif\n#ifdef REFLECTIONMAP_SKYBOX\nvarying vec3 vPositionUVW;\n#else\n#if defined(REFLECTIONMAP_EQUIRECTANGULAR_FIXED) || defined(REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED)\nvarying vec3 vDirectionW;\n#endif\n#endif\n#include\n#endif\n#ifdef ENVIRONMENTBRDF\nuniform sampler2D environmentBrdfSampler;\n#endif\n\n#ifndef FROMLINEARSPACE\n#define FROMLINEARSPACE;\n#endif\n#include\n#include\n#include\n\n#include\n#include\n#include\n#include\n#include\n#include\n#include\n\n#include\nvoid main(void) {\n#include\n\n\nvec3 viewDirectionW=normalize(vEyePosition.xyz-vPositionW);\n#ifdef NORMAL\nvec3 normalW=normalize(vNormalW);\n#else\nvec3 normalW=normalize(cross(dFdx(vPositionW),dFdy(vPositionW)))*vEyePosition.w;\n#endif\n#include\n#ifdef SPECULARAA\nvec3 nDfdx=dFdx(normalW.xyz);\nvec3 nDfdy=dFdy(normalW.xyz);\nfloat slopeSquare=max(dot(nDfdx,nDfdx),dot(nDfdy,nDfdy));\n\nfloat geometricRoughnessFactor=pow(clamp(slopeSquare ,0.,1.),0.333);\n\nfloat geometricAlphaGFactor=sqrt(slopeSquare);\n#else\nfloat geometricRoughnessFactor=0.;\n#endif\n#if defined(FORCENORMALFORWARD) && defined(NORMAL)\nvec3 faceNormal=normalize(cross(dFdx(vPositionW),dFdy(vPositionW)))*vEyePosition.w;\n#if defined(TWOSIDEDLIGHTING)\nfaceNormal=gl_FrontFacing ? faceNormal : -faceNormal;\n#endif\nnormalW*=sign(dot(normalW,faceNormal));\n#endif\n#if defined(TWOSIDEDLIGHTING) && defined(NORMAL)\nnormalW=gl_FrontFacing ? normalW : -normalW;\n#endif\n\n\nvec3 surfaceAlbedo=vAlbedoColor.rgb;\n\nfloat alpha=vAlbedoColor.a;\n#ifdef ALBEDO\nvec4 albedoTexture=texture2D(albedoSampler,vAlbedoUV+uvOffset);\n#if defined(ALPHAFROMALBEDO) || defined(ALPHATEST)\nalpha*=albedoTexture.a;\n#endif\nsurfaceAlbedo*=toLinearSpace(albedoTexture.rgb);\nsurfaceAlbedo*=vAlbedoInfos.y;\n#endif\n\n#ifdef OPACITY\nvec4 opacityMap=texture2D(opacitySampler,vOpacityUV+uvOffset);\n#ifdef OPACITYRGB\nalpha=getLuminance(opacityMap.rgb);\n#else\nalpha*=opacityMap.a;\n#endif\nalpha*=vOpacityInfos.y;\n#endif\n#ifdef VERTEXALPHA\nalpha*=vColor.a;\n#endif\n#if !defined(LINKREFRACTIONTOTRANSPARENCY) && !defined(ALPHAFRESNEL)\n#ifdef ALPHATEST\nif (alpha\n#ifdef VERTEXCOLOR\nsurfaceAlbedo*=vColor.rgb;\n#endif\n\nvec3 ambientOcclusionColor=vec3(1.,1.,1.);\n#ifdef AMBIENT\nvec3 ambientOcclusionColorMap=texture2D(ambientSampler,vAmbientUV+uvOffset).rgb*vAmbientInfos.y;\n#ifdef AMBIENTINGRAYSCALE\nambientOcclusionColorMap=vec3(ambientOcclusionColorMap.r,ambientOcclusionColorMap.r,ambientOcclusionColorMap.r);\n#endif\nambientOcclusionColor=mix(ambientOcclusionColor,ambientOcclusionColorMap,vAmbientInfos.z);\n#endif\n#ifdef UNLIT\nvec3 diffuseBase=vec3(1.,1.,1.);\n#else\n\nfloat microSurface=vReflectivityColor.a;\nvec3 surfaceReflectivityColor=vReflectivityColor.rgb;\n#ifdef METALLICWORKFLOW\nvec2 metallicRoughness=surfaceReflectivityColor.rg;\n#ifdef REFLECTIVITY\nvec4 surfaceMetallicColorMap=texture2D(reflectivitySampler,vReflectivityUV+uvOffset);\n#ifdef AOSTOREINMETALMAPRED\nvec3 aoStoreInMetalMap=vec3(surfaceMetallicColorMap.r,surfaceMetallicColorMap.r,surfaceMetallicColorMap.r);\nambientOcclusionColor=mix(ambientOcclusionColor,aoStoreInMetalMap,vReflectivityInfos.z);\n#endif\n#ifdef METALLNESSSTOREINMETALMAPBLUE\nmetallicRoughness.r*=surfaceMetallicColorMap.b;\n#else\nmetallicRoughness.r*=surfaceMetallicColorMap.r;\n#endif\n#ifdef ROUGHNESSSTOREINMETALMAPALPHA\nmetallicRoughness.g*=surfaceMetallicColorMap.a;\n#else\n#ifdef ROUGHNESSSTOREINMETALMAPGREEN\nmetallicRoughness.g*=surfaceMetallicColorMap.g;\n#endif\n#endif\n#endif\n#ifdef MICROSURFACEMAP\nvec4 microSurfaceTexel=texture2D(microSurfaceSampler,vMicroSurfaceSamplerUV+uvOffset)*vMicroSurfaceSamplerInfos.y;\nmetallicRoughness.g*=microSurfaceTexel.r;\n#endif\n\nmicroSurface=1.0-metallicRoughness.g;\n\nvec3 baseColor=surfaceAlbedo;\n\n\nconst vec3 DefaultSpecularReflectanceDielectric=vec3(0.04,0.04,0.04);\n\nsurfaceAlbedo=mix(baseColor.rgb*(1.0-DefaultSpecularReflectanceDielectric.r),vec3(0.,0.,0.),metallicRoughness.r);\n\nsurfaceReflectivityColor=mix(DefaultSpecularReflectanceDielectric,baseColor,metallicRoughness.r);\n#else\n#ifdef REFLECTIVITY\nvec4 surfaceReflectivityColorMap=texture2D(reflectivitySampler,vReflectivityUV+uvOffset);\nsurfaceReflectivityColor*=toLinearSpace(surfaceReflectivityColorMap.rgb);\nsurfaceReflectivityColor*=vReflectivityInfos.y;\n#ifdef MICROSURFACEFROMREFLECTIVITYMAP\nmicroSurface*=surfaceReflectivityColorMap.a;\nmicroSurface*=vReflectivityInfos.z;\n#else\n#ifdef MICROSURFACEAUTOMATIC\nmicroSurface*=computeDefaultMicroSurface(microSurface,surfaceReflectivityColor);\n#endif\n#ifdef MICROSURFACEMAP\nvec4 microSurfaceTexel=texture2D(microSurfaceSampler,vMicroSurfaceSamplerUV+uvOffset)*vMicroSurfaceSamplerInfos.y;\nmicroSurface*=microSurfaceTexel.r;\n#endif\n#endif\n#endif\n#endif\n\nmicroSurface=clamp(microSurface,0.,1.);\n\nfloat roughness=1.-microSurface;\n\n#ifdef ALPHAFRESNEL\n#if defined(ALPHATEST) || defined(ALPHABLEND)\n\n\n\nfloat opacityPerceptual=alpha;\n#ifdef LINEARALPHAFRESNEL\nfloat opacity0=opacityPerceptual;\n#else\nfloat opacity0=opacityPerceptual*opacityPerceptual;\n#endif\nfloat opacity90=fresnelGrazingReflectance(opacity0);\nvec3 normalForward=faceforward(normalW,-viewDirectionW,normalW);\n\nalpha=fresnelSchlickEnvironmentGGX(clamp(dot(viewDirectionW,normalForward),0.0,1.0),vec3(opacity0),vec3(opacity90),sqrt(microSurface)).x;\n#ifdef ALPHATEST\nif (alpha[0..maxSimultaneousLights]\n\n#if defined(ENVIRONMENTBRDF) && !defined(REFLECTIONMAP_SKYBOX)\n\nvec2 brdfSamplerUV=vec2(NdotV,roughness);\n\nvec4 environmentBrdf=texture2D(environmentBrdfSampler,brdfSamplerUV);\nvec3 specularEnvironmentReflectance=specularEnvironmentR0*environmentBrdf.x+environmentBrdf.y;\n#ifdef RADIANCEOCCLUSION\n#ifdef AMBIENTINGRAYSCALE\nfloat ambientMonochrome=ambientOcclusionColor.r;\n#else\nfloat ambientMonochrome=getLuminance(ambientOcclusionColor);\n#endif\nfloat seo=environmentRadianceOcclusion(ambientMonochrome,NdotVUnclamped);\nspecularEnvironmentReflectance*=seo;\n#endif\n#ifdef HORIZONOCCLUSION\n#ifdef BUMP\n#ifdef REFLECTIONMAP_3D\nfloat eho=environmentHorizonOcclusion(-viewDirectionW,normalW);\nspecularEnvironmentReflectance*=eho;\n#endif\n#endif\n#endif\n#else\n\nvec3 specularEnvironmentReflectance=fresnelSchlickEnvironmentGGX(NdotV,specularEnvironmentR0,specularEnvironmentR90,sqrt(microSurface));\n#endif\n\n#ifdef REFRACTION\nvec3 refractance=vec3(0.0,0.0,0.0);\nvec3 transmission=vec3(1.0,1.0,1.0);\n#ifdef LINKREFRACTIONTOTRANSPARENCY\n\ntransmission*=(1.0-alpha);\n\n\nvec3 mixedAlbedo=surfaceAlbedo;\nfloat maxChannel=max(max(mixedAlbedo.r,mixedAlbedo.g),mixedAlbedo.b);\nvec3 tint=clamp(maxChannel*mixedAlbedo,0.0,1.0);\n\nsurfaceAlbedo*=alpha;\n\nenvironmentIrradiance*=alpha;\n\nenvironmentRefraction.rgb*=tint;\n\nalpha=1.0;\n#endif\n\nvec3 bounceSpecularEnvironmentReflectance=(2.0*specularEnvironmentReflectance)/(1.0+specularEnvironmentReflectance);\nspecularEnvironmentReflectance=mix(bounceSpecularEnvironmentReflectance,specularEnvironmentReflectance,alpha);\n\ntransmission*=1.0-specularEnvironmentReflectance;\n\nrefractance=transmission;\n#endif\n\n\n\n\nsurfaceAlbedo.rgb=(1.-reflectance)*surfaceAlbedo.rgb;\n\n#ifdef REFLECTION\nvec3 finalIrradiance=environmentIrradiance;\nfinalIrradiance*=surfaceAlbedo.rgb;\n#endif\n\n#ifdef SPECULARTERM\nvec3 finalSpecular=specularBase;\nfinalSpecular=max(finalSpecular,0.0);\n\nvec3 finalSpecularScaled=finalSpecular*vLightingIntensity.x*vLightingIntensity.w;\n#endif\n\n#ifdef REFLECTION\nvec3 finalRadiance=environmentRadiance.rgb;\nfinalRadiance*=specularEnvironmentReflectance;\n\nvec3 finalRadianceScaled=finalRadiance*vLightingIntensity.z;\n#endif\n\n#ifdef REFRACTION\nvec3 finalRefraction=environmentRefraction.rgb;\nfinalRefraction*=refractance;\n#endif\n\n#ifdef ALPHABLEND\nfloat luminanceOverAlpha=0.0;\n#if defined(REFLECTION) && defined(RADIANCEOVERALPHA)\nluminanceOverAlpha+=getLuminance(finalRadianceScaled);\n#endif\n#if defined(SPECULARTERM) && defined(SPECULAROVERALPHA)\nluminanceOverAlpha+=getLuminance(finalSpecularScaled);\n#endif\n#if defined(RADIANCEOVERALPHA) || defined(SPECULAROVERALPHA)\nalpha=clamp(alpha+luminanceOverAlpha*luminanceOverAlpha,0.,1.);\n#endif\n#endif\n#endif\n\nvec3 finalDiffuse=diffuseBase;\nfinalDiffuse.rgb+=vAmbientColor;\nfinalDiffuse*=surfaceAlbedo.rgb;\nfinalDiffuse=max(finalDiffuse,0.0);\n\nvec3 finalEmissive=vEmissiveColor;\n#ifdef EMISSIVE\nvec3 emissiveColorTex=texture2D(emissiveSampler,vEmissiveUV+uvOffset).rgb;\nfinalEmissive*=toLinearSpace(emissiveColorTex.rgb);\nfinalEmissive*=vEmissiveInfos.y;\n#endif\n\n\n\nvec4 finalColor=vec4(\nfinalDiffuse*ambientOcclusionColor*vLightingIntensity.x +\n#ifndef UNLIT\n#ifdef REFLECTION\nfinalIrradiance*ambientOcclusionColor*vLightingIntensity.z +\n#endif\n#ifdef SPECULARTERM\n\n\nfinalSpecularScaled +\n#endif\n#ifdef REFLECTION\n\n\nfinalRadianceScaled +\n#endif\n#ifdef REFRACTION\nfinalRefraction*vLightingIntensity.z +\n#endif\n#endif\nfinalEmissive*vLightingIntensity.y,\nalpha);\n\n#ifdef LIGHTMAP\n#ifndef LIGHTMAPEXCLUDED\n#ifdef USELIGHTMAPASSHADOWMAP\nfinalColor.rgb*=lightmapColor;\n#else\nfinalColor.rgb+=lightmapColor;\n#endif\n#endif\n#endif\n\nfinalColor=max(finalColor,0.0);\n#include\n#include(color,finalColor)\n#ifdef IMAGEPROCESSINGPOSTPROCESS\n\n\nfinalColor.rgb=clamp(finalColor.rgb,0.,30.0);\n#else\n\nfinalColor=applyImageProcessing(finalColor);\n#endif\n#ifdef PREMULTIPLYALPHA\n\nfinalColor.rgb*=finalColor.a;\n#endif\ngl_FragColor=finalColor;\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n}","rgbdEncodePixelShader":"\nvarying vec2 vUV;\nuniform sampler2D textureSampler;\n#include\nvoid main(void) \n{\ngl_FragColor=toRGBD(texture2D(textureSampler,vUV).rgb);\n}","rgbdDecodePixelShader":"\nvarying vec2 vUV;\nuniform sampler2D textureSampler;\n#include\nvoid main(void) \n{\ngl_FragColor=vec4(fromRGBD(texture2D(textureSampler,vUV)),1.0);\n}","spritesVertexShader":"\nattribute vec4 position;\nattribute vec4 options;\nattribute vec4 cellInfo;\nattribute vec4 color;\n\nuniform vec2 textureInfos;\nuniform mat4 view;\nuniform mat4 projection;\n\nvarying vec2 vUV;\nvarying vec4 vColor;\n#include\nvoid main(void) { \nvec3 viewPos=(view*vec4(position.xyz,1.0)).xyz; \nvec2 cornerPos;\nfloat angle=position.w;\nvec2 size=vec2(options.x,options.y);\nvec2 offset=options.zw;\nvec2 uvScale=textureInfos.xy;\ncornerPos=vec2(offset.x-0.5,offset.y-0.5)*size;\n\nvec3 rotatedCorner;\nrotatedCorner.x=cornerPos.x*cos(angle)-cornerPos.y*sin(angle);\nrotatedCorner.y=cornerPos.x*sin(angle)+cornerPos.y*cos(angle);\nrotatedCorner.z=0.;\n\nviewPos+=rotatedCorner;\ngl_Position=projection*vec4(viewPos,1.0); \n\nvColor=color;\n\nvec2 uvOffset=vec2(abs(offset.x-cellInfo.x),1.0-abs(offset.y-cellInfo.y));\nvUV=(uvOffset+cellInfo.zw)*uvScale;\n\n#ifdef FOG\nvFogDistance=viewPos;\n#endif\n}","spritesPixelShader":"uniform bool alphaTest;\nvarying vec4 vColor;\n\nvarying vec2 vUV;\nuniform sampler2D diffuseSampler;\n\n#include\nvoid main(void) {\nvec4 color=texture2D(diffuseSampler,vUV);\nif (alphaTest) \n{\nif (color.a<0.95)\ndiscard;\n}\ncolor*=vColor;\n#include\ngl_FragColor=color;\n}","particlesVertexShader":"\nattribute vec3 position;\nattribute vec4 color;\nattribute float angle;\nattribute vec2 size;\n#ifdef ANIMATESHEET \nattribute float cellIndex;\n#endif\n#ifndef BILLBOARD \nattribute vec3 direction;\n#endif\nattribute vec2 offset;\n\nuniform mat4 view;\nuniform mat4 projection;\nuniform vec2 translationPivot;\n#ifdef ANIMATESHEET \nuniform vec3 particlesInfos; \n#endif\n\nvarying vec2 vUV;\nvarying vec4 vColor;\n#ifdef CLIPPLANE\nuniform vec4 vClipPlane;\nuniform mat4 invView;\nvarying float fClipDistance;\n#endif\n#ifdef BILLBOARD\nuniform vec3 eyePosition; \n#endif\nvec3 rotate(vec3 yaxis,vec3 rotatedCorner) {\nvec3 xaxis=normalize(cross(vec3(0.,1.0,0.),yaxis));\nvec3 zaxis=normalize(cross(yaxis,xaxis));\nvec3 row0=vec3(xaxis.x,xaxis.y,xaxis.z);\nvec3 row1=vec3(yaxis.x,yaxis.y,yaxis.z);\nvec3 row2=vec3(zaxis.x,zaxis.y,zaxis.z);\nmat3 rotMatrix=mat3(row0,row1,row2);\nvec3 alignedCorner=rotMatrix*rotatedCorner;\nreturn position+alignedCorner; \n}\nvoid main(void) { \nvec2 cornerPos;\ncornerPos=(vec2(offset.x-0.5,offset.y-0.5)-translationPivot)*size+translationPivot;\n#ifdef BILLBOARD \n\nvec3 rotatedCorner;\n#ifdef BILLBOARDY \nrotatedCorner.x=cornerPos.x*cos(angle)-cornerPos.y*sin(angle);\nrotatedCorner.z=cornerPos.x*sin(angle)+cornerPos.y*cos(angle);\nrotatedCorner.y=0.;\nvec3 yaxis=position-eyePosition;\nyaxis.y=0.;\nvec3 worldPos=rotate(normalize(yaxis),rotatedCorner);\nvec3 viewPos=(view*vec4(worldPos,1.0)).xyz; \n#else\nrotatedCorner.x=cornerPos.x*cos(angle)-cornerPos.y*sin(angle);\nrotatedCorner.y=cornerPos.x*sin(angle)+cornerPos.y*cos(angle);\nrotatedCorner.z=0.;\nvec3 viewPos=(view*vec4(position,1.0)).xyz+rotatedCorner; \n#endif\n\ngl_Position=projection*vec4(viewPos,1.0); \n#else\n\nvec3 rotatedCorner;\nrotatedCorner.x=cornerPos.x*cos(angle)-cornerPos.y*sin(angle);\nrotatedCorner.z=cornerPos.x*sin(angle)+cornerPos.y*cos(angle);\nrotatedCorner.y=0.;\nvec3 yaxis=normalize(direction);\nvec3 worldPos=rotate(yaxis,rotatedCorner);\ngl_Position=projection*view*vec4(worldPos,1.0); \n#endif \nvColor=color;\n#ifdef ANIMATESHEET\nfloat rowOffset=floor(cellIndex/particlesInfos.z);\nfloat columnOffset=cellIndex-rowOffset*particlesInfos.z;\nvec2 uvScale=particlesInfos.xy;\nvec2 uvOffset=vec2(offset.x ,1.0-offset.y);\nvUV=(uvOffset+vec2(columnOffset,rowOffset))*uvScale;\n#else\nvUV=offset;\n#endif\n\n#ifdef CLIPPLANE\nvec4 worldPos=invView*vec4(viewPos,1.0);\nfClipDistance=dot(worldPos,vClipPlane);\n#endif\n}","particlesPixelShader":"\nvarying vec2 vUV;\nvarying vec4 vColor;\nuniform vec4 textureMask;\nuniform sampler2D diffuseSampler;\n#ifdef CLIPPLANE\nvarying float fClipDistance;\n#endif\nvoid main(void) {\n#ifdef CLIPPLANE\nif (fClipDistance>0.0)\ndiscard;\n#endif\nvec4 baseColor=texture2D(diffuseSampler,vUV);\ngl_FragColor=(baseColor*textureMask+(vec4(1.,1.,1.,1.)-textureMask))*vColor;\n}","colorVertexShader":"\nattribute vec3 position;\n#ifdef VERTEXCOLOR\nattribute vec4 color;\n#endif\n#include\n\nuniform mat4 viewProjection;\nuniform mat4 world;\n\n#ifdef VERTEXCOLOR\nvarying vec4 vColor;\n#endif\nvoid main(void) {\nmat4 finalWorld=world;\n#include\ngl_Position=viewProjection*finalWorld*vec4(position,1.0);\n#ifdef VERTEXCOLOR\n\nvColor=color;\n#endif\n}","colorPixelShader":"#ifdef VERTEXCOLOR\nvarying vec4 vColor;\n#else\nuniform vec4 color;\n#endif\nvoid main(void) {\n#ifdef VERTEXCOLOR\ngl_FragColor=vColor;\n#else\ngl_FragColor=color;\n#endif\n}","gpuRenderParticlesVertexShader":"#version 300 es\nuniform mat4 view;\nuniform mat4 projection;\nuniform vec2 translationPivot;\n\nin vec3 position;\nin float age;\nin float life;\nin vec3 size;\n#ifndef BILLBOARD\nin vec3 initialDirection;\n#endif\nin float angle;\n#ifdef ANIMATESHEET\nin float cellIndex;\n#endif\nin vec2 offset;\nin vec2 uv;\nout vec2 vUV;\nout vec4 vColor;\n#ifdef CLIPPLANE\nuniform vec4 vClipPlane;\nuniform mat4 invView;\nout float fClipDistance;\n#endif\n#ifdef COLORGRADIENTS\nuniform sampler2D colorGradientSampler;\n#else\nuniform vec4 colorDead;\nin vec4 color;\n#endif\n#ifdef ANIMATESHEET\nuniform vec3 sheetInfos;\n#endif\n#ifdef BILLBOARD\nuniform vec3 eyePosition; \n#endif\nvec3 rotate(vec3 yaxis,vec3 rotatedCorner) {\nvec3 xaxis=normalize(cross(vec3(0.,1.0,0.),yaxis));\nvec3 zaxis=normalize(cross(yaxis,xaxis));\nvec3 row0=vec3(xaxis.x,xaxis.y,xaxis.z);\nvec3 row1=vec3(yaxis.x,yaxis.y,yaxis.z);\nvec3 row2=vec3(zaxis.x,zaxis.y,zaxis.z);\nmat3 rotMatrix=mat3(row0,row1,row2);\nvec3 alignedCorner=rotMatrix*rotatedCorner;\nreturn position+alignedCorner;\n}\nvoid main() {\n#ifdef ANIMATESHEET\nfloat rowOffset=floor(cellIndex/sheetInfos.z);\nfloat columnOffset=cellIndex-rowOffset*sheetInfos.z;\nvec2 uvScale=sheetInfos.xy;\nvec2 uvOffset=vec2(uv.x ,1.0-uv.y);\nvUV=(uvOffset+vec2(columnOffset,rowOffset))*uvScale;\n#else \nvUV=uv;\n#endif\nfloat ratio=age/life;\n#ifdef COLORGRADIENTS\nvColor=texture(colorGradientSampler,vec2(ratio,0));\n#else\nvColor=color*vec4(1.0-ratio)+colorDead*vec4(ratio);\n#endif\nvec2 cornerPos=(offset-translationPivot)*size.yz*size.x+translationPivot;\n#ifdef BILLBOARD\nvec4 rotatedCorner;\nrotatedCorner.w=0.;\n#ifdef BILLBOARDY \nrotatedCorner.x=cornerPos.x*cos(angle)-cornerPos.y*sin(angle);\nrotatedCorner.z=cornerPos.x*sin(angle)+cornerPos.y*cos(angle);\nrotatedCorner.y=0.;\nvec3 yaxis=position-eyePosition;\nyaxis.y=0.;\nvec3 worldPos=rotate(normalize(yaxis),rotatedCorner.xyz);\nvec4 viewPosition=(view*vec4(worldPos,1.0)); \n#else\n\nrotatedCorner.x=cornerPos.x*cos(angle)-cornerPos.y*sin(angle);\nrotatedCorner.y=cornerPos.x*sin(angle)+cornerPos.y*cos(angle);\nrotatedCorner.z=0.;\n\nvec4 viewPosition=view*vec4(position,1.0)+rotatedCorner;\n#endif\n#else\n\nvec3 rotatedCorner;\nrotatedCorner.x=cornerPos.x*cos(angle)-cornerPos.y*sin(angle);\nrotatedCorner.y=0.;\nrotatedCorner.z=cornerPos.x*sin(angle)+cornerPos.y*cos(angle);\nvec3 yaxis=normalize(initialDirection);\nvec3 worldPos=rotate(yaxis,rotatedCorner);\n\nvec4 viewPosition=view*vec4(worldPos,1.0); \n#endif\ngl_Position=projection*viewPosition;\n\n#ifdef CLIPPLANE\nvec4 worldPos=invView*viewPosition;\nfClipDistance=dot(worldPos,vClipPlane);\n#endif \n}","gpuRenderParticlesPixelShader":"#version 300 es\nuniform sampler2D textureSampler;\nin vec2 vUV;\nin vec4 vColor;\nout vec4 outFragColor;\n#ifdef CLIPPLANE\nin float fClipDistance;\n#endif\nvoid main() {\n#ifdef CLIPPLANE\nif (fClipDistance>0.0)\ndiscard;\n#endif \noutFragColor=texture(textureSampler,vUV)*vColor;\n}\n","gpuUpdateParticlesVertexShader":"#version 300 es\n#define PI 3.14159\nuniform float currentCount;\nuniform float timeDelta;\nuniform float stopFactor;\nuniform mat4 emitterWM;\nuniform vec2 lifeTime;\nuniform vec2 emitPower;\nuniform vec2 sizeRange;\nuniform vec4 scaleRange;\n#ifndef COLORGRADIENTS\nuniform vec4 color1;\nuniform vec4 color2;\n#endif\nuniform vec3 gravity;\nuniform sampler2D randomSampler;\nuniform sampler2D randomSampler2;\nuniform vec4 angleRange;\n#ifdef BOXEMITTER\nuniform vec3 direction1;\nuniform vec3 direction2;\nuniform vec3 minEmitBox;\nuniform vec3 maxEmitBox;\n#endif\n#ifdef SPHEREEMITTER\nuniform float radius;\nuniform float radiusRange;\n#ifdef DIRECTEDSPHEREEMITTER\nuniform vec3 direction1;\nuniform vec3 direction2;\n#else\nuniform float directionRandomizer;\n#endif\n#endif\n#ifdef CONEEMITTER\nuniform vec2 radius;\nuniform float coneAngle;\nuniform vec2 height;\nuniform float directionRandomizer;\n#endif\n\nin vec3 position;\nin float age;\nin float life;\nin vec4 seed;\nin vec3 size;\n#ifndef COLORGRADIENTS\nin vec4 color;\n#endif\nin vec3 direction;\n#ifndef BILLBOARD\nin vec3 initialDirection;\n#endif\n#ifdef ANGULARSPEEDGRADIENTS\nin float angle;\n#else\nin vec2 angle;\n#endif\n#ifdef ANIMATESHEET\nin float cellIndex;\n#endif\n\nout vec3 outPosition;\nout float outAge;\nout float outLife;\nout vec4 outSeed;\nout vec3 outSize;\n#ifndef COLORGRADIENTS\nout vec4 outColor;\n#endif\nout vec3 outDirection;\n#ifndef BILLBOARD\nout vec3 outInitialDirection;\n#endif\n#ifdef ANGULARSPEEDGRADIENTS\nout float outAngle;\n#else\nout vec2 outAngle;\n#endif\n#ifdef ANIMATESHEET\nout float outCellIndex;\n#endif\n#ifdef SIZEGRADIENTS\nuniform sampler2D sizeGradientSampler;\n#endif \n#ifdef ANGULARSPEEDGRADIENTS\nuniform sampler2D angularSpeedGradientSampler;\n#endif \n#ifdef VELOCITYGRADIENTS\nuniform sampler2D velocityGradientSampler;\n#endif\n#ifdef NOISE\nuniform vec3 noiseStrength;\nuniform sampler2D noiseSampler;\n#endif\n#ifdef ANIMATESHEET\nuniform vec3 cellInfos;\n#endif\nvec3 getRandomVec3(float offset) {\nreturn texture(randomSampler2,vec2(float(gl_VertexID)*offset/currentCount,0)).rgb;\n}\nvec4 getRandomVec4(float offset) {\nreturn texture(randomSampler,vec2(float(gl_VertexID)*offset/currentCount,0));\n}\nvoid main() {\nif (age>=life) {\nif (stopFactor == 0.) {\noutPosition=position;\noutAge=life;\noutLife=life;\noutSeed=seed;\n#ifndef COLORGRADIENTS \noutColor=vec4(0.,0.,0.,0.);\n#endif\noutSize=vec3(0.,0.,0.);\n#ifndef BILLBOARD \noutInitialDirection=initialDirection;\n#endif \noutDirection=direction;\noutAngle=angle;\n#ifdef ANIMATESHEET \noutCellIndex=cellIndex;\n#endif\nreturn;\n}\nvec3 position;\nvec3 direction;\n\nvec4 randoms=getRandomVec4(seed.x);\n\noutAge=0.0;\noutLife=lifeTime.x+(lifeTime.y-lifeTime.x)*randoms.r;\n\noutSeed=seed;\n\n#ifdef SIZEGRADIENTS \noutSize.x=texture(sizeGradientSampler,vec2(0,0)).r;\n#else\noutSize.x=sizeRange.x+(sizeRange.y-sizeRange.x)*randoms.g;\n#endif\noutSize.y=scaleRange.x+(scaleRange.y-scaleRange.x)*randoms.b;\noutSize.z=scaleRange.z+(scaleRange.w-scaleRange.z)*randoms.a; \n#ifndef COLORGRADIENTS\n\noutColor=color1+(color2-color1)*randoms.b;\n#endif\n\n#ifndef ANGULARSPEEDGRADIENTS \noutAngle.y=angleRange.x+(angleRange.y-angleRange.x)*randoms.a;\noutAngle.x=angleRange.z+(angleRange.w-angleRange.z)*randoms.r;\n#else\noutAngle=angleRange.z+(angleRange.w-angleRange.z)*randoms.r;\n#endif \n\n#ifdef BOXEMITTER\nvec3 randoms2=getRandomVec3(seed.y);\nvec3 randoms3=getRandomVec3(seed.z);\nposition=minEmitBox+(maxEmitBox-minEmitBox)*randoms2;\ndirection=direction1+(direction2-direction1)*randoms3;\n#elif defined(SPHEREEMITTER)\nvec3 randoms2=getRandomVec3(seed.y);\nvec3 randoms3=getRandomVec3(seed.z);\n\nfloat phi=2.0*PI*randoms2.x;\nfloat theta=acos(2.0*randoms2.y-1.0);\nfloat randX=cos(phi)*sin(theta);\nfloat randY=cos(theta);\nfloat randZ=sin(phi)*sin(theta);\nposition=(radius-(radius*radiusRange*randoms2.z))*vec3(randX,randY,randZ);\n#ifdef DIRECTEDSPHEREEMITTER\ndirection=direction1+(direction2-direction1)*randoms3;\n#else\n\ndirection=position+directionRandomizer*randoms3;\n#endif\n#elif defined(CONEEMITTER)\nvec3 randoms2=getRandomVec3(seed.y);\nfloat s=2.0*PI*randoms2.x;\nfloat h=randoms2.y*height.y;\n\nh=1.-h*h;\nfloat lRadius=radius.x-radius.x*randoms2.z*radius.y;\nlRadius=lRadius*h;\nfloat randX=lRadius*sin(s);\nfloat randZ=lRadius*cos(s);\nfloat randY=h*height.x;\nposition=vec3(randX,randY,randZ); \n\nif (abs(cos(coneAngle)) == 1.0) {\ndirection=vec3(0.,1.0,0.);\n} else {\nvec3 randoms3=getRandomVec3(seed.z);\ndirection=position+directionRandomizer*randoms3;\n}\n#else \n\nposition=vec3(0.,0.,0.);\n\ndirection=2.0*(getRandomVec3(seed.w)-vec3(0.5,0.5,0.5));\n#endif\nfloat power=emitPower.x+(emitPower.y-emitPower.x)*randoms.a;\noutPosition=(emitterWM*vec4(position,1.)).xyz;\nvec3 initial=(emitterWM*vec4(normalize(direction),0.)).xyz;\noutDirection=initial*power;\n#ifndef BILLBOARD \noutInitialDirection=initial;\n#endif\n#ifdef ANIMATESHEET \noutCellIndex=cellInfos.x;\n#endif\n} else { \nfloat directionScale=timeDelta;\nfloat ageGradient=age/life;\n#ifdef VELOCITYGRADIENTS\ndirectionScale*=texture(velocityGradientSampler,vec2(ageGradient,0)).r;\n#endif\noutPosition=position+direction*directionScale;\noutAge=age+timeDelta;\noutLife=life;\noutSeed=seed;\n#ifndef COLORGRADIENTS \noutColor=color;\n#endif\n#ifdef SIZEGRADIENTS\noutSize.x=texture(sizeGradientSampler,vec2(ageGradient,0)).r;\noutSize.yz=size.yz;\n#else\noutSize=size;\n#endif \n#ifndef BILLBOARD \noutInitialDirection=initialDirection;\n#endif\noutDirection=direction+gravity*timeDelta;\n#ifdef NOISE\nvec3 localPosition=outPosition-emitterWM[3].xyz;\nfloat fetchedR=texture(noiseSampler,vec2(localPosition.y,localPosition.z)*vec2(0.5)+vec2(0.5)).r;\nfloat fetchedG=texture(noiseSampler,vec2(localPosition.x+0.33,localPosition.z+0.33)*vec2(0.5)+vec2(0.5)).r;\nfloat fetchedB=texture(noiseSampler,vec2(localPosition.z-0.33,localPosition.y-0.33)*vec2(0.5)+vec2(0.5)).r;\nvec3 force=vec3(2.*fetchedR-1.,2.*fetchedG-1.,2.*fetchedB-1.)*noiseStrength;\noutDirection=outDirection+force*timeDelta;\n#endif \n#ifdef ANGULARSPEEDGRADIENTS\nfloat angularSpeed=texture(angularSpeedGradientSampler,vec2(ageGradient,0)).r;\noutAngle=angle+angularSpeed*timeDelta;\n#else\noutAngle=vec2(angle.x+angle.y*timeDelta,angle.y);\n#endif\n#ifdef ANIMATESHEET \nfloat dist=cellInfos.y-cellInfos.x;\nfloat ratio=clamp(mod(outAge*cellInfos.z,life)/life,0.,1.0);\noutCellIndex=float(int(cellInfos.x+ratio*dist));\n#endif\n}\n}","gpuUpdateParticlesPixelShader":"#version 300 es\nvoid main() {\ndiscard;\n}\n","postprocessVertexShader":"\nattribute vec2 position;\nuniform vec2 scale;\n\nvarying vec2 vUV;\nconst vec2 madd=vec2(0.5,0.5);\nvoid main(void) { \nvUV=(position*madd+madd)*scale;\ngl_Position=vec4(position,0.0,1.0);\n}","passPixelShader":"\nvarying vec2 vUV;\nuniform sampler2D textureSampler;\nvoid main(void) \n{\ngl_FragColor=texture2D(textureSampler,vUV);\n}","shadowMapVertexShader":"\nattribute vec3 position;\n#ifdef NORMAL\nattribute vec3 normal;\nuniform vec3 lightData;\n#endif\n#include\n#include\n#include[0..maxSimultaneousMorphTargets]\n\n#include\n#include\nuniform mat4 viewProjection;\nuniform vec3 biasAndScale;\nuniform vec2 depthValues;\nvarying float vDepthMetric;\n#ifdef ALPHATEST\nvarying vec2 vUV;\nuniform mat4 diffuseMatrix;\n#ifdef UV1\nattribute vec2 uv;\n#endif\n#ifdef UV2\nattribute vec2 uv2;\n#endif\n#endif\nvoid main(void)\n{\nvec3 positionUpdated=position;\n#include[0..maxSimultaneousMorphTargets]\n#include\n#include\nvec4 worldPos=finalWorld*vec4(positionUpdated,1.0);\n\n#ifdef NORMAL\nmat3 normalWorld=mat3(finalWorld);\n#ifdef NONUNIFORMSCALING\nnormalWorld=transposeMat3(inverseMat3(normalWorld));\n#endif\nvec3 worldNor=normalize(normalWorld*normal);\n#ifdef DIRECTIONINLIGHTDATA\nvec3 worldLightDir=normalize(-lightData.xyz);\n#else\nvec3 directionToLight=lightData.xyz-worldPos.xyz;\nvec3 worldLightDir=normalize(directionToLight);\n#endif\nfloat ndl=dot(worldNor,worldLightDir);\nfloat sinNL=sqrt(1.0-ndl*ndl);\nfloat normalBias=biasAndScale.y*sinNL;\nworldPos.xyz-=worldNor*normalBias;\n#endif\n\ngl_Position=viewProjection*worldPos;\n#ifdef DEPTHTEXTURE\n\ngl_Position.z+=biasAndScale.x*gl_Position.w;\n#endif\n\nvDepthMetric=((gl_Position.z+depthValues.x)/(depthValues.y))+biasAndScale.x;\n#ifdef ALPHATEST\n#ifdef UV1\nvUV=vec2(diffuseMatrix*vec4(uv,1.0,0.0));\n#endif\n#ifdef UV2\nvUV=vec2(diffuseMatrix*vec4(uv2,1.0,0.0));\n#endif\n#endif\n}","shadowMapPixelShader":"#ifndef FLOAT\nvec4 pack(float depth)\n{\nconst vec4 bit_shift=vec4(255.0*255.0*255.0,255.0*255.0,255.0,1.0);\nconst vec4 bit_mask=vec4(0.0,1.0/255.0,1.0/255.0,1.0/255.0);\nvec4 res=fract(depth*bit_shift);\nres-=res.xxyz*bit_mask;\nreturn res;\n}\n#endif\nvarying float vDepthMetric;\n#ifdef ALPHATEST\nvarying vec2 vUV;\nuniform sampler2D diffuseSampler;\n#endif\nuniform vec3 biasAndScale;\nuniform vec2 depthValues;\nvoid main(void)\n{\n#ifdef ALPHATEST\nif (texture2D(diffuseSampler,vUV).a<0.4)\ndiscard;\n#endif\nfloat depth=vDepthMetric;\n#ifdef ESM\ndepth=clamp(exp(-min(87.,biasAndScale.z*depth)),0.,1.);\n#endif\n#ifdef FLOAT\ngl_FragColor=vec4(depth,1.0,1.0,1.0);\n#else\ngl_FragColor=pack(depth);\n#endif\n}","depthBoxBlurPixelShader":"\nvarying vec2 vUV;\nuniform sampler2D textureSampler;\n\nuniform vec2 screenSize;\nvoid main(void)\n{\nvec4 colorDepth=vec4(0.0);\nfor (int x=-OFFSET; x<=OFFSET; x++)\nfor (int y=-OFFSET; y<=OFFSET; y++)\ncolorDepth+=texture2D(textureSampler,vUV+vec2(x,y)/screenSize);\ngl_FragColor=(colorDepth/float((OFFSET*2+1)*(OFFSET*2+1)));\n}","proceduralVertexShader":"\nattribute vec2 position;\n\nvarying vec2 vPosition;\nvarying vec2 vUV;\nconst vec2 madd=vec2(0.5,0.5);\nvoid main(void) { \nvPosition=position;\nvUV=position*madd+madd;\ngl_Position=vec4(position,0.0,1.0);\n}","depthVertexShader":"\nattribute vec3 position;\n#include\n\n#include\nuniform mat4 viewProjection;\nuniform vec2 depthValues;\n#if defined(ALPHATEST) || defined(NEED_UV)\nvarying vec2 vUV;\nuniform mat4 diffuseMatrix;\n#ifdef UV1\nattribute vec2 uv;\n#endif\n#ifdef UV2\nattribute vec2 uv2;\n#endif\n#endif\nvarying float vDepthMetric;\nvoid main(void)\n{\n#include\n#include\ngl_Position=viewProjection*finalWorld*vec4(position,1.0);\nvDepthMetric=((gl_Position.z+depthValues.x)/(depthValues.y));\n#if defined(ALPHATEST) || defined(BASIC_RENDER)\n#ifdef UV1\nvUV=vec2(diffuseMatrix*vec4(uv,1.0,0.0));\n#endif\n#ifdef UV2\nvUV=vec2(diffuseMatrix*vec4(uv2,1.0,0.0));\n#endif\n#endif\n}","depthPixelShader":"#ifdef ALPHATEST\nvarying vec2 vUV;\nuniform sampler2D diffuseSampler;\n#endif\nvarying float vDepthMetric;\nvoid main(void)\n{\n#ifdef ALPHATEST\nif (texture2D(diffuseSampler,vUV).a<0.4)\ndiscard;\n#endif\ngl_FragColor=vec4(vDepthMetric,vDepthMetric*vDepthMetric,0.0,1.0);\n}","ssaoPixelShader":"\nuniform sampler2D textureSampler;\nvarying vec2 vUV;\n#ifdef SSAO\nuniform sampler2D randomSampler;\nuniform float randTextureTiles;\nuniform float samplesFactor;\nuniform vec3 sampleSphere[SAMPLES];\nuniform float totalStrength;\nuniform float radius;\nuniform float area;\nuniform float fallOff;\nuniform float base;\nvec3 normalFromDepth(float depth,vec2 coords)\n{\nvec2 offset1=vec2(0.0,radius);\nvec2 offset2=vec2(radius,0.0);\nfloat depth1=texture2D(textureSampler,coords+offset1).r;\nfloat depth2=texture2D(textureSampler,coords+offset2).r;\nvec3 p1=vec3(offset1,depth1-depth);\nvec3 p2=vec3(offset2,depth2-depth);\nvec3 normal=cross(p1,p2);\nnormal.z=-normal.z;\nreturn normalize(normal);\n}\nvoid main()\n{\nvec3 random=normalize(texture2D(randomSampler,vUV*randTextureTiles).rgb);\nfloat depth=texture2D(textureSampler,vUV).r;\nvec3 position=vec3(vUV,depth);\nvec3 normal=normalFromDepth(depth,vUV);\nfloat radiusDepth=radius/depth;\nfloat occlusion=0.0;\nvec3 ray;\nvec3 hemiRay;\nfloat occlusionDepth;\nfloat difference;\nfor (int i=0; imaxZ) {\ngl_FragColor=vec4(1.0,1.0,1.0,1.0);\nreturn;\n}\nfor (int i=0; i1.0 || offset.y>1.0) {\ncontinue;\n}\n\nfloat sampleDepth=abs(texture2D(textureSampler,offset.xy).r);\n\nfloat rangeCheck=abs(depth-sampleDepth)=1e-5 ? 1.0 : 0.0)*rangeCheck;\n}\n\nfloat ao=1.0-totalStrength*occlusion*samplesFactor;\nfloat result=clamp(ao+base,0.0,1.0);\ngl_FragColor=vec4(vec3(result),1.0);\n}\n#endif\n#ifdef BILATERAL_BLUR\nuniform sampler2D depthSampler;\nuniform float outSize;\nuniform float samplerOffsets[SAMPLES];\nvec4 blur9(sampler2D image,vec2 uv,float resolution,vec2 direction) {\nvec4 color=vec4(0.0);\nvec2 off1=vec2(1.3846153846)*direction;\nvec2 off2=vec2(3.2307692308)*direction;\ncolor+=texture2D(image,uv)*0.2270270270;\ncolor+=texture2D(image,uv+(off1/resolution))*0.3162162162;\ncolor+=texture2D(image,uv-(off1/resolution))*0.3162162162;\ncolor+=texture2D(image,uv+(off2/resolution))*0.0702702703;\ncolor+=texture2D(image,uv-(off2/resolution))*0.0702702703;\nreturn color;\n}\nvec4 blur13(sampler2D image,vec2 uv,float resolution,vec2 direction) {\nvec4 color=vec4(0.0);\nvec2 off1=vec2(1.411764705882353)*direction;\nvec2 off2=vec2(3.2941176470588234)*direction;\nvec2 off3=vec2(5.176470588235294)*direction;\ncolor+=texture2D(image,uv)*0.1964825501511404;\ncolor+=texture2D(image,uv+(off1/resolution))*0.2969069646728344;\ncolor+=texture2D(image,uv-(off1/resolution))*0.2969069646728344;\ncolor+=texture2D(image,uv+(off2/resolution))*0.09447039785044732;\ncolor+=texture2D(image,uv-(off2/resolution))*0.09447039785044732;\ncolor+=texture2D(image,uv+(off3/resolution))*0.010381362401148057;\ncolor+=texture2D(image,uv-(off3/resolution))*0.010381362401148057;\nreturn color;\n}\nvec4 blur13Bilateral(sampler2D image,vec2 uv,float resolution,vec2 direction) {\nvec4 color=vec4(0.0);\nvec2 off1=vec2(1.411764705882353)*direction;\nvec2 off2=vec2(3.2941176470588234)*direction;\nvec2 off3=vec2(5.176470588235294)*direction;\nfloat compareDepth=abs(texture2D(depthSampler,uv).r);\nfloat sampleDepth;\nfloat weight;\nfloat weightSum=30.0;\ncolor+=texture2D(image,uv)*30.0;\nsampleDepth=abs(texture2D(depthSampler,uv+(off1/resolution)).r);\nweight=clamp(1.0/( 0.003+abs(compareDepth-sampleDepth)),0.0,30.0);\nweightSum+=weight;\ncolor+=texture2D(image,uv+(off1/resolution))*weight;\nsampleDepth=abs(texture2D(depthSampler,uv-(off1/resolution)).r);\nweight=clamp(1.0/( 0.003+abs(compareDepth-sampleDepth)),0.0,30.0);\nweightSum+=weight;\ncolor+=texture2D(image,uv-(off1/resolution))*weight;\nsampleDepth=abs(texture2D(depthSampler,uv+(off2/resolution)).r);\nweight=clamp(1.0/( 0.003+abs(compareDepth-sampleDepth)),0.0,30.0);\nweightSum+=weight;\ncolor+=texture2D(image,uv+(off2/resolution))*weight;\nsampleDepth=abs(texture2D(depthSampler,uv-(off2/resolution)).r);\nweight=clamp(1.0/( 0.003+abs(compareDepth-sampleDepth)),0.0,30.0);\nweightSum+=weight;\ncolor+=texture2D(image,uv-(off2/resolution))*weight;\nsampleDepth=abs(texture2D(depthSampler,uv+(off3/resolution)).r);\nweight=clamp(1.0/( 0.003+abs(compareDepth-sampleDepth)),0.0,30.0);\nweightSum+=weight;\ncolor+=texture2D(image,uv+(off3/resolution))*weight;\nsampleDepth=abs(texture2D(depthSampler,uv-(off3/resolution)).r);\nweight=clamp(1.0/( 0.003+abs(compareDepth-sampleDepth)),0.0,30.0);\nweightSum+=weight;\ncolor+=texture2D(image,uv-(off3/resolution))*weight;\nreturn color/weightSum;\n}\nvoid main()\n{\n#if EXPENSIVE\nfloat compareDepth=abs(texture2D(depthSampler,vUV).r);\nfloat texelsize=1.0/outSize;\nfloat result=0.0;\nfloat weightSum=0.0;\nfor (int i=0; i1.0) { lum_threshold=0.94+0.01*threshold; }\nelse { lum_threshold=0.5+0.44*threshold; }\nluminance=clamp((luminance-lum_threshold)*(1.0/(1.0-lum_threshold)),0.0,1.0);\nhighlight*=luminance*gain;\nhighlight.a=1.0;\nreturn highlight;\n}\nvoid main(void)\n{\nvec4 original=texture2D(textureSampler,vUV);\n\nif (gain == -1.0) {\ngl_FragColor=vec4(0.0,0.0,0.0,1.0);\nreturn;\n}\nfloat w=2.0/screen_width;\nfloat h=2.0/screen_height;\nfloat weight=1.0;\n\nvec4 blurred=vec4(0.0,0.0,0.0,0.0);\n#ifdef PENTAGON\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(-0.84*w,0.43*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(0.48*w,-1.29*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(0.61*w,1.51*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(-1.55*w,-0.74*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(1.71*w,-0.52*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(-0.94*w,1.59*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(-0.40*w,-1.87*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(1.62*w,1.16*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(-2.09*w,0.25*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(1.46*w,-1.71*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(0.08*w,2.42*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(-1.85*w,-1.89*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(2.89*w,0.16*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(-2.29*w,1.88*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(0.40*w,-2.81*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(1.54*w,2.26*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(-2.60*w,-0.61*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(2.31*w,-1.30*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(-0.83*w,2.53*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(-1.12*w,-2.48*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(2.60*w,1.11*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(-2.82*w,0.99*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(1.50*w,-2.81*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(0.85*w,3.33*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(-2.94*w,-1.92*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(3.27*w,-0.53*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(-1.95*w,2.48*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(-0.23*w,-3.04*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(2.17*w,2.05*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(-2.97*w,-0.04*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(2.25*w,-2.00*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(-0.31*w,3.08*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(-1.94*w,-2.59*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(3.37*w,0.64*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(-3.13*w,1.93*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(1.03*w,-3.65*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(1.60*w,3.17*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(-3.14*w,-1.19*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(3.00*w,-1.19*h)));\n#else\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(-0.85*w,0.36*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(0.52*w,-1.14*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(0.46*w,1.42*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(-1.46*w,-0.83*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(1.79*w,-0.42*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(-1.11*w,1.62*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(-0.29*w,-2.07*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(1.69*w,1.39*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(-2.28*w,0.12*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(1.65*w,-1.69*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(-0.08*w,2.44*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(-1.63*w,-1.90*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(2.55*w,0.31*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(-2.13*w,1.52*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(0.56*w,-2.61*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(1.38*w,2.34*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(-2.64*w,-0.81*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(2.53*w,-1.21*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(-1.06*w,2.63*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(-1.00*w,-2.69*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(2.59*w,1.32*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(-2.82*w,0.78*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(1.57*w,-2.50*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(0.54*w,2.93*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(-2.39*w,-1.81*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(3.01*w,-0.28*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(-2.04*w,2.25*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(-0.02*w,-3.05*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(2.09*w,2.25*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(-3.07*w,-0.25*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(2.44*w,-1.90*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(-0.52*w,3.05*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(-1.68*w,-2.61*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(3.01*w,0.79*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(-2.76*w,1.46*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(1.05*w,-2.94*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(1.21*w,2.88*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(-2.84*w,-1.30*h)));\nblurred+=highlightColor(texture2D(textureSampler,vUV+vec2(2.98*w,-0.96*h)));\n#endif\nblurred/=39.0;\ngl_FragColor=blurred;\n\n}","depthOfFieldPixelShader":"\n\n\n\n\nuniform sampler2D textureSampler;\nuniform sampler2D highlightsSampler;\nuniform sampler2D depthSampler;\nuniform sampler2D grainSampler;\n\nuniform float grain_amount;\nuniform bool blur_noise;\nuniform float screen_width;\nuniform float screen_height;\nuniform float distortion;\nuniform bool dof_enabled;\n\nuniform float screen_distance; \nuniform float aperture;\nuniform float darken;\nuniform float edge_blur;\nuniform bool highlights;\n\nuniform float near;\nuniform float far;\n\nvarying vec2 vUV;\n\n#define PI 3.14159265\n#define TWOPI 6.28318530\n#define inverse_focal_length 0.1 \n\nvec2 centered_screen_pos;\nvec2 distorted_coords;\nfloat radius2;\nfloat radius;\n\nvec2 rand(vec2 co)\n{\nfloat noise1=(fract(sin(dot(co,vec2(12.9898,78.233)))*43758.5453));\nfloat noise2=(fract(sin(dot(co,vec2(12.9898,78.233)*2.0))*43758.5453));\nreturn clamp(vec2(noise1,noise2),0.0,1.0);\n}\n\nvec2 getDistortedCoords(vec2 coords) {\nif (distortion == 0.0) { return coords; }\nvec2 direction=1.0*normalize(centered_screen_pos);\nvec2 dist_coords=vec2(0.5,0.5);\ndist_coords.x=0.5+direction.x*radius2*1.0;\ndist_coords.y=0.5+direction.y*radius2*1.0;\nfloat dist_amount=clamp(distortion*0.23,0.0,1.0);\ndist_coords=mix(coords,dist_coords,dist_amount);\nreturn dist_coords;\n}\n\nfloat sampleScreen(inout vec4 color,const in vec2 offset,const in float weight) {\n\nvec2 coords=distorted_coords;\nfloat angle=rand(coords*100.0).x*TWOPI;\ncoords+=vec2(offset.x*cos(angle)-offset.y*sin(angle),offset.x*sin(angle)+offset.y*cos(angle));\ncolor+=texture2D(textureSampler,coords)*weight;\nreturn weight;\n}\n\nfloat getBlurLevel(float size) {\nreturn min(3.0,ceil(size/1.0));\n}\n\nvec4 getBlurColor(float size) {\nvec4 col=texture2D(textureSampler,distorted_coords);\nif (size == 0.0) { return col; }\n\n\nfloat blur_level=getBlurLevel(size);\nfloat w=(size/screen_width);\nfloat h=(size/screen_height);\nfloat total_weight=1.0;\nvec2 sample_coords;\ntotal_weight+=sampleScreen(col,vec2(-0.50*w,0.24*h),0.93);\ntotal_weight+=sampleScreen(col,vec2(0.30*w,-0.75*h),0.90);\ntotal_weight+=sampleScreen(col,vec2(0.36*w,0.96*h),0.87);\ntotal_weight+=sampleScreen(col,vec2(-1.08*w,-0.55*h),0.85);\ntotal_weight+=sampleScreen(col,vec2(1.33*w,-0.37*h),0.83);\ntotal_weight+=sampleScreen(col,vec2(-0.82*w,1.31*h),0.80);\ntotal_weight+=sampleScreen(col,vec2(-0.31*w,-1.67*h),0.78);\ntotal_weight+=sampleScreen(col,vec2(1.47*w,1.11*h),0.76);\ntotal_weight+=sampleScreen(col,vec2(-1.97*w,0.19*h),0.74);\ntotal_weight+=sampleScreen(col,vec2(1.42*w,-1.57*h),0.72);\nif (blur_level>1.0) {\ntotal_weight+=sampleScreen(col,vec2(0.01*w,2.25*h),0.70);\ntotal_weight+=sampleScreen(col,vec2(-1.62*w,-1.74*h),0.67);\ntotal_weight+=sampleScreen(col,vec2(2.49*w,0.20*h),0.65);\ntotal_weight+=sampleScreen(col,vec2(-2.07*w,1.61*h),0.63);\ntotal_weight+=sampleScreen(col,vec2(0.46*w,-2.70*h),0.61);\ntotal_weight+=sampleScreen(col,vec2(1.55*w,2.40*h),0.59);\ntotal_weight+=sampleScreen(col,vec2(-2.88*w,-0.75*h),0.56);\ntotal_weight+=sampleScreen(col,vec2(2.73*w,-1.44*h),0.54);\ntotal_weight+=sampleScreen(col,vec2(-1.08*w,3.02*h),0.52);\ntotal_weight+=sampleScreen(col,vec2(-1.28*w,-3.05*h),0.49);\n}\nif (blur_level>2.0) {\ntotal_weight+=sampleScreen(col,vec2(3.11*w,1.43*h),0.46);\ntotal_weight+=sampleScreen(col,vec2(-3.36*w,1.08*h),0.44);\ntotal_weight+=sampleScreen(col,vec2(1.80*w,-3.16*h),0.41);\ntotal_weight+=sampleScreen(col,vec2(0.83*w,3.65*h),0.38);\ntotal_weight+=sampleScreen(col,vec2(-3.16*w,-2.19*h),0.34);\ntotal_weight+=sampleScreen(col,vec2(3.92*w,-0.53*h),0.31);\ntotal_weight+=sampleScreen(col,vec2(-2.59*w,3.12*h),0.26);\ntotal_weight+=sampleScreen(col,vec2(-0.20*w,-4.15*h),0.22);\ntotal_weight+=sampleScreen(col,vec2(3.02*w,3.00*h),0.15);\n}\ncol/=total_weight; \n\nif (darken>0.0) {\ncol.rgb*=clamp(0.3,1.0,1.05-size*0.5*darken);\n}\n\n\n\n\nreturn col;\n}\nvoid main(void)\n{\n\ncentered_screen_pos=vec2(vUV.x-0.5,vUV.y-0.5);\nradius2=centered_screen_pos.x*centered_screen_pos.x+centered_screen_pos.y*centered_screen_pos.y;\nradius=sqrt(radius2);\ndistorted_coords=getDistortedCoords(vUV); \nvec2 texels_coords=vec2(vUV.x*screen_width,vUV.y*screen_height); \nfloat depth=texture2D(depthSampler,distorted_coords).r; \nfloat distance=near+(far-near)*depth; \nvec4 color=texture2D(textureSampler,vUV); \n\n\nfloat coc=abs(aperture*(screen_distance*(inverse_focal_length-1.0/distance)-1.0));\n\nif (dof_enabled == false || coc<0.07) { coc=0.0; }\n\nfloat edge_blur_amount=0.0;\nif (edge_blur>0.0) {\nedge_blur_amount=clamp((radius*2.0-1.0+0.15*edge_blur)*1.5,0.0,1.0)*1.3;\n}\n\nfloat blur_amount=max(edge_blur_amount,coc);\n\nif (blur_amount == 0.0) {\ngl_FragColor=texture2D(textureSampler,distorted_coords);\n}\nelse {\n\ngl_FragColor=getBlurColor(blur_amount*1.7);\n\nif (highlights) {\ngl_FragColor.rgb+=clamp(coc,0.0,1.0)*texture2D(highlightsSampler,distorted_coords).rgb;\n}\nif (blur_noise) {\n\nvec2 noise=rand(distorted_coords)*0.01*blur_amount;\nvec2 blurred_coord=vec2(distorted_coords.x+noise.x,distorted_coords.y+noise.y);\ngl_FragColor=0.04*texture2D(textureSampler,blurred_coord)+0.96*gl_FragColor;\n}\n}\n\nif (grain_amount>0.0) {\nvec4 grain_color=texture2D(grainSampler,texels_coords*0.003);\ngl_FragColor.rgb+=(-0.5+grain_color.rgb)*0.30*grain_amount;\n}\n}\n","standardPixelShader":"uniform sampler2D textureSampler;\nvarying vec2 vUV;\n#if defined(PASS_POST_PROCESS)\nvoid main(void)\n{\nvec4 color=texture2D(textureSampler,vUV);\ngl_FragColor=color;\n}\n#endif\n#if defined(DOWN_SAMPLE_X4)\nuniform vec2 dsOffsets[16];\nvoid main(void)\n{\nvec4 average=vec4(0.0,0.0,0.0,0.0);\naverage=texture2D(textureSampler,vUV+dsOffsets[0]);\naverage+=texture2D(textureSampler,vUV+dsOffsets[1]);\naverage+=texture2D(textureSampler,vUV+dsOffsets[2]);\naverage+=texture2D(textureSampler,vUV+dsOffsets[3]);\naverage+=texture2D(textureSampler,vUV+dsOffsets[4]);\naverage+=texture2D(textureSampler,vUV+dsOffsets[5]);\naverage+=texture2D(textureSampler,vUV+dsOffsets[6]);\naverage+=texture2D(textureSampler,vUV+dsOffsets[7]);\naverage+=texture2D(textureSampler,vUV+dsOffsets[8]);\naverage+=texture2D(textureSampler,vUV+dsOffsets[9]);\naverage+=texture2D(textureSampler,vUV+dsOffsets[10]);\naverage+=texture2D(textureSampler,vUV+dsOffsets[11]);\naverage+=texture2D(textureSampler,vUV+dsOffsets[12]);\naverage+=texture2D(textureSampler,vUV+dsOffsets[13]);\naverage+=texture2D(textureSampler,vUV+dsOffsets[14]);\naverage+=texture2D(textureSampler,vUV+dsOffsets[15]);\naverage/=16.0;\ngl_FragColor=average;\n}\n#endif\n#if defined(BRIGHT_PASS)\nuniform vec2 dsOffsets[4];\nuniform float brightThreshold;\nvoid main(void)\n{\nvec4 average=vec4(0.0,0.0,0.0,0.0);\naverage=texture2D(textureSampler,vUV+vec2(dsOffsets[0].x,dsOffsets[0].y));\naverage+=texture2D(textureSampler,vUV+vec2(dsOffsets[1].x,dsOffsets[1].y));\naverage+=texture2D(textureSampler,vUV+vec2(dsOffsets[2].x,dsOffsets[2].y));\naverage+=texture2D(textureSampler,vUV+vec2(dsOffsets[3].x,dsOffsets[3].y));\naverage*=0.25;\nfloat luminance=length(average.rgb);\nif (luminanceshadowPixelDepth)\naccumFog+=sunColor*computeScattering(dot(rayDirection,sunDirection));\ncurrentPosition+=stepL;\n}\naccumFog/=NB_STEPS;\nvec3 color=accumFog*scatteringPower;\ngl_FragColor=vec4(color*exp(color) ,1.0);\n}\n#endif\n#if defined(VLSMERGE)\nuniform sampler2D originalSampler;\nvoid main(void)\n{\ngl_FragColor=texture2D(originalSampler,vUV)+texture2D(textureSampler,vUV);\n}\n#endif\n#if defined(LUMINANCE)\nuniform vec2 lumOffsets[4];\nvoid main()\n{\nfloat average=0.0;\nvec4 color=vec4(0.0);\nfloat maximum=-1e20;\nvec3 weight=vec3(0.299,0.587,0.114);\nfor (int i=0; i<4; i++)\n{\ncolor=texture2D(textureSampler,vUV+ lumOffsets[i]);\n\nfloat GreyValue=dot(color.rgb,vec3(0.33,0.33,0.33));\n\n#ifdef WEIGHTED_AVERAGE\nfloat GreyValue=dot(color.rgb,weight);\n#endif\n#ifdef BRIGHTNESS\nfloat GreyValue=max(color.r,max(color.g,color.b));\n#endif\n#ifdef HSL_COMPONENT\nfloat GreyValue=0.5*(max(color.r,max(color.g,color.b))+min(color.r,min(color.g,color.b)));\n#endif\n#ifdef MAGNITUDE\nfloat GreyValue=length(color.rgb);\n#endif\nmaximum=max(maximum,GreyValue);\naverage+=(0.25*log(1e-5+GreyValue));\n}\naverage=exp(average);\ngl_FragColor=vec4(average,maximum,0.0,1.0);\n}\n#endif\n#if defined(LUMINANCE_DOWN_SAMPLE)\nuniform vec2 dsOffsets[9];\nuniform float halfDestPixelSize;\n#ifdef FINAL_DOWN_SAMPLER\nvec4 pack(float value) {\nconst vec4 bit_shift=vec4(255.0*255.0*255.0,255.0*255.0,255.0,1.0);\nconst vec4 bit_mask=vec4(0.0,1.0/255.0,1.0/255.0,1.0/255.0);\nvec4 res=fract(value*bit_shift);\nres-=res.xxyz*bit_mask;\nreturn res;\n}\n#endif\nvoid main()\n{\nvec4 color=vec4(0.0);\nfloat average=0.0;\nfor (int i=0; i<9; i++)\n{\ncolor=texture2D(textureSampler,vUV+vec2(halfDestPixelSize,halfDestPixelSize)+dsOffsets[i]);\naverage+=color.r;\n}\naverage/=9.0;\n#ifdef FINAL_DOWN_SAMPLER\ngl_FragColor=pack(average);\n#else\ngl_FragColor=vec4(average,average,0.0,1.0);\n#endif\n}\n#endif\n#if defined(HDR)\nuniform sampler2D textureAdderSampler;\nuniform float averageLuminance;\nvoid main()\n{\nvec4 color=texture2D(textureAdderSampler,vUV);\nvec4 adjustedColor=color/averageLuminance;\ncolor=adjustedColor;\ncolor.a=1.0;\ngl_FragColor=color;\n}\n#endif\n#if defined(LENS_FLARE)\n#define GHOSTS 3\nuniform sampler2D lensColorSampler;\nuniform float strength;\nuniform float ghostDispersal;\nuniform float haloWidth;\nuniform vec2 resolution;\nuniform float distortionStrength;\nfloat hash(vec2 p)\n{\nfloat h=dot(p,vec2(127.1,311.7));\nreturn -1.0+2.0*fract(sin(h)*43758.5453123);\n}\nfloat noise(in vec2 p)\n{\nvec2 i=floor(p);\nvec2 f=fract(p);\nvec2 u=f*f*(3.0-2.0*f);\nreturn mix(mix(hash(i+vec2(0.0,0.0)),\nhash(i+vec2(1.0,0.0)),u.x),\nmix(hash(i+vec2(0.0,1.0)),\nhash(i+vec2(1.0,1.0)),u.x),u.y);\n}\nfloat fbm(vec2 p)\n{\nfloat f=0.0;\nf+=0.5000*noise(p); p*=2.02;\nf+=0.2500*noise(p); p*=2.03;\nf+=0.1250*noise(p); p*=2.01;\nf+=0.0625*noise(p); p*=2.04;\nf/=0.9375;\nreturn f;\n}\nvec3 pattern(vec2 uv)\n{\nvec2 p=-1.0+2.0*uv;\nfloat p2=dot(p,p);\nfloat f=fbm(vec2(15.0*p2))/2.0;\nfloat r=0.2+0.6*sin(12.5*length(uv-vec2(0.5)));\nfloat g=0.2+0.6*sin(20.5*length(uv-vec2(0.5)));\nfloat b=0.2+0.6*sin(17.2*length(uv-vec2(0.5)));\nreturn (1.0-f)*vec3(r,g,b);\n}\nfloat luminance(vec3 color)\n{\nreturn dot(color.rgb,vec3(0.2126,0.7152,0.0722));\n}\nvec4 textureDistorted(sampler2D tex,vec2 texcoord,vec2 direction,vec3 distortion)\n{\nreturn vec4(\ntexture2D(tex,texcoord+direction*distortion.r).r,\ntexture2D(tex,texcoord+direction*distortion.g).g,\ntexture2D(tex,texcoord+direction*distortion.b).b,\n1.0\n);\n}\nvoid main(void)\n{\nvec2 uv=-vUV+vec2(1.0);\nvec2 ghostDir=(vec2(0.5)-uv)*ghostDispersal;\nvec2 texelSize=1.0/resolution;\nvec3 distortion=vec3(-texelSize.x*distortionStrength,0.0,texelSize.x*distortionStrength);\nvec4 result=vec4(0.0);\nfloat ghostIndice=1.0;\nfor (int i=0; i=nSamples)\nbreak;\nvec2 offset1=vUV+velocity*(float(i)/float(nSamples-1)-0.5);\nresult+=texture2D(textureSampler,offset1);\n}\ngl_FragColor=result/float(nSamples);\n}\n#endif\n","fxaaVertexShader":"\nattribute vec2 position;\nuniform vec2 texelSize;\n\nvarying vec2 vUV;\nvarying vec2 sampleCoordS;\nvarying vec2 sampleCoordE;\nvarying vec2 sampleCoordN;\nvarying vec2 sampleCoordW;\nvarying vec2 sampleCoordNW;\nvarying vec2 sampleCoordSE;\nvarying vec2 sampleCoordNE;\nvarying vec2 sampleCoordSW;\nconst vec2 madd=vec2(0.5,0.5);\nvoid main(void) { \nvUV=(position*madd+madd);\nsampleCoordS=vUV+vec2( 0.0,1.0)*texelSize;\nsampleCoordE=vUV+vec2( 1.0,0.0)*texelSize;\nsampleCoordN=vUV+vec2( 0.0,-1.0)*texelSize;\nsampleCoordW=vUV+vec2(-1.0,0.0)*texelSize;\nsampleCoordNW=vUV+vec2(-1.0,-1.0)*texelSize;\nsampleCoordSE=vUV+vec2( 1.0,1.0)*texelSize;\nsampleCoordNE=vUV+vec2( 1.0,-1.0)*texelSize;\nsampleCoordSW=vUV+vec2(-1.0,1.0)*texelSize;\ngl_Position=vec4(position,0.0,1.0);\n}","fxaaPixelShader":"uniform sampler2D textureSampler;\nuniform vec2 texelSize;\nvarying vec2 vUV;\nvarying vec2 sampleCoordS;\nvarying vec2 sampleCoordE;\nvarying vec2 sampleCoordN;\nvarying vec2 sampleCoordW;\nvarying vec2 sampleCoordNW;\nvarying vec2 sampleCoordSE;\nvarying vec2 sampleCoordNE;\nvarying vec2 sampleCoordSW;\nconst float fxaaQualitySubpix=1.0;\nconst float fxaaQualityEdgeThreshold=0.166;\nconst float fxaaQualityEdgeThresholdMin=0.0833;\nconst vec3 kLumaCoefficients=vec3(0.2126,0.7152,0.0722);\n#define FxaaLuma(rgba) dot(rgba.rgb,kLumaCoefficients)\nvoid main(){\nvec2 posM;\nposM.x=vUV.x;\nposM.y=vUV.y;\nvec4 rgbyM=texture2D(textureSampler,vUV,0.0);\nfloat lumaM=FxaaLuma(rgbyM);\nfloat lumaS=FxaaLuma(texture2D(textureSampler,sampleCoordS,0.0));\nfloat lumaE=FxaaLuma(texture2D(textureSampler,sampleCoordE,0.0));\nfloat lumaN=FxaaLuma(texture2D(textureSampler,sampleCoordN,0.0));\nfloat lumaW=FxaaLuma(texture2D(textureSampler,sampleCoordW,0.0));\nfloat maxSM=max(lumaS,lumaM);\nfloat minSM=min(lumaS,lumaM);\nfloat maxESM=max(lumaE,maxSM);\nfloat minESM=min(lumaE,minSM);\nfloat maxWN=max(lumaN,lumaW);\nfloat minWN=min(lumaN,lumaW);\nfloat rangeMax=max(maxWN,maxESM);\nfloat rangeMin=min(minWN,minESM);\nfloat rangeMaxScaled=rangeMax*fxaaQualityEdgeThreshold;\nfloat range=rangeMax-rangeMin;\nfloat rangeMaxClamped=max(fxaaQualityEdgeThresholdMin,rangeMaxScaled);\n#ifndef MALI\nif(range=edgeVert;\nfloat subpixA=subpixNSWE*2.0+subpixNWSWNESE;\nif (!horzSpan)\n{\nlumaN=lumaW;\n}\nif (!horzSpan) \n{\nlumaS=lumaE;\n}\nif (horzSpan) \n{\nlengthSign=texelSize.y;\n}\nfloat subpixB=(subpixA*(1.0/12.0))-lumaM;\nfloat gradientN=lumaN-lumaM;\nfloat gradientS=lumaS-lumaM;\nfloat lumaNN=lumaN+lumaM;\nfloat lumaSS=lumaS+lumaM;\nbool pairN=abs(gradientN)>=abs(gradientS);\nfloat gradient=max(abs(gradientN),abs(gradientS));\nif (pairN)\n{\nlengthSign=-lengthSign;\n}\nfloat subpixC=clamp(abs(subpixB)*subpixRcpRange,0.0,1.0);\nvec2 posB;\nposB.x=posM.x;\nposB.y=posM.y;\nvec2 offNP;\noffNP.x=(!horzSpan) ? 0.0 : texelSize.x;\noffNP.y=(horzSpan) ? 0.0 : texelSize.y;\nif (!horzSpan) \n{\nposB.x+=lengthSign*0.5;\n}\nif (horzSpan)\n{\nposB.y+=lengthSign*0.5;\n}\nvec2 posN;\nposN.x=posB.x-offNP.x*1.5;\nposN.y=posB.y-offNP.y*1.5;\nvec2 posP;\nposP.x=posB.x+offNP.x*1.5;\nposP.y=posB.y+offNP.y*1.5;\nfloat subpixD=((-2.0)*subpixC)+3.0;\nfloat lumaEndN=FxaaLuma(texture2D(textureSampler,posN,0.0));\nfloat subpixE=subpixC*subpixC;\nfloat lumaEndP=FxaaLuma(texture2D(textureSampler,posP,0.0));\nif (!pairN) \n{\nlumaNN=lumaSS;\n}\nfloat gradientScaled=gradient*1.0/4.0;\nfloat lumaMM=lumaM-lumaNN*0.5;\nfloat subpixF=subpixD*subpixE;\nbool lumaMLTZero=lumaMM<0.0;\nlumaEndN-=lumaNN*0.5;\nlumaEndP-=lumaNN*0.5;\nbool doneN=abs(lumaEndN)>=gradientScaled;\nbool doneP=abs(lumaEndP)>=gradientScaled;\nif (!doneN) \n{\nposN.x-=offNP.x*3.0;\n}\nif (!doneN) \n{\nposN.y-=offNP.y*3.0;\n}\nbool doneNP=(!doneN) || (!doneP);\nif (!doneP) \n{\nposP.x+=offNP.x*3.0;\n}\nif (!doneP)\n{\nposP.y+=offNP.y*3.0;\n}\nif (doneNP)\n{\nif (!doneN) lumaEndN=FxaaLuma(texture2D(textureSampler,posN.xy,0.0));\nif (!doneP) lumaEndP=FxaaLuma(texture2D(textureSampler,posP.xy,0.0));\nif (!doneN) lumaEndN=lumaEndN-lumaNN*0.5;\nif (!doneP) lumaEndP=lumaEndP-lumaNN*0.5;\ndoneN=abs(lumaEndN)>=gradientScaled;\ndoneP=abs(lumaEndP)>=gradientScaled;\nif (!doneN) posN.x-=offNP.x*12.0;\nif (!doneN) posN.y-=offNP.y*12.0;\ndoneNP=(!doneN) || (!doneP);\nif (!doneP) posP.x+=offNP.x*12.0;\nif (!doneP) posP.y+=offNP.y*12.0;\n}\nfloat dstN=posM.x-posN.x;\nfloat dstP=posP.x-posM.x;\nif (!horzSpan)\n{\ndstN=posM.y-posN.y;\n}\nif (!horzSpan) \n{\ndstP=posP.y-posM.y;\n}\nbool goodSpanN=(lumaEndN<0.0) != lumaMLTZero;\nfloat spanLength=(dstP+dstN);\nbool goodSpanP=(lumaEndP<0.0) != lumaMLTZero;\nfloat spanLengthRcp=1.0/spanLength;\nbool directionN=dstN\n\nuniform sampler2D textureSampler; \n\nuniform float intensity;\nuniform float animatedSeed;\n\nvarying vec2 vUV;\nvoid main(void)\n{\ngl_FragColor=texture2D(textureSampler,vUV);\nvec2 seed=vUV*(animatedSeed);\nfloat grain=dither(seed,intensity);\n\nfloat lum=getLuminance(gl_FragColor.rgb);\nfloat grainAmount=(cos(-PI+(lum*PI*2.))+1.)/2.;\ngl_FragColor.rgb+=grain*grainAmount;\ngl_FragColor.rgb=max(gl_FragColor.rgb,0.0);\n}","sharpenPixelShader":"\nvarying vec2 vUV;\nuniform sampler2D textureSampler;\nuniform vec2 screenSize;\nuniform vec2 sharpnessAmounts;\nvoid main(void)\n{\nvec2 onePixel=vec2(1.0,1.0)/screenSize;\nvec4 color=texture2D(textureSampler,vUV);\nvec4 edgeDetection=texture2D(textureSampler,vUV+onePixel*vec2(0,-1)) +\ntexture2D(textureSampler,vUV+onePixel*vec2(-1,0)) +\ntexture2D(textureSampler,vUV+onePixel*vec2(1,0)) +\ntexture2D(textureSampler,vUV+onePixel*vec2(0,1)) -\ncolor*4.0;\ngl_FragColor=max(vec4(color.rgb*sharpnessAmounts.y,color.a)-(sharpnessAmounts.x*vec4(edgeDetection.rgb,0)),0.);\n}","kernelBlurVertexShader":"\nattribute vec2 position;\n\nuniform vec2 delta;\n\nvarying vec2 sampleCenter;\n#include[0..varyingCount]\nconst vec2 madd=vec2(0.5,0.5);\nvoid main(void) { \nsampleCenter=(position*madd+madd);\n#include[0..varyingCount]\ngl_Position=vec4(position,0.0,1.0);\n}","kernelBlurPixelShader":"\nuniform sampler2D textureSampler;\nuniform vec2 delta;\n\nvarying vec2 sampleCenter;\n#ifdef DOF\nuniform sampler2D circleOfConfusionSampler;\nuniform vec2 cameraMinMaxZ;\nfloat sampleDistance(const in vec2 offset) {\nfloat depth=texture2D(circleOfConfusionSampler,offset).g; \nreturn cameraMinMaxZ.x+(cameraMinMaxZ.y-cameraMinMaxZ.x)*depth; \n}\nfloat sampleCoC(const in vec2 offset) {\nfloat coc=texture2D(circleOfConfusionSampler,offset).r; \nreturn coc; \n}\n#endif\n#include[0..varyingCount]\n#ifdef PACKEDFLOAT\nvec4 pack(float depth)\n{\nconst vec4 bit_shift=vec4(255.0*255.0*255.0,255.0*255.0,255.0,1.0);\nconst vec4 bit_mask=vec4(0.0,1.0/255.0,1.0/255.0,1.0/255.0);\nvec4 res=fract(depth*bit_shift);\nres-=res.xxyz*bit_mask;\nreturn res;\n}\nfloat unpack(vec4 color)\n{\nconst vec4 bit_shift=vec4(1.0/(255.0*255.0*255.0),1.0/(255.0*255.0),1.0/255.0,1.0);\nreturn dot(color,bit_shift);\n}\n#endif\nvoid main(void)\n{\nfloat computedWeight=0.0;\n#ifdef PACKEDFLOAT \nfloat blend=0.;\n#else\nvec4 blend=vec4(0.);\n#endif\n#ifdef DOF\nfloat sumOfWeights=CENTER_WEIGHT; \nfloat factor=0.0;\n\n#ifdef PACKEDFLOAT\nblend+=unpack(texture2D(textureSampler,sampleCenter))*CENTER_WEIGHT;\n#else\nblend+=texture2D(textureSampler,sampleCenter)*CENTER_WEIGHT;\n#endif\n#endif\n#include[0..varyingCount]\n#include[0..depCount]\n#ifdef PACKEDFLOAT\ngl_FragColor=pack(blend);\n#else\ngl_FragColor=blend;\n#endif\n#ifdef DOF\ngl_FragColor/=sumOfWeights;\n#endif\n}","depthOfFieldMergePixelShader":"uniform sampler2D textureSampler;\nvarying vec2 vUV;\nuniform sampler2D circleOfConfusionSampler;\nuniform sampler2D blurStep0;\n#if BLUR_LEVEL>0\nuniform sampler2D blurStep1;\n#endif\n#if BLUR_LEVEL>1\nuniform sampler2D blurStep2;\n#endif\nvoid main(void)\n{\nfloat coc=texture2D(circleOfConfusionSampler,vUV).r;\n#if BLUR_LEVEL == 0\nvec4 original=texture2D(textureSampler,vUV);\nvec4 blurred0=texture2D(blurStep0,vUV);\ngl_FragColor=mix(original,blurred0,coc);\n#endif\n#if BLUR_LEVEL == 1\nif(coc<0.5){\nvec4 original=texture2D(textureSampler,vUV);\nvec4 blurred1=texture2D(blurStep1,vUV);\ngl_FragColor=mix(original,blurred1,coc/0.5);\n}else{\nvec4 blurred0=texture2D(blurStep0,vUV); \nvec4 blurred1=texture2D(blurStep1,vUV);\ngl_FragColor=mix(blurred1,blurred0,(coc-0.5)/0.5);\n}\n#endif\n#if BLUR_LEVEL == 2\nif(coc<0.33){\nvec4 original=texture2D(textureSampler,vUV);\nvec4 blurred2=texture2D(blurStep2,vUV);\ngl_FragColor=mix(original,blurred2,coc/0.33);\n}else if(coc<0.66){\nvec4 blurred1=texture2D(blurStep1,vUV);\nvec4 blurred2=texture2D(blurStep2,vUV);\ngl_FragColor=mix(blurred2,blurred1,(coc-0.33)/0.33);\n}else{\nvec4 blurred0=texture2D(blurStep0,vUV);\nvec4 blurred1=texture2D(blurStep1,vUV);\ngl_FragColor=mix(blurred1,blurred0,(coc-0.66)/0.34);\n}\n#endif\n}\n","circleOfConfusionPixelShader":"\nuniform sampler2D depthSampler;\n\nvarying vec2 vUV;\n\nuniform vec2 cameraMinMaxZ;\n\nuniform float focusDistance;\nuniform float cocPrecalculation;\nvoid main(void)\n{\nfloat depth=texture2D(depthSampler,vUV).r;\nfloat pixelDistance=(cameraMinMaxZ.x+(cameraMinMaxZ.y-cameraMinMaxZ.x)*depth)*1000.0; \nfloat coc=abs(cocPrecalculation* ((focusDistance-pixelDistance)/pixelDistance));\ncoc=clamp(coc,0.0,1.0);\ngl_FragColor=vec4(coc,depth,coc,1.0);\n}\n","bloomMergePixelShader":"uniform sampler2D textureSampler;\nuniform sampler2D bloomBlur;\nvarying vec2 vUV;\nuniform float bloomWeight;\nvoid main(void)\n{\ngl_FragColor=texture2D(textureSampler,vUV);\nvec3 blurred=texture2D(bloomBlur,vUV).rgb;\ngl_FragColor.rgb=gl_FragColor.rgb+(blurred.rgb*bloomWeight); \n}\n","extractHighlightsPixelShader":"#include\n\nvarying vec2 vUV;\nuniform sampler2D textureSampler;\nuniform float threshold;\nuniform float exposure;\nvoid main(void) \n{\ngl_FragColor=texture2D(textureSampler,vUV);\nfloat luma=getLuminance(gl_FragColor.rgb*exposure);\ngl_FragColor.rgb=step(threshold,luma)*gl_FragColor.rgb;\n}","geometryVertexShader":"precision highp float;\nprecision highp int;\n#include\n#include\nattribute vec3 position;\nattribute vec3 normal;\n#if defined(ALPHATEST) || defined(NEED_UV)\nvarying vec2 vUV;\nuniform mat4 diffuseMatrix;\n#ifdef UV1\nvarying vec2 uv;\n#endif\n#ifdef UV2\nvarying vec2 uv2;\n#endif\n#endif\n\nuniform mat4 viewProjection;\nuniform mat4 view;\nvarying vec3 vNormalV;\nvarying vec4 vViewPos;\n#ifdef POSITION\nvarying vec3 vPosition;\n#endif\nvoid main(void)\n{\n#include\n#include\nvec4 pos=vec4(finalWorld*vec4(position,1.0));\nvNormalV=normalize(vec3((view*finalWorld)*vec4(normal,0.0)));\nvViewPos=view*pos;\n#ifdef POSITION\nvPosition=pos.xyz/pos.w;\n#endif\ngl_Position=viewProjection*finalWorld*vec4(position,1.0);\n#if defined(ALPHATEST) || defined(BASIC_RENDER)\n#ifdef UV1\nvUV=vec2(diffuseMatrix*vec4(uv,1.0,0.0));\n#endif\n#ifdef UV2\nvUV=vec2(diffuseMatrix*vec4(uv2,1.0,0.0));\n#endif\n#endif\n}","geometryPixelShader":"#extension GL_EXT_draw_buffers : require\nprecision highp float;\nprecision highp int;\nvarying vec3 vNormalV;\nvarying vec4 vViewPos;\n#ifdef POSITION\nvarying vec3 vPosition;\n#endif\n#ifdef ALPHATEST\nvarying vec2 vUV;\nuniform sampler2D diffuseSampler;\n#endif\n#ifdef POSITION\n#include[3]\n#else\n#include[2]\n#endif\nvoid main() {\n#ifdef ALPHATEST\nif (texture2D(diffuseSampler,vUV).a<0.4)\ndiscard;\n#endif\ngl_FragData[0]=vec4(vViewPos.z/vViewPos.w,0.0,0.0,1.0);\n\ngl_FragData[1]=vec4(normalize(vNormalV),1.0);\n\n#ifdef POSITION\ngl_FragData[2]=vec4(vPosition,1.0);\n#endif\n}","refractionPixelShader":"\nvarying vec2 vUV;\nuniform sampler2D textureSampler;\nuniform sampler2D refractionSampler;\n\nuniform vec3 baseColor;\nuniform float depth;\nuniform float colorLevel;\nvoid main() {\nfloat ref=1.0-texture2D(refractionSampler,vUV).r;\nvec2 uv=vUV-vec2(0.5);\nvec2 offset=uv*depth*ref;\nvec3 sourceColor=texture2D(textureSampler,vUV-offset).rgb;\ngl_FragColor=vec4(sourceColor+sourceColor*ref*colorLevel,1.0);\n}","blackAndWhitePixelShader":"\nvarying vec2 vUV;\nuniform sampler2D textureSampler;\nuniform float degree;\nvoid main(void) \n{\nvec3 color=texture2D(textureSampler,vUV).rgb;\nfloat luminance=dot(color,vec3(0.3,0.59,0.11)); \nvec3 blackAndWhite=vec3(luminance,luminance,luminance);\ngl_FragColor=vec4(color-((color-blackAndWhite)*degree),1.0);\n}","convolutionPixelShader":"\nvarying vec2 vUV;\nuniform sampler2D textureSampler;\nuniform vec2 screenSize;\nuniform float kernel[9];\nvoid main(void)\n{\nvec2 onePixel=vec2(1.0,1.0)/screenSize;\nvec4 colorSum =\ntexture2D(textureSampler,vUV+onePixel*vec2(-1,-1))*kernel[0] +\ntexture2D(textureSampler,vUV+onePixel*vec2(0,-1))*kernel[1] +\ntexture2D(textureSampler,vUV+onePixel*vec2(1,-1))*kernel[2] +\ntexture2D(textureSampler,vUV+onePixel*vec2(-1,0))*kernel[3] +\ntexture2D(textureSampler,vUV+onePixel*vec2(0,0))*kernel[4] +\ntexture2D(textureSampler,vUV+onePixel*vec2(1,0))*kernel[5] +\ntexture2D(textureSampler,vUV+onePixel*vec2(-1,1))*kernel[6] +\ntexture2D(textureSampler,vUV+onePixel*vec2(0,1))*kernel[7] +\ntexture2D(textureSampler,vUV+onePixel*vec2(1,1))*kernel[8];\nfloat kernelWeight =\nkernel[0] +\nkernel[1] +\nkernel[2] +\nkernel[3] +\nkernel[4] +\nkernel[5] +\nkernel[6] +\nkernel[7] +\nkernel[8];\nif (kernelWeight<=0.0) {\nkernelWeight=1.0;\n}\ngl_FragColor=vec4((colorSum/kernelWeight).rgb,1);\n}","filterPixelShader":"\nvarying vec2 vUV;\nuniform sampler2D textureSampler;\nuniform mat4 kernelMatrix;\nvoid main(void)\n{\nvec3 baseColor=texture2D(textureSampler,vUV).rgb;\nvec3 updatedColor=(kernelMatrix*vec4(baseColor,1.0)).rgb;\ngl_FragColor=vec4(updatedColor,1.0);\n}","volumetricLightScatteringPixelShader":"uniform sampler2D textureSampler;\nuniform sampler2D lightScatteringSampler;\nuniform float decay;\nuniform float exposure;\nuniform float weight;\nuniform float density;\nuniform vec2 meshPositionOnScreen;\nvarying vec2 vUV;\nvoid main(void) {\nvec2 tc=vUV;\nvec2 deltaTexCoord=(tc-meshPositionOnScreen.xy);\ndeltaTexCoord*=1.0/float(NUM_SAMPLES)*density;\nfloat illuminationDecay=1.0;\nvec4 color=texture2D(lightScatteringSampler,tc)*0.4;\nfor(int i=0; i\n#include\n#include\nvoid main(void)\n{\nvec4 result=texture2D(textureSampler,vUV);\n#ifdef IMAGEPROCESSING\n#ifndef FROMLINEARSPACE\n\nresult.rgb=toLinearSpace(result.rgb);\n#endif\nresult=applyImageProcessing(result);\n#else\n\n#ifdef FROMLINEARSPACE\nresult=applyImageProcessing(result);\n#endif\n#endif\ngl_FragColor=result;\n}","lensFlareVertexShader":"\nattribute vec2 position;\n\nuniform mat4 viewportMatrix;\n\nvarying vec2 vUV;\nconst vec2 madd=vec2(0.5,0.5);\nvoid main(void) { \nvUV=position*madd+madd;\ngl_Position=viewportMatrix*vec4(position,0.0,1.0);\n}","lensFlarePixelShader":"\nvarying vec2 vUV;\nuniform sampler2D textureSampler;\n\nuniform vec4 color;\nvoid main(void) {\nvec4 baseColor=texture2D(textureSampler,vUV);\ngl_FragColor=baseColor*color;\n}","anaglyphPixelShader":"\nvarying vec2 vUV;\nuniform sampler2D textureSampler;\nuniform sampler2D leftSampler;\nvoid main(void)\n{\nvec4 leftFrag=texture2D(leftSampler,vUV);\nleftFrag=vec4(1.0,leftFrag.g,leftFrag.b,1.0);\nvec4 rightFrag=texture2D(textureSampler,vUV);\nrightFrag=vec4(rightFrag.r,1.0,1.0,1.0);\ngl_FragColor=vec4(rightFrag.rgb*leftFrag.rgb,1.0);\n}","stereoscopicInterlacePixelShader":"const vec3 TWO=vec3(2.0,2.0,2.0);\nvarying vec2 vUV;\nuniform sampler2D camASampler;\nuniform sampler2D textureSampler;\nuniform vec2 stepSize;\nvoid main(void)\n{\nbool useCamB;\nvec2 texCoord1;\nvec2 texCoord2;\nvec3 frag1;\nvec3 frag2;\n#ifdef IS_STEREOSCOPIC_HORIZ\nuseCamB=vUV.x>0.5;\ntexCoord1=vec2(useCamB ? (vUV.x-0.5)*2.0 : vUV.x*2.0,vUV.y);\ntexCoord2=vec2(texCoord1.x+stepSize.x,vUV.y);\n#else\nuseCamB=vUV.y>0.5;\ntexCoord1=vec2(vUV.x,useCamB ? (vUV.y-0.5)*2.0 : vUV.y*2.0);\ntexCoord2=vec2(vUV.x,texCoord1.y+stepSize.y);\n#endif\n\nif (useCamB){\nfrag1=texture2D(textureSampler,texCoord1).rgb;\nfrag2=texture2D(textureSampler,texCoord2).rgb;\n}else{\nfrag1=texture2D(camASampler ,texCoord1).rgb;\nfrag2=texture2D(camASampler ,texCoord2).rgb;\n}\ngl_FragColor=vec4((frag1+frag2)/TWO,1.0);\n}","vrDistortionCorrectionPixelShader":"\nvarying vec2 vUV;\nuniform sampler2D textureSampler;\nuniform vec2 LensCenter;\nuniform vec2 Scale;\nuniform vec2 ScaleIn;\nuniform vec4 HmdWarpParam;\nvec2 HmdWarp(vec2 in01) {\nvec2 theta=(in01-LensCenter)*ScaleIn; \nfloat rSq=theta.x*theta.x+theta.y*theta.y;\nvec2 rvector=theta*(HmdWarpParam.x+HmdWarpParam.y*rSq+HmdWarpParam.z*rSq*rSq+HmdWarpParam.w*rSq*rSq*rSq);\nreturn LensCenter+Scale*rvector;\n}\nvoid main(void)\n{\nvec2 tc=HmdWarp(vUV);\nif (tc.x <0.0 || tc.x>1.0 || tc.y<0.0 || tc.y>1.0)\ngl_FragColor=vec4(0.0,0.0,0.0,0.0);\nelse{\ngl_FragColor=texture2D(textureSampler,tc);\n}\n}","glowBlurPostProcessPixelShader":"\nvarying vec2 vUV;\nuniform sampler2D textureSampler;\n\nuniform vec2 screenSize;\nuniform vec2 direction;\nuniform float blurWidth;\n\nfloat getLuminance(vec3 color)\n{\nreturn dot(color,vec3(0.2126,0.7152,0.0722));\n}\nvoid main(void)\n{\nfloat weights[7];\nweights[0]=0.05;\nweights[1]=0.1;\nweights[2]=0.2;\nweights[3]=0.3;\nweights[4]=0.2;\nweights[5]=0.1;\nweights[6]=0.05;\nvec2 texelSize=vec2(1.0/screenSize.x,1.0/screenSize.y);\nvec2 texelStep=texelSize*direction*blurWidth;\nvec2 start=vUV-3.0*texelStep;\nvec4 baseColor=vec4(0.,0.,0.,0.);\nvec2 texelOffset=vec2(0.,0.);\nfor (int i=0; i<7; i++)\n{\n\nvec4 texel=texture2D(textureSampler,start+texelOffset);\nbaseColor.a+=texel.a*weights[i];\n\nfloat luminance=getLuminance(baseColor.rgb);\nfloat luminanceTexel=getLuminance(texel.rgb);\nfloat choice=step(luminanceTexel,luminance);\nbaseColor.rgb=choice*baseColor.rgb+(1.0-choice)*texel.rgb;\ntexelOffset+=texelStep;\n}\ngl_FragColor=baseColor;\n}","glowMapGenerationPixelShader":"#ifdef ALPHATEST\nvarying vec2 vUVDiffuse;\nuniform sampler2D diffuseSampler;\n#endif\n#ifdef EMISSIVE\nvarying vec2 vUVEmissive;\nuniform sampler2D emissiveSampler;\n#endif\nuniform vec4 color;\nvoid main(void)\n{\n#ifdef ALPHATEST\nif (texture2D(diffuseSampler,vUVDiffuse).a<0.4)\ndiscard;\n#endif\n#ifdef EMISSIVE\ngl_FragColor=texture2D(emissiveSampler,vUVEmissive)*color;\n#else\ngl_FragColor=color;\n#endif\n}","glowMapGenerationVertexShader":"\nattribute vec3 position;\n#include\n#include\n#include[0..maxSimultaneousMorphTargets]\n\n#include\nuniform mat4 viewProjection;\nvarying vec4 vPosition;\n#ifdef UV1\nattribute vec2 uv;\n#endif\n#ifdef UV2\nattribute vec2 uv2;\n#endif\n#ifdef ALPHATEST\nvarying vec2 vUVDiffuse;\nuniform mat4 diffuseMatrix;\n#endif\n#ifdef EMISSIVE\nvarying vec2 vUVEmissive;\nuniform mat4 emissiveMatrix;\n#endif\nvoid main(void)\n{\nvec3 positionUpdated=position;\n#include[0..maxSimultaneousMorphTargets]\n#include\n#include\n#ifdef CUBEMAP\nvPosition=finalWorld*vec4(positionUpdated,1.0);\ngl_Position=viewProjection*finalWorld*vec4(position,1.0);\n#else\nvPosition=viewProjection*finalWorld*vec4(positionUpdated,1.0);\ngl_Position=vPosition;\n#endif\n#ifdef ALPHATEST\n#ifdef DIFFUSEUV1\nvUVDiffuse=vec2(diffuseMatrix*vec4(uv,1.0,0.0));\n#endif\n#ifdef DIFFUSEUV2\nvUVDiffuse=vec2(diffuseMatrix*vec4(uv2,1.0,0.0));\n#endif\n#endif\n#ifdef EMISSIVE\n#ifdef EMISSIVEUV1\nvUVEmissive=vec2(emissiveMatrix*vec4(uv,1.0,0.0));\n#endif\n#ifdef EMISSIVEUV2\nvUVEmissive=vec2(emissiveMatrix*vec4(uv2,1.0,0.0));\n#endif\n#endif\n}","glowMapMergePixelShader":"\nvarying vec2 vUV;\nuniform sampler2D textureSampler;\n#ifdef EMISSIVE\nuniform sampler2D textureSampler2;\n#endif\n\nuniform float offset;\nvoid main(void) {\nvec4 baseColor=texture2D(textureSampler,vUV);\n#ifdef EMISSIVE\nbaseColor+=texture2D(textureSampler2,vUV);\nbaseColor*=offset;\n#else\nbaseColor.a=abs(offset-baseColor.a);\n#ifdef STROKE\nfloat alpha=smoothstep(.0,.1,baseColor.a);\nbaseColor.a=alpha;\nbaseColor.rgb=baseColor.rgb*alpha;\n#endif\n#endif\ngl_FragColor=baseColor;\n}","glowMapMergeVertexShader":"\nattribute vec2 position;\n\nvarying vec2 vUV;\nconst vec2 madd=vec2(0.5,0.5);\nvoid main(void) {\nvUV=position*madd+madd;\ngl_Position=vec4(position,0.0,1.0);\n}","lineVertexShader":"\nattribute vec3 position;\nattribute vec4 normal;\n\nuniform mat4 worldViewProjection;\nuniform float width;\nuniform float aspectRatio;\nvoid main(void) {\nvec4 viewPosition=worldViewProjection*vec4(position,1.0);\nvec4 viewPositionNext=worldViewProjection*vec4(normal.xyz,1.0);\nvec2 currentScreen=viewPosition.xy/viewPosition.w;\nvec2 nextScreen=viewPositionNext.xy/viewPositionNext.w;\ncurrentScreen.x*=aspectRatio;\nnextScreen.x*=aspectRatio;\nvec2 dir=normalize(nextScreen-currentScreen);\nvec2 normalDir=vec2(-dir.y,dir.x);\nnormalDir*=width/2.0;\nnormalDir.x/=aspectRatio;\nvec4 offset=vec4(normalDir*normal.w,0.0,0.0);\ngl_Position=viewPosition+offset;\n}","linePixelShader":"uniform vec4 color;\nvoid main(void) {\ngl_FragColor=color;\n}","outlineVertexShader":"\nattribute vec3 position;\nattribute vec3 normal;\n#include\n\nuniform float offset;\n#include\nuniform mat4 viewProjection;\n#ifdef ALPHATEST\nvarying vec2 vUV;\nuniform mat4 diffuseMatrix;\n#ifdef UV1\nattribute vec2 uv;\n#endif\n#ifdef UV2\nattribute vec2 uv2;\n#endif\n#endif\n#include\nvoid main(void)\n{\nvec3 offsetPosition=position+normal*offset;\n#include\n#include\ngl_Position=viewProjection*finalWorld*vec4(offsetPosition,1.0);\n#ifdef ALPHATEST\n#ifdef UV1\nvUV=vec2(diffuseMatrix*vec4(uv,1.0,0.0));\n#endif\n#ifdef UV2\nvUV=vec2(diffuseMatrix*vec4(uv2,1.0,0.0));\n#endif\n#endif\n#include\n}\n","outlinePixelShader":"#ifdef LOGARITHMICDEPTH\n#extension GL_EXT_frag_depth : enable\n#endif\nuniform vec4 color;\n#ifdef ALPHATEST\nvarying vec2 vUV;\nuniform sampler2D diffuseSampler;\n#endif\n#include\nvoid main(void) {\n#ifdef ALPHATEST\nif (texture2D(diffuseSampler,vUV).a<0.4)\ndiscard;\n#endif\n#include\ngl_FragColor=color;\n}","layerVertexShader":"\nattribute vec2 position;\n\nuniform vec2 scale;\nuniform vec2 offset;\nuniform mat4 textureMatrix;\n\nvarying vec2 vUV;\nconst vec2 madd=vec2(0.5,0.5);\nvoid main(void) { \nvec2 shiftedPosition=position*scale+offset;\nvUV=vec2(textureMatrix*vec4(shiftedPosition*madd+madd,1.0,0.0));\ngl_Position=vec4(shiftedPosition,0.0,1.0);\n}","layerPixelShader":"\nvarying vec2 vUV;\nuniform sampler2D textureSampler;\n\nuniform vec4 color;\nvoid main(void) {\nvec4 baseColor=texture2D(textureSampler,vUV);\n#ifdef ALPHATEST\nif (baseColor.a<0.4)\ndiscard;\n#endif\ngl_FragColor=baseColor*color;\n}","backgroundVertexShader":"precision highp float;\n#include<__decl__backgroundVertex>\n#include\n\nattribute vec3 position;\n#ifdef NORMAL\nattribute vec3 normal;\n#endif\n#include\n\n#include\n#ifdef POINTSIZE\nuniform float pointSize;\n#endif\n\nvarying vec3 vPositionW;\n#ifdef NORMAL\nvarying vec3 vNormalW;\n#endif\n#ifdef UV1\nattribute vec2 uv;\n#endif\n#ifdef UV2\nattribute vec2 uv2;\n#endif\n#ifdef MAINUV1\nvarying vec2 vMainUV1;\n#endif\n#ifdef MAINUV2\nvarying vec2 vMainUV2; \n#endif\n#if defined(DIFFUSE) && DIFFUSEDIRECTUV == 0\nvarying vec2 vDiffuseUV;\n#endif\n#include\n#include\n#include<__decl__lightFragment>[0..maxSimultaneousLights]\n#ifdef REFLECTIONMAP_SKYBOX\nvarying vec3 vPositionUVW;\n#endif\n#if defined(REFLECTIONMAP_EQUIRECTANGULAR_FIXED) || defined(REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED)\nvarying vec3 vDirectionW;\n#endif\nvoid main(void) {\n#ifdef REFLECTIONMAP_SKYBOX\nvPositionUVW=position;\n#endif \n#include\n#include\ngl_Position=viewProjection*finalWorld*vec4(position,1.0);\nvec4 worldPos=finalWorld*vec4(position,1.0);\nvPositionW=vec3(worldPos);\n#ifdef NORMAL\nmat3 normalWorld=mat3(finalWorld);\n#ifdef NONUNIFORMSCALING\nnormalWorld=transposeMat3(inverseMat3(normalWorld));\n#endif\nvNormalW=normalize(normalWorld*normal);\n#endif\n#if defined(REFLECTIONMAP_EQUIRECTANGULAR_FIXED) || defined(REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED)\nvDirectionW=normalize(vec3(finalWorld*vec4(position,0.0)));\n#ifdef EQUIRECTANGULAR_RELFECTION_FOV\nmat3 screenToWorld=inverseMat3(mat3(finalWorld*viewProjection));\nvec3 segment=mix(vDirectionW,screenToWorld*vec3(0.0,0.0,1.0),abs(fFovMultiplier-1.0));\nif (fFovMultiplier<=1.0) {\nvDirectionW=normalize(segment);\n} else {\nvDirectionW=normalize(vDirectionW+(vDirectionW-segment));\n}\n#endif\n#endif\n#ifndef UV1\nvec2 uv=vec2(0.,0.);\n#endif\n#ifndef UV2\nvec2 uv2=vec2(0.,0.);\n#endif\n#ifdef MAINUV1\nvMainUV1=uv;\n#endif \n#ifdef MAINUV2\nvMainUV2=uv2;\n#endif\n#if defined(DIFFUSE) && DIFFUSEDIRECTUV == 0 \nif (vDiffuseInfos.x == 0.)\n{\nvDiffuseUV=vec2(diffuseMatrix*vec4(uv,1.0,0.0));\n}\nelse\n{\nvDiffuseUV=vec2(diffuseMatrix*vec4(uv2,1.0,0.0));\n}\n#endif\n\n#include\n\n#include\n\n#include[0..maxSimultaneousLights]\n\n#ifdef VERTEXCOLOR\nvColor=color;\n#endif\n\n#ifdef POINTSIZE\ngl_PointSize=pointSize;\n#endif\n}\n","backgroundPixelShader":"#ifdef TEXTURELODSUPPORT\n#extension GL_EXT_shader_texture_lod : enable\n#endif\nprecision highp float;\n#include<__decl__backgroundFragment>\n#define RECIPROCAL_PI2 0.15915494\n\nuniform vec3 vEyePosition;\n\nvarying vec3 vPositionW;\n#ifdef MAINUV1\nvarying vec2 vMainUV1;\n#endif \n#ifdef MAINUV2 \nvarying vec2 vMainUV2; \n#endif \n#ifdef NORMAL\nvarying vec3 vNormalW;\n#endif\n#ifdef DIFFUSE\n#if DIFFUSEDIRECTUV == 1\n#define vDiffuseUV vMainUV1\n#elif DIFFUSEDIRECTUV == 2\n#define vDiffuseUV vMainUV2\n#else\nvarying vec2 vDiffuseUV;\n#endif\nuniform sampler2D diffuseSampler;\n#endif\n\n#ifdef REFLECTION\n#ifdef REFLECTIONMAP_3D\n#define sampleReflection(s,c) textureCube(s,c)\nuniform samplerCube reflectionSampler;\n#ifdef TEXTURELODSUPPORT\n#define sampleReflectionLod(s,c,l) textureCubeLodEXT(s,c,l)\n#else\nuniform samplerCube reflectionSamplerLow;\nuniform samplerCube reflectionSamplerHigh;\n#endif\n#else\n#define sampleReflection(s,c) texture2D(s,c)\nuniform sampler2D reflectionSampler;\n#ifdef TEXTURELODSUPPORT\n#define sampleReflectionLod(s,c,l) texture2DLodEXT(s,c,l)\n#else\nuniform samplerCube reflectionSamplerLow;\nuniform samplerCube reflectionSamplerHigh;\n#endif\n#endif\n#ifdef REFLECTIONMAP_SKYBOX\nvarying vec3 vPositionUVW;\n#else\n#if defined(REFLECTIONMAP_EQUIRECTANGULAR_FIXED) || defined(REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED)\nvarying vec3 vDirectionW;\n#endif\n#endif\n#include\n#endif\n\n#ifndef FROMLINEARSPACE\n#define FROMLINEARSPACE;\n#endif\n\n#ifndef SHADOWONLY\n#define SHADOWONLY;\n#endif\n#include\n\n#include<__decl__lightFragment>[0..maxSimultaneousLights]\n#include\n#include\n#include\n#include\n#include\n\n#include\n#ifdef REFLECTIONFRESNEL\n#define FRESNEL_MAXIMUM_ON_ROUGH 0.25\nvec3 fresnelSchlickEnvironmentGGX(float VdotN,vec3 reflectance0,vec3 reflectance90,float smoothness)\n{\n\nfloat weight=mix(FRESNEL_MAXIMUM_ON_ROUGH,1.0,smoothness);\nreturn reflectance0+weight*(reflectance90-reflectance0)*pow(clamp(1.0-VdotN,0.,1.),5.0);\n}\n#endif\nvoid main(void) {\n#include\nvec3 viewDirectionW=normalize(vEyePosition-vPositionW);\n\n#ifdef NORMAL\nvec3 normalW=normalize(vNormalW);\n#else\nvec3 normalW=vec3(0.0,1.0,0.0);\n#endif\n\nfloat shadow=1.;\nfloat globalShadow=0.;\nfloat shadowLightCount=0.;\n#include[0..maxSimultaneousLights]\n#ifdef SHADOWINUSE\nglobalShadow/=shadowLightCount;\n#else\nglobalShadow=1.0;\n#endif\n\nvec4 reflectionColor=vec4(1.,1.,1.,1.);\n#ifdef REFLECTION\nvec3 reflectionVector=computeReflectionCoords(vec4(vPositionW,1.0),normalW);\n#ifdef REFLECTIONMAP_OPPOSITEZ\nreflectionVector.z*=-1.0;\n#endif\n\n#ifdef REFLECTIONMAP_3D\nvec3 reflectionCoords=reflectionVector;\n#else\nvec2 reflectionCoords=reflectionVector.xy;\n#ifdef REFLECTIONMAP_PROJECTION\nreflectionCoords/=reflectionVector.z;\n#endif\nreflectionCoords.y=1.0-reflectionCoords.y;\n#endif\n#ifdef REFLECTIONBLUR\nfloat reflectionLOD=vReflectionInfos.y;\n#ifdef TEXTURELODSUPPORT\n\nreflectionLOD=reflectionLOD*log2(vReflectionMicrosurfaceInfos.x)*vReflectionMicrosurfaceInfos.y+vReflectionMicrosurfaceInfos.z;\nreflectionColor=sampleReflectionLod(reflectionSampler,reflectionCoords,reflectionLOD);\n#else\nfloat lodReflectionNormalized=clamp(reflectionLOD,0.,1.);\nfloat lodReflectionNormalizedDoubled=lodReflectionNormalized*2.0;\nvec4 reflectionSpecularMid=sampleReflection(reflectionSampler,reflectionCoords);\nif(lodReflectionNormalizedDoubled<1.0){\nreflectionColor=mix(\nsampleReflection(reflectionSamplerHigh,reflectionCoords),\nreflectionSpecularMid,\nlodReflectionNormalizedDoubled\n);\n} else {\nreflectionColor=mix(\nreflectionSpecularMid,\nsampleReflection(reflectionSamplerLow,reflectionCoords),\nlodReflectionNormalizedDoubled-1.0\n);\n}\n#endif\n#else\nvec4 reflectionSample=sampleReflection(reflectionSampler,reflectionCoords);\nreflectionColor=reflectionSample;\n#endif\n#ifdef RGBDREFLECTION\nreflectionColor.rgb=fromRGBD(reflectionColor);\n#endif\n#ifdef GAMMAREFLECTION\nreflectionColor.rgb=toLinearSpace(reflectionColor.rgb);\n#endif\n#ifdef REFLECTIONBGR\nreflectionColor.rgb=reflectionColor.bgr;\n#endif\n\nreflectionColor.rgb*=vReflectionInfos.x;\n#endif\n\nvec3 diffuseColor=vec3(1.,1.,1.);\nfloat finalAlpha=alpha;\n#ifdef DIFFUSE\nvec4 diffuseMap=texture2D(diffuseSampler,vDiffuseUV);\n#ifdef GAMMADIFFUSE\ndiffuseMap.rgb=toLinearSpace(diffuseMap.rgb);\n#endif\n\ndiffuseMap.rgb*=vDiffuseInfos.y;\n#ifdef DIFFUSEHASALPHA\nfinalAlpha*=diffuseMap.a;\n#endif\ndiffuseColor=diffuseMap.rgb;\n#endif\n\n#ifdef REFLECTIONFRESNEL\nvec3 colorBase=diffuseColor;\n#else\nvec3 colorBase=reflectionColor.rgb*diffuseColor;\n#endif\ncolorBase=max(colorBase,0.0);\n\n#ifdef USERGBCOLOR\nvec3 finalColor=colorBase;\n#else\n#ifdef USEHIGHLIGHTANDSHADOWCOLORS\nvec3 mainColor=mix(vPrimaryColorShadow.rgb,vPrimaryColor.rgb,colorBase);\n#else\nvec3 mainColor=vPrimaryColor.rgb;\n#endif\nvec3 finalColor=colorBase*mainColor;\n#endif\n\n#ifdef REFLECTIONFRESNEL\nvec3 reflectionAmount=vReflectionControl.xxx;\nvec3 reflectionReflectance0=vReflectionControl.yyy;\nvec3 reflectionReflectance90=vReflectionControl.zzz;\nfloat VdotN=dot(normalize(vEyePosition),normalW);\nvec3 planarReflectionFresnel=fresnelSchlickEnvironmentGGX(clamp(VdotN,0.0,1.0),reflectionReflectance0,reflectionReflectance90,1.0);\nreflectionAmount*=planarReflectionFresnel;\n#ifdef REFLECTIONFALLOFF\nfloat reflectionDistanceFalloff=1.0-clamp(length(vPositionW.xyz-vBackgroundCenter)*vReflectionControl.w,0.0,1.0);\nreflectionDistanceFalloff*=reflectionDistanceFalloff;\nreflectionAmount*=reflectionDistanceFalloff;\n#endif\nfinalColor=mix(finalColor,reflectionColor.rgb,clamp(reflectionAmount,0.,1.));\n#endif\n#ifdef OPACITYFRESNEL\nfloat viewAngleToFloor=dot(normalW,normalize(vEyePosition-vBackgroundCenter));\n\nconst float startAngle=0.1;\nfloat fadeFactor=clamp(viewAngleToFloor/startAngle,0.0,1.0);\nfinalAlpha*=fadeFactor*fadeFactor;\n#endif\n\n#ifdef SHADOWINUSE\nfinalColor=mix(finalColor*shadowLevel,finalColor,globalShadow);\n#endif\n\nvec4 color=vec4(finalColor,finalAlpha);\n#include\n#ifdef IMAGEPROCESSINGPOSTPROCESS\n\n\ncolor.rgb=clamp(color.rgb,0.,30.0);\n#else\n\ncolor=applyImageProcessing(color);\n#endif\n#ifdef PREMULTIPLYALPHA\n\ncolor.rgb*=color.a;\n#endif\n#ifdef NOISE\ncolor.rgb+=dither(vPositionW.xy,0.5);\ncolor=max(color,0.0);\n#endif\ngl_FragColor=color;\n}\n","noisePixelShader":"\n\nuniform float brightness;\nuniform int octaves;\nuniform float persistence;\nuniform float timeScale;\n\nvarying vec2 vUV;\n\nvec2 hash22(vec2 p)\n{\np=p*mat2(127.1,311.7,269.5,183.3);\np=-1.0+2.0*fract(sin(p)*43758.5453123);\nreturn sin(p*6.283+timeScale);\n}\nfloat interpolationNoise(vec2 p)\n{\nvec2 pi=floor(p);\nvec2 pf=p-pi;\nvec2 w=pf*pf*(3.-2.*pf);\nfloat f00=dot(hash22(pi+vec2(.0,.0)),pf-vec2(.0,.0));\nfloat f01=dot(hash22(pi+vec2(.0,1.)),pf-vec2(.0,1.));\nfloat f10=dot(hash22(pi+vec2(1.0,0.)),pf-vec2(1.0,0.));\nfloat f11=dot(hash22(pi+vec2(1.0,1.)),pf-vec2(1.0,1.));\nfloat xm1=mix(f00,f10,w.x);\nfloat xm2=mix(f01,f11,w.x);\nfloat ym=mix(xm1,xm2,w.y); \nreturn ym;\n}\nfloat perlinNoise2D(float x,float y)\n{\nfloat sum=0.0;\nfloat frequency=0.0;\nfloat amplitude=0.0;\nfor(int i=0; i0\nuniform mat4 mBones[BonesPerMesh];\nattribute vec4 matricesIndices;\nattribute vec4 matricesWeights;\n#if NUM_BONE_INFLUENCERS>4\nattribute vec4 matricesIndicesExtra;\nattribute vec4 matricesWeightsExtra;\n#endif\n#endif","instancesDeclaration":"#ifdef INSTANCES\nattribute vec4 world0;\nattribute vec4 world1;\nattribute vec4 world2;\nattribute vec4 world3;\n#else\nuniform mat4 world;\n#endif","pointCloudVertexDeclaration":"#ifdef POINTSIZE\nuniform float pointSize;\n#endif","bumpVertexDeclaration":"#if defined(BUMP) || defined(PARALLAX)\n#if defined(TANGENT) && defined(NORMAL) \nvarying mat3 vTBN;\n#endif\n#endif\n","clipPlaneVertexDeclaration":"#ifdef CLIPPLANE\nuniform vec4 vClipPlane;\nvarying float fClipDistance;\n#endif","fogVertexDeclaration":"#ifdef FOG\nvarying vec3 vFogDistance;\n#endif","morphTargetsVertexGlobalDeclaration":"#ifdef MORPHTARGETS\nuniform float morphTargetInfluences[NUM_MORPH_INFLUENCERS];\n#endif","morphTargetsVertexDeclaration":"#ifdef MORPHTARGETS\nattribute vec3 position{X};\n#ifdef MORPHTARGETS_NORMAL\nattribute vec3 normal{X};\n#endif\n#ifdef MORPHTARGETS_TANGENT\nattribute vec3 tangent{X};\n#endif\n#endif","logDepthDeclaration":"#ifdef LOGARITHMICDEPTH\nuniform float logarithmicDepthConstant;\nvarying float vFragmentDepth;\n#endif","morphTargetsVertex":"#ifdef MORPHTARGETS\npositionUpdated+=(position{X}-position)*morphTargetInfluences[{X}];\n#ifdef MORPHTARGETS_NORMAL\nnormalUpdated+=(normal{X}-normal)*morphTargetInfluences[{X}];\n#endif\n#ifdef MORPHTARGETS_TANGENT\ntangentUpdated.xyz+=(tangent{X}-tangent.xyz)*morphTargetInfluences[{X}];\n#endif\n#endif","instancesVertex":"#ifdef INSTANCES\nmat4 finalWorld=mat4(world0,world1,world2,world3);\n#else\nmat4 finalWorld=world;\n#endif","bonesVertex":"#if NUM_BONE_INFLUENCERS>0\nmat4 influence;\ninfluence=mBones[int(matricesIndices[0])]*matricesWeights[0];\n#if NUM_BONE_INFLUENCERS>1\ninfluence+=mBones[int(matricesIndices[1])]*matricesWeights[1];\n#endif \n#if NUM_BONE_INFLUENCERS>2\ninfluence+=mBones[int(matricesIndices[2])]*matricesWeights[2];\n#endif \n#if NUM_BONE_INFLUENCERS>3\ninfluence+=mBones[int(matricesIndices[3])]*matricesWeights[3];\n#endif \n#if NUM_BONE_INFLUENCERS>4\ninfluence+=mBones[int(matricesIndicesExtra[0])]*matricesWeightsExtra[0];\n#endif \n#if NUM_BONE_INFLUENCERS>5\ninfluence+=mBones[int(matricesIndicesExtra[1])]*matricesWeightsExtra[1];\n#endif \n#if NUM_BONE_INFLUENCERS>6\ninfluence+=mBones[int(matricesIndicesExtra[2])]*matricesWeightsExtra[2];\n#endif \n#if NUM_BONE_INFLUENCERS>7\ninfluence+=mBones[int(matricesIndicesExtra[3])]*matricesWeightsExtra[3];\n#endif \nfinalWorld=finalWorld*influence;\n#endif","bumpVertex":"#if defined(BUMP) || defined(PARALLAX)\n#if defined(TANGENT) && defined(NORMAL)\nvec3 tbnNormal=normalize(normalUpdated);\nvec3 tbnTangent=normalize(tangentUpdated.xyz);\nvec3 tbnBitangent=cross(tbnNormal,tbnTangent)*tangentUpdated.w;\nvTBN=mat3(finalWorld)*mat3(tbnTangent,tbnBitangent,tbnNormal);\n#endif\n#endif","clipPlaneVertex":"#ifdef CLIPPLANE\nfClipDistance=dot(worldPos,vClipPlane);\n#endif","fogVertex":"#ifdef FOG\nvFogDistance=(view*worldPos).xyz;\n#endif","shadowsVertex":"#ifdef SHADOWS\n#if defined(SHADOW{X}) && !defined(SHADOWCUBE{X})\nvPositionFromLight{X}=lightMatrix{X}*worldPos;\nvDepthMetric{X}=((vPositionFromLight{X}.z+light{X}.depthValues.x)/(light{X}.depthValues.y));\n#endif\n#endif","pointCloudVertex":"#ifdef POINTSIZE\ngl_PointSize=pointSize;\n#endif","logDepthVertex":"#ifdef LOGARITHMICDEPTH\nvFragmentDepth=1.0+gl_Position.w;\ngl_Position.z=log2(max(0.000001,vFragmentDepth))*logarithmicDepthConstant;\n#endif","helperFunctions":"const float PI=3.1415926535897932384626433832795;\nconst float LinearEncodePowerApprox=2.2;\nconst float GammaEncodePowerApprox=1.0/LinearEncodePowerApprox;\nconst vec3 LuminanceEncodeApprox=vec3(0.2126,0.7152,0.0722);\nmat3 transposeMat3(mat3 inMatrix) {\nvec3 i0=inMatrix[0];\nvec3 i1=inMatrix[1];\nvec3 i2=inMatrix[2];\nmat3 outMatrix=mat3(\nvec3(i0.x,i1.x,i2.x),\nvec3(i0.y,i1.y,i2.y),\nvec3(i0.z,i1.z,i2.z)\n);\nreturn outMatrix;\n}\n\nmat3 inverseMat3(mat3 inMatrix) {\nfloat a00=inMatrix[0][0],a01=inMatrix[0][1],a02=inMatrix[0][2];\nfloat a10=inMatrix[1][0],a11=inMatrix[1][1],a12=inMatrix[1][2];\nfloat a20=inMatrix[2][0],a21=inMatrix[2][1],a22=inMatrix[2][2];\nfloat b01=a22*a11-a12*a21;\nfloat b11=-a22*a10+a12*a20;\nfloat b21=a21*a10-a11*a20;\nfloat det=a00*b01+a01*b11+a02*b21;\nreturn mat3(b01,(-a22*a01+a02*a21),(a12*a01-a02*a11),\nb11,(a22*a00-a02*a20),(-a12*a00+a02*a10),\nb21,(-a21*a00+a01*a20),(a11*a00-a01*a10))/det;\n}\nfloat computeFallOff(float value,vec2 clipSpace,float frustumEdgeFalloff)\n{\nfloat mask=smoothstep(1.0-frustumEdgeFalloff,1.0,clamp(dot(clipSpace,clipSpace),0.,1.));\nreturn mix(value,1.0,mask);\n}\nvec3 applyEaseInOut(vec3 x){\nreturn x*x*(3.0-2.0*x);\n}\nvec3 toLinearSpace(vec3 color)\n{\nreturn pow(color,vec3(LinearEncodePowerApprox));\n}\nvec3 toGammaSpace(vec3 color)\n{\nreturn pow(color,vec3(GammaEncodePowerApprox));\n}\nfloat square(float value)\n{\nreturn value*value;\n}\nfloat getLuminance(vec3 color)\n{\nreturn clamp(dot(color,LuminanceEncodeApprox),0.,1.);\n}\n\nfloat getRand(vec2 seed) {\nreturn fract(sin(dot(seed.xy ,vec2(12.9898,78.233)))*43758.5453);\n}\nfloat dither(vec2 seed,float varianceAmount) {\nfloat rand=getRand(seed);\nfloat dither=mix(-varianceAmount/255.0,varianceAmount/255.0,rand);\nreturn dither;\n}\n\nconst float rgbdMaxRange=255.0;\nvec4 toRGBD(vec3 color) {\nfloat maxRGB=max(0.0000001,max(color.r,max(color.g,color.b)));\nfloat D=max(rgbdMaxRange/maxRGB,1.);\nD=clamp(floor(D)/255.0,0.,1.);\n\nvec3 rgb=color.rgb*D;\n\nrgb=toGammaSpace(rgb);\nreturn vec4(rgb,D); \n}\nvec3 fromRGBD(vec4 rgbd) {\n\nrgbd.rgb=toLinearSpace(rgbd.rgb);\n\nreturn rgbd.rgb/rgbd.a;\n}","lightFragmentDeclaration":"#ifdef LIGHT{X}\nuniform vec4 vLightData{X};\nuniform vec4 vLightDiffuse{X};\n#ifdef SPECULARTERM\nuniform vec3 vLightSpecular{X};\n#else\nvec3 vLightSpecular{X}=vec3(0.);\n#endif\n#ifdef SHADOW{X}\n#if defined(SHADOWCUBE{X})\nuniform samplerCube shadowSampler{X};\n#else\nvarying vec4 vPositionFromLight{X};\nvarying float vDepthMetric{X};\n#if defined(SHADOWPCSS{X})\nuniform highp sampler2DShadow shadowSampler{X};\nuniform highp sampler2D depthSampler{X};\n#elif defined(SHADOWPCF{X})\nuniform highp sampler2DShadow shadowSampler{X};\n#else\nuniform sampler2D shadowSampler{X};\n#endif\nuniform mat4 lightMatrix{X};\n#endif\nuniform vec4 shadowsInfo{X};\nuniform vec2 depthValues{X};\n#endif\n#ifdef SPOTLIGHT{X}\nuniform vec4 vLightDirection{X};\n#endif\n#ifdef HEMILIGHT{X}\nuniform vec3 vLightGround{X};\n#endif\n#ifdef PROJECTEDLIGHTTEXTURE{X}\nuniform mat4 textureProjectionMatrix{X};\nuniform sampler2D projectionLightSampler{X};\n#endif\n#endif","lightsFragmentFunctions":"\nstruct lightingInfo\n{\nvec3 diffuse;\n#ifdef SPECULARTERM\nvec3 specular;\n#endif\n#ifdef NDOTL\nfloat ndl;\n#endif\n};\nlightingInfo computeLighting(vec3 viewDirectionW,vec3 vNormal,vec4 lightData,vec3 diffuseColor,vec3 specularColor,float range,float glossiness) {\nlightingInfo result;\nvec3 lightVectorW;\nfloat attenuation=1.0;\nif (lightData.w == 0.)\n{\nvec3 direction=lightData.xyz-vPositionW;\nattenuation=max(0.,1.0-length(direction)/range);\nlightVectorW=normalize(direction);\n}\nelse\n{\nlightVectorW=normalize(-lightData.xyz);\n}\n\nfloat ndl=max(0.,dot(vNormal,lightVectorW));\n#ifdef NDOTL\nresult.ndl=ndl;\n#endif\nresult.diffuse=ndl*diffuseColor*attenuation;\n#ifdef SPECULARTERM\n\nvec3 angleW=normalize(viewDirectionW+lightVectorW);\nfloat specComp=max(0.,dot(vNormal,angleW));\nspecComp=pow(specComp,max(1.,glossiness));\nresult.specular=specComp*specularColor*attenuation;\n#endif\nreturn result;\n}\nlightingInfo computeSpotLighting(vec3 viewDirectionW,vec3 vNormal,vec4 lightData,vec4 lightDirection,vec3 diffuseColor,vec3 specularColor,float range,float glossiness) {\nlightingInfo result;\nvec3 direction=lightData.xyz-vPositionW;\nvec3 lightVectorW=normalize(direction);\nfloat attenuation=max(0.,1.0-length(direction)/range);\n\nfloat cosAngle=max(0.,dot(lightDirection.xyz,-lightVectorW));\nif (cosAngle>=lightDirection.w)\n{\ncosAngle=max(0.,pow(cosAngle,lightData.w));\nattenuation*=cosAngle;\n\nfloat ndl=max(0.,dot(vNormal,lightVectorW));\n#ifdef NDOTL\nresult.ndl=ndl;\n#endif\nresult.diffuse=ndl*diffuseColor*attenuation;\n#ifdef SPECULARTERM\n\nvec3 angleW=normalize(viewDirectionW+lightVectorW);\nfloat specComp=max(0.,dot(vNormal,angleW));\nspecComp=pow(specComp,max(1.,glossiness));\nresult.specular=specComp*specularColor*attenuation;\n#endif\nreturn result;\n}\nresult.diffuse=vec3(0.);\n#ifdef SPECULARTERM\nresult.specular=vec3(0.);\n#endif\n#ifdef NDOTL\nresult.ndl=0.;\n#endif\nreturn result;\n}\nlightingInfo computeHemisphericLighting(vec3 viewDirectionW,vec3 vNormal,vec4 lightData,vec3 diffuseColor,vec3 specularColor,vec3 groundColor,float glossiness) {\nlightingInfo result;\n\nfloat ndl=dot(vNormal,lightData.xyz)*0.5+0.5;\n#ifdef NDOTL\nresult.ndl=ndl;\n#endif\nresult.diffuse=mix(groundColor,diffuseColor,ndl);\n#ifdef SPECULARTERM\n\nvec3 angleW=normalize(viewDirectionW+lightData.xyz);\nfloat specComp=max(0.,dot(vNormal,angleW));\nspecComp=pow(specComp,max(1.,glossiness));\nresult.specular=specComp*specularColor;\n#endif\nreturn result;\n}\nvec3 computeProjectionTextureDiffuseLighting(sampler2D projectionLightSampler,mat4 textureProjectionMatrix){\nvec4 strq=textureProjectionMatrix*vec4(vPositionW,1.0);\nstrq/=strq.w;\nvec3 textureColor=texture2D(projectionLightSampler,strq.xy).rgb;\nreturn textureColor;\n}","lightUboDeclaration":"#ifdef LIGHT{X}\nuniform Light{X}\n{\nvec4 vLightData;\nvec4 vLightDiffuse;\nvec3 vLightSpecular;\n#ifdef SPOTLIGHT{X}\nvec4 vLightDirection;\n#endif\n#ifdef HEMILIGHT{X}\nvec3 vLightGround;\n#endif\nvec4 shadowsInfo;\nvec2 depthValues;\n} light{X};\n#ifdef PROJECTEDLIGHTTEXTURE{X}\nuniform mat4 textureProjectionMatrix{X};\nuniform sampler2D projectionLightSampler{X};\n#endif\n#ifdef SHADOW{X}\n#if defined(SHADOWCUBE{X})\nuniform samplerCube shadowSampler{X}; \n#else\nvarying vec4 vPositionFromLight{X};\nvarying float vDepthMetric{X};\n#if defined(SHADOWPCSS{X})\nuniform highp sampler2DShadow shadowSampler{X};\nuniform highp sampler2D depthSampler{X};\n#elif defined(SHADOWPCF{X})\nuniform highp sampler2DShadow shadowSampler{X};\n#else\nuniform sampler2D shadowSampler{X};\n#endif\nuniform mat4 lightMatrix{X};\n#endif\n#endif\n#endif","defaultVertexDeclaration":"\nuniform mat4 viewProjection;\nuniform mat4 view;\n#ifdef DIFFUSE\nuniform mat4 diffuseMatrix;\nuniform vec2 vDiffuseInfos;\n#endif\n#ifdef AMBIENT\nuniform mat4 ambientMatrix;\nuniform vec2 vAmbientInfos;\n#endif\n#ifdef OPACITY\nuniform mat4 opacityMatrix;\nuniform vec2 vOpacityInfos;\n#endif\n#ifdef EMISSIVE\nuniform vec2 vEmissiveInfos;\nuniform mat4 emissiveMatrix;\n#endif\n#ifdef LIGHTMAP\nuniform vec2 vLightmapInfos;\nuniform mat4 lightmapMatrix;\n#endif\n#if defined(SPECULAR) && defined(SPECULARTERM)\nuniform vec2 vSpecularInfos;\nuniform mat4 specularMatrix;\n#endif\n#ifdef BUMP\nuniform vec3 vBumpInfos;\nuniform mat4 bumpMatrix;\n#endif\n#ifdef POINTSIZE\nuniform float pointSize;\n#endif\n","defaultFragmentDeclaration":"uniform vec4 vDiffuseColor;\n#ifdef SPECULARTERM\nuniform vec4 vSpecularColor;\n#endif\nuniform vec3 vEmissiveColor;\n\n#ifdef DIFFUSE\nuniform vec2 vDiffuseInfos;\n#endif\n#ifdef AMBIENT\nuniform vec2 vAmbientInfos;\n#endif\n#ifdef OPACITY \nuniform vec2 vOpacityInfos;\n#endif\n#ifdef EMISSIVE\nuniform vec2 vEmissiveInfos;\n#endif\n#ifdef LIGHTMAP\nuniform vec2 vLightmapInfos;\n#endif\n#ifdef BUMP\nuniform vec3 vBumpInfos;\nuniform vec2 vTangentSpaceParams;\n#endif\n#if defined(REFLECTIONMAP_SPHERICAL) || defined(REFLECTIONMAP_PROJECTION) || defined(REFRACTION)\nuniform mat4 view;\n#endif\n#ifdef REFRACTION\nuniform vec4 vRefractionInfos;\n#ifndef REFRACTIONMAP_3D\nuniform mat4 refractionMatrix;\n#endif\n#ifdef REFRACTIONFRESNEL\nuniform vec4 refractionLeftColor;\nuniform vec4 refractionRightColor;\n#endif\n#endif\n#if defined(SPECULAR) && defined(SPECULARTERM)\nuniform vec2 vSpecularInfos;\n#endif\n#ifdef DIFFUSEFRESNEL\nuniform vec4 diffuseLeftColor;\nuniform vec4 diffuseRightColor;\n#endif\n#ifdef OPACITYFRESNEL\nuniform vec4 opacityParts;\n#endif\n#ifdef EMISSIVEFRESNEL\nuniform vec4 emissiveLeftColor;\nuniform vec4 emissiveRightColor;\n#endif\n\n#ifdef REFLECTION\nuniform vec2 vReflectionInfos;\n#ifdef REFLECTIONMAP_SKYBOX\n#else\n#if defined(REFLECTIONMAP_PLANAR) || defined(REFLECTIONMAP_CUBIC) || defined(REFLECTIONMAP_PROJECTION)\nuniform mat4 reflectionMatrix;\n#endif\n#if defined(USE_LOCAL_REFLECTIONMAP_CUBIC) && defined(REFLECTIONMAP_CUBIC)\nuniform vec3 vReflectionPosition;\nuniform vec3 vReflectionSize; \n#endif\n#endif\n#ifdef REFLECTIONFRESNEL\nuniform vec4 reflectionLeftColor;\nuniform vec4 reflectionRightColor;\n#endif\n#endif","defaultUboDeclaration":"layout(std140,column_major) uniform;\nuniform Material\n{\nvec4 diffuseLeftColor;\nvec4 diffuseRightColor;\nvec4 opacityParts;\nvec4 reflectionLeftColor;\nvec4 reflectionRightColor;\nvec4 refractionLeftColor;\nvec4 refractionRightColor;\nvec4 emissiveLeftColor; \nvec4 emissiveRightColor;\nvec2 vDiffuseInfos;\nvec2 vAmbientInfos;\nvec2 vOpacityInfos;\nvec2 vReflectionInfos;\nvec3 vReflectionPosition;\nvec3 vReflectionSize;\nvec2 vEmissiveInfos;\nvec2 vLightmapInfos;\nvec2 vSpecularInfos;\nvec3 vBumpInfos;\nmat4 diffuseMatrix;\nmat4 ambientMatrix;\nmat4 opacityMatrix;\nmat4 reflectionMatrix;\nmat4 emissiveMatrix;\nmat4 lightmapMatrix;\nmat4 specularMatrix;\nmat4 bumpMatrix; \nvec4 vTangentSpaceParams;\nmat4 refractionMatrix;\nvec4 vRefractionInfos;\nvec4 vSpecularColor;\nvec3 vEmissiveColor;\nvec4 vDiffuseColor;\nfloat pointSize; \n};\nuniform Scene {\nmat4 viewProjection;\nmat4 view;\n};","shadowsFragmentFunctions":"#ifdef SHADOWS\n#ifndef SHADOWFLOAT\nfloat unpack(vec4 color)\n{\nconst vec4 bit_shift=vec4(1.0/(255.0*255.0*255.0),1.0/(255.0*255.0),1.0/255.0,1.0);\nreturn dot(color,bit_shift);\n}\n#endif\nfloat computeShadowCube(vec3 lightPosition,samplerCube shadowSampler,float darkness,vec2 depthValues)\n{\nvec3 directionToLight=vPositionW-lightPosition;\nfloat depth=length(directionToLight);\ndepth=(depth+depthValues.x)/(depthValues.y);\ndepth=clamp(depth,0.,1.0);\ndirectionToLight=normalize(directionToLight);\ndirectionToLight.y=-directionToLight.y;\n#ifndef SHADOWFLOAT\nfloat shadow=unpack(textureCube(shadowSampler,directionToLight));\n#else\nfloat shadow=textureCube(shadowSampler,directionToLight).x;\n#endif\nif (depth>shadow)\n{\nreturn darkness;\n}\nreturn 1.0;\n}\nfloat computeShadowWithPoissonSamplingCube(vec3 lightPosition,samplerCube shadowSampler,float mapSize,float darkness,vec2 depthValues)\n{\nvec3 directionToLight=vPositionW-lightPosition;\nfloat depth=length(directionToLight);\ndepth=(depth+depthValues.x)/(depthValues.y);\ndepth=clamp(depth,0.,1.0);\ndirectionToLight=normalize(directionToLight);\ndirectionToLight.y=-directionToLight.y;\nfloat visibility=1.;\nvec3 poissonDisk[4];\npoissonDisk[0]=vec3(-1.0,1.0,-1.0);\npoissonDisk[1]=vec3(1.0,-1.0,-1.0);\npoissonDisk[2]=vec3(-1.0,-1.0,-1.0);\npoissonDisk[3]=vec3(1.0,-1.0,1.0);\n\n#ifndef SHADOWFLOAT\nif (unpack(textureCube(shadowSampler,directionToLight+poissonDisk[0]*mapSize))1.0 || uv.y<0. || uv.y>1.0)\n{\nreturn 1.0;\n}\nfloat shadowPixelDepth=clamp(depthMetric,0.,1.0);\n#ifndef SHADOWFLOAT\nfloat shadow=unpack(texture2D(shadowSampler,uv));\n#else\nfloat shadow=texture2D(shadowSampler,uv).x;\n#endif\nif (shadowPixelDepth>shadow)\n{\nreturn computeFallOff(darkness,clipSpace.xy,frustumEdgeFalloff);\n}\nreturn 1.;\n}\nfloat computeShadowWithPoissonSampling(vec4 vPositionFromLight,float depthMetric,sampler2D shadowSampler,float mapSize,float darkness,float frustumEdgeFalloff)\n{\nvec3 clipSpace=vPositionFromLight.xyz/vPositionFromLight.w;\nvec2 uv=0.5*clipSpace.xy+vec2(0.5);\nif (uv.x<0. || uv.x>1.0 || uv.y<0. || uv.y>1.0)\n{\nreturn 1.0;\n}\nfloat shadowPixelDepth=clamp(depthMetric,0.,1.0);\nfloat visibility=1.;\nvec2 poissonDisk[4];\npoissonDisk[0]=vec2(-0.94201624,-0.39906216);\npoissonDisk[1]=vec2(0.94558609,-0.76890725);\npoissonDisk[2]=vec2(-0.094184101,-0.92938870);\npoissonDisk[3]=vec2(0.34495938,0.29387760);\n\n#ifndef SHADOWFLOAT\nif (unpack(texture2D(shadowSampler,uv+poissonDisk[0]*mapSize))1.0 || uv.y<0. || uv.y>1.0)\n{\nreturn 1.0;\n}\nfloat shadowPixelDepth=clamp(depthMetric,0.,1.0);\n#ifndef SHADOWFLOAT\nfloat shadowMapSample=unpack(texture2D(shadowSampler,uv));\n#else\nfloat shadowMapSample=texture2D(shadowSampler,uv).x;\n#endif\nfloat esm=1.0-clamp(exp(min(87.,depthScale*shadowPixelDepth))*shadowMapSample,0.,1.-darkness);\nreturn computeFallOff(esm,clipSpace.xy,frustumEdgeFalloff);\n}\nfloat computeShadowWithCloseESM(vec4 vPositionFromLight,float depthMetric,sampler2D shadowSampler,float darkness,float depthScale,float frustumEdgeFalloff)\n{\nvec3 clipSpace=vPositionFromLight.xyz/vPositionFromLight.w;\nvec2 uv=0.5*clipSpace.xy+vec2(0.5);\nif (uv.x<0. || uv.x>1.0 || uv.y<0. || uv.y>1.0)\n{\nreturn 1.0;\n}\nfloat shadowPixelDepth=clamp(depthMetric,0.,1.0); \n#ifndef SHADOWFLOAT\nfloat shadowMapSample=unpack(texture2D(shadowSampler,uv));\n#else\nfloat shadowMapSample=texture2D(shadowSampler,uv).x;\n#endif\nfloat esm=clamp(exp(min(87.,-depthScale*(shadowPixelDepth-shadowMapSample))),darkness,1.);\nreturn computeFallOff(esm,clipSpace.xy,frustumEdgeFalloff);\n}\n#ifdef WEBGL2\n\nfloat computeShadowWithPCF1(vec4 vPositionFromLight,float depthMetric,sampler2DShadow shadowSampler,float darkness,float frustumEdgeFalloff)\n{\nif (depthMetric>1.0 || depthMetric<0.0) {\nreturn 1.0;\n}\nvec3 clipSpace=vPositionFromLight.xyz/vPositionFromLight.w;\nvec3 uvDepth=vec3(0.5*clipSpace.xyz+vec3(0.5));\nfloat shadow=texture2D(shadowSampler,uvDepth);\nshadow=mix(darkness,1.,shadow);\nreturn computeFallOff(shadow,clipSpace.xy,frustumEdgeFalloff);\n}\n\n\n\nfloat computeShadowWithPCF3(vec4 vPositionFromLight,float depthMetric,sampler2DShadow shadowSampler,vec2 shadowMapSizeAndInverse,float darkness,float frustumEdgeFalloff)\n{\nif (depthMetric>1.0 || depthMetric<0.0) {\nreturn 1.0;\n}\nvec3 clipSpace=vPositionFromLight.xyz/vPositionFromLight.w;\nvec3 uvDepth=vec3(0.5*clipSpace.xyz+vec3(0.5));\nvec2 uv=uvDepth.xy*shadowMapSizeAndInverse.x; \nuv+=0.5; \nvec2 st=fract(uv); \nvec2 base_uv=floor(uv)-0.5; \nbase_uv*=shadowMapSizeAndInverse.y; \n\n\n\n\nvec2 uvw0=3.-2.*st;\nvec2 uvw1=1.+2.*st;\nvec2 u=vec2((2.-st.x)/uvw0.x-1.,st.x/uvw1.x+1.)*shadowMapSizeAndInverse.y;\nvec2 v=vec2((2.-st.y)/uvw0.y-1.,st.y/uvw1.y+1.)*shadowMapSizeAndInverse.y;\nfloat shadow=0.;\nshadow+=uvw0.x*uvw0.y*texture2D(shadowSampler,vec3(base_uv.xy+vec2(u[0],v[0]),uvDepth.z));\nshadow+=uvw1.x*uvw0.y*texture2D(shadowSampler,vec3(base_uv.xy+vec2(u[1],v[0]),uvDepth.z));\nshadow+=uvw0.x*uvw1.y*texture2D(shadowSampler,vec3(base_uv.xy+vec2(u[0],v[1]),uvDepth.z));\nshadow+=uvw1.x*uvw1.y*texture2D(shadowSampler,vec3(base_uv.xy+vec2(u[1],v[1]),uvDepth.z));\nshadow=shadow/16.;\nshadow=mix(darkness,1.,shadow);\nreturn computeFallOff(shadow,clipSpace.xy,frustumEdgeFalloff);\n}\n\n\n\nfloat computeShadowWithPCF5(vec4 vPositionFromLight,float depthMetric,sampler2DShadow shadowSampler,vec2 shadowMapSizeAndInverse,float darkness,float frustumEdgeFalloff)\n{\nif (depthMetric>1.0 || depthMetric<0.0) {\nreturn 1.0;\n}\nvec3 clipSpace=vPositionFromLight.xyz/vPositionFromLight.w;\nvec3 uvDepth=vec3(0.5*clipSpace.xyz+vec3(0.5));\nvec2 uv=uvDepth.xy*shadowMapSizeAndInverse.x; \nuv+=0.5; \nvec2 st=fract(uv); \nvec2 base_uv=floor(uv)-0.5; \nbase_uv*=shadowMapSizeAndInverse.y; \n\n\nvec2 uvw0=4.-3.*st;\nvec2 uvw1=vec2(7.);\nvec2 uvw2=1.+3.*st;\nvec3 u=vec3((3.-2.*st.x)/uvw0.x-2.,(3.+st.x)/uvw1.x,st.x/uvw2.x+2.)*shadowMapSizeAndInverse.y;\nvec3 v=vec3((3.-2.*st.y)/uvw0.y-2.,(3.+st.y)/uvw1.y,st.y/uvw2.y+2.)*shadowMapSizeAndInverse.y;\nfloat shadow=0.;\nshadow+=uvw0.x*uvw0.y*texture2D(shadowSampler,vec3(base_uv.xy+vec2(u[0],v[0]),uvDepth.z));\nshadow+=uvw1.x*uvw0.y*texture2D(shadowSampler,vec3(base_uv.xy+vec2(u[1],v[0]),uvDepth.z));\nshadow+=uvw2.x*uvw0.y*texture2D(shadowSampler,vec3(base_uv.xy+vec2(u[2],v[0]),uvDepth.z));\nshadow+=uvw0.x*uvw1.y*texture2D(shadowSampler,vec3(base_uv.xy+vec2(u[0],v[1]),uvDepth.z));\nshadow+=uvw1.x*uvw1.y*texture2D(shadowSampler,vec3(base_uv.xy+vec2(u[1],v[1]),uvDepth.z));\nshadow+=uvw2.x*uvw1.y*texture2D(shadowSampler,vec3(base_uv.xy+vec2(u[2],v[1]),uvDepth.z));\nshadow+=uvw0.x*uvw2.y*texture2D(shadowSampler,vec3(base_uv.xy+vec2(u[0],v[2]),uvDepth.z));\nshadow+=uvw1.x*uvw2.y*texture2D(shadowSampler,vec3(base_uv.xy+vec2(u[1],v[2]),uvDepth.z));\nshadow+=uvw2.x*uvw2.y*texture2D(shadowSampler,vec3(base_uv.xy+vec2(u[2],v[2]),uvDepth.z));\nshadow=shadow/144.;\nshadow=mix(darkness,1.,shadow);\nreturn computeFallOff(shadow,clipSpace.xy,frustumEdgeFalloff);\n}\nconst vec3 PoissonSamplers32[64]=vec3[64](\nvec3(0.06407013,0.05409927,0.),\nvec3(0.7366577,0.5789394,0.),\nvec3(-0.6270542,-0.5320278,0.),\nvec3(-0.4096107,0.8411095,0.),\nvec3(0.6849564,-0.4990818,0.),\nvec3(-0.874181,-0.04579735,0.),\nvec3(0.9989998,0.0009880066,0.),\nvec3(-0.004920578,-0.9151649,0.),\nvec3(0.1805763,0.9747483,0.),\nvec3(-0.2138451,0.2635818,0.),\nvec3(0.109845,0.3884785,0.),\nvec3(0.06876755,-0.3581074,0.),\nvec3(0.374073,-0.7661266,0.),\nvec3(0.3079132,-0.1216763,0.),\nvec3(-0.3794335,-0.8271583,0.),\nvec3(-0.203878,-0.07715034,0.),\nvec3(0.5912697,0.1469799,0.),\nvec3(-0.88069,0.3031784,0.),\nvec3(0.5040108,0.8283722,0.),\nvec3(-0.5844124,0.5494877,0.),\nvec3(0.6017799,-0.1726654,0.),\nvec3(-0.5554981,0.1559997,0.),\nvec3(-0.3016369,-0.3900928,0.),\nvec3(-0.5550632,-0.1723762,0.),\nvec3(0.925029,0.2995041,0.),\nvec3(-0.2473137,0.5538505,0.),\nvec3(0.9183037,-0.2862392,0.),\nvec3(0.2469421,0.6718712,0.),\nvec3(0.3916397,-0.4328209,0.),\nvec3(-0.03576927,-0.6220032,0.),\nvec3(-0.04661255,0.7995201,0.),\nvec3(0.4402924,0.3640312,0.),\nvec3(0.,0.,0.),\nvec3(0.,0.,0.),\nvec3(0.,0.,0.),\nvec3(0.,0.,0.),\nvec3(0.,0.,0.),\nvec3(0.,0.,0.),\nvec3(0.,0.,0.),\nvec3(0.,0.,0.),\nvec3(0.,0.,0.),\nvec3(0.,0.,0.),\nvec3(0.,0.,0.),\nvec3(0.,0.,0.),\nvec3(0.,0.,0.),\nvec3(0.,0.,0.),\nvec3(0.,0.,0.),\nvec3(0.,0.,0.),\nvec3(0.,0.,0.),\nvec3(0.,0.,0.),\nvec3(0.,0.,0.),\nvec3(0.,0.,0.),\nvec3(0.,0.,0.),\nvec3(0.,0.,0.),\nvec3(0.,0.,0.),\nvec3(0.,0.,0.),\nvec3(0.,0.,0.),\nvec3(0.,0.,0.),\nvec3(0.,0.,0.),\nvec3(0.,0.,0.),\nvec3(0.,0.,0.),\nvec3(0.,0.,0.),\nvec3(0.,0.,0.),\nvec3(0.,0.,0.)\n);\nconst vec3 PoissonSamplers64[64]=vec3[64](\nvec3(-0.613392,0.617481,0.),\nvec3(0.170019,-0.040254,0.),\nvec3(-0.299417,0.791925,0.),\nvec3(0.645680,0.493210,0.),\nvec3(-0.651784,0.717887,0.),\nvec3(0.421003,0.027070,0.),\nvec3(-0.817194,-0.271096,0.),\nvec3(-0.705374,-0.668203,0.),\nvec3(0.977050,-0.108615,0.),\nvec3(0.063326,0.142369,0.),\nvec3(0.203528,0.214331,0.),\nvec3(-0.667531,0.326090,0.),\nvec3(-0.098422,-0.295755,0.),\nvec3(-0.885922,0.215369,0.),\nvec3(0.566637,0.605213,0.),\nvec3(0.039766,-0.396100,0.),\nvec3(0.751946,0.453352,0.),\nvec3(0.078707,-0.715323,0.),\nvec3(-0.075838,-0.529344,0.),\nvec3(0.724479,-0.580798,0.),\nvec3(0.222999,-0.215125,0.),\nvec3(-0.467574,-0.405438,0.),\nvec3(-0.248268,-0.814753,0.),\nvec3(0.354411,-0.887570,0.),\nvec3(0.175817,0.382366,0.),\nvec3(0.487472,-0.063082,0.),\nvec3(-0.084078,0.898312,0.),\nvec3(0.488876,-0.783441,0.),\nvec3(0.470016,0.217933,0.),\nvec3(-0.696890,-0.549791,0.),\nvec3(-0.149693,0.605762,0.),\nvec3(0.034211,0.979980,0.),\nvec3(0.503098,-0.308878,0.),\nvec3(-0.016205,-0.872921,0.),\nvec3(0.385784,-0.393902,0.),\nvec3(-0.146886,-0.859249,0.),\nvec3(0.643361,0.164098,0.),\nvec3(0.634388,-0.049471,0.),\nvec3(-0.688894,0.007843,0.),\nvec3(0.464034,-0.188818,0.),\nvec3(-0.440840,0.137486,0.),\nvec3(0.364483,0.511704,0.),\nvec3(0.034028,0.325968,0.),\nvec3(0.099094,-0.308023,0.),\nvec3(0.693960,-0.366253,0.),\nvec3(0.678884,-0.204688,0.),\nvec3(0.001801,0.780328,0.),\nvec3(0.145177,-0.898984,0.),\nvec3(0.062655,-0.611866,0.),\nvec3(0.315226,-0.604297,0.),\nvec3(-0.780145,0.486251,0.),\nvec3(-0.371868,0.882138,0.),\nvec3(0.200476,0.494430,0.),\nvec3(-0.494552,-0.711051,0.),\nvec3(0.612476,0.705252,0.),\nvec3(-0.578845,-0.768792,0.),\nvec3(-0.772454,-0.090976,0.),\nvec3(0.504440,0.372295,0.),\nvec3(0.155736,0.065157,0.),\nvec3(0.391522,0.849605,0.),\nvec3(-0.620106,-0.328104,0.),\nvec3(0.789239,-0.419965,0.),\nvec3(-0.545396,0.538133,0.),\nvec3(-0.178564,-0.596057,0.)\n);\n\n\n\n\n\nfloat computeShadowWithPCSS(vec4 vPositionFromLight,float depthMetric,sampler2D depthSampler,sampler2DShadow shadowSampler,float shadowMapSizeInverse,float lightSizeUV,float darkness,float frustumEdgeFalloff,int searchTapCount,int pcfTapCount,vec3[64] poissonSamplers)\n{\nif (depthMetric>1.0 || depthMetric<0.0) {\nreturn 1.0;\n}\nvec3 clipSpace=vPositionFromLight.xyz/vPositionFromLight.w;\nvec3 uvDepth=vec3(0.5*clipSpace.xyz+vec3(0.5));\nfloat blockerDepth=0.0;\nfloat sumBlockerDepth=0.0;\nfloat numBlocker=0.0;\nfor (int i=0; icurrRayHeight)\n{\nfloat delta1=currSampledHeight-currRayHeight;\nfloat delta2=(currRayHeight+stepSize)-lastSampledHeight;\nfloat ratio=delta1/(delta1+delta2);\nvCurrOffset=(ratio)* vLastOffset+(1.0-ratio)*vCurrOffset;\n\nbreak;\n}\nelse\n{\ncurrRayHeight-=stepSize;\nvLastOffset=vCurrOffset;\nvCurrOffset+=stepSize*vMaxOffset;\nlastSampledHeight=currSampledHeight;\n}\n}\nreturn vCurrOffset;\n}\nvec2 parallaxOffset(vec3 viewDir,float heightScale)\n{\n\nfloat height=texture2D(bumpSampler,vBumpUV).w;\nvec2 texCoordOffset=heightScale*viewDir.xy*height;\nreturn -texCoordOffset;\n}\n#endif\n#endif","clipPlaneFragmentDeclaration":"#ifdef CLIPPLANE\nvarying float fClipDistance;\n#endif","fogFragmentDeclaration":"#ifdef FOG\n#define FOGMODE_NONE 0.\n#define FOGMODE_EXP 1.\n#define FOGMODE_EXP2 2.\n#define FOGMODE_LINEAR 3.\n#define E 2.71828\nuniform vec4 vFogInfos;\nuniform vec3 vFogColor;\nvarying vec3 vFogDistance;\nfloat CalcFogFactor()\n{\nfloat fogCoeff=1.0;\nfloat fogStart=vFogInfos.y;\nfloat fogEnd=vFogInfos.z;\nfloat fogDensity=vFogInfos.w;\nfloat fogDistance=length(vFogDistance);\nif (FOGMODE_LINEAR == vFogInfos.x)\n{\nfogCoeff=(fogEnd-fogDistance)/(fogEnd-fogStart);\n}\nelse if (FOGMODE_EXP == vFogInfos.x)\n{\nfogCoeff=1.0/pow(E,fogDistance*fogDensity);\n}\nelse if (FOGMODE_EXP2 == vFogInfos.x)\n{\nfogCoeff=1.0/pow(E,fogDistance*fogDistance*fogDensity*fogDensity);\n}\nreturn clamp(fogCoeff,0.0,1.0);\n}\n#endif","clipPlaneFragment":"#ifdef CLIPPLANE\nif (fClipDistance>0.0)\n{\ndiscard;\n}\n#endif","bumpFragment":"vec2 uvOffset=vec2(0.0,0.0);\n#if defined(BUMP) || defined(PARALLAX)\n#ifdef NORMALXYSCALE\nfloat normalScale=1.0;\n#else \nfloat normalScale=vBumpInfos.y;\n#endif\n#if defined(TANGENT) && defined(NORMAL)\nmat3 TBN=vTBN;\n#else\nmat3 TBN=cotangent_frame(normalW*normalScale,vPositionW,vBumpUV);\n#endif\n#endif\n#ifdef PARALLAX\nmat3 invTBN=transposeMat3(TBN);\n#ifdef PARALLAXOCCLUSION\nuvOffset=parallaxOcclusion(invTBN*-viewDirectionW,invTBN*normalW,vBumpUV,vBumpInfos.z);\n#else\nuvOffset=parallaxOffset(invTBN*viewDirectionW,vBumpInfos.z);\n#endif\n#endif\n#ifdef BUMP\n#ifdef OBJECTSPACE_NORMALMAP\nnormalW=normalize(texture2D(bumpSampler,vBumpUV).xyz*2.0-1.0);\nnormalW=normalize(mat3(normalMatrix)*normalW); \n#else\nnormalW=perturbNormal(TBN,vBumpUV+uvOffset);\n#endif\n#endif","lightFragment":"#ifdef LIGHT{X}\n#if defined(SHADOWONLY) || (defined(LIGHTMAP) && defined(LIGHTMAPEXCLUDED{X}) && defined(LIGHTMAPNOSPECULAR{X}))\n\n#else\n#ifdef PBR\n#ifdef SPOTLIGHT{X}\ninfo=computeSpotLighting(viewDirectionW,normalW,light{X}.vLightData,light{X}.vLightDirection,light{X}.vLightDiffuse.rgb,light{X}.vLightSpecular,light{X}.vLightDiffuse.a,roughness,NdotV,specularEnvironmentR0,specularEnvironmentR90,geometricRoughnessFactor,NdotL);\n#endif\n#ifdef HEMILIGHT{X}\ninfo=computeHemisphericLighting(viewDirectionW,normalW,light{X}.vLightData,light{X}.vLightDiffuse.rgb,light{X}.vLightSpecular,light{X}.vLightGround,roughness,NdotV,specularEnvironmentR0,specularEnvironmentR90,geometricRoughnessFactor,NdotL);\n#endif\n#if defined(POINTLIGHT{X}) || defined(DIRLIGHT{X})\ninfo=computeLighting(viewDirectionW,normalW,light{X}.vLightData,light{X}.vLightDiffuse.rgb,light{X}.vLightSpecular,light{X}.vLightDiffuse.a,roughness,NdotV,specularEnvironmentR0,specularEnvironmentR90,geometricRoughnessFactor,NdotL);\n#endif\n#else\n#ifdef SPOTLIGHT{X}\ninfo=computeSpotLighting(viewDirectionW,normalW,light{X}.vLightData,light{X}.vLightDirection,light{X}.vLightDiffuse.rgb,light{X}.vLightSpecular,light{X}.vLightDiffuse.a,glossiness);\n#endif\n#ifdef HEMILIGHT{X}\ninfo=computeHemisphericLighting(viewDirectionW,normalW,light{X}.vLightData,light{X}.vLightDiffuse.rgb,light{X}.vLightSpecular,light{X}.vLightGround,glossiness);\n#endif\n#if defined(POINTLIGHT{X}) || defined(DIRLIGHT{X})\ninfo=computeLighting(viewDirectionW,normalW,light{X}.vLightData,light{X}.vLightDiffuse.rgb,light{X}.vLightSpecular,light{X}.vLightDiffuse.a,glossiness);\n#endif\n#endif\n#ifdef PROJECTEDLIGHTTEXTURE{X}\ninfo.diffuse*=computeProjectionTextureDiffuseLighting(projectionLightSampler{X},textureProjectionMatrix{X});\n#endif\n#endif\n#ifdef SHADOW{X}\n#ifdef SHADOWCLOSEESM{X}\n#if defined(SHADOWCUBE{X})\nshadow=computeShadowWithCloseESMCube(light{X}.vLightData.xyz,shadowSampler{X},light{X}.shadowsInfo.x,light{X}.shadowsInfo.z,light{X}.depthValues);\n#else\nshadow=computeShadowWithCloseESM(vPositionFromLight{X},vDepthMetric{X},shadowSampler{X},light{X}.shadowsInfo.x,light{X}.shadowsInfo.z,light{X}.shadowsInfo.w);\n#endif\n#elif defined(SHADOWESM{X})\n#if defined(SHADOWCUBE{X})\nshadow=computeShadowWithESMCube(light{X}.vLightData.xyz,shadowSampler{X},light{X}.shadowsInfo.x,light{X}.shadowsInfo.z,light{X}.depthValues);\n#else\nshadow=computeShadowWithESM(vPositionFromLight{X},vDepthMetric{X},shadowSampler{X},light{X}.shadowsInfo.x,light{X}.shadowsInfo.z,light{X}.shadowsInfo.w);\n#endif\n#elif defined(SHADOWPOISSON{X})\n#if defined(SHADOWCUBE{X})\nshadow=computeShadowWithPoissonSamplingCube(light{X}.vLightData.xyz,shadowSampler{X},light{X}.shadowsInfo.y,light{X}.shadowsInfo.x,light{X}.depthValues);\n#else\nshadow=computeShadowWithPoissonSampling(vPositionFromLight{X},vDepthMetric{X},shadowSampler{X},light{X}.shadowsInfo.y,light{X}.shadowsInfo.x,light{X}.shadowsInfo.w);\n#endif\n#elif defined(SHADOWPCF{X})\n#if defined(SHADOWLOWQUALITY{X})\nshadow=computeShadowWithPCF1(vPositionFromLight{X},vDepthMetric{X},shadowSampler{X},light{X}.shadowsInfo.x,light{X}.shadowsInfo.w);\n#elif defined(SHADOWMEDIUMQUALITY{X})\nshadow=computeShadowWithPCF3(vPositionFromLight{X},vDepthMetric{X},shadowSampler{X},light{X}.shadowsInfo.yz,light{X}.shadowsInfo.x,light{X}.shadowsInfo.w);\n#else\nshadow=computeShadowWithPCF5(vPositionFromLight{X},vDepthMetric{X},shadowSampler{X},light{X}.shadowsInfo.yz,light{X}.shadowsInfo.x,light{X}.shadowsInfo.w);\n#endif\n#elif defined(SHADOWPCSS{X})\n#if defined(SHADOWLOWQUALITY{X})\nshadow=computeShadowWithPCSS16(vPositionFromLight{X},vDepthMetric{X},depthSampler{X},shadowSampler{X},light{X}.shadowsInfo.y,light{X}.shadowsInfo.z,light{X}.shadowsInfo.x,light{X}.shadowsInfo.w);\n#elif defined(SHADOWMEDIUMQUALITY{X})\nshadow=computeShadowWithPCSS32(vPositionFromLight{X},vDepthMetric{X},depthSampler{X},shadowSampler{X},light{X}.shadowsInfo.y,light{X}.shadowsInfo.z,light{X}.shadowsInfo.x,light{X}.shadowsInfo.w);\n#else\nshadow=computeShadowWithPCSS64(vPositionFromLight{X},vDepthMetric{X},depthSampler{X},shadowSampler{X},light{X}.shadowsInfo.y,light{X}.shadowsInfo.z,light{X}.shadowsInfo.x,light{X}.shadowsInfo.w);\n#endif\n#else\n#if defined(SHADOWCUBE{X})\nshadow=computeShadowCube(light{X}.vLightData.xyz,shadowSampler{X},light{X}.shadowsInfo.x,light{X}.depthValues);\n#else\nshadow=computeShadow(vPositionFromLight{X},vDepthMetric{X},shadowSampler{X},light{X}.shadowsInfo.x,light{X}.shadowsInfo.w);\n#endif\n#endif\n#ifdef SHADOWONLY\n#ifndef SHADOWINUSE\n#define SHADOWINUSE\n#endif\nglobalShadow+=shadow;\nshadowLightCount+=1.0;\n#endif\n#else\nshadow=1.;\n#endif\n#ifndef SHADOWONLY\n#ifdef CUSTOMUSERLIGHTING\ndiffuseBase+=computeCustomDiffuseLighting(info,diffuseBase,shadow);\n#ifdef SPECULARTERM\nspecularBase+=computeCustomSpecularLighting(info,specularBase,shadow);\n#endif\n#elif defined(LIGHTMAP) && defined(LIGHTMAPEXCLUDED{X})\ndiffuseBase+=lightmapColor*shadow;\n#ifdef SPECULARTERM\n#ifndef LIGHTMAPNOSPECULAR{X}\nspecularBase+=info.specular*shadow*lightmapColor;\n#endif\n#endif\n#else\ndiffuseBase+=info.diffuse*shadow;\n#ifdef SPECULARTERM\nspecularBase+=info.specular*shadow;\n#endif\n#endif\n#endif\n#endif","logDepthFragment":"#ifdef LOGARITHMICDEPTH\ngl_FragDepthEXT=log2(vFragmentDepth)*logarithmicDepthConstant*0.5;\n#endif","fogFragment":"#ifdef FOG\nfloat fog=CalcFogFactor();\ncolor.rgb=fog*color.rgb+(1.0-fog)*vFogColor;\n#endif","pbrVertexDeclaration":"uniform mat4 view;\nuniform mat4 viewProjection;\n#ifdef ALBEDO\nuniform mat4 albedoMatrix;\nuniform vec2 vAlbedoInfos;\n#endif\n#ifdef AMBIENT\nuniform mat4 ambientMatrix;\nuniform vec3 vAmbientInfos;\n#endif\n#ifdef OPACITY\nuniform mat4 opacityMatrix;\nuniform vec2 vOpacityInfos;\n#endif\n#ifdef EMISSIVE\nuniform vec2 vEmissiveInfos;\nuniform mat4 emissiveMatrix;\n#endif\n#ifdef LIGHTMAP\nuniform vec2 vLightmapInfos;\nuniform mat4 lightmapMatrix;\n#endif\n#ifdef REFLECTIVITY \nuniform vec3 vReflectivityInfos;\nuniform mat4 reflectivityMatrix;\n#endif\n#ifdef MICROSURFACEMAP\nuniform vec2 vMicroSurfaceSamplerInfos;\nuniform mat4 microSurfaceSamplerMatrix;\n#endif\n#ifdef BUMP\nuniform vec3 vBumpInfos;\nuniform mat4 bumpMatrix;\n#endif\n#ifdef POINTSIZE\nuniform float pointSize;\n#endif\n\n#ifdef REFRACTION\nuniform vec4 vRefractionInfos;\nuniform mat4 refractionMatrix;\nuniform vec3 vRefractionMicrosurfaceInfos;\n#endif\n\n#ifdef REFLECTION\nuniform vec2 vReflectionInfos;\nuniform mat4 reflectionMatrix;\nuniform vec3 vReflectionMicrosurfaceInfos;\n#endif\n","pbrFragmentDeclaration":"uniform vec3 vReflectionColor;\nuniform vec4 vAlbedoColor;\n\nuniform vec4 vLightingIntensity;\nuniform vec4 vReflectivityColor;\nuniform vec3 vEmissiveColor;\n\n#ifdef ALBEDO\nuniform vec2 vAlbedoInfos;\n#endif\n#ifdef AMBIENT\nuniform vec3 vAmbientInfos;\n#endif\n#ifdef BUMP\nuniform vec3 vBumpInfos;\nuniform vec2 vTangentSpaceParams;\n#endif\n#ifdef OPACITY \nuniform vec2 vOpacityInfos;\n#endif\n#ifdef EMISSIVE\nuniform vec2 vEmissiveInfos;\n#endif\n#ifdef LIGHTMAP\nuniform vec2 vLightmapInfos;\n#endif\n#ifdef REFLECTIVITY\nuniform vec3 vReflectivityInfos;\n#endif\n#ifdef MICROSURFACEMAP\nuniform vec2 vMicroSurfaceSamplerInfos;\n#endif\n\n#if defined(REFLECTIONMAP_SPHERICAL) || defined(REFLECTIONMAP_PROJECTION) || defined(REFRACTION)\nuniform mat4 view;\n#endif\n\n#ifdef REFRACTION\nuniform vec4 vRefractionInfos;\nuniform mat4 refractionMatrix;\nuniform vec3 vRefractionMicrosurfaceInfos;\n#endif\n\n#ifdef REFLECTION\nuniform vec2 vReflectionInfos;\nuniform mat4 reflectionMatrix;\nuniform vec3 vReflectionMicrosurfaceInfos;\n#if defined(USE_LOCAL_REFLECTIONMAP_CUBIC) && defined(REFLECTIONMAP_CUBIC)\nuniform vec3 vReflectionPosition;\nuniform vec3 vReflectionSize; \n#endif\n#endif","pbrUboDeclaration":"layout(std140,column_major) uniform;\nuniform Material\n{\nuniform vec2 vAlbedoInfos;\nuniform vec3 vAmbientInfos;\nuniform vec2 vOpacityInfos;\nuniform vec2 vEmissiveInfos;\nuniform vec2 vLightmapInfos;\nuniform vec3 vReflectivityInfos;\nuniform vec2 vMicroSurfaceSamplerInfos;\nuniform vec4 vRefractionInfos;\nuniform vec2 vReflectionInfos;\nuniform vec3 vReflectionPosition;\nuniform vec3 vReflectionSize; \nuniform vec3 vBumpInfos;\nuniform mat4 albedoMatrix;\nuniform mat4 ambientMatrix;\nuniform mat4 opacityMatrix;\nuniform mat4 emissiveMatrix;\nuniform mat4 lightmapMatrix;\nuniform mat4 reflectivityMatrix;\nuniform mat4 microSurfaceSamplerMatrix;\nuniform mat4 bumpMatrix;\nuniform vec2 vTangentSpaceParams;\nuniform mat4 refractionMatrix;\nuniform mat4 reflectionMatrix;\nuniform vec3 vReflectionColor;\nuniform vec4 vAlbedoColor;\nuniform vec4 vLightingIntensity;\nuniform vec3 vRefractionMicrosurfaceInfos;\nuniform vec3 vReflectionMicrosurfaceInfos;\nuniform vec4 vReflectivityColor;\nuniform vec3 vEmissiveColor;\nuniform float pointSize;\n};\nuniform Scene {\nmat4 viewProjection;\nmat4 view;\n};","pbrFunctions":"\n#define RECIPROCAL_PI2 0.15915494\n#define FRESNEL_MAXIMUM_ON_ROUGH 0.25\n\nconst float kRougnhessToAlphaScale=0.1;\nconst float kRougnhessToAlphaOffset=0.29248125;\nfloat convertRoughnessToAverageSlope(float roughness)\n{\n\nconst float kMinimumVariance=0.0005;\nfloat alphaG=square(roughness)+kMinimumVariance;\nreturn alphaG;\n}\n\nfloat smithVisibilityG1_TrowbridgeReitzGGX(float dot,float alphaG)\n{\nfloat tanSquared=(1.0-dot*dot)/(dot*dot);\nreturn 2.0/(1.0+sqrt(1.0+alphaG*alphaG*tanSquared));\n}\nfloat smithVisibilityG_TrowbridgeReitzGGX_Walter(float NdotL,float NdotV,float alphaG)\n{\nreturn smithVisibilityG1_TrowbridgeReitzGGX(NdotL,alphaG)*smithVisibilityG1_TrowbridgeReitzGGX(NdotV,alphaG);\n}\n\n\nfloat normalDistributionFunction_TrowbridgeReitzGGX(float NdotH,float alphaG)\n{\n\n\n\nfloat a2=square(alphaG);\nfloat d=NdotH*NdotH*(a2-1.0)+1.0;\nreturn a2/(PI*d*d);\n}\nvec3 fresnelSchlickGGX(float VdotH,vec3 reflectance0,vec3 reflectance90)\n{\nreturn reflectance0+(reflectance90-reflectance0)*pow(clamp(1.0-VdotH,0.,1.),5.0);\n}\nvec3 fresnelSchlickEnvironmentGGX(float VdotN,vec3 reflectance0,vec3 reflectance90,float smoothness)\n{\n\nfloat weight=mix(FRESNEL_MAXIMUM_ON_ROUGH,1.0,smoothness);\nreturn reflectance0+weight*(reflectance90-reflectance0)*pow(clamp(1.0-VdotN,0.,1.),5.0);\n}\n\nvec3 computeSpecularTerm(float NdotH,float NdotL,float NdotV,float VdotH,float roughness,vec3 reflectance0,vec3 reflectance90,float geometricRoughnessFactor)\n{\nroughness=max(roughness,geometricRoughnessFactor);\nfloat alphaG=convertRoughnessToAverageSlope(roughness);\nfloat distribution=normalDistributionFunction_TrowbridgeReitzGGX(NdotH,alphaG);\nfloat visibility=smithVisibilityG_TrowbridgeReitzGGX_Walter(NdotL,NdotV,alphaG);\nvisibility/=(4.0*NdotL*NdotV); \nfloat specTerm=max(0.,visibility*distribution)*NdotL;\nvec3 fresnel=fresnelSchlickGGX(VdotH,reflectance0,reflectance90);\nreturn fresnel*specTerm;\n}\nfloat computeDiffuseTerm(float NdotL,float NdotV,float VdotH,float roughness)\n{\n\n\nfloat diffuseFresnelNV=pow(clamp(1.0-NdotL,0.000001,1.),5.0);\nfloat diffuseFresnelNL=pow(clamp(1.0-NdotV,0.000001,1.),5.0);\nfloat diffuseFresnel90=0.5+2.0*VdotH*VdotH*roughness;\nfloat fresnel =\n(1.0+(diffuseFresnel90-1.0)*diffuseFresnelNL) *\n(1.0+(diffuseFresnel90-1.0)*diffuseFresnelNV);\nreturn fresnel*NdotL/PI;\n}\nfloat adjustRoughnessFromLightProperties(float roughness,float lightRadius,float lightDistance)\n{\n#ifdef USEPHYSICALLIGHTFALLOFF\n\nfloat lightRoughness=lightRadius/lightDistance;\n\nfloat totalRoughness=clamp(lightRoughness+roughness,0.,1.);\nreturn totalRoughness;\n#else\nreturn roughness;\n#endif\n}\nfloat computeDefaultMicroSurface(float microSurface,vec3 reflectivityColor)\n{\nconst float kReflectivityNoAlphaWorkflow_SmoothnessMax=0.95;\nfloat reflectivityLuminance=getLuminance(reflectivityColor);\nfloat reflectivityLuma=sqrt(reflectivityLuminance);\nmicroSurface=reflectivityLuma*kReflectivityNoAlphaWorkflow_SmoothnessMax;\nreturn microSurface;\n}\n\n\nfloat fresnelGrazingReflectance(float reflectance0) {\nfloat reflectance90=clamp(reflectance0*25.0,0.0,1.0);\nreturn reflectance90;\n}\n\n\n#define UNPACK_LOD(x) (1.0-x)*255.0\nfloat getLodFromAlphaG(float cubeMapDimensionPixels,float alphaG,float NdotV) {\nfloat microsurfaceAverageSlope=alphaG;\n\n\n\n\n\n\nmicrosurfaceAverageSlope*=sqrt(abs(NdotV));\nfloat microsurfaceAverageSlopeTexels=microsurfaceAverageSlope*cubeMapDimensionPixels;\nfloat lod=log2(microsurfaceAverageSlopeTexels);\nreturn lod;\n}\nfloat environmentRadianceOcclusion(float ambientOcclusion,float NdotVUnclamped) {\n\n\nfloat temp=NdotVUnclamped+ambientOcclusion;\nreturn clamp(square(temp)-1.0+ambientOcclusion,0.0,1.0);\n}\nfloat environmentHorizonOcclusion(vec3 view,vec3 normal) {\n\nvec3 reflection=reflect(view,normal);\nfloat temp=clamp( 1.0+1.1*dot(reflection,normal),0.0,1.0);\nreturn square(temp);\n}","harmonicsFunctions":"#ifdef USESPHERICALFROMREFLECTIONMAP\nuniform vec3 vSphericalX;\nuniform vec3 vSphericalY;\nuniform vec3 vSphericalZ;\nuniform vec3 vSphericalXX_ZZ;\nuniform vec3 vSphericalYY_ZZ;\nuniform vec3 vSphericalZZ;\nuniform vec3 vSphericalXY;\nuniform vec3 vSphericalYZ;\nuniform vec3 vSphericalZX;\nvec3 quaternionVectorRotation_ScaledSqrtTwo(vec4 Q,vec3 V){\nvec3 T=cross(Q.xyz,V);\nT+=Q.www*V;\nreturn cross(Q.xyz,T)+V;\n}\nvec3 environmentIrradianceJones(vec3 normal)\n{\n\n\n\n\n\n\n\n\n\nfloat Nx=normal.x;\nfloat Ny=normal.y;\nfloat Nz=normal.z;\nvec3 C1=vSphericalZZ.rgb;\nvec3 Cx=vSphericalX.rgb;\nvec3 Cy=vSphericalY.rgb;\nvec3 Cz=vSphericalZ.rgb;\nvec3 Cxx_zz=vSphericalXX_ZZ.rgb;\nvec3 Cyy_zz=vSphericalYY_ZZ.rgb;\nvec3 Cxy=vSphericalXY.rgb;\nvec3 Cyz=vSphericalYZ.rgb;\nvec3 Czx=vSphericalZX.rgb;\nvec3 a1=Cyy_zz*Ny+Cy;\nvec3 a2=Cyz*Nz+a1;\nvec3 b1=Czx*Nz+Cx;\nvec3 b2=Cxy*Ny+b1;\nvec3 b3=Cxx_zz*Nx+b2;\nvec3 t1=Cz*Nz+C1;\nvec3 t2=a2*Ny+t1;\nvec3 t3=b3*Nx+t2;\nreturn t3;\n}\n#endif","pbrLightFunctions":"\nstruct lightingInfo\n{\nvec3 diffuse;\n#ifdef SPECULARTERM\nvec3 specular;\n#endif\n};\nfloat computeDistanceLightFalloff(vec3 lightOffset,float lightDistanceSquared,float range)\n{ \n#ifdef USEPHYSICALLIGHTFALLOFF\nfloat lightDistanceFalloff=1.0/((lightDistanceSquared+0.001));\n#else\nfloat lightDistanceFalloff=max(0.,1.0-length(lightOffset)/range);\n#endif\nreturn lightDistanceFalloff;\n}\nfloat computeDirectionalLightFalloff(vec3 lightDirection,vec3 directionToLightCenterW,float cosHalfAngle,float exponent)\n{\nfloat falloff=0.0;\n#ifdef USEPHYSICALLIGHTFALLOFF\nconst float kMinusLog2ConeAngleIntensityRatio=6.64385618977; \n\n\n\n\n\nfloat concentrationKappa=kMinusLog2ConeAngleIntensityRatio/(1.0-cosHalfAngle);\n\n\nvec4 lightDirectionSpreadSG=vec4(-lightDirection*concentrationKappa,-concentrationKappa);\nfalloff=exp2(dot(vec4(directionToLightCenterW,1.0),lightDirectionSpreadSG));\n#else\nfloat cosAngle=max(0.000000000000001,dot(-lightDirection,directionToLightCenterW));\nif (cosAngle>=cosHalfAngle)\n{\nfalloff=max(0.,pow(cosAngle,exponent));\n}\n#endif\nreturn falloff;\n}\nlightingInfo computeLighting(vec3 viewDirectionW,vec3 vNormal,vec4 lightData,vec3 diffuseColor,vec3 specularColor,float rangeRadius,float roughness,float NdotV,vec3 reflectance0,vec3 reflectance90,float geometricRoughnessFactor,out float NdotL) {\nlightingInfo result;\nvec3 lightDirection;\nfloat attenuation=1.0;\nfloat lightDistance;\n\nif (lightData.w == 0.)\n{\nvec3 lightOffset=lightData.xyz-vPositionW;\nfloat lightDistanceSquared=dot(lightOffset,lightOffset);\nattenuation=computeDistanceLightFalloff(lightOffset,lightDistanceSquared,rangeRadius);\nlightDistance=sqrt(lightDistanceSquared);\nlightDirection=normalize(lightOffset);\n}\n\nelse\n{\nlightDistance=length(-lightData.xyz);\nlightDirection=normalize(-lightData.xyz);\n}\n\nroughness=adjustRoughnessFromLightProperties(roughness,rangeRadius,lightDistance);\n\nvec3 H=normalize(viewDirectionW+lightDirection);\nNdotL=clamp(dot(vNormal,lightDirection),0.00000000001,1.0);\nfloat VdotH=clamp(dot(viewDirectionW,H),0.0,1.0);\nfloat diffuseTerm=computeDiffuseTerm(NdotL,NdotV,VdotH,roughness);\nresult.diffuse=diffuseTerm*diffuseColor*attenuation;\n#ifdef SPECULARTERM\n\nfloat NdotH=clamp(dot(vNormal,H),0.000000000001,1.0);\nvec3 specTerm=computeSpecularTerm(NdotH,NdotL,NdotV,VdotH,roughness,reflectance0,reflectance90,geometricRoughnessFactor);\nresult.specular=specTerm*diffuseColor*attenuation;\n#endif\nreturn result;\n}\nlightingInfo computeSpotLighting(vec3 viewDirectionW,vec3 vNormal,vec4 lightData,vec4 lightDirection,vec3 diffuseColor,vec3 specularColor,float rangeRadius,float roughness,float NdotV,vec3 reflectance0,vec3 reflectance90,float geometricRoughnessFactor,out float NdotL) {\nlightingInfo result;\nvec3 lightOffset=lightData.xyz-vPositionW;\nvec3 directionToLightCenterW=normalize(lightOffset);\n\nfloat lightDistanceSquared=dot(lightOffset,lightOffset);\nfloat attenuation=computeDistanceLightFalloff(lightOffset,lightDistanceSquared,rangeRadius);\n\nfloat directionalAttenuation=computeDirectionalLightFalloff(lightDirection.xyz,directionToLightCenterW,lightDirection.w,lightData.w);\nattenuation*=directionalAttenuation;\n\nfloat lightDistance=sqrt(lightDistanceSquared);\nroughness=adjustRoughnessFromLightProperties(roughness,rangeRadius,lightDistance);\n\nvec3 H=normalize(viewDirectionW+directionToLightCenterW);\nNdotL=clamp(dot(vNormal,directionToLightCenterW),0.000000000001,1.0);\nfloat VdotH=clamp(dot(viewDirectionW,H),0.0,1.0);\nfloat diffuseTerm=computeDiffuseTerm(NdotL,NdotV,VdotH,roughness);\nresult.diffuse=diffuseTerm*diffuseColor*attenuation;\n#ifdef SPECULARTERM\n\nfloat NdotH=clamp(dot(vNormal,H),0.000000000001,1.0);\nvec3 specTerm=computeSpecularTerm(NdotH,NdotL,NdotV,VdotH,roughness,reflectance0,reflectance90,geometricRoughnessFactor);\nresult.specular=specTerm*diffuseColor*attenuation;\n#endif\nreturn result;\n}\nlightingInfo computeHemisphericLighting(vec3 viewDirectionW,vec3 vNormal,vec4 lightData,vec3 diffuseColor,vec3 specularColor,vec3 groundColor,float roughness,float NdotV,vec3 reflectance0,vec3 reflectance90,float geometricRoughnessFactor,out float NdotL) {\nlightingInfo result;\n\n\n\nNdotL=dot(vNormal,lightData.xyz)*0.5+0.5;\nresult.diffuse=mix(groundColor,diffuseColor,NdotL);\n#ifdef SPECULARTERM\n\nvec3 lightVectorW=normalize(lightData.xyz);\nvec3 H=normalize(viewDirectionW+lightVectorW);\nfloat NdotH=clamp(dot(vNormal,H),0.000000000001,1.0);\nNdotL=clamp(NdotL,0.000000000001,1.0);\nfloat VdotH=clamp(dot(viewDirectionW,H),0.0,1.0);\nvec3 specTerm=computeSpecularTerm(NdotH,NdotL,NdotV,VdotH,roughness,reflectance0,reflectance90,geometricRoughnessFactor);\nresult.specular=specTerm*diffuseColor;\n#endif\nreturn result;\n}\nvec3 computeProjectionTextureDiffuseLighting(sampler2D projectionLightSampler,mat4 textureProjectionMatrix){\nvec4 strq=textureProjectionMatrix*vec4(vPositionW,1.0);\nstrq/=strq.w;\nvec3 textureColor=texture2D(projectionLightSampler,strq.xy).rgb;\nreturn toLinearSpace(textureColor);\n}","kernelBlurFragment":"#ifdef DOF\nfactor=sampleCoC(sampleCoord{X}); \ncomputedWeight=KERNEL_WEIGHT{X}*factor;\nsumOfWeights+=computedWeight;\n#else\ncomputedWeight=KERNEL_WEIGHT{X};\n#endif\n#ifdef PACKEDFLOAT\nblend+=unpack(texture2D(textureSampler,sampleCoord{X}))*computedWeight;\n#else\nblend+=texture2D(textureSampler,sampleCoord{X})*computedWeight;\n#endif","kernelBlurFragment2":"#ifdef DOF\nfactor=sampleCoC(sampleCenter+delta*KERNEL_DEP_OFFSET{X});\ncomputedWeight=KERNEL_DEP_WEIGHT{X}*factor;\nsumOfWeights+=computedWeight;\n#else\ncomputedWeight=KERNEL_DEP_WEIGHT{X};\n#endif\n#ifdef PACKEDFLOAT\nblend+=unpack(texture2D(textureSampler,sampleCenter+delta*KERNEL_DEP_OFFSET{X}))*computedWeight;\n#else\nblend+=texture2D(textureSampler,sampleCenter+delta*KERNEL_DEP_OFFSET{X})*computedWeight;\n#endif","kernelBlurVaryingDeclaration":"varying vec2 sampleCoord{X};","kernelBlurVertex":"sampleCoord{X}=sampleCenter+delta*KERNEL_OFFSET{X};","mrtFragmentDeclaration":"#if __VERSION__>=200\nlayout(location=0) out vec4 glFragData[{X}];\n#endif\n","bones300Declaration":"#if NUM_BONE_INFLUENCERS>0\nuniform mat4 mBones[BonesPerMesh];\nin vec4 matricesIndices;\nin vec4 matricesWeights;\n#if NUM_BONE_INFLUENCERS>4\nin vec4 matricesIndicesExtra;\nin vec4 matricesWeightsExtra;\n#endif\n#endif","instances300Declaration":"#ifdef INSTANCES\nin vec4 world0;\nin vec4 world1;\nin vec4 world2;\nin vec4 world3;\n#else\nuniform mat4 world;\n#endif","backgroundVertexDeclaration":"uniform mat4 view;\nuniform mat4 viewProjection;\nuniform float shadowLevel;\n#ifdef DIFFUSE\nuniform mat4 diffuseMatrix;\nuniform vec2 vDiffuseInfos;\n#endif\n#ifdef REFLECTION\nuniform vec2 vReflectionInfos;\nuniform mat4 reflectionMatrix;\nuniform vec3 vReflectionMicrosurfaceInfos;\nuniform float fFovMultiplier;\n#endif\n#ifdef POINTSIZE\nuniform float pointSize;\n#endif","backgroundFragmentDeclaration":" uniform vec4 vPrimaryColor;\n#ifdef USEHIGHLIGHTANDSHADOWCOLORS\nuniform vec4 vPrimaryColorShadow;\n#endif\nuniform float shadowLevel;\nuniform float alpha;\n#ifdef DIFFUSE\nuniform vec2 vDiffuseInfos;\n#endif\n#ifdef REFLECTION\nuniform vec2 vReflectionInfos;\nuniform mat4 reflectionMatrix;\nuniform vec3 vReflectionMicrosurfaceInfos;\n#endif\n#if defined(REFLECTIONFRESNEL) || defined(OPACITYFRESNEL)\nuniform vec3 vBackgroundCenter;\n#endif\n#ifdef REFLECTIONFRESNEL\nuniform vec4 vReflectionControl;\n#endif\n#if defined(REFLECTIONMAP_SPHERICAL) || defined(REFLECTIONMAP_PROJECTION) || defined(REFRACTION)\nuniform mat4 view;\n#endif","backgroundUboDeclaration":"layout(std140,column_major) uniform;\nuniform Material\n{\nuniform vec4 vPrimaryColor;\nuniform vec4 vPrimaryColorShadow;\nuniform vec2 vDiffuseInfos;\nuniform vec2 vReflectionInfos;\nuniform mat4 diffuseMatrix;\nuniform mat4 reflectionMatrix;\nuniform vec3 vReflectionMicrosurfaceInfos;\nuniform float fFovMultiplier;\nuniform float pointSize;\nuniform float shadowLevel;\nuniform float alpha;\n#if defined(REFLECTIONFRESNEL) || defined(OPACITYFRESNEL)\nuniform vec3 vBackgroundCenter;\n#endif\n#ifdef REFLECTIONFRESNEL\nuniform vec4 vReflectionControl;\n#endif\n};\nuniform Scene {\nmat4 viewProjection;\nmat4 view;\n};"};