瀏覽代碼

Merge pull request #686 from jbousquie/fix.CylinderMesh.Reimplementation

re-implement CreateCylinder() method code with dedicated normal computation
Raanan Weber 10 年之前
父節點
當前提交
255d4c748e
共有 1 個文件被更改,包括 71 次插入45 次删除
  1. 71 45
      src/Mesh/babylon.mesh.vertexData.ts

+ 71 - 45
src/Mesh/babylon.mesh.vertexData.ts

@@ -711,54 +711,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 +781,22 @@
                     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);
+                    else 
+                    {
+                        indices.push(vbase);
+                        indices.push(vbase + (i + 2) % tessellation);
+                        indices.push(vbase + (i + 1) % tessellation);
                     }
                 }
             };
@@ -789,7 +805,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) {