瀏覽代碼

Merge branch 'master' of https://github.com/BabylonJS/Babylon.js

Conflicts:
	dist/preview release - beta/babylon.2.2.d.ts
	dist/preview release - beta/babylon.2.2.js
	dist/preview release - beta/babylon.2.2.noworker.js
David catuhe 10 年之前
父節點
當前提交
d55c131617

File diff suppressed because it is too large
+ 1326 - 1321
dist/preview release - beta/babylon.2.2.d.ts


File diff suppressed because it is too large
+ 24 - 21
dist/preview release - beta/babylon.2.2.js


File diff suppressed because it is too large
+ 181 - 76
dist/preview release - beta/babylon.2.2.max.js


File diff suppressed because it is too large
+ 26 - 23
dist/preview release - beta/babylon.2.2.noworker.js


+ 22 - 6
src/Cameras/babylon.arcRotateCamera.js

@@ -25,7 +25,8 @@ var BABYLON;
             this.upperBetaLimit = Math.PI;
             this.lowerRadiusLimit = null;
             this.upperRadiusLimit = null;
-            this.angularSensibility = 1000.0;
+            this.angularSensibilityX = 1000.0;
+            this.angularSensibilityY = 1000.0;
             this.wheelPrecision = 3.0;
             this.pinchPrecision = 2.0;
             this.panningSensibility = 50.0;
@@ -86,6 +87,21 @@ var BABYLON;
             }
             this.getViewMatrix();
         }
+        Object.defineProperty(ArcRotateCamera.prototype, "angularSensibility", {
+            //deprecated angularSensibility support
+            get: function () {
+                BABYLON.Tools.Warn("Warning: angularSensibility is deprecated, use angularSensibilityX and angularSensibilityY instead.");
+                return Math.max(this.angularSensibilityX, this.angularSensibilityY);
+            },
+            //deprecated angularSensibility support
+            set: function (value) {
+                BABYLON.Tools.Warn("Warning: angularSensibility is deprecated, use angularSensibilityX and angularSensibilityY instead.");
+                this.angularSensibilityX = value;
+                this.angularSensibilityY = value;
+            },
+            enumerable: true,
+            configurable: true
+        });
         ArcRotateCamera.prototype._getTargetPosition = function () {
             return this.target.position || this.target;
         };
@@ -169,8 +185,8 @@ var BABYLON;
                             else {
                                 var offsetX = evt.clientX - cacheSoloPointer.x;
                                 var offsetY = evt.clientY - cacheSoloPointer.y;
-                                _this.inertialAlphaOffset -= offsetX / _this.angularSensibility;
-                                _this.inertialBetaOffset -= offsetY / _this.angularSensibility;
+                                _this.inertialAlphaOffset -= offsetX / _this.angularSensibilityX;
+                                _this.inertialBetaOffset -= offsetY / _this.angularSensibilityY;
                             }
                             cacheSoloPointer.x = evt.clientX;
                             cacheSoloPointer.y = evt.clientY;
@@ -188,7 +204,7 @@ var BABYLON;
                                 return;
                             }
                             if (pinchSquaredDistance !== previousPinchDistance) {
-                                _this.inertialRadiusOffset += (pinchSquaredDistance - previousPinchDistance) / (_this.pinchPrecision * _this.wheelPrecision * _this.angularSensibility * direction);
+                                _this.inertialRadiusOffset += (pinchSquaredDistance - previousPinchDistance) / (_this.pinchPrecision * _this.wheelPrecision * ((_this.angularSensibilityX + _this.angularSensibilityY) / 2) * direction);
                                 previousPinchDistance = pinchSquaredDistance;
                             }
                             break;
@@ -205,8 +221,8 @@ var BABYLON;
                     }
                     var offsetX = evt.movementX || evt.mozMovementX || evt.webkitMovementX || evt.msMovementX || 0;
                     var offsetY = evt.movementY || evt.mozMovementY || evt.webkitMovementY || evt.msMovementY || 0;
-                    _this.inertialAlphaOffset -= offsetX / _this.angularSensibility;
-                    _this.inertialBetaOffset -= offsetY / _this.angularSensibility;
+                    _this.inertialAlphaOffset -= offsetX / _this.angularSensibilityX;
+                    _this.inertialBetaOffset -= offsetY / _this.angularSensibilityY;
                     if (!noPreventDefault) {
                         evt.preventDefault();
                     }

+ 22 - 7
src/Cameras/babylon.arcRotateCamera.ts

@@ -11,7 +11,8 @@
         public upperBetaLimit = Math.PI;
         public lowerRadiusLimit = null;
         public upperRadiusLimit = null;
-        public angularSensibility = 1000.0;
+        public angularSensibilityX = 1000.0;
+        public angularSensibilityY = 1000.0;
         public wheelPrecision = 3.0;
         public pinchPrecision = 2.0;
         public panningSensibility: number = 50.0;
@@ -63,6 +64,19 @@
         private _previousRadius: number;
         //due to async collision inspection
         private _collisionTriggered: boolean;
+        
+        //deprecated angularSensibility support
+        public get angularSensibility() {
+            Tools.Warn("Warning: angularSensibility is deprecated, use angularSensibilityX and angularSensibilityY instead.");
+            return Math.max(this.angularSensibilityX, this.angularSensibilityY);
+        }
+        
+        //deprecated angularSensibility support
+        public set angularSensibility(value) {
+            Tools.Warn("Warning: angularSensibility is deprecated, use angularSensibilityX and angularSensibilityY instead.");
+            this.angularSensibilityX = value;
+            this.angularSensibilityY = value;
+        }
 
         constructor(name: string, public alpha: number, public beta: number, public radius: number, public target: any, scene: Scene) {
             super(name, Vector3.Zero(), scene);
@@ -147,7 +161,7 @@
                     //when changing orientation while pinching camera, one pointer stay pressed forever if we don't release all pointers  
                     //will be ok to put back pointers.remove(evt.pointerId); when iPhone bug corrected
                     pointers.empty();
-                                       
+
                     if (!noPreventDefault) {
                         evt.preventDefault();
                     }
@@ -171,8 +185,8 @@
                             } else {
                                 var offsetX = evt.clientX - cacheSoloPointer.x;
                                 var offsetY = evt.clientY - cacheSoloPointer.y;
-                                this.inertialAlphaOffset -= offsetX / this.angularSensibility;
-                                this.inertialBetaOffset -= offsetY / this.angularSensibility;
+                                this.inertialAlphaOffset -= offsetX / this.angularSensibilityX;
+                                this.inertialBetaOffset -= offsetY / this.angularSensibilityY;
                             }
                             cacheSoloPointer.x = evt.clientX;
                             cacheSoloPointer.y = evt.clientY;
@@ -192,7 +206,7 @@
                             }
 
                             if (pinchSquaredDistance !== previousPinchDistance) {
-                                this.inertialRadiusOffset += (pinchSquaredDistance - previousPinchDistance) / (this.pinchPrecision * this.wheelPrecision * this.angularSensibility * direction);
+                                this.inertialRadiusOffset += (pinchSquaredDistance - previousPinchDistance) / (this.pinchPrecision * this.wheelPrecision * ((this.angularSensibilityX + this.angularSensibilityY) / 2) * direction);
                                 previousPinchDistance = pinchSquaredDistance;
                             }
                             break;
@@ -213,8 +227,8 @@
                     var offsetX = evt.movementX || evt.mozMovementX || evt.webkitMovementX || evt.msMovementX || 0;
                     var offsetY = evt.movementY || evt.mozMovementY || evt.webkitMovementY || evt.msMovementY || 0;
 
-                    this.inertialAlphaOffset -= offsetX / this.angularSensibility;
-                    this.inertialBetaOffset -= offsetY / this.angularSensibility;
+                    this.inertialAlphaOffset -= offsetX / this.angularSensibilityX;
+                    this.inertialBetaOffset -= offsetY / this.angularSensibilityY;
 
                     if (!noPreventDefault) {
                         evt.preventDefault();
@@ -628,3 +642,4 @@
         }
     }
 } 
+

+ 2 - 1
src/Cameras/babylon.camera.ts

@@ -584,4 +584,5 @@
             }
         }
     }
-}
+}
+

+ 6 - 0
src/Cameras/babylon.targetCamera.js

@@ -26,6 +26,12 @@ var BABYLON;
             this._lookAtTemp = BABYLON.Matrix.Zero();
             this._tempMatrix = BABYLON.Matrix.Zero();
         }
+        TargetCamera.prototype.getFrontPosition = function (distance) {
+            var direction = this.getTarget().subtract(this.position);
+            direction.normalize();
+            direction.scaleInPlace(distance);
+            return this.globalPosition.add(direction);
+        };
         TargetCamera.prototype._getLockedTargetPosition = function () {
             if (!this.lockedTarget) {
                 return null;

+ 7 - 0
src/Cameras/babylon.targetCamera.ts

@@ -29,6 +29,13 @@
             super(name, position, scene);
         }
 
+        public getFrontPosition(distance: number): Vector3 {
+            var direction = this.getTarget().subtract(this.position);
+            direction.normalize();
+            direction.scaleInPlace(distance);
+            return this.globalPosition.add(direction);
+        }
+
         public _getLockedTargetPosition(): Vector3 {
             if (!this.lockedTarget) {
                 return null;

+ 1 - 1
src/Materials/Textures/Procedurals/babylon.standardProceduralTexture.js

@@ -320,7 +320,7 @@ var BABYLON;
                 return this._numberOfBricksWidth;
             },
             set: function (value) {
-                this._numberOfBricksHeight = value;
+                this._numberOfBricksWidth = value;
                 this.updateShaderUniforms();
             },
             enumerable: true,

+ 1 - 1
src/Materials/Textures/Procedurals/babylon.standardProceduralTexture.ts

@@ -284,7 +284,7 @@
         }
 
         public set numberOfBricksWidth(value: number) {
-            this._numberOfBricksHeight = value;
+            this._numberOfBricksWidth = value;
             this.updateShaderUniforms();
         }
 

+ 4 - 0
src/Materials/babylon.shaderMaterial.js

@@ -28,6 +28,7 @@ var BABYLON;
             options.attributes = options.attributes || ["position", "normal", "uv"];
             options.uniforms = options.uniforms || ["worldViewProjection"];
             options.samplers = options.samplers || [];
+            options.defines = options.defines || [];
             this._options = options;
         }
         ShaderMaterial.prototype.needAlphaBlending = function () {
@@ -112,6 +113,9 @@ var BABYLON;
             if (useInstances) {
                 defines.push("#define INSTANCES");
             }
+            for (var index = 0; index < this._options.defines.length; index++) {
+                defines.push(this._options.defines[index]);
+            }
             // Bones
             if (mesh && mesh.useBones && mesh.computeBonesUsingShaders) {
                 defines.push("#define BONES");

+ 5 - 0
src/Materials/babylon.shaderMaterial.ts

@@ -25,6 +25,7 @@
             options.attributes = options.attributes || ["position", "normal", "uv"];
             options.uniforms = options.uniforms || ["worldViewProjection"];
             options.samplers = options.samplers || [];
+            options.defines = options.defines || [];
 
             this._options = options;
         }
@@ -139,6 +140,10 @@
                 defines.push("#define INSTANCES");
             }
 
+            for (var index = 0; index < this._options.defines.length; index++) {
+                defines.push(this._options.defines[index]);
+            }
+
             // Bones
             if (mesh && mesh.useBones && mesh.computeBonesUsingShaders) {
                 defines.push("#define BONES");

+ 3 - 2
src/Mesh/babylon.abstractMesh.js

@@ -133,10 +133,11 @@ var BABYLON;
                 this._edgesRenderer = undefined;
             }
         };
-        AbstractMesh.prototype.enableEdgesRendering = function (epsilon) {
+        AbstractMesh.prototype.enableEdgesRendering = function (epsilon, checkVerticesInsteadOfIndices) {
             if (epsilon === void 0) { epsilon = 0.95; }
+            if (checkVerticesInsteadOfIndices === void 0) { checkVerticesInsteadOfIndices = false; }
             this.disableEdgesRendering();
-            this._edgesRenderer = new BABYLON.EdgesRenderer(this, epsilon);
+            this._edgesRenderer = new BABYLON.EdgesRenderer(this, epsilon, checkVerticesInsteadOfIndices);
         };
         Object.defineProperty(AbstractMesh.prototype, "isBlocked", {
             get: function () {

+ 2 - 2
src/Mesh/babylon.abstractMesh.ts

@@ -139,10 +139,10 @@
                 this._edgesRenderer = undefined;
             }
         }
-        public enableEdgesRendering(epsilon = 0.95) {
+        public enableEdgesRendering(epsilon = 0.95, checkVerticesInsteadOfIndices = false) {
             this.disableEdgesRendering();
 
-            this._edgesRenderer = new EdgesRenderer(this, epsilon);
+            this._edgesRenderer = new EdgesRenderer(this, epsilon, checkVerticesInsteadOfIndices);
         }
 
         public get isBlocked(): boolean {

+ 6 - 2
src/Mesh/babylon.mesh.js

@@ -49,6 +49,7 @@ var BABYLON;
                 }
                 // Deep copy
                 BABYLON.Tools.DeepCopy(source, this, ["name", "material", "skeleton", "instances"], []);
+                this.id = name + "." + source.id;
                 // Material
                 this.material = source.material;
                 if (!doNotCloneChildren) {
@@ -1137,10 +1138,13 @@ var BABYLON;
             vertexData.applyToMesh(disc, updatable);
             return disc;
         };
-        Mesh.CreateBox = function (name, size, scene, updatable, sideOrientation) {
+        Mesh.CreateBox = function (name, options, scene, updatable, sideOrientation) {
             if (sideOrientation === void 0) { sideOrientation = Mesh.DEFAULTSIDE; }
+            // Check parameters
+            updatable = updatable || options.updatable;
+            sideOrientation = sideOrientation || options.sideOrientation;
             var box = new Mesh(name, scene);
-            var vertexData = BABYLON.VertexData.CreateBox(size, sideOrientation);
+            var vertexData = BABYLON.VertexData.CreateBox(options, sideOrientation);
             vertexData.applyToMesh(box, updatable);
             return box;
         };

+ 8 - 2
src/Mesh/babylon.mesh.ts

@@ -94,6 +94,8 @@
                 // Deep copy
                 Tools.DeepCopy(source, this, ["name", "material", "skeleton", "instances"], []);
 
+                this.id = name + "." + source.id;
+
                 // Material
                 this.material = source.material;
 
@@ -1328,9 +1330,13 @@
             return disc;
         }
 
-        public static CreateBox(name: string, size: number, scene: Scene, updatable?: boolean, sideOrientation: number = Mesh.DEFAULTSIDE): Mesh {
+        public static CreateBox(name: string, options: any, scene: Scene, updatable?: boolean, sideOrientation: number = Mesh.DEFAULTSIDE): Mesh {
+            // Check parameters
+            updatable = updatable || options.updatable;
+            sideOrientation = sideOrientation || options.sideOrientation;
+
             var box = new Mesh(name, scene);
-            var vertexData = VertexData.CreateBox(size, sideOrientation);
+            var vertexData = VertexData.CreateBox(options, sideOrientation);
 
             vertexData.applyToMesh(box, updatable);
 

+ 84 - 45
src/Mesh/babylon.mesh.vertexData.js

@@ -466,7 +466,7 @@ var BABYLON;
             }
             return vertexData;
         };
-        VertexData.CreateBox = function (size, sideOrientation) {
+        VertexData.CreateBox = function (options, sideOrientation) {
             if (sideOrientation === void 0) { sideOrientation = BABYLON.Mesh.DEFAULTSIDE; }
             var normalsSource = [
                 new BABYLON.Vector3(0, 0, 1),
@@ -480,7 +480,20 @@ var BABYLON;
             var positions = [];
             var normals = [];
             var uvs = [];
-            size = size || 1;
+            var width = 1;
+            var height = 1;
+            var depth = 1;
+            if (options.width !== undefined) {
+                width = options.width || 1;
+                height = options.height || 1;
+                depth = options.depth || 1;
+            }
+            else {
+                width = options || 1;
+                height = options || 1;
+                depth = options || 1;
+            }
+            var scaleVector = new BABYLON.Vector3(width / 2, height / 2, depth / 2);
             // Create each face in turn.
             for (var index = 0; index < normalsSource.length; index++) {
                 var normal = normalsSource[index];
@@ -496,19 +509,19 @@ var BABYLON;
                 indices.push(verticesLength + 2);
                 indices.push(verticesLength + 3);
                 // Four vertices per face.
-                var vertex = normal.subtract(side1).subtract(side2).scale(size / 2);
+                var vertex = normal.subtract(side1).subtract(side2).multiply(scaleVector);
                 positions.push(vertex.x, vertex.y, vertex.z);
                 normals.push(normal.x, normal.y, normal.z);
                 uvs.push(1.0, 1.0);
-                vertex = normal.subtract(side1).add(side2).scale(size / 2);
+                vertex = normal.subtract(side1).add(side2).multiply(scaleVector);
                 positions.push(vertex.x, vertex.y, vertex.z);
                 normals.push(normal.x, normal.y, normal.z);
                 uvs.push(0.0, 1.0);
-                vertex = normal.add(side1).add(side2).scale(size / 2);
+                vertex = normal.add(side1).add(side2).multiply(scaleVector);
                 positions.push(vertex.x, vertex.y, vertex.z);
                 normals.push(normal.x, normal.y, normal.z);
                 uvs.push(0.0, 0.0);
-                vertex = normal.add(side1).subtract(side2).scale(size / 2);
+                vertex = normal.add(side1).subtract(side2).multiply(scaleVector);
                 positions.push(vertex.x, vertex.y, vertex.z);
                 normals.push(normal.x, normal.y, normal.z);
                 uvs.push(1.0, 0.0);
@@ -576,46 +589,65 @@ var BABYLON;
         VertexData.CreateCylinder = function (height, diameterTop, diameterBottom, tessellation, subdivisions, sideOrientation) {
             if (subdivisions === void 0) { subdivisions = 1; }
             if (sideOrientation === void 0) { sideOrientation = BABYLON.Mesh.DEFAULTSIDE; }
-            // setup tube creation parameters
-            var path = [];
-            for (var i = 0; i <= subdivisions; i++) {
-                path.push(new BABYLON.Vector3(0, height * (-0.5 + i / subdivisions), 0));
-            }
-            // this is what defines the radius along the cylinder
-            var radiusFunction = function (i, distance) {
-                return (diameterBottom + (diameterTop - diameterBottom) * distance / height) / 2;
-            };
-            // shortcut to 3d path data
-            var path3D = new BABYLON.Path3D(path);
-            var tangents = path3D.getTangents();
-            var normals = path3D.getNormals();
-            var distances = path3D.getDistances();
-            // let's build the array of paths (rings)
-            var pathArray = [];
-            var ringVertex;
-            var angle;
+            var indices = [];
+            var positions = [];
+            var normals = [];
+            var uvs = [];
             var angle_step = Math.PI * 2 / tessellation;
-            var distance = 0;
+            var angle;
+            var subdivision_step = height / subdivisions;
+            var h;
+            var radius;
+            var tan = (diameterBottom - diameterTop) / 2 / height;
+            var ringVertex = BABYLON.Vector3.Zero();
+            var ringNormal = BABYLON.Vector3.Zero();
+            // positions, normals, uvs
             for (var i = 0; i <= subdivisions; i++) {
-                pathArray[i] = [];
-                for (var j = 0; j < tessellation; j++) {
+                h = i / subdivisions;
+                radius = (h * (diameterTop - diameterBottom) + diameterBottom) / 2;
+                for (var j = 0; j <= tessellation; j++) {
                     angle = j * angle_step;
-                    ringVertex = new BABYLON.Vector3(Math.cos(-angle), 0, Math.sin(-angle));
-                    ringVertex.scaleInPlace(radiusFunction(i, distances[i])).addInPlace(path[i]);
-                    pathArray[i].push(ringVertex);
+                    ringVertex.x = Math.cos(-angle) * radius;
+                    ringVertex.y = -height / 2 + h * height;
+                    ringVertex.z = Math.sin(-angle) * radius;
+                    if (diameterTop === 0 && i === subdivisions) {
+                        // if no top cap, reuse former normals
+                        ringNormal.x = normals[normals.length - (tessellation + 1) * 3];
+                        ringNormal.y = normals[normals.length - (tessellation + 1) * 3 + 1];
+                        ringNormal.z = normals[normals.length - (tessellation + 1) * 3 + 2];
+                    }
+                    else {
+                        ringNormal.x = ringVertex.x;
+                        ringNormal.z = ringVertex.z;
+                        ringNormal.y = Math.sqrt(ringNormal.x * ringNormal.x + ringNormal.z * ringNormal.z) * tan;
+                        ringNormal.normalize();
+                    }
+                    positions.push(ringVertex.x, ringVertex.y, ringVertex.z);
+                    normals.push(ringNormal.x, ringNormal.y, ringNormal.z);
+                    uvs.push(j / tessellation, 1 - h);
                 }
             }
-            // create ribbon based on computed paths (& close seam)
-            var vertexdata = VertexData.CreateRibbon(pathArray, false, true, 0, sideOrientation);
+            // indices
+            for (var i = 0; i < subdivisions; i++) {
+                for (var j = 0; j < tessellation; j++) {
+                    var i0 = i * (tessellation + 1) + j;
+                    var i1 = (i + 1) * (tessellation + 1) + j;
+                    var i2 = i * (tessellation + 1) + (j + 1);
+                    var i3 = (i + 1) * (tessellation + 1) + (j + 1);
+                    indices.push(i0, i1, i2);
+                    indices.push(i3, i2, i1);
+                }
+            }
+            // Caps
             var createCylinderCap = function (isTop) {
                 var radius = isTop ? diameterTop / 2 : diameterBottom / 2;
                 if (radius === 0) {
                     return;
                 }
-                var vbase = vertexdata.positions.length / 3;
+                var vbase = positions.length / 3;
                 var offset = new BABYLON.Vector3(0, isTop ? height / 2 : -height / 2, 0);
                 var textureScale = new BABYLON.Vector2(0.5, 0.5);
-                // Positions, normals & uvs
+                // Cap positions, normals & uvs
                 var angle;
                 var circleVector;
                 for (var i = 0; i < tessellation; i++) {
@@ -623,28 +655,35 @@ var BABYLON;
                     circleVector = new BABYLON.Vector3(Math.cos(-angle), 0, Math.sin(-angle));
                     var position = circleVector.scale(radius).add(offset);
                     var textureCoordinate = new BABYLON.Vector2(circleVector.x * textureScale.x + 0.5, circleVector.z * textureScale.y + 0.5);
-                    vertexdata.positions.push(position.x, position.y, position.z);
-                    vertexdata.normals.push(0, isTop ? 1 : -1, 0);
-                    vertexdata.uvs.push(textureCoordinate.x, textureCoordinate.y);
+                    positions.push(position.x, position.y, position.z);
+                    normals.push(0, isTop ? 1 : -1, 0);
+                    uvs.push(textureCoordinate.x, textureCoordinate.y);
                 }
-                // Indices
+                // Cap indices
                 for (i = 0; i < tessellation - 2; i++) {
                     if (!isTop) {
-                        vertexdata.indices.push(vbase);
-                        vertexdata.indices.push(vbase + (i + 1) % tessellation);
-                        vertexdata.indices.push(vbase + (i + 2) % tessellation);
+                        indices.push(vbase);
+                        indices.push(vbase + (i + 1) % tessellation);
+                        indices.push(vbase + (i + 2) % tessellation);
                     }
                     else {
-                        vertexdata.indices.push(vbase);
-                        vertexdata.indices.push(vbase + (i + 2) % tessellation);
-                        vertexdata.indices.push(vbase + (i + 1) % tessellation);
+                        indices.push(vbase);
+                        indices.push(vbase + (i + 2) % tessellation);
+                        indices.push(vbase + (i + 1) % tessellation);
                     }
                 }
             };
             // add caps to geometry
             createCylinderCap(true);
             createCylinderCap(false);
-            return vertexdata;
+            // Sides
+            VertexData._ComputeSides(sideOrientation, positions, indices, normals, uvs);
+            var vertexData = new VertexData();
+            vertexData.indices = indices;
+            vertexData.positions = positions;
+            vertexData.normals = normals;
+            vertexData.uvs = uvs;
+            return vertexData;
         };
         VertexData.CreateTorus = function (diameter, thickness, tessellation, sideOrientation) {
             if (sideOrientation === void 0) { sideOrientation = BABYLON.Mesh.DEFAULTSIDE; }

+ 90 - 50
src/Mesh/babylon.mesh.vertexData.ts

@@ -572,7 +572,7 @@
             return vertexData;
         }
 
-        public static CreateBox(size: number, sideOrientation: number = Mesh.DEFAULTSIDE): VertexData {
+        public static CreateBox(options: any, sideOrientation: number = Mesh.DEFAULTSIDE): VertexData {
             var normalsSource = [
                 new Vector3(0, 0, 1),
                 new Vector3(0, 0, -1),
@@ -587,7 +587,21 @@
             var normals = [];
             var uvs = [];
 
-            size = size || 1;
+            var width = 1;
+            var height = 1;
+            var depth = 1;
+
+            if (options.width !== undefined) {
+                width = options.width || 1;
+                height = options.height || 1;
+                depth = options.depth || 1;
+            } else { // back-compat with size parameter
+                width = options || 1;
+                height = options || 1;
+                depth = options || 1;
+            }
+
+            var scaleVector = new Vector3(width / 2, height / 2, depth / 2);
 
             // Create each face in turn.
             for (var index = 0; index < normalsSource.length; index++) {
@@ -608,22 +622,22 @@
                 indices.push(verticesLength + 3);
 
                 // Four vertices per face.
-                var vertex = normal.subtract(side1).subtract(side2).scale(size / 2);
+                var vertex = normal.subtract(side1).subtract(side2).multiply(scaleVector);
                 positions.push(vertex.x, vertex.y, vertex.z);
                 normals.push(normal.x, normal.y, normal.z);
                 uvs.push(1.0, 1.0);
 
-                vertex = normal.subtract(side1).add(side2).scale(size / 2);
+                vertex = normal.subtract(side1).add(side2).multiply(scaleVector);
                 positions.push(vertex.x, vertex.y, vertex.z);
                 normals.push(normal.x, normal.y, normal.z);
                 uvs.push(0.0, 1.0);
 
-                vertex = normal.add(side1).add(side2).scale(size / 2);
+                vertex = normal.add(side1).add(side2).multiply(scaleVector);
                 positions.push(vertex.x, vertex.y, vertex.z);
                 normals.push(normal.x, normal.y, normal.z);
                 uvs.push(0.0, 0.0);
 
-                vertex = normal.add(side1).subtract(side2).scale(size / 2);
+                vertex = normal.add(side1).subtract(side2).multiply(scaleVector);
                 positions.push(vertex.x, vertex.y, vertex.z);
                 normals.push(normal.x, normal.y, normal.z);
                 uvs.push(1.0, 0.0);
@@ -711,54 +725,69 @@
         // Cylinder and cone (made using ribbons)
         public static CreateCylinder(height: number, diameterTop: number, diameterBottom: number, tessellation: number, subdivisions: number = 1, sideOrientation: number = Mesh.DEFAULTSIDE): VertexData {
 
-            // setup tube creation parameters
-            var path = [];
-            for (var i = 0; i <= subdivisions; i++) {
-                path.push(new Vector3(0, height * (- 0.5 + i / subdivisions), 0));
-            }
+            var indices = [];
+            var positions = [];
+            var normals = [];
+            var uvs = [];
 
-            // this is what defines the radius along the cylinder
-            var radiusFunction = function (i, distance) {
-                return (diameterBottom + (diameterTop - diameterBottom) * distance / height) / 2;
-            };
-            
-            // shortcut to 3d path data
-            var path3D = new Path3D(path);
-            var tangents = path3D.getTangents();
-            var normals = path3D.getNormals();
-            var distances = path3D.getDistances();
-
-            // let's build the array of paths (rings)
-            var pathArray: Vector3[][] = [];
-            var ringVertex: Vector3;
-            var angle;
             var angle_step = Math.PI * 2 / tessellation;
-            var distance = 0;
-
+            var angle: number;
+            var subdivision_step = height / subdivisions;
+            var h: number;
+            var radius: number;
+            var tan = (diameterBottom - diameterTop) / 2 / height;
+            var ringVertex: Vector3 = Vector3.Zero();
+            var ringNormal: Vector3 = Vector3.Zero();
+
+            // positions, normals, uvs
             for (var i = 0; i <= subdivisions; i++) {
-
-                pathArray[i] = [];
-
-                for (var j = 0; j < tessellation; j++) {
+                h = i / subdivisions;
+                radius = (h * (diameterTop - diameterBottom) + diameterBottom) / 2;
+                for (var j = 0; j <= tessellation; j++) {
                     angle = j * angle_step;
-                    ringVertex = new Vector3(Math.cos(-angle), 0, Math.sin(-angle));
-                    ringVertex.scaleInPlace(radiusFunction(i, distances[i])).addInPlace(path[i]);
-                    pathArray[i].push(ringVertex);
+                    ringVertex.x = Math.cos(-angle) * radius;
+                    ringVertex.y = -height / 2 + h * height;
+                    ringVertex.z = Math.sin(-angle) * radius;
+                    if (diameterTop === 0 && i === subdivisions) {
+                        // if no top cap, reuse former normals
+                        ringNormal.x = normals[normals.length - (tessellation + 1) * 3];
+                        ringNormal.y = normals[normals.length - (tessellation + 1) * 3 + 1];
+                        ringNormal.z = normals[normals.length - (tessellation + 1) * 3 + 2];
+                    }
+                    else {
+                        ringNormal.x = ringVertex.x;
+                        ringNormal.z = ringVertex.z
+                        ringNormal.y = Math.sqrt(ringNormal.x * ringNormal.x + ringNormal.z * ringNormal.z) * tan;
+                        ringNormal.normalize();
+                    }
+                    positions.push(ringVertex.x, ringVertex.y, ringVertex.z);
+                    normals.push(ringNormal.x, ringNormal.y, ringNormal.z);
+                    uvs.push(j / tessellation, 1 - h);
                 }
             }
 
-            // create ribbon based on computed paths (& close seam)
-            var vertexdata = VertexData.CreateRibbon(pathArray, false, true, 0, sideOrientation);
+            // indices
+            for (var i = 0; i < subdivisions; i++) {
+                for (var j = 0; j < tessellation; j++) {
+                    var i0 = i * (tessellation + 1) + j;
+                    var i1 = (i + 1) * (tessellation + 1) + j;
+                    var i2 = i * (tessellation + 1) + (j + 1);
+                    var i3 = (i + 1) * (tessellation + 1) + (j + 1);
+                    indices.push(i0, i1, i2);
+                    indices.push(i3, i2, i1);
+                }
+            }
 
+            // Caps
             var createCylinderCap = function (isTop) {
                 var radius = isTop ? diameterTop / 2 : diameterBottom / 2;
                 if (radius === 0) {
                     return;
                 }
-                var vbase = vertexdata.positions.length / 3;
+                var vbase = positions.length / 3;
                 var offset = new Vector3(0, isTop ? height / 2 : -height / 2, 0);
                 var textureScale = new Vector2(0.5, 0.5);
-                // Positions, normals & uvs
+                // Cap positions, normals & uvs
                 var angle;
                 var circleVector;
                 for (var i = 0; i < tessellation; i++) {
@@ -766,21 +795,21 @@
                     circleVector = new Vector3(Math.cos(-angle), 0, Math.sin(-angle));
                     var position = circleVector.scale(radius).add(offset);
                     var textureCoordinate = new Vector2(circleVector.x * textureScale.x + 0.5, circleVector.z * textureScale.y + 0.5);
-                    vertexdata.positions.push(position.x, position.y, position.z);
-                    vertexdata.normals.push(0, isTop ? 1 : -1, 0);
-                    vertexdata.uvs.push(textureCoordinate.x, textureCoordinate.y);
+                    positions.push(position.x, position.y, position.z);
+                    normals.push(0, isTop ? 1 : -1, 0);
+                    uvs.push(textureCoordinate.x, textureCoordinate.y);
                 }
-                // Indices
+                // Cap indices
                 for (i = 0; i < tessellation - 2; i++) {
                     if (!isTop) {
-                        vertexdata.indices.push(vbase);
-                        vertexdata.indices.push(vbase + (i + 1) % tessellation);
-                        vertexdata.indices.push(vbase + (i + 2) % tessellation);
+                        indices.push(vbase);
+                        indices.push(vbase + (i + 1) % tessellation);
+                        indices.push(vbase + (i + 2) % tessellation);
                     }
                     else {
-                        vertexdata.indices.push(vbase);
-                        vertexdata.indices.push(vbase + (i + 2) % tessellation);
-                        vertexdata.indices.push(vbase + (i + 1) % tessellation);
+                        indices.push(vbase);
+                        indices.push(vbase + (i + 2) % tessellation);
+                        indices.push(vbase + (i + 1) % tessellation);
                     }
                 }
             };
@@ -789,7 +818,17 @@
             createCylinderCap(true);
             createCylinderCap(false);
 
-            return vertexdata;
+            // Sides
+            VertexData._ComputeSides(sideOrientation, positions, indices, normals, uvs);
+
+            var vertexData = new VertexData();
+
+            vertexData.indices = indices;
+            vertexData.positions = positions;
+            vertexData.normals = normals;
+            vertexData.uvs = uvs;
+
+            return vertexData;
         }
 
         public static CreateTorus(diameter, thickness, tessellation, sideOrientation: number = Mesh.DEFAULTSIDE) {
@@ -1403,3 +1442,4 @@
 
 
 
+

+ 54 - 19
src/Rendering/babylon.edgesRenderer.js

@@ -9,13 +9,16 @@ var BABYLON;
     })();
     var EdgesRenderer = (function () {
         // Beware when you use this class with complex objects as the adjacencies computation can be really long
-        function EdgesRenderer(source, epsilon) {
+        function EdgesRenderer(source, epsilon, checkVerticesInsteadOfIndices) {
             if (epsilon === void 0) { epsilon = 0.95; }
+            if (checkVerticesInsteadOfIndices === void 0) { checkVerticesInsteadOfIndices = false; }
             this._linesPositions = new Array();
             this._linesNormals = new Array();
             this._linesIndices = new Array();
             this._buffers = new Array();
+            this._checkVerticesInsteadOfIndices = false;
             this._source = source;
+            this._checkVerticesInsteadOfIndices = checkVerticesInsteadOfIndices;
             this._epsilon = epsilon;
             this._prepareRessources();
             this._generateEdgesLines();
@@ -26,7 +29,7 @@ var BABYLON;
             }
             this._lineShader = new BABYLON.ShaderMaterial("lineShader", this._source.getScene(), "line", {
                 attributes: ["position", "normal"],
-                uniforms: ["worldViewProjection", "color", "width"]
+                uniforms: ["worldViewProjection", "color", "width", "aspectRatio"]
             });
             this._lineShader.disableDepthWrite = true;
             this._lineShader.backFaceCulling = false;
@@ -49,6 +52,18 @@ var BABYLON;
             }
             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) {
@@ -76,18 +91,22 @@ var BABYLON;
                 this._linesPositions.push(p1.y);
                 this._linesPositions.push(p1.z);
                 // Normals
-                this._linesNormals.push(normal.x);
-                this._linesNormals.push(normal.y);
-                this._linesNormals.push(normal.z);
-                this._linesNormals.push(-normal.x);
-                this._linesNormals.push(-normal.y);
-                this._linesNormals.push(-normal.z);
-                this._linesNormals.push(-normal.x);
-                this._linesNormals.push(-normal.y);
-                this._linesNormals.push(-normal.z);
-                this._linesNormals.push(normal.x);
-                this._linesNormals.push(normal.y);
-                this._linesNormals.push(normal.z);
+                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);
@@ -140,13 +159,28 @@ var BABYLON;
                         }
                         switch (edgeIndex) {
                             case 0:
-                                otherEdgeIndex = this._processEdgeForAdjacencies(indices[index * 3], indices[index * 3 + 1], otherP0, otherP1, otherP2);
+                                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:
-                                otherEdgeIndex = this._processEdgeForAdjacencies(indices[index * 3 + 1], indices[index * 3 + 2], otherP0, otherP1, otherP2);
+                                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:
-                                otherEdgeIndex = this._processEdgeForAdjacencies(indices[index * 3 + 2], indices[index * 3], otherP0, otherP1, otherP2);
+                                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) {
@@ -173,7 +207,7 @@ var BABYLON;
             // Merge into a single mesh
             var engine = this._source.getScene().getEngine();
             this._vb0 = new BABYLON.VertexBuffer(engine, this._linesPositions, BABYLON.VertexBuffer.PositionKind, false);
-            this._vb1 = new BABYLON.VertexBuffer(engine, this._linesNormals, BABYLON.VertexBuffer.NormalKind, false);
+            this._vb1 = new BABYLON.VertexBuffer(engine, this._linesNormals, BABYLON.VertexBuffer.NormalKind, false, false, 4);
             this._buffers[BABYLON.VertexBuffer.PositionKind] = this._vb0;
             this._buffers[BABYLON.VertexBuffer.NormalKind] = this._vb1;
             this._ib = engine.createIndexBuffer(this._linesIndices);
@@ -190,7 +224,8 @@ var BABYLON;
             engine.bindMultiBuffers(this._buffers, this._ib, this._lineShader.getEffect());
             scene.resetCachedMaterial();
             this._lineShader.setColor4("color", this._source.edgesColor);
-            this._lineShader.setFloat("width", this._source.edgesWidth / 100.0);
+            this._lineShader.setFloat("width", this._source.edgesWidth / 50.0);
+            this._lineShader.setFloat("aspectRatio", engine.getAspectRatio(scene.activeCamera));
             this._lineShader.bind(this._source.getWorldMatrix());
             // Draw order
             engine.draw(true, 0, this._indicesCount);

+ 57 - 22
src/Rendering/babylon.edgesRenderer.ts

@@ -21,10 +21,12 @@
         private _vb1: VertexBuffer;
         private _ib: WebGLBuffer;
         private _buffers = new Array<VertexBuffer>();
+        private _checkVerticesInsteadOfIndices = false;
 
         // Beware when you use this class with complex objects as the adjacencies computation can be really long
-        constructor(source: AbstractMesh, epsilon = 0.95) {
+        constructor(source: AbstractMesh, epsilon = 0.95, checkVerticesInsteadOfIndices = false) {
             this._source = source;
+            this._checkVerticesInsteadOfIndices = checkVerticesInsteadOfIndices;
 
             this._epsilon = epsilon;
 
@@ -40,7 +42,7 @@
             this._lineShader = new ShaderMaterial("lineShader", this._source.getScene(), "line",
                 {
                     attributes: ["position", "normal"],
-                    uniforms: ["worldViewProjection", "color", "width"]
+                    uniforms: ["worldViewProjection", "color", "width", "aspectRatio"]
                 });
 
             this._lineShader.disableDepthWrite = true;
@@ -70,6 +72,22 @@
             return -1;
         }
 
+        private _processEdgeForAdjacenciesWithVertices(pa: Vector3, pb: Vector3, p0: Vector3, p1: Vector3, p2: Vector3): number {
+            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;
+        }
+
         private _checkEdge(faceIndex: number, edge: number, faceNormals: Array<Vector3>, p0: Vector3, p1: Vector3): void {
             var needToCreateLine;
 
@@ -104,21 +122,25 @@
                 this._linesPositions.push(p1.z);
 
                 // Normals
-                this._linesNormals.push(normal.x);
-                this._linesNormals.push(normal.y);
-                this._linesNormals.push(normal.z);
-
-                this._linesNormals.push(-normal.x);
-                this._linesNormals.push(-normal.y);
-                this._linesNormals.push(-normal.z);
-
-                this._linesNormals.push(-normal.x);
-                this._linesNormals.push(-normal.y);
-                this._linesNormals.push(-normal.z);
-
-                this._linesNormals.push(normal.x);
-                this._linesNormals.push(normal.y);
-                this._linesNormals.push(normal.z);
+                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);
@@ -186,13 +208,25 @@
 
                         switch (edgeIndex) {
                             case 0:
-                                otherEdgeIndex = this._processEdgeForAdjacencies(indices[index * 3], indices[index * 3 + 1], otherP0, otherP1, otherP2);
+                                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:
-                                otherEdgeIndex = this._processEdgeForAdjacencies(indices[index * 3 + 1], indices[index * 3 + 2], otherP0, otherP1, otherP2);
+                                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:
-                                otherEdgeIndex = this._processEdgeForAdjacencies(indices[index * 3 + 2], indices[index * 3], otherP0, otherP1, otherP2);
+                                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;
                         }
 
@@ -226,7 +260,7 @@
             // Merge into a single mesh
             var engine = this._source.getScene().getEngine();
             this._vb0 = new VertexBuffer(engine, this._linesPositions, VertexBuffer.PositionKind, false);
-            this._vb1 = new VertexBuffer(engine, this._linesNormals, VertexBuffer.NormalKind, false);
+            this._vb1 = new VertexBuffer(engine, this._linesNormals, VertexBuffer.NormalKind, false, false, 4);
 
             this._buffers[VertexBuffer.PositionKind] = this._vb0;
             this._buffers[VertexBuffer.NormalKind] = this._vb1;
@@ -250,7 +284,8 @@
 
             scene.resetCachedMaterial();
             this._lineShader.setColor4("color", this._source.edgesColor);
-            this._lineShader.setFloat("width", this._source.edgesWidth / 100.0);
+            this._lineShader.setFloat("width", this._source.edgesWidth / 50.0);
+            this._lineShader.setFloat("aspectRatio", engine.getAspectRatio(scene.activeCamera));
             this._lineShader.bind(this._source.getWorldMatrix());
 
             // Draw order

+ 16 - 6
src/Shaders/line.vertex.fx

@@ -2,20 +2,30 @@
 
 // Attributes
 attribute vec3 position;
-attribute vec3 normal;
+attribute vec4 normal;
 
 // Uniforms
 uniform mat4 worldViewProjection;
 
 uniform float width;
+uniform float aspectRatio;
 
 void main(void) {
 	vec4 viewPosition = worldViewProjection * vec4(position, 1.0);
-	vec4 viewNormal = worldViewProjection * vec4(normal, 0.0);
-	vec3 direction = cross(viewNormal.xyz, vec3(0., 0., 1.));
+	vec4 viewPositionNext = worldViewProjection * vec4(normal.xyz, 1.0);
 
-	direction = normalize(direction);
-	viewPosition.xy += direction.xy *  width;
+	vec2 currentScreen = viewPosition.xy / viewPosition.w;
+	vec2 nextScreen = viewPositionNext.xy / viewPositionNext.w;
 
-	gl_Position = viewPosition;
+	currentScreen.x *= aspectRatio;
+	nextScreen.x *= aspectRatio;
+
+	vec2 dir = normalize(nextScreen - currentScreen);
+	vec2 normalDir = vec2(-dir.y, dir.x);
+
+	normalDir *= width / 2.0;
+	normalDir.x /= aspectRatio;
+
+	vec4 offset = vec4(normalDir * normal.w, 0.0, 0.0);
+	gl_Position = viewPosition + offset;
 }