I am trying to position a div such that it is always at the highest point of an object offset left and up a little so it is not right on top of the vertex. You can see that here. Please see the working with no scene rotation snippet below if the jsfiddle link no longer works. I can tell you, it works fairly marvellously.
However, for a project at work, I need to rotate the scene, itself. Apparently, this messes up the conversion to 2D screen coordinates. You can view this here. You can view the not working with scene rotation snippet below as well. As you can see, the label does not update in the vertical ("y-") direction, but it does update "horizontally". This would be because the camera's position does, indeed, change around the x-z plane (phi changes), but it never changes its y-position (theta never changes)--rather the scene is rotated when the mouse is dragged up/down. As I wrote, I need to rotate the scene to achieve the desired affect.
If someone could point me in the right direction or make a quick example in any of the html/js/css snippet sites (like jsfiddle, etc, etc), {,s}he would be a life-saver!
side-note: I tried (with no success, obviously) to jump through some hoops to convert the x- and y-coordinates for each vertex to a "properly-rotated" position (ie, by multiplying by
sin(sceneRotation)
andcos(sceneRotation)
, but that just made it even worse.side-note 2: I also just spent an hour rotating each object in the scene, but since the objects are actually stored in
THREE.Group
s, it has the exact same effect.
working with no scene rotation
click run snippet below
var scene = new THREE.Scene();
var w = window.innerWidth, h = window.innerHeight;
var camera = new THREE.PerspectiveCamera(60, w / h, 1, 1000);
camera.position.set(0, 0, -60);
var renderer = new THREE.WebGLRenderer({
alpha: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.domElement.style.backgroundColor = "#bbbbbb"
document.body.appendChild(renderer.domElement);
var label = document.getElementById("label");
var controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.addEventListener("change", updateLabel);
var geom = new THREE.Geometry();
geom.vertices.push(new THREE.Vector3(-10, 10, -10));
geom.vertices.push(new THREE.Vector3(10, 10, -10));
geom.vertices.push(new THREE.Vector3(10, -10, -10));
geom.vertices.push(new THREE.Vector3(-10, -10, -10));
geom.vertices.push(new THREE.Vector3(-10, 10, 10));
geom.vertices.push(new THREE.Vector3(10, 10, 10));
geom.vertices.push(new THREE.Vector3(10, -10, 10));
geom.vertices.push(new THREE.Vector3(-10, -10, 10));
geom.faces.push(new THREE.Face3(0, 1, 2));
geom.faces.push(new THREE.Face3(0, 2, 3));
geom.faces.push(new THREE.Face3(7, 6, 5));
geom.faces.push(new THREE.Face3(7, 5, 4));
geom.faces.push(new THREE.Face3(4, 5, 1));
geom.faces.push(new THREE.Face3(4, 1, 0));
geom.faces.push(new THREE.Face3(3, 2, 6));
geom.faces.push(new THREE.Face3(3, 6, 7));
geom.faces.push(new THREE.Face3(4, 0, 3));
geom.faces.push(new THREE.Face3(4, 3, 7));
geom.faces.push(new THREE.Face3(1, 5, 6));
geom.faces.push(new THREE.Face3(1, 6, 2));
var mat = new THREE.MeshBasicMaterial({ color: 0x3377dd, transparent: true, opacity: .65, wireframe: false });
var cube = new THREE.Mesh(geom, mat);
scene.add(cube);
var matWire = new THREE.MeshBasicMaterial({ color: 0xffffff, wireframe: true });
var cube1 = new THREE.Mesh(geom, matWire);
scene.add(cube1);
render();
function render() {
requestAnimationFrame(render);
renderer.render(scene, camera);
}
function getScreenPosition(position) {
var vector = new THREE.Vector3( position.x, position.y, position.z );
vector.project(camera);
vector.x = Math.round( ( vector.x + 1 ) * w / 2 );
vector.y = Math.round( ( - vector.y + 1 ) * h / 2 );
return vector;
}
function updateLabel() {
var minY = null, x = null,
verts = cube.geometry.vertices;
for (var i = 0, iLen = verts.length; i < iLen; i++) {
var pos = getScreenPosition(verts[i]);
if (minY === null || pos.y < minY) {
minY = pos.y;
x = pos.x;
}
}
label.style.left = (x - 3) + "px";
label.style.top = (minY - 28) + "px";
}
body {
overflow: hidden;
margin: 0;
}
#label {
position: absolute;
left: 20px; top: 20px;
}
<div id="label">label</div>
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
not working with scene rotation
click run snippet below
/* "globals" */
/* ~~~~~~~~~ */
var PI = Math.PI;
/* camera stuff */
var lastX, lastY, r = 60, phi = 0, c = new THREE.Vector3(0, 0, 0);
/* three.js stuff */
var scene = new THREE.Scene();
var w = window.innerWidth, h = window.innerHeight;
var camera = new THREE.PerspectiveCamera(60, w / h, 1, 1000);
//camera.position.set(0, 0, -60);
updateCamera();
var renderer = new THREE.WebGLRenderer({
alpha: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.domElement.style.backgroundColor = "#bbbbbb"
document.body.appendChild(renderer.domElement);
var label = document.getElementById("label");
//var controls = new THREE.OrbitControls(camera, renderer.domElement);
//controls.addEventListener("change", updateLabel);
document.body.addEventListener("mousedown", handleMouseDown);
document.body.addEventListener("touchstart", handleTouchStart);
var geom = new THREE.Geometry();
geom.vertices.push(new THREE.Vector3(-10, 10, -10));
geom.vertices.push(new THREE.Vector3(10, 10, -10));
geom.vertices.push(new THREE.Vector3(10, -10, -10));
geom.vertices.push(new THREE.Vector3(-10, -10, -10));
geom.vertices.push(new THREE.Vector3(-10, 10, 10));
geom.vertices.push(new THREE.Vector3(10, 10, 10));
geom.vertices.push(new THREE.Vector3(10, -10, 10));
geom.vertices.push(new THREE.Vector3(-10, -10, 10));
geom.faces.push(new THREE.Face3(0, 1, 2));
geom.faces.push(new THREE.Face3(0, 2, 3));
geom.faces.push(new THREE.Face3(7, 6, 5));
geom.faces.push(new THREE.Face3(7, 5, 4));
geom.faces.push(new THREE.Face3(4, 5, 1));
geom.faces.push(new THREE.Face3(4, 1, 0));
geom.faces.push(new THREE.Face3(3, 2, 6));
geom.faces.push(new THREE.Face3(3, 6, 7));
geom.faces.push(new THREE.Face3(4, 0, 3));
geom.faces.push(new THREE.Face3(4, 3, 7));
geom.faces.push(new THREE.Face3(1, 5, 6));
geom.faces.push(new THREE.Face3(1, 6, 2));
var mat = new THREE.MeshBasicMaterial({ color: 0x3377dd, transparent: true, opacity: .65, wireframe: false });
var cube = new THREE.Mesh(geom, mat);
//cube.translateX(10);
scene.add(cube);
var matWire = new THREE.MeshBasicMaterial({ color: 0xffffff, wireframe: true });
var cube1 = new THREE.Mesh(geom, matWire);
//cube1.translateX(10);
scene.add(cube1);
render();
function render() {
requestAnimationFrame(render);
renderer.render(scene, camera);
}
function getScreenPosition(position) {
var vector = new THREE.Vector3( position.x, position.y, position.z );
vector.project(camera);
vector.x = Math.round( ( vector.x + 1 ) * w / 2 );
vector.y = Math.round( ( - vector.y + 1 ) * h / 2 );
return vector;
}
function updateLabel() {
var minY = null, x = null,
verts = cube.geometry.vertices;
for (var i = 0, iLen = verts.length; i < iLen; i++) {
var pos = getScreenPosition(verts[i]);
if (minY === null || pos.y < minY) {
minY = pos.y;
x = pos.x;
}
}
label.style.left = (x - 3) + "px";
label.style.top = (minY - 28) + "px";
}
function handleMouseDown(ev) {
ev.preventDefault();
mouseOrTouchDown(ev.pageX, ev.pageY);
}
function handleTouchStart(ev) {
var touches = ev.touches;
if (touches.length !== 1) {
return;
}
ev.preventDefault();
mouseOrTouchDown(touches.item(0).pageX, touches.item(0).pageY, true);
}
function mouseOrTouchDown(downX, downY, touch) {
if (touch === undefined) { touch = false; }
lastX = downX;
lastY = downY;
if (touch) {
document.ontouchmove = handleTouchMove;
document.addEventListener("touchend", function(ev) {
document.ontouchmove = null;
});
document.addEventListener("touchcancel", function(ev) {
document.removeEventListener("touchmove", handleTouchMove);
});
} else {
document.addEventListener("mousemove", handleMouseMove);
document.addEventListener("mouseup", function(ev) {
document.removeEventListener("mousemove", handleMouseMove);
});
}
}
function handleMouseMove(ev) {
ev.preventDefault();
mouseOrTouchMove(ev.pageX, ev.pageY);
}
function handleTouchMove(ev) {
var touches = ev.touches;
if (touches.length !== 1) {
return;
}
ev.preventDefault();
mouseOrTouchMove(touches.item(0).pageX, touches.item(0).pageY);
}
function mouseOrTouchMove(x, y) {
var dx = lastX - x, dy = y - lastY; /* change in {x, y} */
phi -= dx / 100;
if (phi > 2 * PI) {
phi -= 2 * PI;
} else if (phi < 0) {
phi += 2 * PI;
}
if (phi < PI / 2 || phi > 3 * PI / 2) {
sign = -1;
} else {
sign = 1;
}
if (scene.rotation.z + sign * dy / 100 < -PI) {
scene.rotation.z = -PI;
} else if (scene.rotation.z + sign * dy / 100 > 0) {
scene.rotation.z = 0;
} else {
scene.rotateZ(sign * dy / 100);
}
lastX = x;
lastY = y;
updateCamera();
updateLabel();
}
function updateCamera() {
var z = r * Math.sin(phi); /* new y pos (z-axis) in x-z plane */
var x = r * Math.cos(phi); /* new x pos (x-axis) in x-z plane */
camera.position.set(x, 1, z);
camera.lookAt(c);
}
body {
overflow: hidden;
margin: 0;
}
#label {
position: absolute;
left: 20px; top: 20px;
}
<div id="label">label</div>
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>