浏览代码

initial PR

Andrew V Butt Sr 5 年之前
父节点
当前提交
387a08994f
共有 4 个文件被更改,包括 329 次插入1 次删除
  1. 269 0
      src/Meshes/Builders/capsuleBuilder.ts
  2. 3 1
      src/Meshes/Builders/index.ts
  3. 24 0
      src/Meshes/mesh.vertexData.ts
  4. 33 0
      src/Meshes/meshBuilder.ts

+ 269 - 0
src/Meshes/Builders/capsuleBuilder.ts

@@ -0,0 +1,269 @@
+import { VertexData } from "../mesh.vertexData";
+import { Vector2, Vector3 } from "../../Maths/math.vector";
+import { Mesh, _CreationDataStorage } from "../mesh";
+
+VertexData.CreateCapsule = function(options: {
+        orientation: Vector3, 
+        subdivisions: number, 
+        tessellation: number, 
+        height: number, 
+        radius:number, 
+        capSubdivisions: number, 
+        radiusTop:number, 
+        radiusBottom: number, 
+        thetaStart:number, 
+        thetaLength:number,
+        topCapSubdivisions:number,
+        bottomCapSubdivisions:number
+    }): VertexData {
+    //let path = options.orientation || Vector3.Up()
+    let subdivisions = Math.max(options.subdivisions?options.subdivisions:2, 1)
+    let tessellation = Math.max(options.tessellation?options.tessellation:16, 3)
+    let height = Math.max(options.height?options.height:2, 0.)
+    let radius = Math.max(options.radius?options.radius:1, 0.)
+    let capDetail = Math.max(options.capSubdivisions?options.capSubdivisions:6, 1)
+
+    let  radialSegments = tessellation;
+	let  heightSegments = subdivisions;
+
+    let radiusTop = Math.max(options.radiusTop?options.radiusTop:radius, 0.)
+    let radiusBottom = Math.max(options.radiusBottom?options.radiusBottom:radius, 0.)
+
+    let thetaStart = options.thetaStart || 0.0
+    let thetaLength = options.thetaLength || (2.0 * Math.PI)
+
+    let capsTopSegments = Math.max(options.topCapSubdivisions?options.topCapSubdivisions:capDetail, 1)
+    let capsBottomSegments = Math.max(options.bottomCapSubdivisions?options.bottomCapSubdivisions:capDetail, 1)
+
+    var alpha = Math.acos((radiusBottom-radiusTop)/height)
+    //var eqRadii = (radiusTop-radiusBottom === 0)
+
+    var indices = []
+	var vertices = []
+	var normals = []
+	var uvs = []
+    
+    var index = 0,
+	    //indexOffset = 0,
+	    indexArray = [],
+	    halfHeight = height / 2;
+    
+    var x, y;
+    var normal = Vector3.Zero();
+    var vertex = Vector3.Zero();
+
+        var cosAlpha = Math.cos(alpha);
+        var sinAlpha = Math.sin(alpha);
+
+        var cone_length =
+            new Vector2(
+                radiusTop*sinAlpha,
+                halfHeight+radiusTop*cosAlpha
+                ).subtract(new Vector2(
+                    radiusBottom*sinAlpha,
+                    -halfHeight+radiusBottom*cosAlpha
+                )
+            ).length();
+
+        // Total length for v texture coord
+        var vl = radiusTop*alpha
+                 + cone_length
+                 + radiusBottom*(Math.PI/2-alpha);
+
+		//var groupCount = 0;
+
+		// generate vertices, normals and uvs
+
+        var v = 0;
+        for( y = 0; y <= capsTopSegments; y++ ) {
+
+            var indexRow = [];
+
+            var a = Math.PI/2 - alpha*(y / capsTopSegments);
+
+            v += radiusTop*alpha/capsTopSegments;
+
+            var cosA = Math.cos(a);
+            var sinA = Math.sin(a);
+
+            // calculate the radius of the current row
+			var _radius = cosA*radiusTop;
+
+            for ( x = 0; x <= radialSegments; x ++ ) {
+
+				var u = x / radialSegments;
+
+				var theta = u * thetaLength + thetaStart;
+
+				var sinTheta = Math.sin( theta );
+				var cosTheta = Math.cos( theta );
+
+				// vertex
+				vertex.x = _radius * sinTheta;
+				vertex.y = halfHeight + sinA*radiusTop;
+				vertex.z = _radius * cosTheta;
+				vertices.push( vertex.x, vertex.y, vertex.z );
+
+				// normal
+				normal.set( cosA*sinTheta, sinA, cosA*cosTheta );
+				normals.push( normal.x, normal.y, normal.z );
+				// uv
+				uvs.push( u, 1 - v/vl );
+				// save index of vertex in respective row
+				indexRow.push( index );
+				// increase index
+				index ++;
+			}
+
+            // now save vertices of the row in our index array
+			indexArray.push( indexRow );
+
+        }
+
+        var cone_height = height + cosAlpha*radiusTop - cosAlpha*radiusBottom;
+        var slope = sinAlpha * ( radiusBottom - radiusTop ) / cone_height;
+		for ( y = 1; y <= heightSegments; y++ ) {
+
+			var indexRow = [];
+
+			v += cone_length/heightSegments;
+
+			// calculate the radius of the current row
+			var _radius = sinAlpha * ( y * ( radiusBottom - radiusTop ) / heightSegments + radiusTop);
+
+			for ( x = 0; x <= radialSegments; x ++ ) {
+
+				var u = x / radialSegments;
+
+				var theta = u * thetaLength + thetaStart;
+
+				var sinTheta = Math.sin( theta );
+				var cosTheta = Math.cos( theta );
+
+				// vertex
+				vertex.x = _radius * sinTheta;
+				vertex.y = halfHeight + cosAlpha*radiusTop - y * cone_height / heightSegments;
+				vertex.z = _radius * cosTheta;
+				vertices.push( vertex.x, vertex.y, vertex.z );
+
+				// normal
+				normal.set( sinTheta, slope, cosTheta ).normalize();
+				normals.push( normal.x, normal.y, normal.z );
+
+				// uv
+				uvs.push( u, 1 - v/vl );
+
+				// save index of vertex in respective row
+				indexRow.push( index );
+
+				// increase index
+				index ++;
+
+			}
+
+			// now save vertices of the row in our index array
+			indexArray.push( indexRow );
+
+		}
+
+        for( y = 1; y <= capsBottomSegments; y++ ) {
+
+            var indexRow = [];
+
+            var a = (Math.PI/2 - alpha) - (Math.PI - alpha)*( y / capsBottomSegments);
+
+            v += radiusBottom*alpha/capsBottomSegments;
+
+            var cosA = Math.cos(a);
+            var sinA = Math.sin(a);
+
+            // calculate the radius of the current row
+			var _radius = cosA*radiusBottom;
+
+            for ( x = 0; x <= radialSegments; x ++ ) {
+
+				var u = x / radialSegments;
+
+				var theta = u * thetaLength + thetaStart;
+
+				var sinTheta = Math.sin( theta );
+				var cosTheta = Math.cos( theta );
+
+				// vertex
+				vertex.x = _radius * sinTheta;
+				vertex.y = -halfHeight + sinA*radiusBottom;;
+				vertex.z = _radius * cosTheta;
+				vertices.push( vertex.x, vertex.y, vertex.z );
+
+				// normal
+				normal.set( cosA*sinTheta, sinA, cosA*cosTheta );
+				normals.push( normal.x, normal.y, normal.z );
+
+				// uv
+				uvs.push( u, 1 - v/vl );
+
+				// save index of vertex in respective row
+				indexRow.push( index );
+				// increase index
+				index ++;
+			}
+            // now save vertices of the row in our index array
+			indexArray.push( indexRow );
+        }
+		// generate indices
+		for ( x = 0; x < radialSegments; x ++ ) {
+			for ( y = 0; y < capsTopSegments + heightSegments + capsBottomSegments; y ++ ) {
+				// we use the index array to access the correct indices
+				var i1 = indexArray[ y ][ x ];
+				var i2 = indexArray[ y + 1 ][ x ];
+				var i3 = indexArray[ y + 1 ][ x + 1 ];
+				var i4 = indexArray[ y ][ x + 1 ];
+				// face one
+				indices.push( i1 ); 
+				indices.push( i2 );
+				indices.push( i4 );
+				// face two
+				indices.push( i2 ); 
+				indices.push( i3 );
+				indices.push( i4 );
+			}
+		}
+        indices = indices.reverse()
+
+       let vDat = new VertexData()
+       vDat.positions = vertices
+       vDat.normals = normals
+       vDat.uvs = uvs
+       vDat.indices = indices
+
+       return vDat
+}
+
+/**
+ * Class containing static functions to help procedurally build meshes
+ */
+export class CapsuleBuilder {
+    /**
+     * Creates a capsule or a pill mesh  
+     */
+    public static CreateCapsule(name: string, options:{ 
+            orientation: Vector3, 
+            subdivisions: number, 
+            tessellation: number, 
+            height: number, 
+            radius:number, 
+            capSubdivisions: number, 
+            radiusTop:number, 
+            radiusBottom: number, 
+            thetaStart:number, 
+            thetaLength:number,
+            topCapSubdivisions:number,
+            bottomCapSubdivisions:number
+        }, scene: any): Mesh {
+
+        var capsule = new Mesh(name, scene);
+        var vertexData = VertexData.CreateCapsule(options);
+        vertexData.applyToMesh(capsule);
+        return capsule;
+    }
+}

+ 3 - 1
src/Meshes/Builders/index.ts

@@ -17,4 +17,6 @@ export * from "./groundBuilder";
 export * from "./tubeBuilder";
 export * from "./polyhedronBuilder";
 export * from "./icoSphereBuilder";
-export * from "./decalBuilder";
+export * from "./decalBuilder";
+export * from "./icoSphereBuilder";
+export * from "./capsuleBuilder";

+ 24 - 0
src/Meshes/mesh.vertexData.ts

@@ -1041,6 +1041,30 @@ export class VertexData {
         throw _DevTools.WarnImport("polyhedronBuilder");
     }
 
+    // 
+    /**
+     * Creates the VertexData for a Capsule, inspired from https://github.com/maximeq/three-js-capsule-geometry/blob/master/src/CapsuleBufferGeometry.js
+     * @param options an object used to set the following optional parameters for the capsule, required but can be empty
+     * type provided types are:    
+     * @returns the VertexData of the Capsule
+     */
+    public static CreateCapsule(options: {
+            orientation: Vector3,
+            subdivisions: number,
+            tessellation: number,
+            height: number,
+            radius: number,
+            capSubdivisions: number,
+            radiusTop:number,
+            radiusBottom: number,
+            thetaStart:number,
+            thetaLength:number,
+            topCapSubdivisions:number,
+            bottomCapSubdivisions:number
+        }): VertexData {
+        throw _DevTools.WarnImport("capsuleBuilder");
+    }
+
     // based on http://code.google.com/p/away3d/source/browse/trunk/fp10/Away3D/src/away3d/primitives/TorusKnot.as?spec=svn2473&r=2473
     /**
      * Creates the VertexData for a TorusKnot

+ 33 - 0
src/Meshes/meshBuilder.ts

@@ -17,6 +17,7 @@ import { TubeBuilder } from "./Builders/tubeBuilder";
 import { PolyhedronBuilder } from "./Builders/polyhedronBuilder";
 import { IcoSphereBuilder } from "./Builders/icoSphereBuilder";
 import { DecalBuilder } from "./Builders/decalBuilder";
+import { CapsuleBuilder } from "./Builders/capsuleBuilder";
 
 import { Vector4, Vector3, Vector2 } from "../Maths/math.vector";
 import { Nullable } from "../types";
@@ -546,4 +547,36 @@ export class MeshBuilder {
     public static CreateDecal(name: string, sourceMesh: AbstractMesh, options: { position?: Vector3, normal?: Vector3, size?: Vector3, angle?: number }): Mesh {
         return DecalBuilder.CreateDecal(name, sourceMesh, options);
     }
+
+
+    /**
+     * Creates a decal mesh.
+     * A decal is a mesh usually applied as a model onto the surface of another mesh. So don't forget the parameter `sourceMesh` depicting the decal
+     * * The parameter `position` (Vector3, default `(0, 0, 0)`) sets the position of the decal in World coordinates
+     * * The parameter `normal` (Vector3, default `Vector3.Up`) sets the normal of the mesh where the decal is applied onto in World coordinates
+     * * The parameter `size` (Vector3, default `(1, 1, 1)`) sets the decal scaling
+     * * The parameter `angle` (float in radian, default 0) sets the angle to rotate the decal
+     * @param name defines the name of the mesh
+     * @param sourceMesh defines the mesh where the decal must be applied
+     * @param options defines the options used to create the mesh
+     * @param scene defines the hosting scene
+     * @returns the decal mesh
+     * @see https://doc.babylonjs.com/how_to/decals
+     */
+    public static CreateCapsule(name: string, options: {
+        orientation: Vector3,
+        subdivisions: number,
+        tessellation: number,
+        height: number,
+        radius: number,
+        capSubdivisions: number,
+        radiusTop:number,
+        radiusBottom: number,
+        thetaStart:number,
+        thetaLength:number,
+        topCapSubdivisions:number,
+        bottomCapSubdivisions:number
+    }, scene: Nullable<Scene> = null): Mesh {
+        return CapsuleBuilder.CreateCapsule(name, options, scene);
+    }
 }