I have my a 3D earth, with markers/labels for specific locations added onto it. I want my earth to rotate, and it does. However, all of the CSS2DObjects (The markers/labels) start shaking as the earth rotates. I am guessing this is due to the objects being added on top of the earth, and they are not actually part of it spinning? Here is my code:
(function ($) {
$(document).ready(function () {
/* Update/Add site values here, and they will display on earth view */
var sites = [];
//THREE JS setup variables
var camera, scene, renderer, labelRenderer;
var group;
init();
animate();
function init() {
const EARTH_RADIUS = 225;
const EARTH_SEGMENTS = 75;
const EARTH_RINGS = 75;
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 2000);
camera.position.set(-70, 375, 450);
scene = new THREE.Scene();
var light = new THREE.PointLight(0xffffff, 1, Infinity);
camera.add(light);
scene.add(camera);
//Starfield
var starGeometry = new THREE.SphereGeometry(1000, 50, 50);
var starMaterial = new THREE.MeshPhongMaterial({
map: new THREE.ImageUtils.loadTexture(basePath + 'Content/images/galaxy_starfield.png'),
side: THREE.DoubleSide,
shininess: 0
});
var starField = new THREE.Mesh(starGeometry, starMaterial);
scene.add(starField);
//Create group to hold sphere and texture
group = new THREE.Group();
scene.add(group);
//Create sphere and texture, and mesh together using texture loader
var loader = new THREE.TextureLoader();
loader.load(basePath + 'Content/images/earth_no_clouds_16k.jpg', function (texture) {
// Create the sphere
var sphere = new THREE.SphereGeometry(EARTH_RADIUS, EARTH_SEGMENTS, EARTH_RINGS);
// Map the texture to the material.
var material = new THREE.MeshBasicMaterial({
map: texture
//overdraw: 0.5,
//transparent: true,
//opacity: 0.9
});
// Create a new mesh with sphere geometry.
var mesh = new THREE.Mesh(sphere, material);
// Add mesh to globe
group.add(mesh);
});
scene.add(group);
//Add Sites to Earth
for (var i = 0; i < sites.length; i++) {
if (sites[i].lat != null && sites[i].lon != null) {
var name = sites[i].name;
var lat = sites[i].lat;
var lon = sites[i].lon;
var status = sites[i].status;
//Create dot for each site
var siteDiv = document.createElement('div');
siteDiv.className = 'dot';
siteDiv.setAttribute("id", name);
siteDiv.setAttribute("title", name);
siteDiv.style.backgroundColor =
status == "FMC" ? "green" :
status == "PMC" ? "yellow" : "red";
//Create label to append to each site's dot
var siteDivLabel = document.createElement('label');
siteDivLabel.setAttribute("id", name + '_label');
siteDivLabel.setAttribute("title", name + ' label');
siteDivLabel.textContent = name;
//Setting the label's class (Some labels need to display on different sides of the dot so that all can be seen in initial view.)
if (name == 'BU' || name == 'COD') {
siteDivLabel.className = 'label_top_right label-default';
} else if (name == 'FGA' || name == 'PAFB' || name == 'MDIOC') {
siteDivLabel.className = 'label_bottom_right label-default';
} else if (name == 'CMD') {
siteDivLabel.className = 'label_bottom_left label-default';
} else {
siteDivLabel.className = 'label_top_left label-default';
}
siteDiv.appendChild(siteDivLabel);
var siteDot = new THREE.CSS2DObject(siteDiv);
siteDiv.parent = siteDot;
siteDot.element.style.cursor = "pointer";
siteDot.element.onclick = function () { alert('clicked a site!') };
var sitePosition = calcPosFromLatLonRad(lat, lon, EARTH_RADIUS);
// Some code to manually move certain site markers so that they don't overlap each other too much.
if (name == 'BO') {
siteDot.position.set(sitePosition[0] - 1, sitePosition[1] + 1, Math.abs(sitePosition[2]));
} else if (name == 'CMD') {
siteDot.position.set(sitePosition[0] - 1, sitePosition[1] - 1, Math.abs(sitePosition[2]));
} else if (name == 'PAFB') {
siteDot.position.set(sitePosition[0] + 1, sitePosition[1] - 6, Math.abs(sitePosition[2]));
} else if (name == 'MDIOC') {
siteDot.position.set(sitePosition[0] + 5, sitePosition[1] + 4, Math.abs(sitePosition[2]));
} else if (name == 'BU') {
siteDot.position.set(sitePosition[0] + 2, sitePosition[1] + 3, Math.abs(sitePosition[2]));
} else {
siteDot.position.set(sitePosition[0], sitePosition[1], Math.abs(sitePosition[2]));
}
group.add(siteDot);
}
}
renderer = new THREE.WebGLRenderer({ alpha: true });
renderer.setClearColor(0xffffff, 0);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
$('#earth_container').append(renderer.domElement);
labelRenderer = new THREE.CSS2DRenderer();
labelRenderer.setSize(window.innerWidth, window.innerHeight);
labelRenderer.domElement.style.position = 'absolute';
labelRenderer.domElement.style.top = 0;
document.body.appendChild(labelRenderer.domElement);
//For rotation and mouse controls
var controls = new THREE.OrbitControls(camera, labelRenderer.domElement);
}
function animate() {
//group.rotation.y -= .0004;
requestAnimationFrame(animate);
renderer.render(scene, camera);
labelRenderer.render(scene, camera);
//requestAnimationFrame(render);
}
/* Referenced from answer found here:
https://stackoverflow.com/questions/28365948/javascript-latitude-longitude-to-xyz-position-on-earth-threejs
*/
function calcPosFromLatLonRad(lat, lon, radius) {
var phi = (90 - lat) * (Math.PI / 180)
var theta = (lon + 180) * (Math.PI / 180)
x = -((radius) * Math.sin(phi) * Math.cos(theta))
z = ((radius) * Math.sin(phi) * Math.sin(theta))
y = ((radius) * Math.cos(phi))
return [x, y, z];
}
}); /* END DOCUMENT READY */
}(jQuery));