UNPKG

@awayjs/graphics

Version:
423 lines (422 loc) 14.8 kB
import { Rectangle, Vector3D, } from '@awayjs/core'; var Vertice3DView = /** @class */ (function () { function Vertice3DView() { this._data = []; } Object.defineProperty(Vertice3DView.prototype, "length", { get: function () { return this._data.length; }, enumerable: false, configurable: true }); Vertice3DView.prototype.toVec = function (vect, index) { if (vect === void 0) { vect = new Vector3D(); } if (index === void 0) { index = 0; } var s = this._data[index]; var l = s.length; for (var i = 0; i < 4; i++) { vect._rawData[i] = i < l ? s[i] : 0; } return vect; }; Vertice3DView.prototype.fromVec = function (vect, index) { if (index === void 0) { index = 0; } var s = this._data[index]; var l = s.length; for (var i = 0; i < l; i++) { s[i] = vect._rawData[i]; } return this; }; Vertice3DView.prototype.setData = function (data, index, clone) { if (clone === void 0) { clone = false; } this._data[index] = clone ? data.slice() : data; return this; }; Vertice3DView.prototype.getData = function (index) { return this._data[index]; }; Vertice3DView.prototype.lerpTo = function (target, alpha) { if (alpha === 0) { return this; } if (alpha === 1) { return this.copyFrom(target); } // interpolate all values for (var i = 0; i < this._data.length; i++) { var to = target._data[i]; var from = this._data[i]; for (var k = 0; k < this._data[i].length; k++) { from[k] = (1 - alpha) * from[k] + alpha * to[k]; } } return this; }; Vertice3DView.prototype.add = function (source, scale) { if (scale === void 0) { scale = 1; } // interpolate all values for (var i = 0; i < this._data.length; i++) { var from = source._data[i]; var to = this._data[i]; for (var k = 0; k < this._data[i].length; k++) { to[k] += from[k] * scale; } } return this; }; Vertice3DView.prototype.scale = function (s) { // interpolate all values for (var i = 0; i < this._data.length; i++) { var to = this._data[i]; for (var k = 0; k < this._data[i].length; k++) { to[k] *= s; } } return this; }; Vertice3DView.prototype.copyFrom = function (from) { var to = this._data; for (var i = 0; i < from.length; i++) { if (to[i]) { to[i].set(from._data[i]); } else { to[i] = from._data[i].slice(); } } return this; }; Vertice3DView.prototype.clone = function () { return new Vertice3DView().copyFrom(this); }; return Vertice3DView; }()); export { Vertice3DView }; var PolygonView = /** @class */ (function () { function PolygonView(points, userData) { this.vertices = []; if (points) { this.vertices = points.map(function (e) { return e.clone(); }); } if (userData) { this.userData = userData; } } Object.defineProperty(PolygonView.prototype, "middle", { get: function () { if (this._middle) return this._middle; this._middle = this.vertices[0].clone(); for (var i = 1; i < this.vertices.length; i++) { this._middle.add(this.vertices[i]); } this._middle.scale(1 / this.vertices.length); return this._middle; }, enumerable: false, configurable: true }); PolygonView.prototype.clone = function () { var p = new PolygonView(); var l = this.vertices.length; for (var i = 0; i < l; i++) { p.vertices[i] = this.vertices[i].clone(); } if (this.userData) { p.userData = this.userData.clone ? this.userData.clone() : Object.assign({}, this.userData); } return p; }; PolygonView.prototype.add = function (view, clone) { if (clone === void 0) { clone = false; } this.vertices.push(clone ? view.clone() : view); return this; }; Object.defineProperty(PolygonView.prototype, "length", { get: function () { return this.vertices.length; }, enumerable: false, configurable: true }); return PolygonView; }()); export { PolygonView }; var MeshView = /** @class */ (function () { function MeshView() { this.poly = []; this.rect = new Rectangle(); this.polySize = 3; this.hasNGones = false; } MeshView.prototype.push = function (p) { this.poly.push(p); return this; }; /** * Unroll all n-gone convex polys to 3-gone polygons */ MeshView.prototype.normalise = function () { if (!this.hasNGones) { return; } var normalised = []; for (var _i = 0, _a = this.poly; _i < _a.length; _i++) { var p = _a[_i]; // invalid vertices if (p.length < this.polySize) { continue; } if (p.length === this.polySize) { normalised.push(p); continue; } for (var i = 1; i < p.length - 1; i++) { var n = new PolygonView(); // shared user data; n.userData = p.userData; // construct poly in direct order with shared 1 vert (CCW or CW? i don't know ;) // fan triangulation // we sure that this a convex polygon n.add(p.vertices[0].clone()); n.add(p.vertices[(i) % p.length].clone()); n.add(p.vertices[(i + 1) % p.length].clone()); normalised.push(n); } } this.poly = normalised; return this; }; /** * Construct buffer from poly data * @param index Index of vertices attribute 0 - pos, 1 - uv etc */ MeshView.prototype.toFloatArray = function (index) { if (index === void 0) { index = 0; } var count = this.poly.length; if (this.poly.length === 0) return null; // check a dimension for calc a output size var test = this.poly[0].vertices[0].getData(index); var dim = test.length; // polygon should has 3 vertices var data = new Float32Array(count * dim * 3); for (var i = 0; i < count * 3; i++) { var poly = this.poly[i / 3 | 0]; var vert = poly.vertices[i % 3]; data.set(vert.getData(index), i * dim); } return data; }; MeshView.fromAttributes = function (attrs, length, polySize, userDataCtor) { if (polySize === void 0) { polySize = 0; } var mesh = new MeshView(); mesh.polySize = polySize; var poly; var views = attrs.map(function (e) { return e.get(length, 0); }); for (var i = 0; i < length; i++) { if (i % polySize === 0) { poly = new PolygonView(); poly.userData = userDataCtor ? new userDataCtor() : null; } mesh.poly.push(poly); var v = new Vertice3DView(); poly.add(v); for (var k = 0; k < attrs.length; k++) { var o = attrs[k].offset; var s = attrs[k].stride; var d = attrs[k].dimensions; v.setData(views[k].slice(o + s * i, o + s * i + d), k); } } return mesh; }; return MeshView; }()); export { MeshView }; var GeneratorUtils = /** @class */ (function () { function GeneratorUtils() { } GeneratorUtils.InFront = function (n, d, p) { return n.dotProduct(p) - d > this.EPS; }; GeneratorUtils.Behind = function (n, d, p) { return n.dotProduct(p) - d < -this.EPS; }; GeneratorUtils.OnPlane = function (n, d, p) { return !this.InFront(n, d, p) && !this.Behind(n, d, p); }; GeneratorUtils.Intersect = function (a, b, d1, d2) { var alpha = d1 / (d1 - d2); return new Vertice3DView().copyFrom(a).lerpTo(b, alpha); }; GeneratorUtils.SliceNaive = function (out, a, b, c, d1, d2, d3) { // Calculate the intersection point from a to b var ab = this.Intersect(a, b, d1, d2); if (d1 < 0.0) { // b to c crosses the clipping plane if (d3 < 0.0) { var bc = this.Intersect(b, c, d2, d3); out .push(new PolygonView([b, bc, ab])) .push(new PolygonView([bc, c, a])) .push(new PolygonView([ab, bc, a])); // c to a crosses the clipping plane } else { var ac = this.Intersect(a, c, d1, d3); out .push(new PolygonView([a, ab, ac])) .push(new PolygonView([ab, b, c])) .push(new PolygonView([ac, ab, c])); } } else { // c to a crosses the clipping plane if (d3 < 0.0) { var ac = this.Intersect(a, c, d1, d3); out .push(new PolygonView([a, ab, ac])) .push(new PolygonView([ac, ab, b])) .push(new PolygonView([b, c, ac])); // b to c crosses the clipping plane } else { var bc = this.Intersect(b, c, d2, d3); out .push(new PolygonView([b, bc, ab])) .push(new PolygonView([a, ab, bc])) .push(new PolygonView([c, a, bc])); } } return out; }; // Slices all triangles given a vector of triangles. // A new output triangle list is generated. The old // list of triangles is discarded. // n - The normal of the clipping plane // d - Distance of clipping plane from the origin // Reference: Exact Bouyancy for Polyhedra by // Erin Catto in Game Programming Gems 6 GeneratorUtils.SliceAllNaive = function (mesh, n, d) { var out = new MeshView(); out.polySize = mesh.polySize; var tmp = new Vector3D(); for (var i = 0; i < mesh.poly.length; ++i) { // Grab a triangle from the global triangle list var tri = mesh.poly[i]; var a = tri.vertices[0]; var b = tri.vertices[1]; var c = tri.vertices[2]; a.toVec(tmp, 0); // Compute distance of each triangle vertex to the clipping plane var d1 = a.toVec(tmp).dotProduct(n) - d; var d2 = b.toVec(tmp).dotProduct(n) - d; var d3 = c.toVec(tmp).dotProduct(n) - d; // a to b crosses the clipping plane if (d1 * d2 < 0.0) { this.SliceNaive(out, a, b, c, d1, d2, d3); // a to c crosses the clipping plane } else if (d1 * d3 < 0.0) { this.SliceNaive(out, c, a, b, d3, d1, d2); // b to c crosses the clipping plane } else if (d2 * d3 < 0.0) { this.SliceNaive(out, b, c, a, d2, d3, d1); } else { out.push(tri); } } return out; }; /** * It gen corrupted results, need improve, eXponenta * * Splits a polygon in half along a splitting plane using a clipping algorithm * call Sutherland-Hodgman clipping * Resource: Page 367 of Ericson (Real-Time Collision Detection) */ GeneratorUtils.SutherlandHodgman = function (poly, normal, d, out, callback) { var frontPoly = new PolygonView(); var backPoly = new PolygonView(); var s = poly.length; var verts = poly.vertices; var tmpA = new Vector3D(); var tmpB = new Vector3D(); if (d < 0) { d = -d; normal.scaleBy(-1); } var vA = verts[s - 1]; var vecA = vA.toVec(tmpA, 0); var da = normal.dotProduct(vecA) - d; for (var i = 0; i < s; ++i) { var vB = verts[i]; var vecB = vB.toVec(tmpB, 0); var db = normal.dotProduct(vecB) - d; if (this.InFront(normal, d, vecB)) { if (this.Behind(normal, d, vecA)) { var itr = this.Intersect(vB, vA, db, da); frontPoly.add(itr); backPoly.add(itr, true); } frontPoly.add(vB, true); } else if (this.Behind(normal, d, vecB)) { if (this.InFront(normal, d, vecA)) { var itr = this.Intersect(vA, vB, da, db); frontPoly.add(itr, false); backPoly.add(itr, true); } else if (this.OnPlane(normal, d, vecA)) { backPoly.add(vA, true); } backPoly.add(vB, true); } else { frontPoly.add(vB, true); if (this.OnPlane(normal, d, vecA)) { backPoly.add(vB, true); } } vA = vB.clone(); vecA = vA.toVec(vecA, 0); da = db; } if (frontPoly.length) { //if (frontPoly.length < 3) debugger; callback && callback(poly, frontPoly, false); if (out.polySize !== frontPoly.length) { out.hasNGones = true; } out.poly.push(frontPoly); } if (backPoly.length) { //if (backPoly.length < 3) debugger; callback && callback(poly, backPoly, true); if (out.polySize !== backPoly.length) { out.hasNGones = true; } out.poly.push(backPoly); } return out; }; GeneratorUtils.SliceHodgman = function (mesh, n, d, callback) { var out = new MeshView(); out.polySize = mesh.polySize; for (var _i = 0, _a = mesh.poly; _i < _a.length; _i++) { var p = _a[_i]; this.SutherlandHodgman(p, n, d, out, callback); } return out; }; GeneratorUtils.EPS = 0.0001; return GeneratorUtils; }()); export { GeneratorUtils };