问题
I have created a Three.js scene in which there is a globe (with an Earth texture) that can be rotated using OrbitControls.
I want to have labels that are "stuck" to a position on the globe i.e. a "Australia" label that is pinned to the Latitude & Longitude of the centre of Australia, which then moves with the Earth object when OrbitControls are used so that the pin always stays above it's location.
For various reasons (easier to content manage, easier to style etc...) I need these labels to be HTML elements (rather than a THREE.Sprite
for example). This makes things a lot trickier (in my eyes) as Three.js objects would easily rotate together, but HTML elements will not.
The easiest way for you to understand what I want is to look at an example, so the one linked below is pretty much exactly how I want my globe to work. You can see that they use a Three.js globe with HTML labels.
https://www.gsmlondon.ac.uk/global-oil-map/#1995-exporters
I have looked through their code and see that they are transforming/translating the HTML elements, but I cannot figure out the calculation that causes the HTML elements to always stay in the position they start in, perfectly above their respective countries.
I am using the below calculation to convert Latitude & Longitude coordinates (from google maps) into X, Y, Z coordinates to use in my three.js scene, and this works perfectly (i.e. I can create a small SphereGeometry
and place it at the generated coordinates and it will appear above the correct location)
function calcPosFromLatLonRad(lat, lon, radius){
let phi = (90 - (lat)) * (Math.PI / 180);
let theta = ((lon) + 180) * (Math.PI / 180);
let x = -((radius) * Math.sin(phi) * Math.cos(theta));
let z = ((radius) * Math.sin(phi) * Math.sin(theta));
let y = -((radius) * Math.cos(phi));
return [x, y, z];
}
To start off I am just trying to get the HTML elements to rotate on the X axis. I came up with the following code but it doesn't work correctly.
The below code is part of a function that sits inside the render function that uses RequestAnimationFrame
.
...element.style.transform = translate(${-Math.sin(camera.rotation.y) * 300}px,...
300 above being the radius of the globe (SphereGeometry
).
Does anyone have any idea how I can achieve an affect like the one achieved in the code I linked to? i.e. no matter the rotation of the scene, the pins are always in the correct position.
Thanks.
回答1:
Three.js has a converter that applies 3D transformations to your HTML elements. It's called CSS3DRenderer. You can see an example of it in action here.
It would save you a lot of time to use this tool instead of manually trying to figure out the positions/rotations of each element:
var scene = new THREE.Scene();
var sceneCSS = new THREE.Scene();
// Adding new CSS3DObjects to your scene:
var object = new THREE.CSS3DObject( HTMLElement );
sceneCSS.add(object);
var renderer = new THREE.WebGLRenderer();
var rendererCSS = new THREE.CSS3DRenderer();
var camera = new THREE.PerspectiveCamera();
onUpdate() {
// This will render your WebGL 3D Scene
renderer.render(scene, camera);
// This will apply 3DTransforms to your HTML elements
rendererCSS.render(sceneCSS, camera);
}
来源:https://stackoverflow.com/questions/53599154/transform-html-elements-in-conjunction-with-orbitcontrols-so-that-they-appear-to