Просмотр исходного кода

Merge remote-tracking branch 'origin/master' into BlenderQuaternions

jackcaron 10 лет назад
Родитель
Сommit
723c9b627f
2 измененных файлов с 62 добавлено и 153 удалено
  1. 4 54
      src/Mesh/babylon.mesh.ts
  2. 58 99
      src/Mesh/babylon.mesh.vertexData.ts

+ 4 - 54
src/Mesh/babylon.mesh.ts

@@ -1343,7 +1343,7 @@
             return sphere;
         }
 
-        // Cylinder and cone (Code inspired by SharpDX.org)
+        // Cylinder and cone
         public static CreateCylinder(name: string, height: number, diameterTop: number, diameterBottom: number, tessellation: number, subdivisions: any, scene: Scene, updatable?: any, sideOrientation: number = Mesh.DEFAULTSIDE): Mesh {
             // subdivisions is a new parameter, we need to support old signature
             if (scene === undefined || !(scene instanceof Scene)) {
@@ -1354,60 +1354,10 @@
                 subdivisions = 1;
             }
 
-            // setup tube creation parameters
-            var path = [
-                new Vector3(0, -height / 2, 0),
-                new Vector3(0, height / 2, 0),
-            ];
+            var cylinder = new Mesh(name, scene);
+            var vertexData = VertexData.CreateCylinder(height, diameterTop, diameterBottom, tessellation, subdivisions, sideOrientation);
 
-            var radiusFunction = function (i, distance) {
-                return (diameterBottom + (diameterTop - diameterBottom) * distance / height) / 2;
-            };
-            
-            // create tube without caps
-            var cylinder = Mesh.CreateTube(name, path, 1.0, tessellation, radiusFunction, Mesh.NO_CAP, scene, updatable, sideOrientation);
-            
-            // extract geometry data to add caps
-            var geometry_data = VertexData.ExtractFromMesh(cylinder);
-
-            var createCylinderCap = function (isTop) {
-                var radius = isTop ? diameterTop / 2 : diameterBottom / 2;
-                if (radius === 0) {
-                    return;
-                }
-                var vbase = geometry_data.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
-                var angle;
-                for (var i = 0; i < tessellation; i++) {
-                    angle = Math.PI * 2 * i / tessellation;
-                    var 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);
-                    geometry_data.positions.push(position.x, position.y, position.z);
-                    geometry_data.normals.push(0, isTop ? 1 : -1, 0);
-                    geometry_data.uvs.push(textureCoordinate.x, textureCoordinate.y);
-                }
-                // Indices
-                for (i = 0; i < tessellation - 2; i++) {
-                    if (!isTop) {
-                        geometry_data.indices.push(vbase);
-                        geometry_data.indices.push(vbase + (i + 2) % tessellation);
-                        geometry_data.indices.push(vbase + (i + 1) % tessellation);
-                    }
-                    else {
-                        geometry_data.indices.push(vbase);
-                        geometry_data.indices.push(vbase + (i + 1) % tessellation);
-                        geometry_data.indices.push(vbase + (i + 2) % tessellation);
-                    }
-                }
-            };
-            
-            // add caps to geometry and apply to mesh
-            createCylinderCap(true);
-            createCylinderCap(false);
-            geometry_data.applyToMesh(cylinder);
+            vertexData.applyToMesh(cylinder, updatable);
 
             return cylinder;
         }

+ 58 - 99
src/Mesh/babylon.mesh.vertexData.ts

@@ -708,128 +708,87 @@
             return vertexData;
         }
 
+        // 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 {
-            var radiusTop = diameterTop / 2;
-            var radiusBottom = diameterBottom / 2;
-            var indices = [];
-            var positions = [];
-            var normals = [];
-            var uvs = [];
 
-            height = height || 1;
-            diameterTop = diameterTop || 0.5;
-            diameterBottom = diameterBottom || 1;
-            tessellation = tessellation || 16;
-            subdivisions = subdivisions || 1;
-            subdivisions = (subdivisions < 1) ? 1 : subdivisions;
-
-            var getCircleVector = i => {
-                var angle = (i * 2.0 * Math.PI / tessellation);
-                var dx = Math.cos(angle);
-                var dz = Math.sin(angle);
+            // setup tube creation parameters
+            var path = [];
+            for (var i = 0; i <= subdivisions; i++) {
+               path.push(new Vector3(0, height * (- 0.5 + i / subdivisions), 0));
+            }
 
-                return new Vector3(dx, 0, dz);
+            // 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;
+
+            for(var i=0; i<=subdivisions; i++) {
+
+                pathArray[i] = [];
+
+                for(var j=0; j<tessellation; j++) {
+                    angle = j * angle_step;
+                    ringVertex = Vector3.TransformCoordinates(normals[i], Matrix.RotationAxis(tangents[i], angle));
+                    ringVertex.scaleInPlace(radiusFunction(i, distances[i])).addInPlace(path[i]);
+                    pathArray[i].push(ringVertex);
+                }
+            }
 
-            var createCylinderCap = isTop => {
-                var radius = isTop ? radiusTop : radiusBottom;
+            // create ribbon based on computed paths (& close seam)
+            var vertexdata = VertexData.CreateRibbon(pathArray, false, true, 0, sideOrientation);
 
+            var createCylinderCap = function (isTop) {
+                var radius = isTop ? diameterTop / 2 : diameterBottom / 2;
                 if (radius === 0) {
                     return;
                 }
-                var vbase = positions.length / 3;
-
-                var offset = new Vector3(0, height / 2, 0);
+                var vbase = vertexdata.positions.length / 3;
+                var offset = new Vector3(0, isTop ? height / 2 : -height / 2, 0);
                 var textureScale = new Vector2(0.5, 0.5);
-
-                if (!isTop) {
-                    offset.scaleInPlace(-1);
-                    textureScale.x = -textureScale.x;
-                }
-
                 // Positions, normals & uvs
+                var angle;
                 for (var i = 0; i < tessellation; i++) {
-                    var circleVector = getCircleVector(i);
+                    angle = Math.PI * 2 * i / tessellation;
+                    var 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
-                        );
-
-                    positions.push(position.x, position.y, position.z);
-                    uvs.push(textureCoordinate.x, textureCoordinate.y);
+                    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);
                 }
-
                 // Indices
                 for (i = 0; i < tessellation - 2; i++) {
                     if (!isTop) {
-                        indices.push(vbase);
-                        indices.push(vbase + (i + 2) % tessellation);
-                        indices.push(vbase + (i + 1) % tessellation);
-                    } else {
-                        indices.push(vbase);
-                        indices.push(vbase + (i + 1) % tessellation);
-                        indices.push(vbase + (i + 2) % tessellation);
+                        vertexdata.indices.push(vbase);
+                        vertexdata.indices.push(vbase + (i + 2) % tessellation);
+                        vertexdata.indices.push(vbase + (i + 1) % tessellation);
+                    }
+                    else {
+                        vertexdata.indices.push(vbase);
+                        vertexdata.indices.push(vbase + (i + 1) % tessellation);
+                        vertexdata.indices.push(vbase + (i + 2) % tessellation);
                     }
                 }
             };
-
-            var base = new Vector3(0, -1, 0).scale(height / 2);
-            var offset = new Vector3(0, 1, 0).scale(height / subdivisions);
-            var stride = tessellation + 1;
-
-            // Positions, normals & uvs
-            for (var i = 0; i <= tessellation; i++) {
-                var circleVector = getCircleVector(i);
-                var textureCoordinate = new Vector2(i / tessellation, 0);
-                var position: Vector3, radius = radiusBottom;
-
-                for (var s = 0; s <= subdivisions; s++) {
-                    // Update variables
-                    position = circleVector.scale(radius);
-                    position.addInPlace(base.add(offset.scale(s)));
-                    textureCoordinate.y += 1 / subdivisions;
-                    radius += (radiusTop - radiusBottom) / subdivisions;
-
-                    // Push in arrays
-                    positions.push(position.x, position.y, position.z);
-                    uvs.push(textureCoordinate.x, textureCoordinate.y);
-                }
-            }
-
-            subdivisions += 1;
-            // Indices
-            for (s = 0; s < subdivisions - 1; s++) {
-                for (i = 0; i <= tessellation; i++) {
-                    indices.push(i * subdivisions + s);
-                    indices.push((i * subdivisions + (s + subdivisions)) % (stride * subdivisions));
-                    indices.push(i * subdivisions + (s + 1));
-
-                    indices.push(i * subdivisions + (s + 1));
-                    indices.push((i * subdivisions + (s + subdivisions)) % (stride * subdivisions));
-                    indices.push((i * subdivisions + (s + subdivisions + 1)) % (stride * subdivisions));
-                }
-            }
-
-            // Create flat triangle fan caps to seal the top and bottom.
+            
+            // add caps to geometry
             createCylinderCap(true);
             createCylinderCap(false);
 
-            // Normals
-            VertexData.ComputeNormals(positions, indices, normals);
-
-            // Sides
-            VertexData._ComputeSides(sideOrientation, positions, indices, normals, uvs);
-
-            // Result
-            var vertexData = new VertexData();
-
-            vertexData.indices = indices;
-            vertexData.positions = positions;
-            vertexData.normals = normals;
-            vertexData.uvs = uvs;
-
-            return vertexData;
+            return vertexdata;
         }
 
         public static CreateTorus(diameter, thickness, tessellation, sideOrientation: number = Mesh.DEFAULTSIDE) {