Add marker to rotating globe object help

geometry

#1

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 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.


#2

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:


#3

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.

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


#4

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?


#5

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>

#6

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().


#7

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


#8

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/


#9

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:


#10

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:


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>

#11

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


#12

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:


#13

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

An example

<!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>

#14

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


#15

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


#16

Fixed thank you.


#17

So I let it run, rotating for about a minute and this happened


As you can see the Instagram frame is no longer looking towards the camera.


#18

Any error messages in the console?


#19

No only warnings about Texture loader


#20

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