Transform HTML elements in conjunction with OrbitControls so that they appear to rotate with the objects in the scene

|▌冷眼眸甩不掉的悲伤 提交于 2020-03-05 03:34:08

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!