赞
踩
利用{antialias: true}
能有效缓解
this.renderer = new this.THREE.WebGLRenderer({antialias: true})
引用路径不当会导致一些奇怪的错误,在threejs中所有的加载的引用都要用绝对路径,资源放在静态文件夹下。
缩放scale
注意不能是0。
如下的函数相当于Math.floor()
,但是该函数在~~(0.5)
返回的就是0,需要注意。
rand:function(min,max){
return ~~(Math.random()*(max-min+1)+min)
}
通常我们使用的是Hex
的颜色,但是我想要很多个粉红的爱心,但是爱心的颜色又要有不同,这样我们最好是用HSL
,我们这里只需要改变一些l
的值就可以得到很多类似的颜色。
// svg是利用爱心svg图像拉伸而成的Three.Mesh对象
// this.heartNum是指爱心的数量
for (let i = 0; i < this.heartNum; i++) {
let heart = svg.clone()
let svgMaterial = new this.THREE.MeshPhongMaterial({
shininess:60
});
heart.material = svgMaterial
let color = new this.THREE.Color(0xFFBBFF) // 粉色
let hsl= {}
color.getHSL(hsl)
heart.material.color.setHSL(hsl.h,hsl.s,this.rand(0.6,1)*hsl.l)
this.scene.add(heart)
}
说明:threejs
中的网格物体对材质的是引用传递,不是值传递,如果material
被 mesh1
和mesh2
用到了,改变 mesh1.material.color
,则mesh2
的材质颜色也改了,所以这里我们给每一个mesh
一个material
transformSVGPathExposed
将svg图像转化成three.shape
对象
ThreeBSP
图像的一些处理
其中用到了coffee语法,将其转化成js可以参考,http://coffee-script.org/
/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ var THREE = require('three') var transformSVGPathExposed; var applySVGTransformExposed; function d3threeD(exports) { const DEGS_TO_RADS = Math.PI / 180, UNIT_SIZE = 1; const DIGIT_0 = 48, DIGIT_9 = 57, COMMA = 44, SPACE = 32, PERIOD = 46, MINUS = 45; function transformSVGPath(pathStr) { var paths = []; var path = new THREE.Shape(); var idx = 1, len = pathStr.length, activeCmd, x = 0, y = 0, nx = 0, ny = 0, firstX = null, firstY = null, x1 = 0, x2 = 0, y1 = 0, y2 = 0, rx = 0, ry = 0, xar = 0, laf = 0, sf = 0, cx, cy; function eatNum() { var sidx, c, isFloat = false, s; // eat delims while (idx < len) { c = pathStr.charCodeAt(idx); if (c !== COMMA && c !== SPACE) break; idx++; } if (c === MINUS) sidx = idx++; else sidx = idx; // eat number while (idx < len) { c = pathStr.charCodeAt(idx); if (DIGIT_0 <= c && c <= DIGIT_9) { idx++; continue; } else if (c === PERIOD) { idx++; isFloat = true; continue; } s = pathStr.substring(sidx, idx); return isFloat ? parseFloat(s) : parseInt(s); } s = pathStr.substring(sidx); return isFloat ? parseFloat(s) : parseInt(s); } function nextIsNum() { var c; // do permanently eat any delims... while (idx < len) { c = pathStr.charCodeAt(idx); if (c !== COMMA && c !== SPACE) break; idx++; } c = pathStr.charCodeAt(idx); return (c === MINUS || (DIGIT_0 <= c && c <= DIGIT_9)); } var canRepeat; var enteredSub = false; var zSeen = false; activeCmd = pathStr[0]; while (idx <= len) { canRepeat = true; switch (activeCmd) { // moveto commands, become lineto's if repeated case 'M': enteredSub = false; x = eatNum(); y = eatNum(); path.moveTo(x, y); activeCmd = 'L'; break; case 'm': x += eatNum(); y += eatNum(); path.moveTo(x, y); activeCmd = 'l'; break; case 'Z': case 'z': // z is a special case. This ends a segment and starts // a new path. Since the three.js path is continuous // we should start a new path here. This also draws a // line from the current location to the start location. canRepeat = false; if (x !== firstX || y !== firstY) path.lineTo(firstX, firstY); paths.push(path); // reset the elements firstX = null; firstY = null; // avoid x,y being set incorrectly enteredSub = true; path = new THREE.Shape(); zSeen = true; break; // - lines! case 'L': case 'H': case 'V': nx = (activeCmd === 'V') ? x : eatNum(); ny = (activeCmd === 'H') ? y : eatNum(); path.lineTo(nx, ny); x = nx; y = ny; break; case 'l': case 'h': case 'v': nx = (activeCmd === 'v') ? x : (x + eatNum()); ny = (activeCmd === 'h') ? y : (y + eatNum()); path.lineTo(nx, ny); x = nx; y = ny; break; // - cubic bezier case 'C': x1 = eatNum(); y1 = eatNum(); case 'S': if (activeCmd === 'S') { x1 = 2 * x - x2; y1 = 2 * y - y2; } x2 = eatNum(); y2 = eatNum(); nx = eatNum(); ny = eatNum(); path.bezierCurveTo(x1, y1, x2, y2, nx, ny); x = nx; y = ny; break; case 'c': x1 = x + eatNum(); y1 = y + eatNum(); case 's': if (activeCmd === 's') { x1 = 2 * x - x2; y1 = 2 * y - y2; } x2 = x + eatNum(); y2 = y + eatNum(); nx = x + eatNum(); ny = y + eatNum(); path.bezierCurveTo(x1, y1, x2, y2, nx, ny); x = nx; y = ny; break; // - quadratic bezier case 'Q': x1 = eatNum(); y1 = eatNum(); case 'T': if (activeCmd === 'T') { x1 = 2 * x - x1; y1 = 2 * y - y1; } nx = eatNum(); ny = eatNum(); path.quadraticCurveTo(x1, y1, nx, ny); x = nx; y = ny; break; case 'q': x1 = x + eatNum(); y1 = y + eatNum(); case 't': if (activeCmd === 't') { x1 = 2 * x - x1; y1 = 2 * y - y1; } nx = x + eatNum(); ny = y + eatNum(); path.quadraticCurveTo(x1, y1, nx, ny); x = nx; y = ny; break; // - elliptical arc case 'A': rx = eatNum(); ry = eatNum(); xar = eatNum() * DEGS_TO_RADS; laf = eatNum(); sf = eatNum(); nx = eatNum(); ny = eatNum(); if (rx !== ry) { console.warn("Forcing elliptical arc to be a circular one :(", rx, ry); } // SVG implementation notes does all the math for us! woo! // http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes // step1, using x1 as x1' x1 = Math.cos(xar) * (x - nx) / 2 + Math.sin(xar) * (y - ny) / 2; y1 = -Math.sin(xar) * (x - nx) / 2 + Math.cos(xar) * (y - ny) / 2; // step 2, using x2 as cx' var norm = Math.sqrt( (rx * rx * ry * ry - rx * rx * y1 * y1 - ry * ry * x1 * x1) / (rx * rx * y1 * y1 + ry * ry * x1 * x1)); if (laf === sf) norm = -norm; x2 = norm * rx * y1 / ry; y2 = norm * -ry * x1 / rx; // step 3 cx = Math.cos(xar) * x2 - Math.sin(xar) * y2 + (x + nx) / 2; cy = Math.sin(xar) * x2 + Math.cos(xar) * y2 + (y + ny) / 2; var u = new THREE.Vector2(1, 0), v = new THREE.Vector2((x1 - x2) / rx, (y1 - y2) / ry); var startAng = Math.acos(u.dot(v) / u.length() / v.length()); if (u.x * v.y - u.y * v.x < 0) startAng = -startAng; // we can reuse 'v' from start angle as our 'u' for delta angle u.x = (-x1 - x2) / rx; u.y = (-y1 - y2) / ry; var deltaAng = Math.acos(v.dot(u) / v.length() / u.length()); // This normalization ends up making our curves fail to triangulate... if (v.x * u.y - v.y * u.x < 0) deltaAng = -deltaAng; if (!sf && deltaAng > 0) deltaAng -= Math.PI * 2; if (sf && deltaAng < 0) deltaAng += Math.PI * 2; path.absarc(cx, cy, rx, startAng, startAng + deltaAng, sf); x = nx; y = ny; break; case ' ': // if it's an empty space, just skip it, and see if we can find a real command break; default: break; } if (firstX === null && !enteredSub) { firstX = x; firstY = y; } // just reissue the command if (canRepeat && nextIsNum()) continue; activeCmd = pathStr[idx++]; } if (zSeen) { return paths; } else { paths.push(path); return paths; } } transformSVGPathExposed = transformSVGPath; function applySVGTransform(obj, tstr) { var idx = tstr.indexOf('('), len = tstr.length, cmd = tstr.substring(0, idx++); function eatNum() { var sidx, c, isFloat = false, s; // eat delims while (idx < len) { c = tstr.charCodeAt(idx); if (c !== COMMA && c !== SPACE) break; idx++; } if (c === MINUS) sidx = idx++; else sidx = idx; // eat number while (idx < len) { c = tstr.charCodeAt(idx); if (DIGIT_0 <= c && c <= DIGIT_9) { idx++; continue; } else if (c === PERIOD) { idx++; isFloat = true; continue; } s = tstr.substring(sidx, idx); return isFloat ? parseFloat(s) : parseInt(s); } s = tstr.substring(sidx); return isFloat ? parseFloat(s) : parseInt(s); } switch (cmd) { case 'translate': obj.position.x = Math.floor(eatNum() * UNIT_SIZE); obj.position.y = Math.floor(eatNum() * UNIT_SIZE); break; case 'scale': obj.scale.x = Math.floor(eatNum() * UNIT_SIZE); obj.scale.y = Math.floor(eatNum() * UNIT_SIZE); break; default: console.warn("don't understand transform", tstr); break; } } applySVGTransformExposed = applySVGTransform; function wrap_setAttribute(name, value) {} function wrap_setAttributeNS(namespace, name, value) {} var extrudeDefaults = { amount: 20, bevelEnabled: true, material: 0, extrudeMaterial: 0, }; function commonSetAttribute(name, value) { switch (name) { case 'x': this.position.x = Math.floor(value * UNIT_SIZE); break; case 'y': this.position.y = Math.floor(value * UNIT_SIZE); break; case 'class': this.clazz = value; break; case 'stroke': case 'fill': if (typeof(value) !== 'string') value = value.toString(); this.material.color.setHex(parseInt(value.substring(1), 16)); break; case 'transform': applySVGTransform(this, value); break; case 'd': var shape = transformSVGPath(value), geom = shape.extrude(extrudeDefaults); this.geometry = geom; this.geometry.boundingSphere = { radius: 3 * UNIT_SIZE }; this.scale.set(UNIT_SIZE, UNIT_SIZE, UNIT_SIZE); break; default: throw new Error("no setter for: " + name); } } function commonSetAttributeNS(namespace, name, value) { this.setAttribute(name, value); } function Group(parentThing) { THREE.Object3D.call(this); this.d3class = ''; parentThing.add(this); }; Group.prototype = new THREE.Object3D(); Group.prototype.constructor = Group; Group.prototype.d3tag = 'g'; Group.prototype.setAttribute = commonSetAttribute; Group.prototype.setAttributeNS = commonSetAttributeNS; function fabGroup() { return new Group(this); } function Mesh(parentThing, tag, geometry, material) { THREE.Mesh.call(this, geometry, material); this.d3tag = tag; this.d3class = ''; parentThing.add(this); } Mesh.prototype = new THREE.Mesh(); Mesh.prototype.constructor = Mesh; Mesh.prototype.setAttribute = commonSetAttribute; Mesh.prototype.setAttributeNS = commonSetAttributeNS; const SPHERE_SEGS = 16, SPHERE_RINGS = 16, DEFAULT_COLOR = 0xcc0000; var sharedSphereGeom = null, sharedCubeGeom = null; function fabSphere() { if (!sharedSphereGeom) sharedSphereGeom = new THREE.SphereGeometry( UNIT_SIZE / 2, SPHERE_SEGS, SPHERE_RINGS); var material = new THREE.MeshLambertMaterial({ color: DEFAULT_COLOR, }); return new Mesh(this, 'sphere', sharedSphereGeom, material); } function fabCube() { if (!sharedCubeGeom) sharedCubeGeom = new THREE.CubeGeometry(UNIT_SIZE, UNIT_SIZE, UNIT_SIZE); var material = new THREE.MeshLambertMaterial({ color: DEFAULT_COLOR, }); return new Mesh(this, 'cube', sharedCubeGeom, material); } function fabPath() { // start with a cube that we will replace with the path once it gets created if (!sharedCubeGeom) sharedCubeGeom = new THREE.CubeGeometry(UNIT_SIZE, UNIT_SIZE, UNIT_SIZE); var material = new THREE.MeshLambertMaterial({ color: DEFAULT_COLOR, }); return new Mesh(this, 'path', sharedCubeGeom, material); } function Scene() { THREE.Scene.call(this); this.renderer = null; this.camera = null; this.controls = null; this._d3_width = null; this._d3_height = null; } Scene.prototype = new THREE.Scene(); Scene.prototype.constructor = Scene; Scene.prototype._setBounds = function() { this.renderer.setSize(this._d3_width, this._d3_height); var aspect = this.camera.aspect; this.camera.position.set( this._d3_width * UNIT_SIZE / 2, this._d3_height * UNIT_SIZE / 2, Math.max(this._d3_width * UNIT_SIZE / Math.sqrt(2), this._d3_height * UNIT_SIZE / Math.sqrt(2))); this.controls.target.set(this.camera.position.x, this.camera.position.y, 0); console.log("camera:", this.camera.position.x, this.camera.position.y, this.camera.position.z); //this.camera.position.z = 1000; }; Scene.prototype.setAttribute = function(name, value) { switch (name) { case 'width': this._d3_width = value; if (this._d3_height) this._setBounds(); break; case 'height': this._d3_height = value; if (this._d3_width) this._setBounds(); break; } }; function fabVis() { var camera, scene, controls, renderer; // - scene scene = new Scene(); threeJsScene = scene; // - camera camera = scene.camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 100000); /* camera = scene.camera = new THREE.OrthographicCamera( window.innerWidth / -2, window.innerWidth / 2, window.innerHeight / 2, window.innerHeight / -2, 1, 50000); */ scene.add(camera); // - controls // from misc_camera_trackball.html example controls = scene.controls = new THREE.TrackballControls(camera); controls.rotateSpeed = 1.0; controls.zoomSpeed = 1.2; controls.panSpeed = 0.8; controls.noZoom = false; controls.noPan = false; controls.staticMoving = true; controls.dynamicDampingFactor = 0.3; controls.keys = [65, 83, 68]; controls.addEventListener('change', render); // - light /* var pointLight = new THREE.PointLight(0xFFFFFF); pointLight.position.set(10, 50, 130); scene.add(pointLight); */ var spotlight = new THREE.SpotLight(0xffffff); spotlight.position.set(-50000, 50000, 100000); scene.add(spotlight); var backlight = new THREE.SpotLight(0x888888); backlight.position.set(50000, -50000, -100000); scene.add(backlight); /* var ambientLight = new THREE.AmbientLight(0x888888); scene.add(ambientLight); */ function helperPlanes(maxBound) { var geom = new THREE.PlaneGeometry(maxBound, maxBound, 4, 4); for (var i = 0; i < 4; i++) { var color, cx, cy; switch (i) { case 0: color = 0xff0000; cx = maxBound / 2; cy = maxBound / 2; break; case 1: color = 0x00ff00; cx = maxBound / 2; cy = -maxBound / 2; break; case 2: color = 0x0000ff; cx = -maxBound / 2; cy = -maxBound / 2; break; case 3: color = 0xffff00; cx = -maxBound / 2; cy = maxBound / 2; break; } var material = new THREE.MeshLambertMaterial({ color: color }); var mesh = new THREE.Mesh(geom, material); mesh.position.set(cx, cy, -1); scene.add(mesh); } } //helperPlanes(UNIT_SIZE * 225); // - renderer renderer = scene.renderer = new THREE.WebGLRenderer({ // too slow... //antialias: true, }); this.appendChild(renderer.domElement); // - stats var stats = new Stats(); stats.domElement.style.position = 'absolute'; stats.domElement.style.top = '0px'; stats.domElement.style.zIndex = 100; this.appendChild(stats.domElement); function animate() { requestAnimationFrame(animate, renderer.domElement); controls.update(); } function render() { renderer.render(scene, camera); stats.update(); } animate(); return scene; }; } var $d3g = {}; d3threeD($d3g); export { transformSVGPathExposed }
var BACK, COPLANAR, EPSILON, FRONT, SPANNING, Timelimit, returning, __bind = function(fn, me) { return function() { return fn.apply(me, arguments); }; }, __slice = [].slice, __hasProp = {}.hasOwnProperty, __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; EPSILON = 1e-5; COPLANAR = 0; FRONT = 1; BACK = 2; SPANNING = 3; var THREE = require('three') var ThreeBSP; returning = function(value, fn) { fn(); return value; }; Timelimit = (function() { function Timelimit(timeout, progress) { this.timeout = timeout; this.progress = progress; this.doTask = __bind(this.doTask, this); this.finish = __bind(this.finish, this); this.start = __bind(this.start, this); this.check = __bind(this.check, this); "NOTHING"; } Timelimit.prototype.check = function() { var elapsed; if (this.started == null) { return; } return returning((elapsed = Date.now() - this.started), (function(_this) { return function() { var _ref, _ref1, _ref2; if ((_ref = elapsed >= _this.timeout) != null ? _ref : Infinity) { throw new Error("Timeout reached: " + elapsed + "/" + _this.timeout + ", " + ((_ref1 = _this.tasks) != null ? _ref1 : 0) + " tasks unfinished " + ((_ref2 = _this.done) != null ? _ref2 : 0) + " finished."); } }; })(this)); }; Timelimit.prototype.start = function() { if (this.started == null) { this.started = Date.now(); } if (this.tasks == null) { this.tasks = 0; } if (this.total == null) { this.total = 0; } this.total += 1; this.tasks += 1; return this.check(); }; Timelimit.prototype.finish = function() { var elapsed; if ((this.tasks != null) && this.tasks < 1) { throw new Error("Finished more tasks than started"); } this.tasks -= 1; elapsed = this.check(); if (this.done == null) { this.done = 0; } this.done += 1; if (this.progress != null) { this.progress(this.done, this.total); } if (this.tasks === 0) { "Finished " + this.done + " tasks in " + elapsed + "/" + this.timeout + " ms"; return this.started = this.done = this.total = void 0; } }; Timelimit.prototype.doTask = function(block) { var result; this.start(); result = block(); this.finish(); return result; }; return Timelimit; })(); ThreeBSP = (function() { function ThreeBSP(treeIsh, matrix, options) { var _base, _ref, _ref1, _ref2, _ref3; this.matrix = matrix; this.options = options != null ? options : {}; this.intersect = __bind(this.intersect, this); this.union = __bind(this.union, this); this.subtract = __bind(this.subtract, this); this.toGeometry = __bind(this.toGeometry, this); this.toMesh = __bind(this.toMesh, this); this.toTree = __bind(this.toTree, this); this.withTimer = __bind(this.withTimer, this); if ((this.matrix != null) && !(this.matrix instanceof THREE.Matrix4)) { this.options = this.matrix; this.matrix = void 0; } if (this.options == null) { this.options = {}; } if (this.matrix == null) { this.matrix = new THREE.Matrix4(); } if ((_base = this.options).timer == null) { _base.timer = new Timelimit((_ref = (_ref1 = this.options.timer) != null ? _ref1.timeout : void 0) != null ? _ref : this.options.timeout, (_ref2 = (_ref3 = this.options.timer) != null ? _ref3.progress : void 0) != null ? _ref2 : this.options.progress); } this.tree = this.toTree(treeIsh); } ThreeBSP.prototype.withTimer = function(new_timer, block) { var old_timer; old_timer = this.options.timer; try { this.options.timer = new_timer; return block(); } finally { this.options.timer = old_timer; } }; ThreeBSP.prototype.toTree = function(treeIsh) { var face, geometry, i, polygons, _fn, _i, _len, _ref; if (treeIsh instanceof ThreeBSP.Node) { return treeIsh; } polygons = []; geometry = treeIsh instanceof THREE.Geometry ? treeIsh : treeIsh instanceof THREE.Mesh ? (treeIsh.updateMatrix(), this.matrix = treeIsh.matrix.clone(), treeIsh.geometry) : void 0; _ref = geometry.faces; _fn = (function(_this) { return function(face, i) { var faceVertexUvs, idx, polygon, vIndex, vName, vertex, _j, _len1, _ref1, _ref2; faceVertexUvs = (_ref1 = geometry.faceVertexUvs) != null ? _ref1[0][i] : void 0; if (faceVertexUvs == null) { faceVertexUvs = [new THREE.Vector2(), new THREE.Vector2(), new THREE.Vector2(), new THREE.Vector2()]; } polygon = new ThreeBSP.Polygon(); _ref2 = ['a', 'b', 'c', 'd']; for (vIndex = _j = 0, _len1 = _ref2.length; _j < _len1; vIndex = ++_j) { vName = _ref2[vIndex]; if ((idx = face[vName]) != null) { vertex = geometry.vertices[idx]; vertex = new ThreeBSP.Vertex(vertex.x, vertex.y, vertex.z, face.vertexNormals[0], new THREE.Vector2(faceVertexUvs[vIndex].x, faceVertexUvs[vIndex].y)); vertex.applyMatrix4(_this.matrix); polygon.vertices.push(vertex); } } return polygons.push(polygon.calculateProperties()); }; })(this); for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) { face = _ref[i]; _fn(face, i); } return new ThreeBSP.Node(polygons, this.options); }; ThreeBSP.prototype.toMesh = function(material) { var geometry, mesh, _this = this; if (material == null) { material = new THREE.MeshNormalMaterial(); } geometry = this.toGeometry(); return returning((mesh = new THREE.Mesh(geometry, material)), function() { mesh.position.setFromMatrixPosition(_this.matrix); return mesh.rotation.setFromRotationMatrix(_this.matrix); }); }; ThreeBSP.prototype.toGeometry = function() { return this.options.timer.doTask((function(_this) { return function() { var geometry, matrix; matrix = new THREE.Matrix4().getInverse(_this.matrix); return returning((geometry = new THREE.Geometry()), function() { var polygon, _i, _len, _ref, _results; _ref = _this.tree.allPolygons(); _results = []; for (_i = 0, _len = _ref.length; _i < _len; _i++) { polygon = _ref[_i]; _results.push(_this.options.timer.doTask(function() { var face, idx, polyVerts, v, vertUvs, verts, _j, _ref1, _results1; polyVerts = (function() { var _j, _len1, _ref1, _results1; _ref1 = polygon.vertices; _results1 = []; for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { v = _ref1[_j]; _results1.push(v.clone().applyMatrix4(matrix)); } return _results1; })(); _results1 = []; for (idx = _j = 2, _ref1 = polyVerts.length; 2 <= _ref1 ? _j < _ref1 : _j > _ref1; idx = 2 <= _ref1 ? ++_j : --_j) { verts = [polyVerts[0], polyVerts[idx - 1], polyVerts[idx]]; vertUvs = (function() { var _k, _len1, _ref2, _ref3, _results2; _results2 = []; for (_k = 0, _len1 = verts.length; _k < _len1; _k++) { v = verts[_k]; _results2.push(new THREE.Vector2((_ref2 = v.uv) != null ? _ref2.x : void 0, (_ref3 = v.uv) != null ? _ref3.y : void 0)); } return _results2; })(); face = (function(func, args, ctor) { ctor.prototype = func.prototype; var child = new ctor, result = func.apply(child, args); return Object(result) === result ? result : child; })(THREE.Face3, __slice.call((function() { var _k, _len1, _results2; _results2 = []; for (_k = 0, _len1 = verts.length; _k < _len1; _k++) { v = verts[_k]; _results2.push(geometry.vertices.push(v) - 1); } return _results2; })()).concat([polygon.normal.clone()]), function() {}); geometry.faces.push(face); _results1.push(geometry.faceVertexUvs[0].push(vertUvs)); } return _results1; })); } return _results; }); }; })(this)); }; ThreeBSP.prototype.subtract = function(other) { return this.options.timer.doTask((function(_this) { return function() { return other.withTimer(_this.options.timer, function() { var them, us, _ref; _ref = [_this.tree.clone(), other.tree.clone()], us = _ref[0], them = _ref[1]; us.invert().clipTo(them); them.clipTo(us).invert().clipTo(us).invert(); return new ThreeBSP(us.build(them.allPolygons()).invert(), _this.matrix, _this.options); }); }; })(this)); }; ThreeBSP.prototype.union = function(other) { return this.options.timer.doTask((function(_this) { return function() { return other.withTimer(_this.options.timer, function() { var them, us, _ref; _ref = [_this.tree.clone(), other.tree.clone()], us = _ref[0], them = _ref[1]; us.clipTo(them); them.clipTo(us).invert().clipTo(us).invert(); return new ThreeBSP(us.build(them.allPolygons()), _this.matrix, _this.options); }); }; })(this)); }; ThreeBSP.prototype.intersect = function(other) { return this.options.timer.doTask((function(_this) { return function() { return other.withTimer(_this.options.timer, function() { var them, us, _ref; _ref = [_this.tree.clone(), other.tree.clone()], us = _ref[0], them = _ref[1]; them.clipTo(us.invert()).invert().clipTo(us.clipTo(them)); return new ThreeBSP(us.build(them.allPolygons()).invert(), _this.matrix, _this.options); }); }; })(this)); }; return ThreeBSP; })(); ThreeBSP.Vertex = (function(_super) { __extends(Vertex, _super); function Vertex(x, y, z, normal, uv) { this.normal = normal != null ? normal : new THREE.Vector3(); this.uv = uv != null ? uv : new THREE.Vector2(); this.interpolate = __bind(this.interpolate, this); this.lerp = __bind(this.lerp, this); Vertex.__super__.constructor.call(this, x, y, z); } Vertex.prototype.clone = function() { return new ThreeBSP.Vertex(this.x, this.y, this.z, this.normal.clone(), this.uv.clone()); }; Vertex.prototype.lerp = function(v, alpha) { return returning(Vertex.__super__.lerp.apply(this, arguments), (function(_this) { return function() { _this.uv.add(v.uv.clone().sub(_this.uv).multiplyScalar(alpha)); return _this.normal.lerp(v, alpha); }; })(this)); }; Vertex.prototype.interpolate = function() { var args, _ref; args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; return (_ref = this.clone()).lerp.apply(_ref, args); }; return Vertex; })(THREE.Vector3); ThreeBSP.Polygon = (function() { function Polygon(vertices, normal, w) { this.vertices = vertices != null ? vertices : []; this.normal = normal; this.w = w; this.subdivide = __bind(this.subdivide, this); this.tessellate = __bind(this.tessellate, this); this.classifySide = __bind(this.classifySide, this); this.classifyVertex = __bind(this.classifyVertex, this); this.invert = __bind(this.invert, this); this.clone = __bind(this.clone, this); this.calculateProperties = __bind(this.calculateProperties, this); if (this.vertices.length) { this.calculateProperties(); } } Polygon.prototype.calculateProperties = function() { return returning(this, (function(_this) { return function() { var a, b, c, _ref; _ref = _this.vertices, a = _ref[0], b = _ref[1], c = _ref[2]; _this.normal = b.clone().sub(a).cross(c.clone().sub(a)).normalize(); return _this.w = _this.normal.clone().dot(a); }; })(this)); }; Polygon.prototype.clone = function() { var v; return new ThreeBSP.Polygon((function() { var _i, _len, _ref, _results; _ref = this.vertices; _results = []; for (_i = 0, _len = _ref.length; _i < _len; _i++) { v = _ref[_i]; _results.push(v.clone()); } return _results; }).call(this), this.normal.clone(), this.w); }; Polygon.prototype.invert = function() { return returning(this, (function(_this) { return function() { _this.normal.multiplyScalar(-1); _this.w *= -1; return _this.vertices.reverse(); }; })(this)); }; Polygon.prototype.classifyVertex = function(vertex) { var side; side = this.normal.dot(vertex) - this.w; switch (false) { case !(side < -EPSILON): return BACK; case !(side > EPSILON): return FRONT; default: return COPLANAR; } }; Polygon.prototype.classifySide = function(polygon) { var back, front, tally, v, _i, _len, _ref, _ref1; _ref = [0, 0], front = _ref[0], back = _ref[1]; tally = (function(_this) { return function(v) { switch (_this.classifyVertex(v)) { case FRONT: return front += 1; case BACK: return back += 1; } }; })(this); _ref1 = polygon.vertices; for (_i = 0, _len = _ref1.length; _i < _len; _i++) { v = _ref1[_i]; tally(v); } if (front > 0 && back === 0) { return FRONT; } if (front === 0 && back > 0) { return BACK; } if ((front === back && back === 0)) { return COPLANAR; } return SPANNING; }; Polygon.prototype.tessellate = function(poly) { var b, count, f, i, j, polys, t, ti, tj, v, vi, vj, _i, _len, _ref, _ref1, _ref2; _ref = { f: [], b: [], count: poly.vertices.length }, f = _ref.f, b = _ref.b, count = _ref.count; if (this.classifySide(poly) !== SPANNING) { return [poly]; } _ref1 = poly.vertices; for (i = _i = 0, _len = _ref1.length; _i < _len; i = ++_i) { vi = _ref1[i]; vj = poly.vertices[(j = (i + 1) % count)]; _ref2 = (function() { var _j, _len1, _ref2, _results; _ref2 = [vi, vj]; _results = []; for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) { v = _ref2[_j]; _results.push(this.classifyVertex(v)); } return _results; }).call(this), ti = _ref2[0], tj = _ref2[1]; if (ti !== BACK) { f.push(vi); } if (ti !== FRONT) { b.push(vi); } if ((ti | tj) === SPANNING) { t = (this.w - this.normal.dot(vi)) / this.normal.dot(vj.clone().sub(vi)); v = vi.interpolate(vj, t); f.push(v); b.push(v); } } return returning((polys = []), (function(_this) { return function() { if (f.length >= 3) { polys.push(new ThreeBSP.Polygon(f)); } if (b.length >= 3) { return polys.push(new ThreeBSP.Polygon(b)); } }; })(this)); }; Polygon.prototype.subdivide = function(polygon, coplanar_front, coplanar_back, front, back) { var poly, side, _i, _len, _ref, _results; _ref = this.tessellate(polygon); _results = []; for (_i = 0, _len = _ref.length; _i < _len; _i++) { poly = _ref[_i]; side = this.classifySide(poly); switch (side) { case FRONT: _results.push(front.push(poly)); break; case BACK: _results.push(back.push(poly)); break; case COPLANAR: if (this.normal.dot(poly.normal) > 0) { _results.push(coplanar_front.push(poly)); } else { _results.push(coplanar_back.push(poly)); } break; default: throw new Error("BUG: Polygon of classification " + side + " in subdivision"); } } return _results; }; return Polygon; })(); ThreeBSP.Node = (function() { Node.prototype.clone = function() { var node; return returning((node = new ThreeBSP.Node(this.options)), (function(_this) { return function() { var _ref; node.divider = (_ref = _this.divider) != null ? _ref.clone() : void 0; node.polygons = _this.options.timer.doTask(function() { var p, _i, _len, _ref1, _results; _ref1 = _this.polygons; _results = []; for (_i = 0, _len = _ref1.length; _i < _len; _i++) { p = _ref1[_i]; _results.push(p.clone()); } return _results; }); node.front = _this.options.timer.doTask(function() { var _ref1; return (_ref1 = _this.front) != null ? _ref1.clone() : void 0; }); return node.back = _this.options.timer.doTask(function() { var _ref1; return (_ref1 = _this.back) != null ? _ref1.clone() : void 0; }); }; })(this)); }; function Node(polygons, options) { this.options = options != null ? options : {}; this.clipTo = __bind(this.clipTo, this); this.clipPolygons = __bind(this.clipPolygons, this); this.invert = __bind(this.invert, this); this.allPolygons = __bind(this.allPolygons, this); this.isConvex = __bind(this.isConvex, this); this.build = __bind(this.build, this); this.clone = __bind(this.clone, this); if ((polygons != null) && !(polygons instanceof Array)) { this.options = polygons; polygons = void 0; } this.polygons = []; this.options.timer.doTask((function(_this) { return function() { if ((polygons != null) && polygons.length) { return _this.build(polygons); } }; })(this)); } Node.prototype.build = function(polygons) { return returning(this, (function(_this) { return function() { var polys, side, sides, _results; sides = { front: [], back: [] }; if (_this.divider == null) { _this.divider = polygons[0].clone(); } _this.options.timer.doTask(function() { var poly, _i, _len, _results; _results = []; for (_i = 0, _len = polygons.length; _i < _len; _i++) { poly = polygons[_i]; _results.push(_this.options.timer.doTask(function() { return _this.divider.subdivide(poly, _this.polygons, _this.polygons, sides.front, sides.back); })); } return _results; }); _results = []; for (side in sides) { if (!__hasProp.call(sides, side)) continue; polys = sides[side]; if (polys.length) { if (_this[side] == null) { _this[side] = new ThreeBSP.Node(_this.options); } _results.push(_this[side].build(polys)); } else { _results.push(void 0); } } return _results; }; })(this)); }; Node.prototype.isConvex = function(polys) { var inner, outer, _i, _j, _len, _len1; for (_i = 0, _len = polys.length; _i < _len; _i++) { inner = polys[_i]; for (_j = 0, _len1 = polys.length; _j < _len1; _j++) { outer = polys[_j]; if (inner !== outer && outer.classifySide(inner) !== BACK) { return false; } } } return true; }; Node.prototype.allPolygons = function() { return this.options.timer.doTask((function(_this) { return function() { var _ref, _ref1; return _this.polygons.slice().concat(((_ref1 = _this.front) != null ? _ref1.allPolygons() : void 0) || []).concat(((_ref = _this.back) != null ? _ref.allPolygons() : void 0) || []); }; })(this)); }; Node.prototype.invert = function() { return returning(this, (function(_this) { return function() { return _this.options.timer.doTask(function() { var flipper, poly, _i, _j, _len, _len1, _ref, _ref1, _ref2; _ref = _this.polygons; for (_i = 0, _len = _ref.length; _i < _len; _i++) { poly = _ref[_i]; _this.options.timer.doTask(function() { return poly.invert(); }); } _ref1 = [_this.divider, _this.front, _this.back]; for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { flipper = _ref1[_j]; _this.options.timer.doTask(function() { return flipper != null ? flipper.invert() : void 0; }); } return _ref2 = [_this.back, _this.front], _this.front = _ref2[0], _this.back = _ref2[1], _ref2; }); }; })(this)); }; Node.prototype.clipPolygons = function(polygons) { return this.options.timer.doTask((function(_this) { return function() { var back, front, poly, _i, _len; if (!_this.divider) { return polygons.slice(); } front = []; back = []; for (_i = 0, _len = polygons.length; _i < _len; _i++) { poly = polygons[_i]; _this.options.timer.doTask(function() { return _this.divider.subdivide(poly, front, back, front, back); }); } if (_this.front) { front = _this.front.clipPolygons(front); } if (_this.back) { back = _this.back.clipPolygons(back); } if (_this.back) { return front.concat(back); } else { return front; } }; })(this)); }; Node.prototype.clipTo = function(node) { return returning(this, (function(_this) { return function() { return _this.options.timer.doTask(function() { var _ref, _ref1; _this.polygons = node.clipPolygons(_this.polygons); if ((_ref = _this.front) != null) { _ref.clipTo(node); } return (_ref1 = _this.back) != null ? _ref1.clipTo(node) : void 0; }); }; })(this)); }; return Node; })(); export { ThreeBSP }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。