admin管理员组文章数量:1297083
Can we draw "lines" with Cube to show "Dimensions" at run time?
Here is how I have created the cube and getting dimensions from user and changing the cube at run time: /
But now I want to show the Dimension, so the user knows what the length, width, and height is, which they will be changing.
This is what I am trying to make as end result:
Here is my code: HTML:
<script src=".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, 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, 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;
};
Here is the Fiddle for the same! /
Let me know if you need any other information.
Please suggest.
Can we draw "lines" with Cube to show "Dimensions" at run time?
Here is how I have created the cube and getting dimensions from user and changing the cube at run time: http://jsfiddle/9Lvk61j3/
But now I want to show the Dimension, so the user knows what the length, width, and height is, which they will be changing.
This is what I am trying to make as end result:
Here is my code: HTML:
<script src="http://www.html5canvastutorials./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, 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, 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;
};
Here is the Fiddle for the same! http://jsfiddle/9Lvk61j3/
Let me know if you need any other information.
Please suggest.
Share Improve this question edited Aug 22, 2014 at 7:11 user128511 asked Aug 21, 2014 at 17:37 UIDUID 4,49411 gold badges47 silver badges76 bronze badges 2- 2 you may need to use some ArrowHelper http://jsfiddle/9Lvk61j3/1/ and fix the scale and position on "btn" click – Abraham Uribe Commented Aug 21, 2014 at 18:45
- 1 Thanks for looking into it!!! Can you please help with creating a working example with arrows showing atleast Height and Width both... Also is there any way to show both side arrows? If not can I simply replace the same code with line? Thanks one again... Also please update ur post in the answer so I can accept... – UID Commented Aug 21, 2014 at 19:16
1 Answer
Reset to default 7There's a bit of a problem with drawing dimensions:
- You may have many of them, and not all of them may be perfectly visible:
- some may be hidden,
- some may appear too small, if the camera is far away from the object,
- some may overlay other dimensions (or even object elements),
- some may be seen from inconvenient angle.
- The text should retain perfectly same size, no matter how you navigate camera,
Most of these points are addressed in my solution: https://jsfiddle/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.puteBoundingBox ();
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.min.y, bbox.max.z);
// in which direction to "extrude" dimension away from object
var direction = new THREE.Vector3(0, 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);
};
Let's see into helper classes now.
✔ Dimension line is only visible when camera angle is not too sharp (more than 45°),
class FacingCamera
will let you know world plane, that is best facing to the camera. Useful to hide dimensions, which are facing camera with too sharp (acute) angle.
Separate fiddle to play with class FacingCamera
can be found here: https://jsfiddle/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, 0),
new THREE.Vector3(-1, 0, 0),
new THREE.Vector3(0, +1, 0),
new THREE.Vector3(0, -1, 0),
new THREE.Vector3(0, 0, +1),
new THREE.Vector3(0, 0, -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);
}
}
}
}
✔ Dimension text is HTML element, styled with CSS and positioned with three.js raycasting logic.
class LinearDimension
creates an instance of linear dimension with arrows and text label, and controls it.
LinearDimension plete implementation:
class LinearDimension {
constructor(domRoot, renderer, 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, p1.x),
extrude.y + Math.min(p0.y, p1.y),
extrude.z + Math.min(p0.z, p1.z));
pmin = new THREE.Vector3(
extrude.x > -1e-16 ? extrude.x + Math.max(p0.x, p1.x) : pmax.x,
extrude.y > -1e-16 ? extrude.y + Math.max(p0.y, p1.y) : pmax.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, origin, length, hex, this.config.headLength, 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;
}
}
}
本文标签: javascriptDraw dimension lines along with 3D cube using ThreejsStack Overflow
版权声明:本文标题:javascript - Draw dimension lines along with 3D cube using Three.js - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741619116a2388705.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论