var WORLDMONGER = WORLDMONGER || {}; (function () { WORLDMONGER.ElevationControl = function (ground) { this._ground = ground; this.radius = 5.0; this._invertDirection = 1.0; this.heightMin = 0; this.heightMax = 11.0; // Particle system var scene = ground.getScene(); var particleSystem = new BABYLON.ParticleSystem("particles", 4000, scene); particleSystem.particleTexture = new BABYLON.Texture("Assets/Flare.png", scene); particleSystem.minAngularSpeed = -4.5; particleSystem.maxAngularSpeed = 4.5; particleSystem.minSize = 0.5; particleSystem.maxSize = 4.0; particleSystem.minLifeTime = 0.5; particleSystem.maxLifeTime = 2.0; particleSystem.minEmitPower = 0.5; particleSystem.maxEmitPower = 1.0; particleSystem.emitRate = 400; particleSystem.blendMode = BABYLON.ParticleSystem.BLENDMODE_ONEONE; particleSystem.minEmitBox = new BABYLON.Vector3(0, 0, 0); particleSystem.maxEmitBox = new BABYLON.Vector3(0, 0, 0); particleSystem.direction1 = new BABYLON.Vector3(0, 1, 0); particleSystem.direction2 = new BABYLON.Vector3(0, 1, 0); particleSystem.color1 = new BABYLON.Color4(0, 0, 1, 1); particleSystem.color2 = new BABYLON.Color4(1, 1, 1, 1); particleSystem.gravity = new BABYLON.Vector3(0, 5, 0); particleSystem.manualEmitCount = 0; particleSystem.emitter = new BABYLON.Vector3(0, 0, 0); particleSystem.start(); this._particleSystem = particleSystem; }; WORLDMONGER.ElevationControl.prototype.direction = 1; WORLDMONGER.ElevationControl.prototype.attachControl = function (canvas) { var currentPosition; var that = this; this._onBeforeRender = function () { if (!currentPosition) { return; } var pickInfo = that._ground.getScene().pick(currentPosition.x, currentPosition.y); if (!pickInfo.hit) return; if (pickInfo.pickedMesh != that._ground) return; that._particleSystem.emitter = pickInfo.pickedPoint.add(new BABYLON.Vector3(0, 3, 0)); that._particleSystem.manualEmitCount += 400; that._elevateFaces(pickInfo, that.radius, 0.2); }; this._onPointerDown = function (evt) { evt.preventDefault(); currentPosition = { x: evt.clientX, y: evt.clientY }; }; this._onPointerUp = function (evt) { evt.preventDefault(); currentPosition = null; }; this._onPointerMove = function (evt) { evt.preventDefault(); if (!currentPosition) { return; } that._invertDirection = evt.button == 2 ? -1 : 1; currentPosition = { x: evt.clientX, y: evt.clientY }; }; this._onLostFocus = function () { currentPosition = null; }; canvas.addEventListener("pointerdown", this._onPointerDown, true); canvas.addEventListener("pointerup", this._onPointerUp, true); canvas.addEventListener("pointerout", this._onPointerUp, true); canvas.addEventListener("pointermove", this._onPointerMove, true); window.addEventListener("blur", this._onLostFocus, true); this._ground.getScene().registerBeforeRender(this._onBeforeRender); }; WORLDMONGER.ElevationControl.prototype.detachControl = function (canvas) { canvas.removeEventListener("pointerdown", this._onPointerDown); canvas.removeEventListener("pointerup", this._onPointerUp); canvas.removeEventListener("pointerout", this._onPointerUp); canvas.removeEventListener("pointermove", this._onPointerMove); window.removeEventListener("blur", this._onLostFocus); this._ground.getScene().unregisterBeforeRender(this._onBeforeRender); }; WORLDMONGER.ElevationControl.prototype._prepareDataModelForElevation = function () { if (this._facesOfVertices == null) { this._facesOfVertices = []; this._groundVertices = this._ground.getVertices(); this._groundIndices = this._ground.getIndices(); this._groundPositions = []; var index; for (index = 0; index < this._groundVertices.length; index += this._ground.getFloatVertexStrideSize()) { this._groundPositions.push(new BABYLON.Vector3(this._groundVertices[index], this._groundVertices[index + 1], this._groundVertices[index + 2])); } this._groundFacesNormals = []; for (index = 0; index < this._ground.getTotalIndices() / 3; index++) { this._computeFaceNormal(index); } this._getFacesOfVertices(); } }; WORLDMONGER.ElevationControl.prototype._getFaceVerticesIndex = function (faceID) { return { v1: this._groundIndices[faceID * 3], v2: this._groundIndices[faceID * 3 + 1], v3: this._groundIndices[faceID * 3 + 2] }; }; WORLDMONGER.ElevationControl.prototype._computeFaceNormal = function (face) { var faceInfo = this._getFaceVerticesIndex(face); var v1v2 = this._groundPositions[faceInfo.v1].subtract(this._groundPositions[faceInfo.v2]); var v3v2 = this._groundPositions[faceInfo.v3].subtract(this._groundPositions[faceInfo.v2]); this._groundFacesNormals[face] = BABYLON.Vector3.Normalize(BABYLON.Vector3.Cross(v1v2, v3v2)); }; WORLDMONGER.ElevationControl.prototype._getFacesOfVertices = function () { this._facesOfVertices = []; this._subdivisionsOfVertices = []; var index; for (index = 0; index < this._groundPositions.length; index++) { this._facesOfVertices[index] = []; this._subdivisionsOfVertices[index] = []; } for (index = 0; index < this._groundIndices.length; index++) { this._facesOfVertices[this._groundIndices[index]].push((index / 3) | 0); } for (var subIndex = 0; subIndex < this._ground.subMeshes.length; subIndex++) { var subMesh = this._ground.subMeshes[subIndex]; for (index = subMesh.verticesStart; index < subMesh.verticesStart + subMesh.verticesCount; index++) { this._subdivisionsOfVertices[index].push(subMesh); } } }; WORLDMONGER.ElevationControl.prototype._isBoxSphereIntersected = function(box, sphereCenter, sphereRadius) { var vector = BABYLON.Vector3.Clamp(sphereCenter, box.minimumWorld, box.maximumWorld); var num = BABYLON.Vector3.DistanceSquared(sphereCenter, vector); return (num <= (sphereRadius * sphereRadius)); }; WORLDMONGER.ElevationControl.prototype._elevateFaces = function (pickInfo, radius, height) { this._prepareDataModelForElevation(); this._selectedVertices = []; // Impact zone var sphereCenter = pickInfo.pickedPoint; sphereCenter.y = 0; var index; // Determine list of vertices for (var subIndex = 0; subIndex < this._ground.subMeshes.length; subIndex++) { var subMesh = this._ground.subMeshes[subIndex]; if (!this._isBoxSphereIntersected(subMesh.getBoundingInfo().boundingBox, sphereCenter, radius)) { continue; } for (index = subMesh.verticesStart; index < subMesh.verticesStart + subMesh.verticesCount; index++) { var position = this._groundPositions[index]; sphereCenter.y = position.y; var distance = BABYLON.Vector3.Distance(position, sphereCenter); if (distance < radius) { this._selectedVertices[index] = distance; } } } // Elevate vertices var stride = this._ground.getFloatVertexStrideSize(); for (var selectedVertice in this._selectedVertices) { var position = this._groundPositions[selectedVertice]; var distance = this._selectedVertices[selectedVertice]; var fullHeight = height * this.direction * this._invertDirection; if (distance < radius * 0.3) { position.y += fullHeight; } else { position.y += fullHeight * (1.0 - (distance - radius * 0.3) / (radius * 0.7)); } if (position.y > this.heightMax) position.y = this.heightMax; else if (position.y < this.heightMin) position.y = this.heightMin; this._groundVertices[selectedVertice * stride + 1] = position.y; this._updateSubdivisions(selectedVertice); } // Normals this._reComputeNormals() // Update vertex buffer this._ground.updateVertices(this._groundVertices); }; WORLDMONGER.ElevationControl.prototype._reComputeNormals = function () { var faces = []; var face; for (selectedVertice in this._selectedVertices) { var faceOfVertices = this._facesOfVertices[selectedVertice]; for (var index = 0; index < faceOfVertices.length; index++) { faces[faceOfVertices[index]] = true; } } for (face in faces) { this._computeFaceNormal(face); } for (face in faces) { var faceInfo = this._getFaceVerticesIndex(face); this._computeNormal(faceInfo.v1); this._computeNormal(faceInfo.v2); this._computeNormal(faceInfo.v3); } }; WORLDMONGER.ElevationControl.prototype._computeNormal = function (vertexIndex) { var faces = this._facesOfVertices[vertexIndex]; var normal = BABYLON.Vector3.Zero(); for (var index = 0; index < faces.length; index++) { normal = normal.add(this._groundFacesNormals[faces[index]]); } normal = BABYLON.Vector3.Normalize(normal.scale(1.0 / faces.length)); var stride = this._ground.getFloatVertexStrideSize(); this._groundVertices[vertexIndex * stride + 3] = normal.x; this._groundVertices[vertexIndex * stride + 4] = normal.y; this._groundVertices[vertexIndex * stride + 5] = normal.z; } WORLDMONGER.ElevationControl.prototype._updateSubdivisions = function (vertexIndex) { for (var index = 0; index < this._subdivisionsOfVertices[vertexIndex].length; index++) { var sub = this._subdivisionsOfVertices[vertexIndex][index]; var boundingBox = sub.getBoundingInfo().boundingBox; var boundingSphere = sub.getBoundingInfo().boundingSphere; if (this._groundPositions[vertexIndex].y < boundingBox.minimum.y) { boundingSphere.radius += Math.abs(this._groundPositions[vertexIndex].y - boundingBox.minimum.y); boundingBox.minimum.y = this._groundPositions[vertexIndex].y; } else if (this._groundPositions[vertexIndex].y > boundingBox.maximum.y) { boundingBox.maximum.y = this._groundPositions[vertexIndex].y; } } var boundingBox = this._ground.getBoundingInfo().boundingBox; var boundingSphere = this._ground.getBoundingInfo().boundingSphere; if (this._groundPositions[vertexIndex].y < boundingBox.minimum.y) { boundingSphere.Radius += Math.abs(this._groundPositions[vertexIndex].y - boundingBox.minimum.y); boundingBox.minimum.y = this._groundPositions[vertexIndex].y; } else if (this._groundPositions[vertexIndex].y > boundingBox.maximum.y) { boundingBox.maximum.y = this._groundPositions[vertexIndex].y; } }; })();