Add marker to rotating globe object help

Hey guys,

I need some help/guidance with a project of mine. I’m currently building a website for myself and I’m looking to break common web-conventions.

The problem I’m currently having with my little knowledge of Three.js and js in general is how to add a marker to a globe and have it rotate with the globe. Preferably I would like the marker to be shaded if it is on the other end of the globe.

I have seen demo websites do sort of what I’m looking for but I can’t figure out their code for the life of me.

Attached is a photo (done in paint)concept concept of what I’m looking for.

I’m a college student so I can’t offer much incentive but if you would like to be paid I can see what I can scrap up.

There are several ways to achieve the desired result. One of them is to use THREE.Sprite() with a texture, another one is to use a simple plane with a texture and quaternion of a camera (and its behaviour will be equal to THREE.Sprite()). Creativity is up to you :slight_smile:

1 Like

Maybe that’s how you can do it :question:

If you go there http://sandboxthreep.threejs.hofk.de/
and mark vertex- face index you will see the numbers attached to the ball.
Also take wireframe.
20171102-1732-30609

The numbers are on invisible panels / boards. Other things can also be pinned there.
board.add( … );

The code is in the function vertexFaceNumbersHelper (mesh, mode, size, color) of THREEp. js.

Also on GitHub https://github.com/hofk/THREEp.js

1 Like

So you guys are suggesting creating a Sprite/Plane and assign that object to a vertex on my Globe?

Would it spin with the globe?

Because the code in vertexFaceNumbersHelper from THREEp. js is not easy, I made a very simple example.

Try it out at http://threejs.hofk.de/knoten/pinned.html
See the code with Ctrl U.

You can add lines to connect to the ball and you can pin other things and use only a few boards.

20171102-2130-14615


<!doctype html>
<html lang="de">
<head>
	<title> picture ball </title>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
</head>
<body>

	<script src="../js/three.min.87.js"></script>
	<script src="../js/OrbitControls.js"></script>
	<script src="../js/THREEx.WindowResize.js"></script>
	<div id="threejs" style="position: absolute; left:0px; top:0px"></div>
	
</body>

<script>

var boards = []; 
var texture = []; 
var matTexture = [];

init();
animate();

//...........................

function init() {	

	scene  = new THREE.Scene();
	camera = new THREE.PerspectiveCamera( 45, window.innerWidth/ window.innerHeight,1, 300000 );
	scene.add( camera );
	camera.position.set( 0, 1500, 5000 );	
	renderer = new THREE.WebGLRenderer( { antialias:true } );	
	renderer.setSize( window.innerWidth, window.innerHeight );
	renderer.setClearColor( 0xeeeeee );
	container = document.getElementById( 'threejs' );
	container.appendChild( renderer.domElement );
	THREEx.WindowResize( renderer, camera );
	controls = new THREE.OrbitControls( camera, renderer.domElement );
	
	texture[0] = new THREE.TextureLoader().load( "waterlily.png" );
	texture[1] = new THREE.TextureLoader().load( "dahlia.jpg" ); 
	texture[2] = new THREE.TextureLoader().load( "petunia.jpg" );
	texture[3] = new THREE.TextureLoader().load( "frog.jpg" );
	
	for (var z = 0; z < 4; z++) { 
	
		matTexture[z] = new THREE.MeshBasicMaterial( { color:0xffdd99, map: texture[z], transparent:true, opacity:0.8, wireframe:false} ); 	
  	}
	
	// ball
	materialSph = new THREE.MeshBasicMaterial( { color: 0x0099dd, transparent: true, opacity: 0.8, wireframe:false } );
	sphGeo  = new THREE.SphereGeometry(1200, 8, 8);             
	sphere = new THREE.Mesh( sphGeo, materialSph );	 
	scene.add( sphere );
 	
	// board for some things	
	materialBoard   = new THREE.MeshBasicMaterial({color:0xdddddd, transparent:true, opacity:0.4, wireframe: true });
	boardGeo  = new THREE.PlaneGeometry(500,500);
	
	picGeo = new THREE.PlaneGeometry( 200, 200 );
	  
	for (var i = 0; i < sphGeo.vertices.length; i++)	{ 	
	
		board = new THREE.Mesh( boardGeo, materialBoard );  		// board for pictures etc.  
		
		pic = new THREE.Mesh( picGeo, matTexture[ i % 4 ] );
		
		board.add( pic ) ;                                      		//  add picture to the board
		
		pic.position.x = -70;										// position on the board
		pic.position.y = 120;
		
		boards.push( board );	                               				
		scene.add( boards[ i ] );                           		
		
		boards[ i ].position.set( 1.3 * sphGeo.vertices[ i ].x , 1.3 * sphGeo.vertices[ i ].y, 1.3 * sphGeo.vertices[ i ].z ); 
		
	}	
	
} 

function animate() {

    requestAnimationFrame( animate );
	
	 for( var n = 0; n < boards.length; n ++ ) {
		
		boards[ n ].lookAt( camera.position );
		
	 }	
	 
	renderer.render( scene, camera );	
	
	controls.update();
}
</script>
</html>
1 Like

Just an idea: boards[ n ].quaternion.copy(camera.quaternion); instead of boards[ n ].lookAt( camera.position ); should give the same behaviour as of THREE.Sprite().

1 Like

Yes, if you add a sprite/plane to the globe mesh as a child.

1 Like

The quaternation of course gives a better alignment of the boards.
. lookAt may be easier for beginners to understand?

I have added the example to my collection of beginner’s examples.
http://threejs.hofk.de/

1 Like

Ok so first I would like to thank you guys for how helpful you are being.

Secondly, Drexel Co-op cycle for me starts tomorrow and I’ve been very busy getting my Resumes ready.
So, what i’m trying to say is expect a update of how things went, from me probably around Tuesday :smiley:

So, I edited down your code to understand what was going on better. But I have one last problem the photos can’t be clicked on :frowning:

image
Here is my edited version of your code and this tutorial https://stackoverflow.com/questions/24690731/three-js-3d-models-as-hyperlink, i’m guessing my problem is the canvas? not sure. I realize i didn’t ask this in my original question, my apologizes.

    <script src="/js/three.min.js"></script>
    <script src="/Teest/three.min.87.js"></script>
	<script src="../js/OrbitControls.js"></script>
    <script src="/Teest/THREEx.WindowResize.js"></script>
	<div id="threejs" style="position: absolute; left:0px; top:0px"></div>
	
</body>

<script>

var boards = []; 
var texture = []; 
var matTexture = [];
var container;
var projector;

init();
animate();

//...........................

function init() {	

    projector = new THREE.Projector();
    scene  = new THREE.Scene();
	camera = new THREE.PerspectiveCamera( 45, window.innerWidth/ window.innerHeight,1, 300000 );
	scene.add( camera );
	camera.position.set( 0, 1500, 5000 );	
	renderer = new THREE.WebGLRenderer( { antialias:true } );	
	renderer.setSize( window.innerWidth, window.innerHeight );
	renderer.setClearColor( 0xeeeeee );
	container = document.getElementById( 'threejs' );
	container.appendChild( renderer.domElement );
	THREEx.WindowResize( renderer, camera );
	controls = new THREE.OrbitControls( camera, renderer.domElement );
	
	texture[0] = new THREE.TextureLoader().load( "Instagram.png" );
	
    matTexture[0] = new THREE.MeshBasicMaterial( { color:0xffffff, map: texture[0], transparent:true, opacity:1, wireframe:false} ); 	
	
	// ball
	materialSph = new THREE.MeshBasicMaterial( { color: 0x0099dd, transparent: true, opacity: 0.8, wireframe:false } );
	sphGeo  = new THREE.SphereGeometry(1200, 8, 8);             
	sphere = new THREE.Mesh( sphGeo, materialSph );	 
	scene.add( sphere );
 	
	// board for some things	
	materialBoard   = new THREE.MeshBasicMaterial({color:0xdddddd, transparent:true, opacity:0.4, wireframe: true });
	boardGeo  = new THREE.PlaneGeometry(500,500);
	
	picGeo = new THREE.PlaneGeometry( 500, 500 );
	
		board = new THREE.Mesh( boardGeo, materialBoard );              // board for pictures etc.  
           board.userData = { URL: "http://stackoverflow.com"};     
		pic = new THREE.Mesh( picGeo, matTexture[ 0 ] );		
		board.add( pic ) ;                                      		//  add picture to the board
		
		
		boards.push( board );
        
		scene.add( boards[ 0 ] );                           		
		
		boards[ 0 ].position.set( 1 * sphGeo.vertices[ 10 ].x , 0.5 * sphGeo.vertices[ 2 ].y, 1.8 * sphGeo.vertices[ 10 ].z ); 
	
   
    document.addEventListener('mousedown', onDocumentMouseDown, false);
} 

function onDocumentMouseDown(event) {
    event.preventDefault();
    var vector = new THREE.Vector3((event.clientX / window.innerWidth) * 2 -
        1, -(event.clientY / window.innerHeight) * 2 + 1, 0.5);
    projector.unprojectVector(vector, camera);
    var raycaster = new THREE.Raycaster(camera.position, vector.sub(camera.position)
        .normalize());
    var intersects = raycaster.intersectObjects(objects);
    if (intersects.length > 0) {
        window.open(intersects[0].object.userData.URL);
    }
}

function animate() {

    requestAnimationFrame( animate );
	
	 for( var n = 0; n < boards.length; n ++ ) {
		
		//boards[ n ].lookAt( camera.position );
		boards[ n ].quaternion.copy( camera.quaternion );
	 }	
	 
	renderer.render( scene, camera );	
	
	controls.update();
}
</script>
</html>

THREE.Raycaster() has .setFromCamera() method, which makes work with it syntactically clearer.

Have you looked at your browser console? I got an error message that objects is undefined, you should pass boards (looks like you just copied and pasted the code from somewhere)

That works:

var mouse = new THREE.Vector2();
var raycaster = new THREE.Raycaster();

function onDocumentMouseDown(event) {
  
  event.preventDefault();
  mouse.set(
    (event.clientX / window.innerWidth) * 2 - 1, 
    -(event.clientY / window.innerHeight) * 2 + 1
  );
  raycaster.setFromCamera( mouse, camera );
  var intersects = raycaster.intersectObjects( boards );
  if ( intersects.length > 0 ) {
    window.open( intersects[0].object.userData.URL );
  }
  
}

jsfiddle example

1 Like

Yea I got the code from the tutorial and in mine I did change it to boards however I didn’t have the rest.

Thank you for your help guys It completely works!

You’re amazing. :slight_smile:

If the ball should become boring, you can also use other geometries.

An example20171107-2138-42432

<!doctype html>
<html lang="de">
<head>
	<title> picture coil </title>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
</head>
<body>

	<script src="../js/three.min.87.js"></script>
	<script src="../js/OrbitControls.js"></script>
	<script src="../js/THREEx.WindowResize.js"></script>
	
	<!--  https://github.com/hofk/THREEf.js/blob/master/THREEf_87/THREEf.js -->
	<script src="../js/THREEf.js"></script>
	
	<div id="threejs" style="position: absolute; left:0px; top:0px"></div>
	
</body>

<script>

var boards = []; 
var texture = []; 
var matTexture = [];

init();
animate();

//...........................

function init() {	

	scene  = new THREE.Scene();
	camera = new THREE.PerspectiveCamera( 75, window.innerWidth/ window.innerHeight,1, 100000 );
	scene.add( camera );
	camera.position.set( -200, 500, 12000 );	
	renderer = new THREE.WebGLRenderer( { antialias:true } );	
	renderer.setSize( window.innerWidth, window.innerHeight );
	renderer.setClearColor( 0xeeeeee );
	container = document.getElementById( 'threejs' );
	container.appendChild( renderer.domElement );
	THREEx.WindowResize( renderer, camera );
	controls = new THREE.OrbitControls( camera, renderer.domElement );
	
	texture[0] = new THREE.TextureLoader().load( "waterlily.png" );
	texture[1] = new THREE.TextureLoader().load( "dahlia.jpg" ); 
	texture[2] = new THREE.TextureLoader().load( "petunia.jpg" );
	texture[3] = new THREE.TextureLoader().load( "frog.jpg" );
	
	for (var z = 0; z < 4; z++) { 
	
		matTexture[z] = new THREE.MeshBasicMaterial( { map: texture[z], transparent:true, opacity:0.8, wireframe:false} ); 	
  	}

	// coil generated with addon THREEf.js 
	var geometry = new THREE.Geometry(); 
	
	geometry.createMorphGeometry = THREEf.createMorphGeometry;  // insert the methode from THREEf.js
	
	// apply the methode with some parameters
	geometry.createMorphGeometry({

		radius: 200,
		height: 600,
		radiusSegments: 18,
		heightSegments: 80,
		withBottom: true,
		withTop: true,
		centerX: function ( v, t ) { return 2 * Math.sin( 6 * Math.PI * v ) },
		centerY: function ( v, t ) { return v * ( v + 10 ) },
		centerZ: function ( v, t ) { return 2 * Math.cos( 6 * Math.PI * v ) }
		
	});
	
	var material = new THREE.MeshBasicMaterial( { color: 0x0099dd, transparent: true, opacity: 0.8, wireframe:false } );
	
	var mesh = new THREE.Mesh( geometry, material );
	scene.add( mesh );
 	
	// board for some things	
	materialBoard   = new THREE.MeshBasicMaterial({color:0xdd00dd, transparent:true, opacity:0.5, wireframe: false });
	boardGeo  = new THREE.PlaneGeometry(500,500);
	
	picGeo = new THREE.PlaneGeometry( 160, 160 );
	 
	idx = 0;  
	for (var i = 0; i < geometry.vertices.length; i++)	{ 	
	
		if ( i % 32 === 0) {
	
			board = new THREE.Mesh( boardGeo, materialBoard );  		// board for pictures etc.  
			
			pic1 = new THREE.Mesh( picGeo, matTexture[ idx % 4 ] );
			pic2 = new THREE.Mesh( picGeo, matTexture[ ( idx % 4 ) % 2 ] );
			
			board.add( pic1 );                                      	//  add picture to the board
			board.add( pic2 );
			
			pic1.position.x = -70;										// position on the board	
			pic1.position.y = 120;
			pic1.position.z = 20;
					
			pic2.position.x = 80;											
			pic2.position.y = -120;
			pic2.position.z = 20;
			
			boards.push( board );
						
			scene.add( boards[ idx ] );                           		
			
			boards[ idx ].position.set( 1.4 * geometry.vertices[ i ].x ,  geometry.vertices[ i ].y + 300, 1.4 * geometry.vertices[ i ].z ); 
		
			idx ++;
			
		}
		
	}	
	
} 

function animate() {

    requestAnimationFrame( animate );
	
	 for( var n = 0; n < boards.length; n ++ ) {
		
		boards[ n ].quaternion.copy( camera.quaternion );
	 }	
	 
	renderer.render( scene, camera );	
	
	controls.update();
}
</script>
</html>
2 Likes

I just implemented my code but currently looking for a fix as the planegeometry does not update its position if the ball is rotating

Because you add each board to the scene instead of to the sphere.

1 Like

Fixed thank you.

So I let it run, rotating for about a minute and this happened image
As you can see the Instagram frame is no longer looking towards the camera.

Any error messages in the console?

No only warnings about Texture loader

Hi, Any update? I need the correct code for spinning earth with marker icons. Please help. I am new to three.js