|
@@ -1,443 +1,76 @@
|
|
|
-"use strict";
|
|
|
-
|
|
|
-var BABYLON = BABYLON || {};
|
|
|
-
|
|
|
-// Constructive Solid Geometry for BABYLON
|
|
|
-// Based on https://github.com/evanw/csg.js/
|
|
|
-(function () {
|
|
|
-
|
|
|
+var BABYLON;
|
|
|
+(function (BABYLON) {
|
|
|
// Unique ID when we import meshes from Babylon to CSG
|
|
|
var currentCSGMeshId = 0;
|
|
|
|
|
|
- BABYLON.CSG = function () {
|
|
|
- this.polygons = [];
|
|
|
- };
|
|
|
-
|
|
|
- // Convert BABYLON.Mesh to BABYLON.CSG
|
|
|
- BABYLON.CSG.FromMesh = function (mesh) {
|
|
|
- var vertex, normal, uv, position,
|
|
|
- polygon,
|
|
|
- polygons = [],
|
|
|
- vertices;
|
|
|
-
|
|
|
- if (mesh instanceof BABYLON.Mesh) {
|
|
|
- mesh.computeWorldMatrix(true);
|
|
|
- this.matrix = mesh.getWorldMatrix();
|
|
|
- this.position = mesh.position.clone();
|
|
|
- this.rotation = mesh.rotation.clone();
|
|
|
- this.scaling = mesh.scaling.clone();
|
|
|
- } else {
|
|
|
- throw 'BABYLON.CSG: Wrong Mesh type, must be BABYLON.Mesh';
|
|
|
- }
|
|
|
-
|
|
|
- var indices = mesh.getIndices(),
|
|
|
- positions = mesh.getVerticesData(BABYLON.VertexBuffer.PositionKind),
|
|
|
- normals = mesh.getVerticesData(BABYLON.VertexBuffer.NormalKind),
|
|
|
- uvs = mesh.getVerticesData(BABYLON.VertexBuffer.UVKind);
|
|
|
-
|
|
|
- var subMeshes = mesh.subMeshes;
|
|
|
-
|
|
|
- for (var sm = 0, sml = subMeshes.length; sm < sml; sm++) {
|
|
|
- for (var i = subMeshes[sm].indexStart, il = subMeshes[sm].indexCount + subMeshes[sm].indexStart; i < il; i += 3) {
|
|
|
- vertices = [];
|
|
|
- for (var j = 0; j < 3; j++) {
|
|
|
- normal = new BABYLON.Vector3(normals[indices[i + j] * 3], normals[indices[i + j] * 3 + 1], normals[indices[i + j] * 3 + 2]);
|
|
|
- uv = new BABYLON.Vector2(uvs[indices[i + j] * 2], uvs[indices[i + j] * 2 + 1]);
|
|
|
- position = new BABYLON.Vector3(positions[indices[i + j] * 3], positions[indices[i + j] * 3 + 1], positions[indices[i + j] * 3 + 2]);
|
|
|
- position = BABYLON.Vector3.TransformCoordinates(position, this.matrix);
|
|
|
- normal = BABYLON.Vector3.TransformNormal(normal, this.matrix);
|
|
|
-
|
|
|
- vertex = new BABYLON.CSG.Vertex(position, normal, uv);
|
|
|
- vertices.push(vertex);
|
|
|
- }
|
|
|
-
|
|
|
- polygon = new BABYLON.CSG.Polygon(vertices, { subMeshId: sm, meshId: currentCSGMeshId, materialIndex: subMeshes[sm].materialIndex });
|
|
|
-
|
|
|
- // To handle the case of degenerated triangle
|
|
|
- // polygon.plane == null <=> the polygon does not represent 1 single plane <=> the triangle is degenerated
|
|
|
- if (polygon.plane)
|
|
|
- polygons.push(polygon);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- var csg = BABYLON.CSG.fromPolygons(polygons);
|
|
|
- csg.copyTransformAttributes(this);
|
|
|
- currentCSGMeshId++;
|
|
|
-
|
|
|
- return csg;
|
|
|
- };
|
|
|
-
|
|
|
-
|
|
|
- // Construct a BABYLON.CSG solid from a list of `BABYLON.CSG.Polygon` instances.
|
|
|
- BABYLON.CSG.fromPolygons = function (polygons) {
|
|
|
- var csg = new BABYLON.CSG();
|
|
|
- csg.polygons = polygons;
|
|
|
- return csg;
|
|
|
- };
|
|
|
-
|
|
|
- BABYLON.CSG.prototype = {
|
|
|
- clone: function () {
|
|
|
- var csg = new BABYLON.CSG();
|
|
|
- csg.polygons = this.polygons.map(function (p) { return p.clone(); });
|
|
|
- csg.copyTransformAttributes(this);
|
|
|
- return csg;
|
|
|
- },
|
|
|
-
|
|
|
- toPolygons: function () {
|
|
|
- return this.polygons;
|
|
|
- },
|
|
|
-
|
|
|
- union: function (csg) {
|
|
|
- var a = new BABYLON.CSG.Node(this.clone().polygons);
|
|
|
- var b = new BABYLON.CSG.Node(csg.clone().polygons);
|
|
|
- a.clipTo(b);
|
|
|
- b.clipTo(a);
|
|
|
- b.invert();
|
|
|
- b.clipTo(a);
|
|
|
- b.invert();
|
|
|
- a.build(b.allPolygons());
|
|
|
- return BABYLON.CSG.fromPolygons(a.allPolygons()).copyTransformAttributes(this);
|
|
|
- },
|
|
|
-
|
|
|
- subtract: function (csg) {
|
|
|
- var a = new BABYLON.CSG.Node(this.clone().polygons);
|
|
|
- var b = new BABYLON.CSG.Node(csg.clone().polygons);
|
|
|
- a.invert();
|
|
|
- a.clipTo(b);
|
|
|
- b.clipTo(a);
|
|
|
- b.invert();
|
|
|
- b.clipTo(a);
|
|
|
- b.invert();
|
|
|
- a.build(b.allPolygons());
|
|
|
- a.invert();
|
|
|
- return BABYLON.CSG.fromPolygons(a.allPolygons()).copyTransformAttributes(this);
|
|
|
- },
|
|
|
-
|
|
|
- intersect: function (csg) {
|
|
|
- var a = new BABYLON.CSG.Node(this.clone().polygons);
|
|
|
- var b = new BABYLON.CSG.Node(csg.clone().polygons);
|
|
|
- a.invert();
|
|
|
- b.clipTo(a);
|
|
|
- b.invert();
|
|
|
- a.clipTo(b);
|
|
|
- b.clipTo(a);
|
|
|
- a.build(b.allPolygons());
|
|
|
- a.invert();
|
|
|
- return BABYLON.CSG.fromPolygons(a.allPolygons()).copyTransformAttributes(this);
|
|
|
- },
|
|
|
-
|
|
|
- // Return a new BABYLON.CSG solid with solid and empty space switched. This solid is
|
|
|
- // not modified.
|
|
|
- inverse: function () {
|
|
|
- var csg = this.clone();
|
|
|
- csg.polygons.map(function (p) { p.flip(); });
|
|
|
- return csg;
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
- // This is used to keep meshes transformations so they can be restored
|
|
|
- // when we build back a Babylon Mesh
|
|
|
- // NB : All CSG operations are performed in world coordinates
|
|
|
- BABYLON.CSG.prototype.copyTransformAttributes = function(object) {
|
|
|
- this.matrix = object.matrix;
|
|
|
- this.position = object.position;
|
|
|
- this.rotation = object.rotation;
|
|
|
- this.scaling = object.scaling;
|
|
|
-
|
|
|
- return this;
|
|
|
- };
|
|
|
-
|
|
|
- // Build Raw mesh from CSG
|
|
|
- // Coordinates here are in world space
|
|
|
- BABYLON.CSG.prototype.buildMeshGeometry = function (name, scene, keepSubMeshes) {
|
|
|
- var matrix = this.matrix.clone();
|
|
|
- matrix.invert();
|
|
|
-
|
|
|
- var mesh = new BABYLON.Mesh(name, scene),
|
|
|
- vertices = [],
|
|
|
- indices = [],
|
|
|
- normals = [],
|
|
|
- uvs = [],
|
|
|
- vertex, normal, uv,
|
|
|
- polygons = this.polygons,
|
|
|
- polygonIndices = [0, 0, 0],
|
|
|
- polygon,
|
|
|
- vertice_dict = {},
|
|
|
- vertex_idx,
|
|
|
- currentIndex = 0,
|
|
|
- subMesh_dict = {},
|
|
|
- subMesh_obj;
|
|
|
-
|
|
|
- if (keepSubMeshes) {
|
|
|
- // Sort Polygons, since subMeshes are indices range
|
|
|
- polygons.sort(function (a, b) {
|
|
|
- if (a.shared.meshId === b.shared.meshId) {
|
|
|
- return a.shared.subMeshId - b.shared.subMeshId;
|
|
|
- } else {
|
|
|
- return a.shared.meshId - b.shared.meshId;
|
|
|
- }
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- for (var i = 0, il = polygons.length; i < il; i++) {
|
|
|
- polygon = polygons[i];
|
|
|
-
|
|
|
- // Building SubMeshes
|
|
|
- if (!subMesh_dict[polygon.shared.meshId]) {
|
|
|
- subMesh_dict[polygon.shared.meshId] = {};
|
|
|
- }
|
|
|
- if (!subMesh_dict[polygon.shared.meshId][polygon.shared.subMeshId]) {
|
|
|
- subMesh_dict[polygon.shared.meshId][polygon.shared.subMeshId] = {
|
|
|
- indexStart: +Infinity,
|
|
|
- indexEnd: -Infinity,
|
|
|
- materialIndex: polygon.shared.materialIndex
|
|
|
- };
|
|
|
- }
|
|
|
- subMesh_obj = subMesh_dict[polygon.shared.meshId][polygon.shared.subMeshId];
|
|
|
-
|
|
|
-
|
|
|
- for (var j = 2, jl = polygon.vertices.length; j < jl; j++) {
|
|
|
-
|
|
|
- polygonIndices[0] = 0;
|
|
|
- polygonIndices[1] = j - 1;
|
|
|
- polygonIndices[2] = j;
|
|
|
-
|
|
|
- for (var k = 0; k < 3; k++) {
|
|
|
- vertex = polygon.vertices[polygonIndices[k]].pos;
|
|
|
- normal = polygon.vertices[polygonIndices[k]].normal;
|
|
|
- uv = polygon.vertices[polygonIndices[k]].uv;
|
|
|
- vertex = new BABYLON.Vector3(vertex.x, vertex.y, vertex.z);
|
|
|
- normal = new BABYLON.Vector3(normal.x, normal.y, normal.z);
|
|
|
- vertex = BABYLON.Vector3.TransformCoordinates(vertex, matrix);
|
|
|
- normal = BABYLON.Vector3.TransformNormal(normal, matrix);
|
|
|
-
|
|
|
- vertex_idx = vertice_dict[vertex.x + ',' + vertex.y + ',' + vertex.z];
|
|
|
-
|
|
|
- // Check if 2 points can be merged
|
|
|
- if (!(typeof vertex_idx !== 'undefined' &&
|
|
|
- normals[vertex_idx * 3] === normal.x &&
|
|
|
- normals[vertex_idx * 3 + 1] === normal.y &&
|
|
|
- normals[vertex_idx * 3 + 2] === normal.z &&
|
|
|
- uvs[vertex_idx * 2] === uv.x &&
|
|
|
- uvs[vertex_idx * 2 + 1] === uv.y)) {
|
|
|
- vertices.push(vertex.x, vertex.y, vertex.z);
|
|
|
- uvs.push(uv.x, uv.y);
|
|
|
- normals.push(normal.x, normal.y, normal.z);
|
|
|
- vertex_idx = vertice_dict[vertex.x + ',' + vertex.y + ',' + vertex.z] = (vertices.length / 3) - 1;
|
|
|
- }
|
|
|
-
|
|
|
- indices.push(vertex_idx);
|
|
|
-
|
|
|
- subMesh_obj.indexStart = Math.min(currentIndex, subMesh_obj.indexStart);
|
|
|
- subMesh_obj.indexEnd = Math.max(currentIndex, subMesh_obj.indexEnd);
|
|
|
- currentIndex++;
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- mesh.setVerticesData(vertices, BABYLON.VertexBuffer.PositionKind);
|
|
|
- mesh.setVerticesData(normals, BABYLON.VertexBuffer.NormalKind);
|
|
|
- mesh.setVerticesData(uvs, BABYLON.VertexBuffer.UVKind);
|
|
|
- mesh.setIndices(indices);
|
|
|
-
|
|
|
- if (keepSubMeshes) {
|
|
|
- // We offset the materialIndex by the previous number of materials in the CSG mixed meshes
|
|
|
- var materialIndexOffset = 0,
|
|
|
- materialMaxIndex;
|
|
|
-
|
|
|
- mesh.subMeshes.length = 0;
|
|
|
-
|
|
|
- for (var m in subMesh_dict) {
|
|
|
- materialMaxIndex = -1;
|
|
|
- for (var sm in subMesh_dict[m]) {
|
|
|
- subMesh_obj = subMesh_dict[m][sm];
|
|
|
- BABYLON.SubMesh.CreateFromIndices(subMesh_obj.materialIndex + materialIndexOffset, subMesh_obj.indexStart, subMesh_obj.indexEnd - subMesh_obj.indexStart + 1, mesh);
|
|
|
- materialMaxIndex = Math.max(subMesh_obj.materialIndex, materialMaxIndex);
|
|
|
- }
|
|
|
- materialIndexOffset += ++materialMaxIndex;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return mesh;
|
|
|
- };
|
|
|
-
|
|
|
- // Build Mesh from CSG taking material and transforms into account
|
|
|
- BABYLON.CSG.prototype.toMesh = function (name, material, scene, keepSubMeshes) {
|
|
|
- var mesh = this.buildMeshGeometry(name, scene, keepSubMeshes);
|
|
|
-
|
|
|
- mesh.material = material;
|
|
|
-
|
|
|
- mesh.position.copyFrom(this.position);
|
|
|
- mesh.rotation.copyFrom(this.rotation);
|
|
|
- mesh.scaling.copyFrom(this.scaling);
|
|
|
- mesh.computeWorldMatrix(true);
|
|
|
-
|
|
|
- return mesh;
|
|
|
- };
|
|
|
-
|
|
|
- // # class Vector
|
|
|
-
|
|
|
- // Represents a 3D vector.
|
|
|
- //
|
|
|
- // Example usage:
|
|
|
- //
|
|
|
- // new BABYLON.CSG.Vector(1, 2, 3);
|
|
|
- // new BABYLON.CSG.Vector([1, 2, 3]);
|
|
|
- // new BABYLON.CSG.Vector({ x: 1, y: 2, z: 3 });
|
|
|
-
|
|
|
- BABYLON.CSG.Vector = function (x, y, z) {
|
|
|
- if (arguments.length == 3) {
|
|
|
- this.x = x;
|
|
|
- this.y = y;
|
|
|
- this.z = z;
|
|
|
- } else if ('x' in x) {
|
|
|
- this.x = x.x;
|
|
|
- this.y = x.y;
|
|
|
- this.z = x.z;
|
|
|
- } else {
|
|
|
- this.x = x[0];
|
|
|
- this.y = x[1];
|
|
|
- this.z = x[2];
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
- BABYLON.CSG.Vector.prototype = {
|
|
|
- clone: function () {
|
|
|
- return new BABYLON.CSG.Vector(this.x, this.y, this.z);
|
|
|
- },
|
|
|
-
|
|
|
- negated: function () {
|
|
|
- return new BABYLON.CSG.Vector(-this.x, -this.y, -this.z);
|
|
|
- },
|
|
|
-
|
|
|
- plus: function (a) {
|
|
|
- return new BABYLON.CSG.Vector(this.x + a.x, this.y + a.y, this.z + a.z);
|
|
|
- },
|
|
|
-
|
|
|
- minus: function (a) {
|
|
|
- return new BABYLON.CSG.Vector(this.x - a.x, this.y - a.y, this.z - a.z);
|
|
|
- },
|
|
|
-
|
|
|
- times: function (a) {
|
|
|
- return new BABYLON.CSG.Vector(this.x * a, this.y * a, this.z * a);
|
|
|
- },
|
|
|
-
|
|
|
- dividedBy: function (a) {
|
|
|
- return new BABYLON.CSG.Vector(this.x / a, this.y / a, this.z / a);
|
|
|
- },
|
|
|
-
|
|
|
- dot: function (a) {
|
|
|
- return this.x * a.x + this.y * a.y + this.z * a.z;
|
|
|
- },
|
|
|
-
|
|
|
- lerp: function (a, t) {
|
|
|
- return this.plus(a.minus(this).times(t));
|
|
|
- },
|
|
|
-
|
|
|
- length: function () {
|
|
|
- return Math.sqrt(this.dot(this));
|
|
|
- },
|
|
|
-
|
|
|
- lengthSq: function () {
|
|
|
- return this.dot(this);
|
|
|
- },
|
|
|
-
|
|
|
- unit: function () {
|
|
|
- return this.dividedBy(this.length());
|
|
|
- },
|
|
|
-
|
|
|
- cross: function (a) {
|
|
|
- return new BABYLON.CSG.Vector(
|
|
|
- this.y * a.z - this.z * a.y,
|
|
|
- this.z * a.x - this.x * a.z,
|
|
|
- this.x * a.y - this.y * a.x
|
|
|
- );
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
// # class Vertex
|
|
|
-
|
|
|
// Represents a vertex of a polygon. Use your own vertex class instead of this
|
|
|
// one to provide additional features like texture coordinates and vertex
|
|
|
// colors. Custom vertex classes need to provide a `pos` property and `clone()`,
|
|
|
// `flip()`, and `interpolate()` methods that behave analogous to the ones
|
|
|
// defined by `BABYLON.CSG.Vertex`. This class provides `normal` so convenience
|
|
|
// functions like `BABYLON.CSG.sphere()` can return a smooth vertex normal, but `normal`
|
|
|
- // is not used anywhere else.
|
|
|
+ // is not used anywhere else.
|
|
|
// Same goes for uv, it allows to keep the original vertex uv coordinates of the 2 meshes
|
|
|
-
|
|
|
- BABYLON.CSG.Vertex = function (pos, normal, uv) {
|
|
|
- this.pos = new BABYLON.CSG.Vector(pos);
|
|
|
- this.normal = new BABYLON.CSG.Vector(normal);
|
|
|
- this.uv = new BABYLON.CSG.Vector(uv.x, uv.y, 0);
|
|
|
- };
|
|
|
-
|
|
|
- BABYLON.CSG.Vertex.prototype = {
|
|
|
- clone: function () {
|
|
|
- return new BABYLON.CSG.Vertex(this.pos.clone(), this.normal.clone(), this.uv.clone());
|
|
|
- },
|
|
|
+ var Vertex = (function () {
|
|
|
+ function Vertex(pos, normal, uv) {
|
|
|
+ this.pos = pos;
|
|
|
+ this.normal = normal;
|
|
|
+ this.uv = uv;
|
|
|
+ }
|
|
|
+ Vertex.prototype.clone = function () {
|
|
|
+ return new Vertex(this.pos.clone(), this.normal.clone(), this.uv.clone());
|
|
|
+ };
|
|
|
|
|
|
// Invert all orientation-specific data (e.g. vertex normal). Called when the
|
|
|
// orientation of a polygon is flipped.
|
|
|
- flip: function () {
|
|
|
- this.normal = this.normal.negated();
|
|
|
- },
|
|
|
+ Vertex.prototype.flip = function () {
|
|
|
+ this.normal = this.normal.scale(-1);
|
|
|
+ };
|
|
|
|
|
|
// Create a new vertex between this vertex and `other` by linearly
|
|
|
// interpolating all properties using a parameter of `t`. Subclasses should
|
|
|
// override this to interpolate additional properties.
|
|
|
- interpolate: function (other, t) {
|
|
|
- return new BABYLON.CSG.Vertex(
|
|
|
- this.pos.lerp(other.pos, t),
|
|
|
- this.normal.lerp(other.normal, t),
|
|
|
- this.uv.lerp(other.uv, t)
|
|
|
- );
|
|
|
- }
|
|
|
- };
|
|
|
+ Vertex.prototype.interpolate = function (other, t) {
|
|
|
+ return new Vertex(BABYLON.Vector3.Lerp(this.pos, other.pos, t), BABYLON.Vector3.Lerp(this.normal, other.normal, t), BABYLON.Vector2.Lerp(this.uv, other.uv, t));
|
|
|
+ };
|
|
|
+ return Vertex;
|
|
|
+ })();
|
|
|
|
|
|
// # class Plane
|
|
|
-
|
|
|
// Represents a plane in 3D space.
|
|
|
-
|
|
|
- BABYLON.CSG.Plane = function (normal, w) {
|
|
|
- this.normal = normal;
|
|
|
- this.w = w;
|
|
|
- };
|
|
|
-
|
|
|
- // `BABYLON.CSG.Plane.EPSILON` is the tolerance used by `splitPolygon()` to decide if a
|
|
|
- // point is on the plane.
|
|
|
- BABYLON.CSG.Plane.EPSILON = 1e-5;
|
|
|
-
|
|
|
- BABYLON.CSG.Plane.fromPoints = function (a, b, c) {
|
|
|
- var v0 = c.minus(a);
|
|
|
- var v1 = b.minus(a);
|
|
|
-
|
|
|
- if (v0.lengthSq() === 0 || v1.lengthSq() === 0) {
|
|
|
- return null;
|
|
|
+ var Plane = (function () {
|
|
|
+ function Plane(normal, w) {
|
|
|
+ this.normal = normal;
|
|
|
+ this.w = w;
|
|
|
}
|
|
|
+ Plane.FromPoints = function (a, b, c) {
|
|
|
+ var v0 = c.subtract(a);
|
|
|
+ var v1 = b.subtract(a);
|
|
|
+
|
|
|
+ if (v0.lengthSquared() === 0 || v1.lengthSquared() === 0) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
|
|
|
- var n = c.minus(a).cross(b.minus(a)).unit();
|
|
|
- return new BABYLON.CSG.Plane(n, n.dot(a));
|
|
|
- };
|
|
|
+ var n = BABYLON.Vector3.Normalize(BABYLON.Vector3.Cross(c.subtract(a), b.subtract(a)));
|
|
|
+ return new Plane(n, BABYLON.Vector3.Dot(n, a));
|
|
|
+ };
|
|
|
|
|
|
- BABYLON.CSG.Plane.prototype = {
|
|
|
- clone: function () {
|
|
|
- return new BABYLON.CSG.Plane(this.normal.clone(), this.w);
|
|
|
- },
|
|
|
+ Plane.prototype.clone = function () {
|
|
|
+ return new Plane(this.normal.clone(), this.w);
|
|
|
+ };
|
|
|
|
|
|
- flip: function () {
|
|
|
- this.normal = this.normal.negated();
|
|
|
+ Plane.prototype.flip = function () {
|
|
|
+ this.normal = this.normal.scale(-1);
|
|
|
this.w = -this.w;
|
|
|
- },
|
|
|
+ };
|
|
|
|
|
|
// Split `polygon` by this plane if needed, then put the polygon or polygon
|
|
|
// fragments in the appropriate lists. Coplanar polygons go into either
|
|
|
// `coplanarFront` or `coplanarBack` depending on their orientation with
|
|
|
// respect to this plane. Polygons in front or in back of this plane go into
|
|
|
// either `front` or `back`.
|
|
|
- splitPolygon: function (polygon, coplanarFront, coplanarBack, front, back) {
|
|
|
+ Plane.prototype.splitPolygon = function (polygon, coplanarFront, coplanarBack, front, back) {
|
|
|
var COPLANAR = 0;
|
|
|
var FRONT = 1;
|
|
|
var BACK = 2;
|
|
@@ -448,16 +81,15 @@ var BABYLON = BABYLON || {};
|
|
|
var polygonType = 0;
|
|
|
var types = [];
|
|
|
for (var i = 0; i < polygon.vertices.length; i++) {
|
|
|
- var t = this.normal.dot(polygon.vertices[i].pos) - this.w;
|
|
|
- var type = (t < -BABYLON.CSG.Plane.EPSILON) ? BACK : (t > BABYLON.CSG.Plane.EPSILON) ? FRONT : COPLANAR;
|
|
|
+ var t = BABYLON.Vector3.Dot(this.normal, polygon.vertices[i].pos) - this.w;
|
|
|
+ var type = (t < -Plane.EPSILON) ? BACK : (t > Plane.EPSILON) ? FRONT : COPLANAR;
|
|
|
polygonType |= type;
|
|
|
types.push(type);
|
|
|
}
|
|
|
|
|
|
- // Put the polygon in the correct list, splitting it when necessary.
|
|
|
switch (polygonType) {
|
|
|
case COPLANAR:
|
|
|
- (this.normal.dot(polygon.plane.normal) > 0 ? coplanarFront : coplanarBack).push(polygon);
|
|
|
+ (BABYLON.Vector3.Dot(this.normal, polygon.plane.normal) > 0 ? coplanarFront : coplanarBack).push(polygon);
|
|
|
break;
|
|
|
case FRONT:
|
|
|
front.push(polygon);
|
|
@@ -467,84 +99,90 @@ var BABYLON = BABYLON || {};
|
|
|
break;
|
|
|
case SPANNING:
|
|
|
var f = [], b = [];
|
|
|
- for (var i = 0; i < polygon.vertices.length; i++) {
|
|
|
+ for (i = 0; i < polygon.vertices.length; i++) {
|
|
|
var j = (i + 1) % polygon.vertices.length;
|
|
|
var ti = types[i], tj = types[j];
|
|
|
var vi = polygon.vertices[i], vj = polygon.vertices[j];
|
|
|
- if (ti != BACK) f.push(vi);
|
|
|
- if (ti != FRONT) b.push(ti != BACK ? vi.clone() : vi);
|
|
|
+ if (ti != BACK)
|
|
|
+ f.push(vi);
|
|
|
+ if (ti != FRONT)
|
|
|
+ b.push(ti != BACK ? vi.clone() : vi);
|
|
|
if ((ti | tj) == SPANNING) {
|
|
|
- var t = (this.w - this.normal.dot(vi.pos)) / this.normal.dot(vj.pos.minus(vi.pos));
|
|
|
+ t = (this.w - BABYLON.Vector3.Dot(this.normal, vi.pos)) / BABYLON.Vector3.Dot(this.normal, vj.pos.subtract(vi.pos));
|
|
|
var v = vi.interpolate(vj, t);
|
|
|
f.push(v);
|
|
|
b.push(v.clone());
|
|
|
}
|
|
|
}
|
|
|
- if (f.length >= 3) front.push(new BABYLON.CSG.Polygon(f, polygon.shared));
|
|
|
- if (b.length >= 3) back.push(new BABYLON.CSG.Polygon(b, polygon.shared));
|
|
|
+ if (f.length >= 3)
|
|
|
+ front.push(new Polygon(f, polygon.shared));
|
|
|
+ if (b.length >= 3)
|
|
|
+ back.push(new Polygon(b, polygon.shared));
|
|
|
break;
|
|
|
}
|
|
|
- }
|
|
|
- };
|
|
|
+ };
|
|
|
+ Plane.EPSILON = 1e-5;
|
|
|
+ return Plane;
|
|
|
+ })();
|
|
|
|
|
|
// # class Polygon
|
|
|
-
|
|
|
// Represents a convex polygon. The vertices used to initialize a polygon must
|
|
|
- // be coplanar and form a convex loop. They do not have to be `BABYLON.CSG.Vertex`
|
|
|
- // instances but they must behave similarly (duck typing can be used for
|
|
|
- // customization).
|
|
|
- //
|
|
|
+ // be coplanar and form a convex loop.
|
|
|
+ //
|
|
|
// Each convex polygon has a `shared` property, which is shared between all
|
|
|
// polygons that are clones of each other or were split from the same polygon.
|
|
|
// This can be used to define per-polygon properties (such as surface color).
|
|
|
+ var Polygon = (function () {
|
|
|
+ function Polygon(vertices, shared) {
|
|
|
+ this.vertices = vertices;
|
|
|
+ this.shared = shared;
|
|
|
+ this.plane = Plane.FromPoints(vertices[0].pos, vertices[1].pos, vertices[2].pos);
|
|
|
+ }
|
|
|
+ Polygon.prototype.clone = function () {
|
|
|
+ var vertices = this.vertices.map(function (v) {
|
|
|
+ return v.clone();
|
|
|
+ });
|
|
|
+ return new Polygon(vertices, this.shared);
|
|
|
+ };
|
|
|
|
|
|
- BABYLON.CSG.Polygon = function (vertices, shared) {
|
|
|
- this.vertices = vertices;
|
|
|
- this.shared = shared;
|
|
|
- this.plane = BABYLON.CSG.Plane.fromPoints(vertices[0].pos, vertices[1].pos, vertices[2].pos);
|
|
|
-
|
|
|
- };
|
|
|
-
|
|
|
- BABYLON.CSG.Polygon.prototype = {
|
|
|
- clone: function () {
|
|
|
- var vertices = this.vertices.map(function (v) { return v.clone(); });
|
|
|
- return new BABYLON.CSG.Polygon(vertices, this.shared);
|
|
|
- },
|
|
|
-
|
|
|
- flip: function () {
|
|
|
- this.vertices.reverse().map(function (v) { v.flip(); });
|
|
|
+ Polygon.prototype.flip = function () {
|
|
|
+ this.vertices.reverse().map(function (v) {
|
|
|
+ v.flip();
|
|
|
+ });
|
|
|
this.plane.flip();
|
|
|
- }
|
|
|
- };
|
|
|
+ };
|
|
|
+ return Polygon;
|
|
|
+ })();
|
|
|
|
|
|
// # class Node
|
|
|
-
|
|
|
// Holds a node in a BSP tree. A BSP tree is built from a collection of polygons
|
|
|
// by picking a polygon to split along. That polygon (and all other coplanar
|
|
|
// polygons) are added directly to that node and the other polygons are added to
|
|
|
// the front and/or back subtrees. This is not a leafy BSP tree since there is
|
|
|
// no distinction between internal and leaf nodes.
|
|
|
-
|
|
|
- BABYLON.CSG.Node = function (polygons) {
|
|
|
- this.plane = null;
|
|
|
- this.front = null;
|
|
|
- this.back = null;
|
|
|
- this.polygons = [];
|
|
|
- if (polygons) this.build(polygons);
|
|
|
- };
|
|
|
-
|
|
|
- BABYLON.CSG.Node.prototype = {
|
|
|
- clone: function () {
|
|
|
- var node = new BABYLON.CSG.Node();
|
|
|
+ var Node = (function () {
|
|
|
+ function Node(polygons) {
|
|
|
+ this.plane = null;
|
|
|
+ this.front = null;
|
|
|
+ this.back = null;
|
|
|
+ this.polygons = [];
|
|
|
+ if (polygons) {
|
|
|
+ this.build(polygons);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ Node.prototype.clone = function () {
|
|
|
+ var node = new Node();
|
|
|
node.plane = this.plane && this.plane.clone();
|
|
|
node.front = this.front && this.front.clone();
|
|
|
node.back = this.back && this.back.clone();
|
|
|
- node.polygons = this.polygons.map(function (p) { return p.clone(); });
|
|
|
+ node.polygons = this.polygons.map(function (p) {
|
|
|
+ return p.clone();
|
|
|
+ });
|
|
|
return node;
|
|
|
- },
|
|
|
+ };
|
|
|
|
|
|
// Convert solid space to empty space and empty space to solid space.
|
|
|
- invert: function () {
|
|
|
+ Node.prototype.invert = function () {
|
|
|
for (var i = 0; i < this.polygons.length; i++) {
|
|
|
this.polygons[i].flip();
|
|
|
}
|
|
@@ -558,12 +196,13 @@ var BABYLON = BABYLON || {};
|
|
|
var temp = this.front;
|
|
|
this.front = this.back;
|
|
|
this.back = temp;
|
|
|
- },
|
|
|
+ };
|
|
|
|
|
|
// Recursively remove all polygons in `polygons` that are inside this BSP
|
|
|
// tree.
|
|
|
- clipPolygons: function (polygons) {
|
|
|
- if (!this.plane) return polygons.slice();
|
|
|
+ Node.prototype.clipPolygons = function (polygons) {
|
|
|
+ if (!this.plane)
|
|
|
+ return polygons.slice();
|
|
|
var front = [], back = [];
|
|
|
for (var i = 0; i < polygons.length; i++) {
|
|
|
this.plane.splitPolygon(polygons[i], front, back, front, back);
|
|
@@ -577,43 +216,301 @@ var BABYLON = BABYLON || {};
|
|
|
back = [];
|
|
|
}
|
|
|
return front.concat(back);
|
|
|
- },
|
|
|
+ };
|
|
|
|
|
|
// Remove all polygons in this BSP tree that are inside the other BSP tree
|
|
|
// `bsp`.
|
|
|
- clipTo: function (bsp) {
|
|
|
+ Node.prototype.clipTo = function (bsp) {
|
|
|
this.polygons = bsp.clipPolygons(this.polygons);
|
|
|
- if (this.front) this.front.clipTo(bsp);
|
|
|
- if (this.back) this.back.clipTo(bsp);
|
|
|
- },
|
|
|
+ if (this.front)
|
|
|
+ this.front.clipTo(bsp);
|
|
|
+ if (this.back)
|
|
|
+ this.back.clipTo(bsp);
|
|
|
+ };
|
|
|
|
|
|
// Return a list of all polygons in this BSP tree.
|
|
|
- allPolygons: function () {
|
|
|
+ Node.prototype.allPolygons = function () {
|
|
|
var polygons = this.polygons.slice();
|
|
|
- if (this.front) polygons = polygons.concat(this.front.allPolygons());
|
|
|
- if (this.back) polygons = polygons.concat(this.back.allPolygons());
|
|
|
+ if (this.front)
|
|
|
+ polygons = polygons.concat(this.front.allPolygons());
|
|
|
+ if (this.back)
|
|
|
+ polygons = polygons.concat(this.back.allPolygons());
|
|
|
return polygons;
|
|
|
- },
|
|
|
+ };
|
|
|
|
|
|
// Build a BSP tree out of `polygons`. When called on an existing tree, the
|
|
|
// new polygons are filtered down to the bottom of the tree and become new
|
|
|
// nodes there. Each set of polygons is partitioned using the first polygon
|
|
|
// (no heuristic is used to pick a good split).
|
|
|
- build: function (polygons) {
|
|
|
- if (!polygons.length) return;
|
|
|
- if (!this.plane) this.plane = polygons[0].plane.clone();
|
|
|
+ Node.prototype.build = function (polygons) {
|
|
|
+ if (!polygons.length)
|
|
|
+ return;
|
|
|
+ if (!this.plane)
|
|
|
+ this.plane = polygons[0].plane.clone();
|
|
|
var front = [], back = [];
|
|
|
for (var i = 0; i < polygons.length; i++) {
|
|
|
this.plane.splitPolygon(polygons[i], this.polygons, this.polygons, front, back);
|
|
|
}
|
|
|
if (front.length) {
|
|
|
- if (!this.front) this.front = new BABYLON.CSG.Node();
|
|
|
+ if (!this.front)
|
|
|
+ this.front = new Node();
|
|
|
this.front.build(front);
|
|
|
}
|
|
|
if (back.length) {
|
|
|
- if (!this.back) this.back = new BABYLON.CSG.Node();
|
|
|
+ if (!this.back)
|
|
|
+ this.back = new Node();
|
|
|
this.back.build(back);
|
|
|
}
|
|
|
+ };
|
|
|
+ return Node;
|
|
|
+ })();
|
|
|
+
|
|
|
+ var CSG = (function () {
|
|
|
+ function CSG() {
|
|
|
+ this.polygons = new Array();
|
|
|
}
|
|
|
- };
|
|
|
-})();
|
|
|
+ // Convert BABYLON.Mesh to BABYLON.CSG
|
|
|
+ CSG.FromMesh = function (mesh) {
|
|
|
+ var vertex, normal, uv, position, polygon, polygons = [], vertices;
|
|
|
+
|
|
|
+ if (mesh instanceof BABYLON.Mesh) {
|
|
|
+ mesh.computeWorldMatrix(true);
|
|
|
+ var matrix = mesh.getWorldMatrix();
|
|
|
+ var meshPosition = mesh.position.clone();
|
|
|
+ var meshRotation = mesh.rotation.clone();
|
|
|
+ var meshScaling = mesh.scaling.clone();
|
|
|
+ } else {
|
|
|
+ throw 'BABYLON.CSG: Wrong Mesh type, must be BABYLON.Mesh';
|
|
|
+ }
|
|
|
+
|
|
|
+ var indices = mesh.getIndices(), positions = mesh.getVerticesData(BABYLON.VertexBuffer.PositionKind), normals = mesh.getVerticesData(BABYLON.VertexBuffer.NormalKind), uvs = mesh.getVerticesData(BABYLON.VertexBuffer.UVKind);
|
|
|
+
|
|
|
+ var subMeshes = mesh.subMeshes;
|
|
|
+
|
|
|
+ for (var sm = 0, sml = subMeshes.length; sm < sml; sm++) {
|
|
|
+ for (var i = subMeshes[sm].indexStart, il = subMeshes[sm].indexCount + subMeshes[sm].indexStart; i < il; i += 3) {
|
|
|
+ vertices = [];
|
|
|
+ for (var j = 0; j < 3; j++) {
|
|
|
+ normal = new BABYLON.Vector3(normals[indices[i + j] * 3], normals[indices[i + j] * 3 + 1], normals[indices[i + j] * 3 + 2]);
|
|
|
+ uv = new BABYLON.Vector2(uvs[indices[i + j] * 2], uvs[indices[i + j] * 2 + 1]);
|
|
|
+ position = new BABYLON.Vector3(positions[indices[i + j] * 3], positions[indices[i + j] * 3 + 1], positions[indices[i + j] * 3 + 2]);
|
|
|
+ position = BABYLON.Vector3.TransformCoordinates(position, matrix);
|
|
|
+ normal = BABYLON.Vector3.TransformNormal(normal, matrix);
|
|
|
+
|
|
|
+ vertex = new Vertex(position, normal, uv);
|
|
|
+ vertices.push(vertex);
|
|
|
+ }
|
|
|
+
|
|
|
+ polygon = new Polygon(vertices, { subMeshId: sm, meshId: currentCSGMeshId, materialIndex: subMeshes[sm].materialIndex });
|
|
|
+
|
|
|
+ // To handle the case of degenerated triangle
|
|
|
+ // polygon.plane == null <=> the polygon does not represent 1 single plane <=> the triangle is degenerated
|
|
|
+ if (polygon.plane)
|
|
|
+ polygons.push(polygon);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ var csg = CSG.FromPolygons(polygons);
|
|
|
+ csg.matrix = matrix;
|
|
|
+ csg.position = meshPosition;
|
|
|
+ csg.rotation = meshRotation;
|
|
|
+ csg.scaling = meshScaling;
|
|
|
+ currentCSGMeshId++;
|
|
|
+
|
|
|
+ return csg;
|
|
|
+ };
|
|
|
+
|
|
|
+ // Construct a BABYLON.CSG solid from a list of `BABYLON.CSG.Polygon` instances.
|
|
|
+ CSG.FromPolygons = function (polygons) {
|
|
|
+ var csg = new BABYLON.CSG();
|
|
|
+ csg.polygons = polygons;
|
|
|
+ return csg;
|
|
|
+ };
|
|
|
+
|
|
|
+ CSG.prototype.clone = function () {
|
|
|
+ var csg = new BABYLON.CSG();
|
|
|
+ csg.polygons = this.polygons.map(function (p) {
|
|
|
+ return p.clone();
|
|
|
+ });
|
|
|
+ csg.copyTransformAttributes(this);
|
|
|
+ return csg;
|
|
|
+ };
|
|
|
+
|
|
|
+ CSG.prototype.toPolygons = function () {
|
|
|
+ return this.polygons;
|
|
|
+ };
|
|
|
+
|
|
|
+ CSG.prototype.union = function (csg) {
|
|
|
+ var a = new Node(this.clone().polygons);
|
|
|
+ var b = new Node(csg.clone().polygons);
|
|
|
+ a.clipTo(b);
|
|
|
+ b.clipTo(a);
|
|
|
+ b.invert();
|
|
|
+ b.clipTo(a);
|
|
|
+ b.invert();
|
|
|
+ a.build(b.allPolygons());
|
|
|
+ return CSG.FromPolygons(a.allPolygons()).copyTransformAttributes(this);
|
|
|
+ };
|
|
|
+
|
|
|
+ CSG.prototype.subtract = function (csg) {
|
|
|
+ var a = new Node(this.clone().polygons);
|
|
|
+ var b = new Node(csg.clone().polygons);
|
|
|
+ a.invert();
|
|
|
+ a.clipTo(b);
|
|
|
+ b.clipTo(a);
|
|
|
+ b.invert();
|
|
|
+ b.clipTo(a);
|
|
|
+ b.invert();
|
|
|
+ a.build(b.allPolygons());
|
|
|
+ a.invert();
|
|
|
+ return CSG.FromPolygons(a.allPolygons()).copyTransformAttributes(this);
|
|
|
+ };
|
|
|
+
|
|
|
+ CSG.prototype.intersect = function (csg) {
|
|
|
+ var a = new Node(this.clone().polygons);
|
|
|
+ var b = new Node(csg.clone().polygons);
|
|
|
+ a.invert();
|
|
|
+ b.clipTo(a);
|
|
|
+ b.invert();
|
|
|
+ a.clipTo(b);
|
|
|
+ b.clipTo(a);
|
|
|
+ a.build(b.allPolygons());
|
|
|
+ a.invert();
|
|
|
+ return CSG.FromPolygons(a.allPolygons()).copyTransformAttributes(this);
|
|
|
+ };
|
|
|
+
|
|
|
+ // Return a new BABYLON.CSG solid with solid and empty space switched. This solid is
|
|
|
+ // not modified.
|
|
|
+ CSG.prototype.inverse = function () {
|
|
|
+ var csg = this.clone();
|
|
|
+ csg.polygons.map(function (p) {
|
|
|
+ p.flip();
|
|
|
+ });
|
|
|
+ return csg;
|
|
|
+ };
|
|
|
+
|
|
|
+ // This is used to keep meshes transformations so they can be restored
|
|
|
+ // when we build back a Babylon Mesh
|
|
|
+ // NB : All CSG operations are performed in world coordinates
|
|
|
+ CSG.prototype.copyTransformAttributes = function (csg) {
|
|
|
+ this.matrix = csg.matrix;
|
|
|
+ this.position = csg.position;
|
|
|
+ this.rotation = csg.rotation;
|
|
|
+ this.scaling = csg.scaling;
|
|
|
+
|
|
|
+ return this;
|
|
|
+ };
|
|
|
+
|
|
|
+ // Build Raw mesh from CSG
|
|
|
+ // Coordinates here are in world space
|
|
|
+ //ANY
|
|
|
+ CSG.prototype.buildMeshGeometry = function (name, scene, keepSubMeshes) {
|
|
|
+ var matrix = this.matrix.clone();
|
|
|
+ matrix.invert();
|
|
|
+
|
|
|
+ var mesh = new BABYLON.Mesh(name, scene), vertices = [], indices = [], normals = [], uvs = [], vertex, normal, uv, polygons = this.polygons, polygonIndices = [0, 0, 0], polygon, vertice_dict = {}, vertex_idx, currentIndex = 0, subMesh_dict = {}, subMesh_obj;
|
|
|
+
|
|
|
+ if (keepSubMeshes) {
|
|
|
+ // Sort Polygons, since subMeshes are indices range
|
|
|
+ polygons.sort(function (a, b) {
|
|
|
+ if (a.shared.meshId === b.shared.meshId) {
|
|
|
+ return a.shared.subMeshId - b.shared.subMeshId;
|
|
|
+ } else {
|
|
|
+ return a.shared.meshId - b.shared.meshId;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ for (var i = 0, il = polygons.length; i < il; i++) {
|
|
|
+ polygon = polygons[i];
|
|
|
+
|
|
|
+ // Building SubMeshes
|
|
|
+ if (!subMesh_dict[polygon.shared.meshId]) {
|
|
|
+ subMesh_dict[polygon.shared.meshId] = {};
|
|
|
+ }
|
|
|
+ if (!subMesh_dict[polygon.shared.meshId][polygon.shared.subMeshId]) {
|
|
|
+ subMesh_dict[polygon.shared.meshId][polygon.shared.subMeshId] = {
|
|
|
+ indexStart: +Infinity,
|
|
|
+ indexEnd: -Infinity,
|
|
|
+ materialIndex: polygon.shared.materialIndex
|
|
|
+ };
|
|
|
+ }
|
|
|
+ subMesh_obj = subMesh_dict[polygon.shared.meshId][polygon.shared.subMeshId];
|
|
|
+
|
|
|
+ for (var j = 2, jl = polygon.vertices.length; j < jl; j++) {
|
|
|
+ polygonIndices[0] = 0;
|
|
|
+ polygonIndices[1] = j - 1;
|
|
|
+ polygonIndices[2] = j;
|
|
|
+
|
|
|
+ for (var k = 0; k < 3; k++) {
|
|
|
+ vertex = polygon.vertices[polygonIndices[k]].pos;
|
|
|
+ normal = polygon.vertices[polygonIndices[k]].normal;
|
|
|
+ uv = polygon.vertices[polygonIndices[k]].uv;
|
|
|
+ vertex = new BABYLON.Vector3(vertex.x, vertex.y, vertex.z);
|
|
|
+ normal = new BABYLON.Vector3(normal.x, normal.y, normal.z);
|
|
|
+ vertex = BABYLON.Vector3.TransformCoordinates(vertex, matrix);
|
|
|
+ normal = BABYLON.Vector3.TransformNormal(normal, matrix);
|
|
|
+
|
|
|
+ vertex_idx = vertice_dict[vertex.x + ',' + vertex.y + ',' + vertex.z];
|
|
|
+
|
|
|
+ // Check if 2 points can be merged
|
|
|
+ if (!(typeof vertex_idx !== 'undefined' && normals[vertex_idx * 3] === normal.x && normals[vertex_idx * 3 + 1] === normal.y && normals[vertex_idx * 3 + 2] === normal.z && uvs[vertex_idx * 2] === uv.x && uvs[vertex_idx * 2 + 1] === uv.y)) {
|
|
|
+ vertices.push(vertex.x, vertex.y, vertex.z);
|
|
|
+ uvs.push(uv.x, uv.y);
|
|
|
+ normals.push(normal.x, normal.y, normal.z);
|
|
|
+ vertex_idx = vertice_dict[vertex.x + ',' + vertex.y + ',' + vertex.z] = (vertices.length / 3) - 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ indices.push(vertex_idx);
|
|
|
+
|
|
|
+ subMesh_obj.indexStart = Math.min(currentIndex, subMesh_obj.indexStart);
|
|
|
+ subMesh_obj.indexEnd = Math.max(currentIndex, subMesh_obj.indexEnd);
|
|
|
+ currentIndex++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ mesh.setVerticesData(vertices, BABYLON.VertexBuffer.PositionKind);
|
|
|
+ mesh.setVerticesData(normals, BABYLON.VertexBuffer.NormalKind);
|
|
|
+ mesh.setVerticesData(uvs, BABYLON.VertexBuffer.UVKind);
|
|
|
+ mesh.setIndices(indices);
|
|
|
+
|
|
|
+ if (keepSubMeshes) {
|
|
|
+ // We offset the materialIndex by the previous number of materials in the CSG mixed meshes
|
|
|
+ var materialIndexOffset = 0, materialMaxIndex;
|
|
|
+
|
|
|
+ mesh.subMeshes.length = 0;
|
|
|
+
|
|
|
+ for (var m in subMesh_dict) {
|
|
|
+ materialMaxIndex = -1;
|
|
|
+ for (var sm in subMesh_dict[m]) {
|
|
|
+ subMesh_obj = subMesh_dict[m][sm];
|
|
|
+ BABYLON.SubMesh.CreateFromIndices(subMesh_obj.materialIndex + materialIndexOffset, subMesh_obj.indexStart, subMesh_obj.indexEnd - subMesh_obj.indexStart + 1, mesh);
|
|
|
+ materialMaxIndex = Math.max(subMesh_obj.materialIndex, materialMaxIndex);
|
|
|
+ }
|
|
|
+ materialIndexOffset += ++materialMaxIndex;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return mesh;
|
|
|
+ };
|
|
|
+
|
|
|
+ // Build Mesh from CSG taking material and transforms into account
|
|
|
+ //ANY
|
|
|
+ CSG.prototype.toMesh = function (name, material, scene, keepSubMeshes) {
|
|
|
+ var mesh = this.buildMeshGeometry(name, scene, keepSubMeshes);
|
|
|
+
|
|
|
+ mesh.material = material;
|
|
|
+
|
|
|
+ mesh.position.copyFrom(this.position);
|
|
|
+ mesh.rotation.copyFrom(this.rotation);
|
|
|
+ mesh.scaling.copyFrom(this.scaling);
|
|
|
+ mesh.computeWorldMatrix(true);
|
|
|
+
|
|
|
+ return mesh;
|
|
|
+ };
|
|
|
+ return CSG;
|
|
|
+ })();
|
|
|
+ BABYLON.CSG = CSG;
|
|
|
+})(BABYLON || (BABYLON = {}));
|
|
|
+//# sourceMappingURL=babylon.csg.js.map
|