|
@@ -1352,675 +1352,131 @@
|
|
|
}
|
|
|
|
|
|
// Extrusion
|
|
|
- public static ExtrudeShape(name: string, shape: Vector3[], path: Vector3[], scale: number, rotation: number, cap: number, scene: Scene, updatable?: boolean, sideOrientation?: number, instance?: Mesh): Mesh;
|
|
|
- public static ExtrudeShape(name: string, options: { shape: Vector3[], path: Vector3[], scale?: number, rotation?: number, cap?: number, updatable?: boolean, sideOrientation?: number, instance?: Mesh }, scene: Scene): Mesh;
|
|
|
- public static ExtrudeShape(name: string, options: any, pathOrScene?: any, scale?: number, rotation?: number, cap?: number, scene?: Scene, updatable?: boolean, sideOrientation: number = Mesh.DEFAULTSIDE, instance: Mesh = null): Mesh {
|
|
|
- var path: Vector3[];
|
|
|
- var shape: Vector3[];
|
|
|
- if (Array.isArray(options)) {
|
|
|
- shape = options;
|
|
|
- path = pathOrScene;
|
|
|
- scale = scale || 1;
|
|
|
- rotation = rotation || 0;
|
|
|
- cap = (cap === 0) ? 0 : cap || Mesh.NO_CAP;
|
|
|
- } else {
|
|
|
- scene = pathOrScene;
|
|
|
- path = options.path;
|
|
|
- shape = options.shape;
|
|
|
- scale = options.scale || 1;
|
|
|
- rotation = options.rotation || 0;
|
|
|
- cap = (options.cap === 0) ? 0 : options.cap || Mesh.NO_CAP;
|
|
|
- updatable = options.updatable;
|
|
|
- sideOrientation = (options.sideOrientation === 0) ? 0 : options.sideOrientation || Mesh.DEFAULTSIDE;
|
|
|
- instance = options.instance;
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- var extruded = Mesh._ExtrudeShapeGeneric(name, shape, path, scale, rotation, null, null, false, false, cap, false, scene, updatable, sideOrientation, instance);
|
|
|
- return extruded;
|
|
|
- }
|
|
|
-
|
|
|
- public static ExtrudeShapeCustom(name: string, shape: Vector3[], path: Vector3[], scaleFunction, rotationFunction, ribbonCloseArray: boolean, ribbonClosePath: boolean, cap: number, scene: Scene, updatable?: boolean, sideOrientation?: number, instance?: Mesh): Mesh;
|
|
|
- public static ExtrudeShapeCustom(name: string, options: { shape: Vector3[], path: Vector3[], scaleFunction?, rotationFunction?, ribbonCloseArray?: boolean, ribbonClosePath?: boolean, cap?: number, updatable?: boolean, sideOrientation?: number, instance?: Mesh }, scene: Scene): Mesh;
|
|
|
- public static ExtrudeShapeCustom(name: string, options: any, pathOrScene?: any, scaleFunction?, rotationFunction?, ribbonCloseArray?: boolean, ribbonClosePath?: boolean, cap?: number, scene?: Scene, updatable?: boolean, sideOrientation: number = Mesh.DEFAULTSIDE, instance: Mesh = null): Mesh {
|
|
|
- var path: Vector3[];
|
|
|
- var shape: Vector3[];
|
|
|
- if (Array.isArray(options)) {
|
|
|
- shape = options;
|
|
|
- path = pathOrScene;
|
|
|
- ribbonCloseArray = ribbonCloseArray || false;
|
|
|
- ribbonClosePath = ribbonClosePath || false;
|
|
|
- cap = (cap === 0) ? 0 : cap || Mesh.NO_CAP;
|
|
|
- } else {
|
|
|
- scene = pathOrScene;
|
|
|
- path = options.path;
|
|
|
- shape = options.shape;
|
|
|
- scaleFunction = options.scaleFunction || ((i, distance) => { return 1; });
|
|
|
- rotationFunction = options.rotationFunction || ((i, distance) => { return 0; });
|
|
|
- ribbonCloseArray = options.ribbonCloseArray || false;
|
|
|
- ribbonClosePath = options.ribbonClosePath || false;
|
|
|
- cap = (options.cap === 0) ? 0 : options.cap || Mesh.NO_CAP;
|
|
|
- updatable = options.updatable;
|
|
|
- sideOrientation = (options.sideOrientation === 0) ? 0 : options.sideOrientation || Mesh.DEFAULTSIDE;
|
|
|
- instance = options.instance;
|
|
|
- }
|
|
|
- var extrudedCustom = Mesh._ExtrudeShapeGeneric(name, shape, path, null, null, scaleFunction, rotationFunction, ribbonCloseArray, ribbonClosePath, cap, true, scene, updatable, sideOrientation, instance);
|
|
|
- return extrudedCustom;
|
|
|
- }
|
|
|
-
|
|
|
- private static _ExtrudeShapeGeneric(name: string, shape: Vector3[], curve: Vector3[], scale: number, rotation: number, scaleFunction: { (i: number, distance: number): number; }, rotateFunction: { (i: number, distance: number): number; }, rbCA: boolean, rbCP: boolean, cap: number, custom: boolean, scene: Scene, updtbl: boolean, side: number, instance: Mesh): Mesh {
|
|
|
-
|
|
|
- // extrusion geometry
|
|
|
- var extrusionPathArray = (shape, curve, path3D, shapePaths, scale, rotation, scaleFunction, rotateFunction, cap, custom) => {
|
|
|
- var tangents = path3D.getTangents();
|
|
|
- var normals = path3D.getNormals();
|
|
|
- var binormals = path3D.getBinormals();
|
|
|
- var distances = path3D.getDistances();
|
|
|
-
|
|
|
- var angle = 0;
|
|
|
- var returnScale: { (i: number, distance: number): number; } = (i, distance) => { return scale; };
|
|
|
- var returnRotation: { (i: number, distance: number): number; } = (i, distance) => { return rotation; };
|
|
|
- var rotate: { (i: number, distance: number): number; } = custom ? rotateFunction : returnRotation;
|
|
|
- var scl: { (i: number, distance: number): number; } = custom ? scaleFunction : returnScale;
|
|
|
- var index = (cap === Mesh.NO_CAP || cap === Mesh.CAP_END) ? 0 : 2;
|
|
|
- var rotationMatrix: Matrix = Matrix.Zero();
|
|
|
-
|
|
|
- for (var i = 0; i < curve.length; i++) {
|
|
|
- var shapePath = new Array<Vector3>();
|
|
|
- var angleStep = rotate(i, distances[i]);
|
|
|
- var scaleRatio = scl(i, distances[i]);
|
|
|
- for (var p = 0; p < shape.length; p++) {
|
|
|
- Matrix.RotationAxisToRef(tangents[i], angle, rotationMatrix);
|
|
|
- var planed = ((tangents[i].scale(shape[p].z)).add(normals[i].scale(shape[p].x)).add(binormals[i].scale(shape[p].y)));
|
|
|
- var rotated = Vector3.TransformCoordinates(planed, rotationMatrix).scaleInPlace(scaleRatio).add(curve[i]);
|
|
|
- shapePath.push(rotated);
|
|
|
- }
|
|
|
- shapePaths[index] = shapePath;
|
|
|
- angle += angleStep;
|
|
|
- index++;
|
|
|
- }
|
|
|
- // cap
|
|
|
- var capPath = shapePath => {
|
|
|
- var pointCap = Array<Vector3>();
|
|
|
- var barycenter = Vector3.Zero();
|
|
|
- var i: number;
|
|
|
- for (i = 0; i < shapePath.length; i++) {
|
|
|
- barycenter.addInPlace(shapePath[i]);
|
|
|
- }
|
|
|
- barycenter.scaleInPlace(1 / shapePath.length);
|
|
|
- for (i = 0; i < shapePath.length; i++) {
|
|
|
- pointCap.push(barycenter);
|
|
|
- }
|
|
|
- return pointCap;
|
|
|
- };
|
|
|
- switch (cap) {
|
|
|
- case Mesh.NO_CAP:
|
|
|
- break;
|
|
|
- case Mesh.CAP_START:
|
|
|
- shapePaths[0] = capPath(shapePaths[2]);
|
|
|
- shapePaths[1] = shapePaths[2].slice(0);
|
|
|
- break;
|
|
|
- case Mesh.CAP_END:
|
|
|
- shapePaths[index] = shapePaths[index - 1];
|
|
|
- shapePaths[index + 1] = capPath(shapePaths[index - 1]);
|
|
|
- break;
|
|
|
- case Mesh.CAP_ALL:
|
|
|
- shapePaths[0] = capPath(shapePaths[2]);
|
|
|
- shapePaths[1] = shapePaths[2].slice(0);
|
|
|
- shapePaths[index] = shapePaths[index - 1];
|
|
|
- shapePaths[index + 1] = capPath(shapePaths[index - 1]);
|
|
|
- break;
|
|
|
- default:
|
|
|
- break;
|
|
|
- }
|
|
|
- return shapePaths;
|
|
|
- };
|
|
|
- var path3D;
|
|
|
- var pathArray;
|
|
|
- if (instance) { // instance update
|
|
|
- path3D = ((<any>instance).path3D).update(curve);
|
|
|
- pathArray = extrusionPathArray(shape, curve, (<any>instance).path3D, (<any>instance).pathArray, scale, rotation, scaleFunction, rotateFunction, (<any>instance).cap, custom);
|
|
|
- instance = Mesh.CreateRibbon(null, pathArray, null, null, null, null, null, null, instance);
|
|
|
-
|
|
|
- return instance;
|
|
|
+ public static ExtrudeShape(name: string, shape: Vector3[], path: Vector3[], scale: number, rotation: number, cap: number, scene: Scene, updatable?: boolean, sideOrientation?: number, instance?: Mesh): Mesh {
|
|
|
+ var options = {
|
|
|
+ shape: shape,
|
|
|
+ path: path,
|
|
|
+ scale: scale,
|
|
|
+ rotation: rotation,
|
|
|
+ cap: (cap === 0) ? 0 : cap || Mesh.NO_CAP,
|
|
|
+ sideOrientation: sideOrientation,
|
|
|
+ instance: instance,
|
|
|
+ updatable: updatable
|
|
|
}
|
|
|
- // extruded shape creation
|
|
|
- path3D = <any>new Path3D(curve);
|
|
|
- var newShapePaths = new Array<Array<Vector3>>();
|
|
|
- cap = (cap < 0 || cap > 3) ? 0 : cap;
|
|
|
- pathArray = extrusionPathArray(shape, curve, path3D, newShapePaths, scale, rotation, scaleFunction, rotateFunction, cap, custom);
|
|
|
- var extrudedGeneric = Mesh.CreateRibbon(name, pathArray, rbCA, rbCP, 0, scene, updtbl, side);
|
|
|
- (<any>extrudedGeneric).pathArray = pathArray;
|
|
|
- (<any>extrudedGeneric).path3D = path3D;
|
|
|
- (<any>extrudedGeneric).cap = cap;
|
|
|
|
|
|
- return extrudedGeneric;
|
|
|
+ return MeshBuilder.ExtrudeShape(name, options, scene);
|
|
|
}
|
|
|
|
|
|
- // Lathe
|
|
|
- public static CreateLathe(name: string, shape: Vector3[], radius: number, tessellation: number, scene: Scene, updatable?: boolean, sideOrientation?: number): Mesh;
|
|
|
- public static CreateLathe(name: string, options: { shape: Vector3[], radius?: number, tessellation?: number, arc?: number, closed: boolean, updatable?: boolean, sideOrientation?: number }, scene: Scene): Mesh;
|
|
|
- public static CreateLathe(name: string, options: any, radiusOrScene: any, tessellation?: number, scene?: Scene, updatable?: boolean, sideOrientation: number = Mesh.DEFAULTSIDE): Mesh {
|
|
|
- var shape: Vector3[];
|
|
|
- var radius: number;
|
|
|
- var arc: number = (options.arc <= 0) ? 1.0 : options.arc || 1.0;
|
|
|
- var closed: boolean = (options.closed === undefined) ? true : options.closed;
|
|
|
-
|
|
|
- if (Array.isArray(options)) {
|
|
|
- shape = options;
|
|
|
- radius = radiusOrScene || 1;
|
|
|
- tessellation = tessellation || 64;
|
|
|
-
|
|
|
- } else {
|
|
|
- scene = radiusOrScene;
|
|
|
- shape = options.shape;
|
|
|
- radius = options.radius || 1;
|
|
|
- tessellation = options.tessellation || 64;
|
|
|
- updatable = options.updatable;
|
|
|
- sideOrientation = (options.sideOrientation === 0) ? 0 : options.sideOrientation || Mesh.DEFAULTSIDE;
|
|
|
+ public static ExtrudeShapeCustom(name: string, shape: Vector3[], path: Vector3[], scaleFunction, rotationFunction, ribbonCloseArray: boolean, ribbonClosePath: boolean, cap: number, scene: Scene, updatable?: boolean, sideOrientation?: number, instance?: Mesh): Mesh {
|
|
|
+ var options = {
|
|
|
+ shape: shape,
|
|
|
+ path: path,
|
|
|
+ scaleFunction: scaleFunction,
|
|
|
+ rotationFunction: rotationFunction,
|
|
|
+ ribbonCloseArray: ribbonCloseArray,
|
|
|
+ ribbonClosePath: ribbonClosePath,
|
|
|
+ cap: (cap === 0) ? 0 : cap || Mesh.NO_CAP,
|
|
|
+ sideOrientation: sideOrientation,
|
|
|
+ instance: instance,
|
|
|
+ updatable: updatable
|
|
|
}
|
|
|
- var pi2 = Math.PI * 2;
|
|
|
- var shapeLathe = new Array<Vector3>();
|
|
|
|
|
|
- // first rotatable point
|
|
|
- var i = 0;
|
|
|
- while (shape[i].x === 0) {
|
|
|
- i++;
|
|
|
- }
|
|
|
- var pt = shape[i];
|
|
|
- for (i = 0; i < shape.length; i++) {
|
|
|
- shapeLathe.push(shape[i].subtract(pt));
|
|
|
- }
|
|
|
+ return MeshBuilder.ExtrudeShapeCustom(name, options, scene);
|
|
|
+ }
|
|
|
|
|
|
- // circle path
|
|
|
- var step = pi2 / tessellation * arc;
|
|
|
- var rotated;
|
|
|
- var path = new Array<Vector3>();;
|
|
|
- for (i = 0; i <= tessellation; i++) {
|
|
|
- rotated = new Vector3(Math.cos(i * step) * radius, 0, Math.sin(i * step) * radius);
|
|
|
- path.push(rotated);
|
|
|
- }
|
|
|
- if (closed) {
|
|
|
- path.push(path[0]);
|
|
|
- }
|
|
|
+ // Lathe
|
|
|
+ public static CreateLathe(name: string, shape: Vector3[], radius: number, tessellation: number, scene: Scene, updatable?: boolean, sideOrientation?: number): Mesh {
|
|
|
+ var options = {
|
|
|
+ shape: shape,
|
|
|
+ radius: radius,
|
|
|
+ tesselation: tessellation,
|
|
|
+ sideOrientation: sideOrientation,
|
|
|
+ updatable: updatable
|
|
|
+ };
|
|
|
|
|
|
- // extrusion
|
|
|
- var scaleFunction = () => { return 1; };
|
|
|
- var rotateFunction = () => { return 0; };
|
|
|
- var lathe = Mesh.ExtrudeShapeCustom(name, shapeLathe, path, scaleFunction, rotateFunction, closed, false, Mesh.NO_CAP, scene, updatable, sideOrientation);
|
|
|
- return lathe;
|
|
|
+ return MeshBuilder.CreateLathe(name, options, scene);
|
|
|
}
|
|
|
|
|
|
// Plane & ground
|
|
|
- public static CreatePlane(name: string, size: number, scene: Scene, updatable?: boolean, sideOrientation?: number): Mesh;
|
|
|
- public static CreatePlane(name: string, options: { size?: number, width?: number, height?: number, sideOrientation?: number, updatable?: boolean }, scene: Scene): Mesh;
|
|
|
- public static CreatePlane(name: string, options: any, scene: Scene, updatable?: boolean, sideOrientation: number = Mesh.DEFAULTSIDE): Mesh {
|
|
|
- if (typeof options === 'number') {
|
|
|
- var size = options;
|
|
|
- options = {
|
|
|
- size: size,
|
|
|
- width: size,
|
|
|
- height: size,
|
|
|
- sideOrientation: sideOrientation
|
|
|
- }
|
|
|
+ public static CreatePlane(name: string, size: number, scene: Scene, updatable?: boolean, sideOrientation?: number): Mesh {
|
|
|
+ var options = {
|
|
|
+ size: size,
|
|
|
+ width: size,
|
|
|
+ height: size,
|
|
|
+ sideOrientation: sideOrientation,
|
|
|
+ updatable: updatable
|
|
|
}
|
|
|
- var plane = new Mesh(name, scene);
|
|
|
-
|
|
|
- var vertexData = VertexData.CreatePlane(options);
|
|
|
|
|
|
- vertexData.applyToMesh(plane, updatable || options.updatable);
|
|
|
-
|
|
|
- return plane;
|
|
|
+ return MeshBuilder.CreatePlane(name, options, scene);
|
|
|
}
|
|
|
|
|
|
- public static CreateGround(name: string, width: number, height: number, subdivisions: number, scene: Scene, updatable?: boolean): Mesh;
|
|
|
- public static CreateGround(name: string, options: { width?: number, height?: number, subdivisions?: number, updatable?: boolean }, scene: any): Mesh;
|
|
|
- public static CreateGround(name: string, options: any, heightOrScene: any, subdivisions?: number, scene?: Scene, updatable?: boolean): Mesh {
|
|
|
- if (heightOrScene instanceof Scene) {
|
|
|
- scene = heightOrScene;
|
|
|
- updatable = options.updatable;
|
|
|
- } else {
|
|
|
- var width = options;
|
|
|
-
|
|
|
- options = {
|
|
|
- width: width,
|
|
|
- height: heightOrScene,
|
|
|
- subdivisions: subdivisions
|
|
|
- }
|
|
|
+ public static CreateGround(name: string, width: number, height: number, subdivisions: number, scene: Scene, updatable?: boolean): Mesh {
|
|
|
+ var options = {
|
|
|
+ width: width,
|
|
|
+ height: height,
|
|
|
+ subdivisions: subdivisions,
|
|
|
+ updatable: updatable
|
|
|
}
|
|
|
|
|
|
- var ground = new GroundMesh(name, scene);
|
|
|
- ground._setReady(false);
|
|
|
- ground._subdivisions = options.subdivisions || 1;
|
|
|
-
|
|
|
- var vertexData = VertexData.CreateGround(options);
|
|
|
-
|
|
|
- vertexData.applyToMesh(ground, updatable || options.updatable);
|
|
|
-
|
|
|
- ground._setReady(true);
|
|
|
-
|
|
|
- return ground;
|
|
|
+ return MeshBuilder.CreateGround(name, options, scene);
|
|
|
}
|
|
|
|
|
|
- public static CreateTiledGround(name: string, xmin: number, zmin: number, xmax: number, zmax: number, subdivisions: { w: number; h: number; }, precision: { w: number; h: number; }, scene: Scene, updatable?: boolean): Mesh;
|
|
|
- public static CreateTiledGround(name: string, options: { xmin?: number, zmin?: number, xmax?: number, zmax?: number, subdivisions?: { w: number; h: number; }, precision?: { w: number; h: number; }, updatable?: boolean }, scene: Scene): Mesh;
|
|
|
- public static CreateTiledGround(name: string, options: any, zminOrScene: any, xmax?: number, zmax?: number, subdivisions?: { w: number; h: number; }, precision?: { w: number; h: number; }, scene?: Scene, updatable?: boolean): Mesh {
|
|
|
- var xmin: number;
|
|
|
- var zmin: number;
|
|
|
- if (typeof options === 'number') {
|
|
|
- xmin = options || -1;
|
|
|
- zmin = zminOrScene || -1;
|
|
|
- xmax = xmax || 1;
|
|
|
- zmax = zmax || 1;
|
|
|
- subdivisions = subdivisions || { w: 6, h: 6 };
|
|
|
- precision = precision || { w: 2, h: 2 };
|
|
|
- } else {
|
|
|
- scene = zminOrScene;
|
|
|
- xmin = options.xmin || -1;
|
|
|
- zmin = options.zmin || -1;
|
|
|
- xmax = options.xmax || 1;
|
|
|
- zmax = options.zmax || 1;
|
|
|
- subdivisions = options.subdivisions || { w: 6, h: 6 };
|
|
|
- precision = options.precision || { w: 2, h: 2 };
|
|
|
+ public static CreateTiledGround(name: string, xmin: number, zmin: number, xmax: number, zmax: number, subdivisions: { w: number; h: number; }, precision: { w: number; h: number; }, scene: Scene, updatable?: boolean): Mesh {
|
|
|
+ var options = {
|
|
|
+ xmin: xmin,
|
|
|
+ zmin: zmin,
|
|
|
+ xmax: xmax,
|
|
|
+ zmax: zmax,
|
|
|
+ subdivisions: subdivisions,
|
|
|
+ precision: precision,
|
|
|
+ updatable: updatable
|
|
|
}
|
|
|
- var tiledGround = new Mesh(name, scene);
|
|
|
-
|
|
|
- var vertexData = VertexData.CreateTiledGround({ xmin: xmin, zmin: zmin, xmax: xmax, zmax: zmax, subdivisions: subdivisions, precision: precision });
|
|
|
|
|
|
- vertexData.applyToMesh(tiledGround, updatable);
|
|
|
-
|
|
|
- return tiledGround;
|
|
|
+ return MeshBuilder.CreateTiledGround(name, options, scene);
|
|
|
}
|
|
|
|
|
|
- public static CreateGroundFromHeightMap(name: string, url: string, options: { width?: number, height?: number, subdivisions?: number, minHeight?: number, maxHeight?: number, updatable?: boolean, onReady?: (mesh: GroundMesh) => void }, scene: Scene);
|
|
|
- public static CreateGroundFromHeightMap(name: string, url: string, width: number, height: number, subdivisions: number, minHeight: number, maxHeight: number, scene: Scene, updatable?: boolean, onReady?: (mesh: GroundMesh) => void);
|
|
|
- public static CreateGroundFromHeightMap(name: string, url: string, widthOrOptions?: any, heightorScene?: any, subdivisions?: number, minHeight?: number, maxHeight?: number, scene?: Scene, updatable?: boolean, onReady?: (mesh: GroundMesh) => void): GroundMesh {
|
|
|
- var width: number;
|
|
|
- var height: number;
|
|
|
-
|
|
|
- if (typeof widthOrOptions === "number") {
|
|
|
- width = widthOrOptions;
|
|
|
- height = heightorScene;
|
|
|
- } else {
|
|
|
- width = widthOrOptions.width || 10;
|
|
|
- height = widthOrOptions.height || 10;
|
|
|
- subdivisions = widthOrOptions.subdivisions || 1;
|
|
|
- minHeight = widthOrOptions.minHeight;
|
|
|
- maxHeight = widthOrOptions.maxHeight || 10;
|
|
|
- updatable = widthOrOptions.updatable;
|
|
|
- onReady = widthOrOptions.onReady;
|
|
|
- scene = heightorScene;
|
|
|
- }
|
|
|
-
|
|
|
- var ground = new GroundMesh(name, scene);
|
|
|
- ground._subdivisions = subdivisions;
|
|
|
-
|
|
|
- ground._setReady(false);
|
|
|
-
|
|
|
- var onload = img => {
|
|
|
- // Getting height map data
|
|
|
- var canvas = document.createElement("canvas");
|
|
|
- var context = canvas.getContext("2d");
|
|
|
- var bufferWidth = img.width;
|
|
|
- var bufferHeight = img.height;
|
|
|
- canvas.width = bufferWidth;
|
|
|
- canvas.height = bufferHeight;
|
|
|
-
|
|
|
- context.drawImage(img, 0, 0);
|
|
|
-
|
|
|
- // Create VertexData from map data
|
|
|
- // Cast is due to wrong definition in lib.d.ts from ts 1.3 - https://github.com/Microsoft/TypeScript/issues/949
|
|
|
- var buffer = <Uint8Array>(<any>context.getImageData(0, 0, bufferWidth, bufferHeight).data);
|
|
|
- var vertexData = VertexData.CreateGroundFromHeightMap({
|
|
|
- width, height,
|
|
|
- subdivisions,
|
|
|
- minHeight, maxHeight,
|
|
|
- buffer, bufferWidth, bufferHeight
|
|
|
- });
|
|
|
-
|
|
|
- vertexData.applyToMesh(ground, updatable);
|
|
|
-
|
|
|
- ground._setReady(true);
|
|
|
-
|
|
|
- //execute ready callback, if set
|
|
|
- if (onReady) {
|
|
|
- onReady(ground);
|
|
|
- }
|
|
|
+ public static CreateGroundFromHeightMap(name: string, url: string, width: number, height: number, subdivisions: number, minHeight: number, maxHeight: number, scene: Scene, updatable?: boolean, onReady?: (mesh: GroundMesh) => void): GroundMesh {
|
|
|
+ var options = {
|
|
|
+ width: width,
|
|
|
+ height: height,
|
|
|
+ subdivisions: subdivisions,
|
|
|
+ minHeight: minHeight,
|
|
|
+ maxHeight: maxHeight,
|
|
|
+ updatable: updatable,
|
|
|
+ onReady: onReady
|
|
|
};
|
|
|
|
|
|
- Tools.LoadImage(url, onload, () => { }, scene.database);
|
|
|
-
|
|
|
- return ground;
|
|
|
+ return MeshBuilder.CreateGroundFromHeightMap(name, url, options, scene);
|
|
|
}
|
|
|
|
|
|
- public static CreateTube(name: string, path: Vector3[], radius: number, tessellation: number, radiusFunction: { (i: number, distance: number): number; }, cap: number, scene: Scene, updatable?: boolean, sideOrientation?: number, instance?: Mesh): Mesh;
|
|
|
- public static CreateTube(name: string, options: { path: Vector3[], radius?: number, tessellation?: number, radiusFunction?: { (i: number, distance: number): number; }, cap?: number, arc?: number, updatable?: boolean, sideOrientation?: number, instance?: Mesh }, scene: Scene): Mesh;
|
|
|
- public static CreateTube(name: string, options: any, radiusOrScene: any, tessellation?: number, radiusFunction?: { (i: number, distance: number): number; }, cap?: number, scene?: Scene, updatable?: boolean, sideOrientation: number = Mesh.DEFAULTSIDE, instance: Mesh = null): Mesh {
|
|
|
- var path: Vector3[];
|
|
|
- var radius: number;
|
|
|
- var arc: number = (options.arc <= 0) ? 1.0 : options.arc || 1.0;;
|
|
|
- if (Array.isArray(options)) {
|
|
|
- path = options;
|
|
|
- radius = radiusOrScene;
|
|
|
- } else {
|
|
|
- scene = radiusOrScene;
|
|
|
- path = options.path;
|
|
|
- radius = options.radius || 1;
|
|
|
- tessellation = options.tessellation || 64;
|
|
|
- radiusFunction = options.radiusFunction;
|
|
|
- cap = options.cap || Mesh.NO_CAP,
|
|
|
- updatable = options.updatable;
|
|
|
- sideOrientation = options.sideOrientation || Mesh.DEFAULTSIDE,
|
|
|
- instance = options.instance;
|
|
|
- }
|
|
|
- // tube geometry
|
|
|
- var tubePathArray = (path, path3D, circlePaths, radius, tessellation, radiusFunction, cap, arc) => {
|
|
|
- var tangents = path3D.getTangents();
|
|
|
- var normals = path3D.getNormals();
|
|
|
- var distances = path3D.getDistances();
|
|
|
- var pi2 = Math.PI * 2;
|
|
|
- var step = pi2 / tessellation * arc;
|
|
|
- var returnRadius: { (i: number, distance: number): number; } = (i, distance) => radius;
|
|
|
- var radiusFunctionFinal: { (i: number, distance: number): number; } = radiusFunction || returnRadius;
|
|
|
-
|
|
|
- var circlePath: Vector3[];
|
|
|
- var rad: number;
|
|
|
- var normal: Vector3;
|
|
|
- var rotated: Vector3;
|
|
|
- var rotationMatrix: Matrix = Matrix.Zero();
|
|
|
- var index = (cap === Mesh._NO_CAP || cap === Mesh.CAP_END) ? 0 : 2;
|
|
|
- for (var i = 0; i < path.length; i++) {
|
|
|
- rad = radiusFunctionFinal(i, distances[i]); // current radius
|
|
|
- circlePath = Array<Vector3>(); // current circle array
|
|
|
- normal = normals[i]; // current normal
|
|
|
- for (var t = 0; t < tessellation; t++) {
|
|
|
- Matrix.RotationAxisToRef(tangents[i], step * t, rotationMatrix);
|
|
|
- rotated = Vector3.TransformCoordinates(normal, rotationMatrix).scaleInPlace(rad).add(path[i]);
|
|
|
- circlePath.push(rotated);
|
|
|
- }
|
|
|
- circlePaths[index] = circlePath;
|
|
|
- index++;
|
|
|
- }
|
|
|
- // cap
|
|
|
- var capPath = (nbPoints, pathIndex) => {
|
|
|
- var pointCap = Array<Vector3>();
|
|
|
- for (var i = 0; i < nbPoints; i++) {
|
|
|
- pointCap.push(path[pathIndex]);
|
|
|
- }
|
|
|
- return pointCap;
|
|
|
- };
|
|
|
- switch (cap) {
|
|
|
- case Mesh.NO_CAP:
|
|
|
- break;
|
|
|
- case Mesh.CAP_START:
|
|
|
- circlePaths[0] = capPath(tessellation, 0);
|
|
|
- circlePaths[1] = circlePaths[2].slice(0);
|
|
|
- break;
|
|
|
- case Mesh.CAP_END:
|
|
|
- circlePaths[index] = circlePaths[index - 1].slice(0);
|
|
|
- circlePaths[index + 1] = capPath(tessellation, path.length - 1);
|
|
|
- break;
|
|
|
- case Mesh.CAP_ALL:
|
|
|
- circlePaths[0] = capPath(tessellation, 0);
|
|
|
- circlePaths[1] = circlePaths[2].slice(0);
|
|
|
- circlePaths[index] = circlePaths[index - 1].slice(0);
|
|
|
- circlePaths[index + 1] = capPath(tessellation, path.length - 1);
|
|
|
- break;
|
|
|
- default:
|
|
|
- break;
|
|
|
- }
|
|
|
- return circlePaths;
|
|
|
- };
|
|
|
- var path3D;
|
|
|
- var pathArray;
|
|
|
- if (instance) { // tube update
|
|
|
- arc = arc || (<any>instance).arc;
|
|
|
- path3D = ((<any>instance).path3D).update(path);
|
|
|
- pathArray = tubePathArray(path, path3D, (<any>instance).pathArray, radius, (<any>instance).tessellation, radiusFunction, (<any>instance).cap, arc);
|
|
|
- instance = MeshBuilder.CreateRibbon(null, { pathArray: pathArray, instance: instance });
|
|
|
- (<any>instance).path3D = path3D;
|
|
|
- (<any>instance).pathArray = pathArray;
|
|
|
- (<any>instance).arc = arc;
|
|
|
-
|
|
|
- return instance;
|
|
|
-
|
|
|
- }
|
|
|
- // tube creation
|
|
|
- path3D = <any>new Path3D(path);
|
|
|
- var newPathArray = new Array<Array<Vector3>>();
|
|
|
- cap = (cap < 0 || cap > 3) ? 0 : cap;
|
|
|
- pathArray = tubePathArray(path, path3D, newPathArray, radius, tessellation, radiusFunction, cap, arc);
|
|
|
- var tube = MeshBuilder.CreateRibbon(name, { pathArray: pathArray, closePath: true, closeArray: false, updatable: updatable, sideOrientation: sideOrientation }, scene);
|
|
|
- (<any>tube).pathArray = pathArray;
|
|
|
- (<any>tube).path3D = path3D;
|
|
|
- (<any>tube).tessellation = tessellation;
|
|
|
- (<any>tube).cap = cap;
|
|
|
- (<any>tube).arc = arc;
|
|
|
-
|
|
|
- return tube;
|
|
|
+ public static CreateTube(name: string, path: Vector3[], radius: number, tessellation: number, radiusFunction: { (i: number, distance: number): number; }, cap: number, scene: Scene, updatable?: boolean, sideOrientation?: number, instance?: Mesh): Mesh {
|
|
|
+ var options = {
|
|
|
+ path: path,
|
|
|
+ radius: radius,
|
|
|
+ tessellation: tessellation,
|
|
|
+ radiusFunction: radiusFunction,
|
|
|
+ cap: cap,
|
|
|
+ updatable: updatable,
|
|
|
+ sideOrientation: sideOrientation,
|
|
|
+ instance: instance
|
|
|
+ }
|
|
|
+ return MeshBuilder.CreateTube(name, options, scene);
|
|
|
}
|
|
|
|
|
|
public static CreatePolyhedron(name: string, options: { type?: number, size?: number, sizeX?: number, sizeY?: number, sizeZ?: number, custom?: any, faceUV?: Vector4[], faceColors?: Color4[], updatable?: boolean, sideOrientation?: number }, scene: Scene): Mesh {
|
|
|
- var polyhedron = new Mesh(name, scene);
|
|
|
-
|
|
|
- var vertexData = VertexData.CreatePolyhedron(options);
|
|
|
-
|
|
|
- vertexData.applyToMesh(polyhedron, options.updatable);
|
|
|
-
|
|
|
- return polyhedron;
|
|
|
+ return MeshBuilder.CreatePolyhedron(name, options, scene);
|
|
|
}
|
|
|
|
|
|
// Decals
|
|
|
- public static CreateDecal(name: string, sourceMesh: AbstractMesh, options: { position?: Vector3, normal?: Vector3, size?: Vector3, angle?: number });
|
|
|
- public static CreateDecal(name: string, sourceMesh: AbstractMesh, position: Vector3, normal: Vector3, size: Vector3, angle: number);
|
|
|
- public static CreateDecal(name: string, sourceMesh: AbstractMesh, positionOrOptions: any, normal?: Vector3, size?: Vector3, angle: number = 0) {
|
|
|
- var indices = sourceMesh.getIndices();
|
|
|
- var positions = sourceMesh.getVerticesData(VertexBuffer.PositionKind);
|
|
|
- var normals = sourceMesh.getVerticesData(VertexBuffer.NormalKind);
|
|
|
- var position: Vector3;
|
|
|
-
|
|
|
- if (positionOrOptions instanceof Vector3) {
|
|
|
- position = <Vector3>positionOrOptions;
|
|
|
- } else {
|
|
|
- position = positionOrOptions.position || Vector3.Zero();
|
|
|
- normal = positionOrOptions.normal || Vector3.Up();
|
|
|
- size = positionOrOptions.size || new Vector3(1, 1, 1);
|
|
|
- angle = positionOrOptions.angle;
|
|
|
- }
|
|
|
-
|
|
|
- // Getting correct rotation
|
|
|
- if (!normal) {
|
|
|
- var target = new Vector3(0, 0, 1);
|
|
|
- var camera = sourceMesh.getScene().activeCamera;
|
|
|
- var cameraWorldTarget = Vector3.TransformCoordinates(target, camera.getWorldMatrix());
|
|
|
-
|
|
|
- normal = camera.globalPosition.subtract(cameraWorldTarget);
|
|
|
- }
|
|
|
-
|
|
|
- var yaw = -Math.atan2(normal.z, normal.x) - Math.PI / 2;
|
|
|
- var len = Math.sqrt(normal.x * normal.x + normal.z * normal.z);
|
|
|
- var pitch = Math.atan2(normal.y, len);
|
|
|
-
|
|
|
- // Matrix
|
|
|
- var decalWorldMatrix = Matrix.RotationYawPitchRoll(yaw, pitch, angle).multiply(Matrix.Translation(position.x, position.y, position.z));
|
|
|
- var inverseDecalWorldMatrix = Matrix.Invert(decalWorldMatrix);
|
|
|
- var meshWorldMatrix = sourceMesh.getWorldMatrix();
|
|
|
- var transformMatrix = meshWorldMatrix.multiply(inverseDecalWorldMatrix);
|
|
|
-
|
|
|
- var vertexData = new VertexData();
|
|
|
- vertexData.indices = [];
|
|
|
- vertexData.positions = [];
|
|
|
- vertexData.normals = [];
|
|
|
- vertexData.uvs = [];
|
|
|
-
|
|
|
- var currentVertexDataIndex = 0;
|
|
|
-
|
|
|
- var extractDecalVector3 = (indexId: number): PositionNormalVertex => {
|
|
|
- var vertexId = indices[indexId];
|
|
|
- var result = new PositionNormalVertex();
|
|
|
- result.position = new Vector3(positions[vertexId * 3], positions[vertexId * 3 + 1], positions[vertexId * 3 + 2]);
|
|
|
-
|
|
|
- // Send vector to decal local world
|
|
|
- result.position = Vector3.TransformCoordinates(result.position, transformMatrix);
|
|
|
-
|
|
|
- // Get normal
|
|
|
- result.normal = new Vector3(normals[vertexId * 3], normals[vertexId * 3 + 1], normals[vertexId * 3 + 2]);
|
|
|
-
|
|
|
- return result;
|
|
|
- }; // Inspired by https://github.com/mrdoob/three.js/blob/eee231960882f6f3b6113405f524956145148146/examples/js/geometries/DecalGeometry.js
|
|
|
- var clip = (vertices: PositionNormalVertex[], axis: Vector3): PositionNormalVertex[]=> {
|
|
|
- if (vertices.length === 0) {
|
|
|
- return vertices;
|
|
|
- }
|
|
|
-
|
|
|
- var clipSize = 0.5 * Math.abs(Vector3.Dot(size, axis));
|
|
|
-
|
|
|
- var clipVertices = (v0: PositionNormalVertex, v1: PositionNormalVertex): PositionNormalVertex => {
|
|
|
- var clipFactor = Vector3.GetClipFactor(v0.position, v1.position, axis, clipSize);
|
|
|
-
|
|
|
- return new PositionNormalVertex(
|
|
|
- Vector3.Lerp(v0.position, v1.position, clipFactor),
|
|
|
- Vector3.Lerp(v0.normal, v1.normal, clipFactor)
|
|
|
- );
|
|
|
- };
|
|
|
- var result = new Array<PositionNormalVertex>();
|
|
|
-
|
|
|
- for (var index = 0; index < vertices.length; index += 3) {
|
|
|
- var v1Out: boolean;
|
|
|
- var v2Out: boolean;
|
|
|
- var v3Out: boolean;
|
|
|
- var total = 0;
|
|
|
- var nV1: PositionNormalVertex, nV2: PositionNormalVertex, nV3: PositionNormalVertex, nV4: PositionNormalVertex;
|
|
|
-
|
|
|
- var d1 = Vector3.Dot(vertices[index].position, axis) - clipSize;
|
|
|
- var d2 = Vector3.Dot(vertices[index + 1].position, axis) - clipSize;
|
|
|
- var d3 = Vector3.Dot(vertices[index + 2].position, axis) - clipSize;
|
|
|
-
|
|
|
- v1Out = d1 > 0;
|
|
|
- v2Out = d2 > 0;
|
|
|
- v3Out = d3 > 0;
|
|
|
-
|
|
|
- total = (v1Out ? 1 : 0) + (v2Out ? 1 : 0) + (v3Out ? 1 : 0);
|
|
|
-
|
|
|
- switch (total) {
|
|
|
- case 0:
|
|
|
- result.push(vertices[index]);
|
|
|
- result.push(vertices[index + 1]);
|
|
|
- result.push(vertices[index + 2]);
|
|
|
- break;
|
|
|
- case 1:
|
|
|
-
|
|
|
- if (v1Out) {
|
|
|
- nV1 = vertices[index + 1];
|
|
|
- nV2 = vertices[index + 2];
|
|
|
- nV3 = clipVertices(vertices[index], nV1);
|
|
|
- nV4 = clipVertices(vertices[index], nV2);
|
|
|
- }
|
|
|
-
|
|
|
- if (v2Out) {
|
|
|
- nV1 = vertices[index];
|
|
|
- nV2 = vertices[index + 2];
|
|
|
- nV3 = clipVertices(vertices[index + 1], nV1);
|
|
|
- nV4 = clipVertices(vertices[index + 1], nV2);
|
|
|
-
|
|
|
- result.push(nV3);
|
|
|
- result.push(nV2.clone());
|
|
|
- result.push(nV1.clone());
|
|
|
-
|
|
|
- result.push(nV2.clone());
|
|
|
- result.push(nV3.clone());
|
|
|
- result.push(nV4);
|
|
|
- break;
|
|
|
- }
|
|
|
- if (v3Out) {
|
|
|
- nV1 = vertices[index];
|
|
|
- nV2 = vertices[index + 1];
|
|
|
- nV3 = clipVertices(vertices[index + 2], nV1);
|
|
|
- nV4 = clipVertices(vertices[index + 2], nV2);
|
|
|
- }
|
|
|
-
|
|
|
- result.push(nV1.clone());
|
|
|
- result.push(nV2.clone());
|
|
|
- result.push(nV3);
|
|
|
-
|
|
|
- result.push(nV4);
|
|
|
- result.push(nV3.clone());
|
|
|
- result.push(nV2.clone());
|
|
|
- break;
|
|
|
- case 2:
|
|
|
- if (!v1Out) {
|
|
|
- nV1 = vertices[index].clone();
|
|
|
- nV2 = clipVertices(nV1, vertices[index + 1]);
|
|
|
- nV3 = clipVertices(nV1, vertices[index + 2]);
|
|
|
- result.push(nV1);
|
|
|
- result.push(nV2);
|
|
|
- result.push(nV3);
|
|
|
- }
|
|
|
- if (!v2Out) {
|
|
|
- nV1 = vertices[index + 1].clone();
|
|
|
- nV2 = clipVertices(nV1, vertices[index + 2]);
|
|
|
- nV3 = clipVertices(nV1, vertices[index]);
|
|
|
- result.push(nV1);
|
|
|
- result.push(nV2);
|
|
|
- result.push(nV3);
|
|
|
- }
|
|
|
- if (!v3Out) {
|
|
|
- nV1 = vertices[index + 2].clone();
|
|
|
- nV2 = clipVertices(nV1, vertices[index]);
|
|
|
- nV3 = clipVertices(nV1, vertices[index + 1]);
|
|
|
- result.push(nV1);
|
|
|
- result.push(nV2);
|
|
|
- result.push(nV3);
|
|
|
- }
|
|
|
- break;
|
|
|
- case 3:
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return result;
|
|
|
- };
|
|
|
- for (var index = 0; index < indices.length; index += 3) {
|
|
|
- var faceVertices = new Array<PositionNormalVertex>();
|
|
|
-
|
|
|
- faceVertices.push(extractDecalVector3(index));
|
|
|
- faceVertices.push(extractDecalVector3(index + 1));
|
|
|
- faceVertices.push(extractDecalVector3(index + 2));
|
|
|
-
|
|
|
- // Clip
|
|
|
- faceVertices = clip(faceVertices, new Vector3(1, 0, 0));
|
|
|
- faceVertices = clip(faceVertices, new Vector3(-1, 0, 0));
|
|
|
- faceVertices = clip(faceVertices, new Vector3(0, 1, 0));
|
|
|
- faceVertices = clip(faceVertices, new Vector3(0, -1, 0));
|
|
|
- faceVertices = clip(faceVertices, new Vector3(0, 0, 1));
|
|
|
- faceVertices = clip(faceVertices, new Vector3(0, 0, -1));
|
|
|
-
|
|
|
- if (faceVertices.length === 0) {
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- // Add UVs and get back to world
|
|
|
- for (var vIndex = 0; vIndex < faceVertices.length; vIndex++) {
|
|
|
- var vertex = faceVertices[vIndex];
|
|
|
-
|
|
|
- vertexData.indices.push(currentVertexDataIndex);
|
|
|
- vertex.position.toArray(vertexData.positions, currentVertexDataIndex * 3);
|
|
|
- vertex.normal.toArray(vertexData.normals, currentVertexDataIndex * 3);
|
|
|
- (<number[]>vertexData.uvs).push(0.5 + vertex.position.x / size.x);
|
|
|
- (<number[]>vertexData.uvs).push(0.5 + vertex.position.y / size.y);
|
|
|
-
|
|
|
- currentVertexDataIndex++;
|
|
|
- }
|
|
|
+ public static CreateDecal(name: string, sourceMesh: AbstractMesh, position: Vector3, normal: Vector3, size: Vector3, angle: number): Mesh {
|
|
|
+ var options = {
|
|
|
+ position: position,
|
|
|
+ normal: normal,
|
|
|
+ size: size,
|
|
|
+ angle: angle
|
|
|
}
|
|
|
|
|
|
- // Return mesh
|
|
|
- var decal = new Mesh(name, sourceMesh.getScene());
|
|
|
- vertexData.applyToMesh(decal);
|
|
|
-
|
|
|
- decal.position = position.clone();
|
|
|
- decal.rotation = new Vector3(pitch, yaw, angle);
|
|
|
-
|
|
|
- return decal;
|
|
|
+ return MeshBuilder.CreateDecal(name, sourceMesh, options);
|
|
|
}
|
|
|
|
|
|
// Skeletons
|