我们可以用Cube绘制“线条”以在运行时显示“尺寸”吗?
以下是我创建多维数据集并从用户获取维度并在运行时更改多维数据集的方法:http://jsfiddle.net/9Lvk61j3/
但现在我想显示Dimension,因此用户知道它们将会改变的长度,宽度和高度.
这是我想要做的最终结果:
这是我的代码:
HTML:
<script src="http://www.html5canvastutorials.com/libraries/three.min.js"></script> <div id="container"></div> <div class="inputRow clear" id="dimensionsNotRound" data-role="tooltip"> <label class="grid-8">Dimensions (pixels):</label> <br/> <br/> <div> <span>Length</span> <input class="numeric-textBox" id="inp-length" type="text" value="100"> <br/> <br/> </div> <div> <span>Width</span> <input class="numeric-textBox" id="inp-width" type="text" value="50"> <br/> <br/> </div> <div> <span>Height</span> <input class="numeric-textBox" id="inp-height" type="text" value="40"> <br/> <br/> </div> <button id="btn">Click me to change the Dimensions</button>
JS
var shape = null; //Script for 3D Box // revolutions per second var angularspeed = 0.2; var lastTime = 0; var cube = 0; // this function is executed on each animation frame function animate() { // update var time = (new Date()).getTime(); var timeDiff = time - lastTime; var angleChange = angularspeed * timeDiff * 2 * Math.PI / 1000; //cube.rotation.y += angleChange; //Starts Rotating Object lastTime = time; // render renderer.render(scene,camera); // request new frame requestAnimationFrame(function () { animate(); }); } // renderer var container = document.getElementById("container"); var renderer = new THREE.Webglrenderer(); renderer.setSize(container.offsetWidth,container.offsetHeight - 4); container.appendChild(renderer.domElement); // camera var camera = new THREE.PerspectiveCamera(60,container.offsetWidth / container.offsetHeight,1,1000); camera.position.z = 800; // scene var scene = new THREE.Scene(); scene.remove(); // cube cube = new THREE.Mesh(new THREE.CubeGeometry(1,1),new THREE.MeshLAmbertMaterial({ color: '#cccccc' })); cube.overdraw = true; cube.rotation.x = Math.PI * 0.1; cube.rotation.y = Math.PI * 0.3; scene.add(cube); // add subtle ambient lighting var ambientLight = new THREE.AmbientLight(0x319ec5); scene.add(ambientLight); // directional lighting var directionalLight = new THREE.DirectionalLight(0x666666); directionalLight.position.set(1,1).normalize(); scene.add(directionalLight); shape = cube; // start animation animate(); var $= function(id) { return document.getElementById(id); }; $('btn').onclick = function() { console.log("Button Clicked"); var width = parseInt(document.getElementById('inp-width').value * 3.779528),height = parseInt(document.getElementById('inp-height').value * 3.779528),length = parseInt(document.getElementById('inp-length').value * 3.779528); console.log("length " + length + " height " + height + " width " + width); shape.scale.x = length; shape.scale.y = height; shape.scale.z = width; };
这是同样的小提琴! http://jsfiddle.net/9Lvk61j3/
如果您需要任何其他信息,请与我们联系.
请建议.
解决方法
绘图尺寸有点问题:
>您可能拥有其中许多,并非所有这些都可能完全可见:
>有些可能是隐藏的,
>有些可能看起来太小,如果相机远离物体,
>有些可能覆盖其他维度(甚至是对象元素),
>有些可能从不方便的角度看出来.
>无论您如何导航相机,文本都应保持完全相同的大小,
我的解决方案中解决了大多数这些问题:https://jsfiddle.net/mmalex/j35p1fw8/
var geometry = new THREE.BoxGeometry(8.15,0.5,12.25); var material = new THREE.MeshphongMaterial({ color: 0x09f9f9,transparent: true,opacity: 0.75 }); var cube = new THREE.Mesh(geometry,material); cube.geometry.computeBoundingBox (); root.add(cube); var bBox = cube.geometry.boundingBox; var dim = new LinearDimension(document.body,renderer,camera); // define start and end point of dimension var from = new THREE.Vector3(bBox.min.x,bBox.min.y,bBox.min.z); var to = new THREE.Vector3(bBox.max.x,bBox.max.z); // in which direction to "extrude" dimension away from object var direction = new THREE.Vector3(0,1); // request LinearDimension to create threejs node var newDimension = dim.create(from,to,direction); // make it cube child cube.add(newDimension); var animate = function() { requestAnimationFrame(animate); // we need to reposition dimension label on each camera change dim.update(camera); renderer.render(scene,camera); };
我们现在看看辅助课程.
✔尺寸线仅在摄像机角度不太锐利(超过45°)时可见,
FacingCamera类会让你知道世界飞机,这是最好的相机.隐藏尺寸的有用,这些尺寸面向摄像机,角度太尖锐(锐角).
可以在这里找到与FacingCamera类分开的小提琴:https://jsfiddle.net/mmalex/56gzn8pL/
class FacingCamera { constructor() { // camera looking direction will be saved here this.dirVector = new THREE.Vector3(); // all world directions this.dirs = [ new THREE.Vector3(+1,0),new THREE.Vector3(-1,new THREE.Vector3(0,+1,-1,+1),-1) ]; // index of best facing direction will be saved here this.facingDirs = []; this.bestFacingDir = undefined; // Todo: add other facing directions too // event listeners are collected here this.cb = { facingDirChange: [] }; } check(camera) { camera.getWorldDirection(this.dirVector); this.dirVector.negate(); var maxk = 0; var maxdot = -1e19; var oldFacingDirs = this.facingDirs; var facingDirsChanged = false; this.facingDirs = []; for (var k = 0; k < this.dirs.length; k++) { var dot = this.dirs[k].dot(this.dirVector); var angle = Math.acos(dot); if (angle > -Math.PI / 2 && angle < Math.PI / 2) { this.facingDirs.push(k); if (oldFacingDirs.indexOf(k) === -1) { facingDirsChanged = true; } if (Math.abs(dot) > maxdot) { maxdot = dot; maxk = k; } } } // and if facing direction changed,notify subscribers if (maxk !== this.bestFacingDir || facingDirsChanged) { var prevDir = this.bestFacingDir; this.bestFacingDir = maxk; for (var i = 0; i < this.cb.facingDirChange.length; i++) { this.cb.facingDirChange[i]({ before: { facing: oldFacingDirs,best: prevDir },current: { facing: this.facingDirs,best: this.bestFacingDir } },this); } } } }
✔尺寸文本是HTML元素,使用CSS设置样式并使用three.js光线投射逻辑定位.
class LinearDimension使用箭头和文本标签创建线性尺寸的实例,并对其进行控制.
LinearDimension完整实现:
class LinearDimension { constructor(domroot,camera) { this.domroot = domroot; this.renderer = renderer; this.camera = camera; this.cb = { onChange: [] }; this.config = { headLength: 0.5,headWidth: 0.35,units: "mm",unitsConverter: function(v) { return v; } }; } create(p0,p1,extrude) { this.from = p0; this.to = p1; this.extrude = extrude; this.node = new THREE.Object3D(); this.hidden = undefined; let el = document.createElement("div"); el.id = this.node.id; el.classList.add("dim"); el.style.left = "100px"; el.style.top = "100px"; el.innerHTML = ""; this.domroot.appendChild(el); this.domElement = el; this.update(this.camera); return this.node; } update(camera) { this.camera = camera; // re-create arrow this.node.children.length = 0; let p0 = this.from; let p1 = this.to; let extrude = this.extrude; var pmin,pmax; if (extrude.x >= 0 && extrude.y >= 0 && extrude.z >= 0) { pmax = new THREE.Vector3( extrude.x + Math.max(p0.x,p1.x),extrude.y + Math.max(p0.y,p1.y),extrude.z + Math.max(p0.z,p1.z)); pmin = new THREE.Vector3( extrude.x < 1e-16 ? extrude.x + Math.min(p0.x,p1.x) : pmax.x,extrude.y < 1e-16 ? extrude.y + Math.min(p0.y,p1.y) : pmax.y,extrude.z < 1e-16 ? extrude.z + Math.min(p0.z,p1.z) : pmax.z); } else if (extrude.x <= 0 && extrude.y <= 0 && extrude.z <= 0) { pmax = new THREE.Vector3( extrude.x + Math.min(p0.x,extrude.y + Math.min(p0.y,extrude.z + Math.min(p0.z,p1.z)); pmin = new THREE.Vector3( extrude.x > -1e-16 ? extrude.x + Math.max(p0.x,extrude.y > -1e-16 ? extrude.y + Math.max(p0.y,extrude.z > -1e-16 ? extrude.z + Math.max(p0.z,p1.z) : pmax.z); } var origin = pmax.clone().add(pmin).multiplyScalar(0.5); var dir = pmax.clone().sub(pmin); dir.normalize(); var length = pmax.distanceto(pmin) / 2; var hex = 0x0; var arrowHelper0 = new THREE.ArrowHelper(dir,origin,length,hex,this.config.headLength,this.config.headWidth); this.node.add(arrowHelper0); dir.negate(); var arrowHelper1 = new THREE.ArrowHelper(dir,this.config.headWidth); this.node.add(arrowHelper1); // reposition label if (this.domElement !== undefined) { let textPos = origin.project(this.camera); let clientX = this.renderer.domElement.offsetWidth * (textPos.x + 1) / 2 - this.config.headLength + this.renderer.domElement.offsetLeft; let clientY = -this.renderer.domElement.offsetHeight * (textPos.y - 1) / 2 - this.config.headLength + this.renderer.domElement.offsetTop; let dimWidth = this.domElement.offsetWidth; let dimHeight = this.domElement.offsetHeight; this.domElement.style.left = `${clientX - dimWidth/2}px`; this.domElement.style.top = `${clientY - dimHeight/2}px`; this.domElement.innerHTML = `${this.config.unitsConverter(pmin.distanceto(pmax)).toFixed(2)}${this.config.units}`; } } detach() { if (this.node && this.node.parent) { this.node.parent.remove(this.node); } if (this.domElement !== undefined) { this.domroot.removeChild(this.domElement); this.domElement = undefined; } } }