浏览代码

Add a smoothing threshole to smooth the sides of an extruded polygon.
If the dot product of the normals of two adjacent side polygons is greater than this threshold, the normal on that edge are set to the average of the two.

Scott Nagy 4 年之前
父节点
当前提交
baf6d0e507
共有 2 个文件被更改,包括 66 次插入32 次删除
  1. 3 2
      src/Meshes/Builders/polygonBuilder.ts
  2. 63 30
      src/Meshes/polygonMesh.ts

+ 3 - 2
src/Meshes/Builders/polygonBuilder.ts

@@ -154,11 +154,12 @@ export class PolygonBuilder {
      * @param earcutInjection can be used to inject your own earcut reference
      * @param earcutInjection can be used to inject your own earcut reference
      * @returns the polygon mesh
      * @returns the polygon mesh
      */
      */
-    public static CreatePolygon(name: string, options: { shape: Vector3[], holes?: Vector3[][], depth?: number, faceUV?: Vector4[], faceColors?: Color4[], updatable?: boolean, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4, wrap?: boolean}, scene: Nullable<Scene> = null, earcutInjection = earcut): Mesh {
+    public static CreatePolygon(name: string, options: { shape: Vector3[], holes?: Vector3[][], depth?: number, smoothingThreshold?: number, faceUV?: Vector4[], faceColors?: Color4[], updatable?: boolean, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4, wrap?: boolean}, scene: Nullable<Scene> = null, earcutInjection = earcut): Mesh {
         options.sideOrientation = Mesh._GetDefaultSideOrientation(options.sideOrientation);
         options.sideOrientation = Mesh._GetDefaultSideOrientation(options.sideOrientation);
         var shape = options.shape;
         var shape = options.shape;
         var holes = options.holes || [];
         var holes = options.holes || [];
         var depth = options.depth || 0;
         var depth = options.depth || 0;
+        var smoothingThreshold = options.smoothingThreshold || 2;
         var contours: Array<Vector2> = [];
         var contours: Array<Vector2> = [];
         var hole: Array<Vector2> = [];
         var hole: Array<Vector2> = [];
 
 
@@ -178,7 +179,7 @@ export class PolygonBuilder {
             }
             }
             polygonTriangulation.addHole(hole);
             polygonTriangulation.addHole(hole);
         }
         }
-        var polygon = polygonTriangulation.build(options.updatable, depth);
+        var polygon = polygonTriangulation.build(options.updatable, depth, smoothingThreshold);
         polygon._originalBuilderSideOrientation = options.sideOrientation;
         polygon._originalBuilderSideOrientation = options.sideOrientation;
         var vertexData = VertexData.CreatePolygon(polygon, options.sideOrientation, options.faceUV, options.faceColors, options.frontUVs, options.backUVs, options.wrap);
         var vertexData = VertexData.CreatePolygon(polygon, options.sideOrientation, options.faceUV, options.faceColors, options.frontUVs, options.backUVs, options.wrap);
         vertexData.applyToMesh(polygon, options.updatable);
         vertexData.applyToMesh(polygon, options.updatable);

+ 63 - 30
src/Meshes/polygonMesh.ts

@@ -7,6 +7,7 @@ import { VertexData } from "../Meshes/mesh.vertexData";
 import { Engine } from "../Engines/engine";
 import { Engine } from "../Engines/engine";
 import { Nullable } from "../types";
 import { Nullable } from "../types";
 import { Path2 } from '../Maths/math.path';
 import { Path2 } from '../Maths/math.path';
+import { Epsilon } from '../Maths/math.constants';
 
 
 declare var earcut: any;
 declare var earcut: any;
 /**
 /**
@@ -201,7 +202,7 @@ export class PolygonMeshBuilder {
     }
     }
 
 
     /**
     /**
-     * Adds a whole within the polygon
+     * Adds a hole within the polygon
      * @param hole Array of points defining the hole
      * @param hole Array of points defining the hole
      * @returns this
      * @returns this
      */
      */
@@ -223,10 +224,10 @@ export class PolygonMeshBuilder {
      * @param depth The depth of the mesh created
      * @param depth The depth of the mesh created
      * @returns the created mesh
      * @returns the created mesh
      */
      */
-    build(updatable: boolean = false, depth: number = 0): Mesh {
+    build(updatable: boolean = false, depth: number = 0, smoothingThreshold: number = 2): Mesh {
         var result = new Mesh(this._name, this._scene);
         var result = new Mesh(this._name, this._scene);
 
 
-        var vertexData = this.buildVertexData(depth);
+        var vertexData = this.buildVertexData(depth, smoothingThreshold);
 
 
         result.setVerticesData(VertexBuffer.PositionKind, <number[]>vertexData.positions, updatable);
         result.setVerticesData(VertexBuffer.PositionKind, <number[]>vertexData.positions, updatable);
         result.setVerticesData(VertexBuffer.NormalKind, <number[]>vertexData.normals, updatable);
         result.setVerticesData(VertexBuffer.NormalKind, <number[]>vertexData.normals, updatable);
@@ -241,7 +242,7 @@ export class PolygonMeshBuilder {
      * @param depth The depth of the mesh created
      * @param depth The depth of the mesh created
      * @returns the created VertexData
      * @returns the created VertexData
      */
      */
-    buildVertexData(depth: number = 0): VertexData {
+    buildVertexData(depth: number = 0, smoothingThreshold: number = 2): VertexData {
         var result = new VertexData();
         var result = new VertexData();
 
 
         var normals = new Array<number>();
         var normals = new Array<number>();
@@ -284,10 +285,10 @@ export class PolygonMeshBuilder {
             }
             }
 
 
             //Add the sides
             //Add the sides
-            this.addSide(positions, normals, uvs, indices, bounds, this._outlinepoints, depth, false);
+            this.addSide(positions, normals, uvs, indices, bounds, this._outlinepoints, depth, false, smoothingThreshold);
 
 
             this._holes.forEach((hole) => {
             this._holes.forEach((hole) => {
-                this.addSide(positions, normals, uvs, indices, bounds, hole, depth, true);
+                this.addSide(positions, normals, uvs, indices, bounds, hole, depth, true, smoothingThreshold);
             });
             });
         }
         }
 
 
@@ -310,43 +311,79 @@ export class PolygonMeshBuilder {
      * @param depth depth of the polygon
      * @param depth depth of the polygon
      * @param flip flip of the polygon
      * @param flip flip of the polygon
      */
      */
-    private addSide(positions: any[], normals: any[], uvs: any[], indices: any[], bounds: any, points: PolygonPoints, depth: number, flip: boolean) {
+    private addSide(positions: any[], normals: any[], uvs: any[], indices: any[], bounds: any, points: PolygonPoints, depth: number, flip: boolean, smoothingThreshold: number) {
         var StartIndex: number = positions.length / 3;
         var StartIndex: number = positions.length / 3;
         var ulength: number = 0;
         var ulength: number = 0;
         for (var i: number = 0; i < points.elements.length; i++) {
         for (var i: number = 0; i < points.elements.length; i++) {
             var p: IndexedVector2 = points.elements[i];
             var p: IndexedVector2 = points.elements[i];
-            var p1: IndexedVector2;
-            if ((i + 1) > points.elements.length - 1) {
-                p1 = points.elements[0];
-            }
-            else {
-                p1 = points.elements[i + 1];
-            }
+            var p1: IndexedVector2 = points.elements[(i + 1)%points.elements.length];
 
 
             positions.push(p.x, 0, p.y);
             positions.push(p.x, 0, p.y);
             positions.push(p.x, -depth, p.y);
             positions.push(p.x, -depth, p.y);
             positions.push(p1.x, 0, p1.y);
             positions.push(p1.x, 0, p1.y);
             positions.push(p1.x, -depth, p1.y);
             positions.push(p1.x, -depth, p1.y);
 
 
-            var v1 = new Vector3(p.x, 0, p.y);
-            var v2 = new Vector3(p1.x, 0, p1.y);
-            var v3 = v2.subtract(v1);
-            var v4 = new Vector3(0, 1, 0);
-            var vn = Vector3.Cross(v3, v4);
-            vn = vn.normalize();
+            let vc = new Vector3(-(p1.y-p.y), 0, p1.x-p.x);
+            const vc_len = vc.length();
+            vc = vc.normalizeFromLength(vc_len);
+
+            
+            const p0: IndexedVector2 = points.elements[(i + points.elements.length - 1)%points.elements.length];
+            const p2: IndexedVector2 = points.elements[(i + 2)%points.elements.length];
+            let vp = new Vector3(-( p.y-p0.y), 0,  p.x-p0.x);
+            const vp_len = vp.length();
+            vp = vp.normalizeFromLength(vp_len);
+            let vn = new Vector3(-(p2.y-p1.y), 0, p2.x-p1.x);
+            const vn_len = vn.length();
+            vn = vn.normalizeFromLength(vn_len);
+            
+            if(!flip) {
+                vp = vp.scale(-1);
+                vn = vn.scale(-1);
+                vc = vc.scale(-1);
+            }
+            
+            const dotp = Vector3.Dot(vp, vc);
+            if(dotp > smoothingThreshold) {
+                if( dotp < Epsilon-1) {
+                    vp = (new Vector3(p.x, 0, p.y)).subtract(new Vector3(p1.x, 0, p1.y)).normalize();
+                }
+                else {
+                    // cheap average
+                    vp = vp.add(vc).normalize();
+                }
+            }
+            else {
+                vp = vc;
+            }
+
+            const dotn = Vector3.Dot(vn, vc)
+            if(dotn > smoothingThreshold) {
+                if( dotn < Epsilon-1) {
+                    // back to back
+                    vn = (new Vector3(p1.x, 0, p1.y)).subtract(new Vector3(p.x, 0, p.y)).normalize();
+                }
+                else {
+                    // cheap average
+                    vn = vn.add(vc).normalize();
+                }
+            }
+            else {
+                vn = vc;
+            }
 
 
             uvs.push(ulength / bounds.width, 0);
             uvs.push(ulength / bounds.width, 0);
             uvs.push(ulength / bounds.width, 1);
             uvs.push(ulength / bounds.width, 1);
-            ulength += v3.length();
+            ulength += vc_len;
             uvs.push((ulength / bounds.width), 0);
             uvs.push((ulength / bounds.width), 0);
             uvs.push((ulength / bounds.width), 1);
             uvs.push((ulength / bounds.width), 1);
 
 
-            if (!flip) {
-                normals.push(-vn.x, - vn.y, -vn.z);
-                normals.push(-vn.x, -vn.y, -vn.z);
-                normals.push(-vn.x, -vn.y, -vn.z);
-                normals.push(-vn.x, -vn.y, -vn.z);
+            normals.push(vp.x, vp.y, vp.z);
+            normals.push(vp.x, vp.y, vp.z);
+            normals.push(vn.x, vn.y, vn.z);
+            normals.push(vn.x, vn.y, vn.z);
 
 
+            if (!flip) {
                 indices.push(StartIndex);
                 indices.push(StartIndex);
                 indices.push(StartIndex + 1);
                 indices.push(StartIndex + 1);
                 indices.push(StartIndex + 2);
                 indices.push(StartIndex + 2);
@@ -356,10 +393,6 @@ export class PolygonMeshBuilder {
                 indices.push(StartIndex + 2);
                 indices.push(StartIndex + 2);
             }
             }
             else {
             else {
-                normals.push(vn.x, vn.y, vn.z);
-                normals.push(vn.x, vn.y, vn.z);
-                normals.push(vn.x, vn.y, vn.z);
-                normals.push(vn.x, vn.y, vn.z);
 
 
                 indices.push(StartIndex);
                 indices.push(StartIndex);
                 indices.push(StartIndex + 2);
                 indices.push(StartIndex + 2);