jharv
November 1, 2017, 5:37am
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.
1 Like
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
1 Like
hofk
November 2, 2017, 4:34pm
3
Maybe that’s how you can do it
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 GitHub - hofk/THREEp.js: three.js addon, to produce almost infinite many time-varying geometries / buffer geometries with polar / spherical coordinate functions
1 Like
jharv
November 2, 2017, 8:24pm
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?
hofk
November 2, 2017, 8:32pm
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.
<!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>
2 Likes
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
hofk
November 3, 2017, 5:29pm
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/
1 Like
jharv
November 3, 2017, 9:28pm
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
jharv
November 7, 2017, 1:12am
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
Here is my edited version of your code and this tutorial
javascript - three.js 3d models as hyperlink - Stack Overflow , 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
jharv
November 7, 2017, 7:33pm
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.
hofk
November 7, 2017, 8:43pm
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>
2 Likes
jharv
November 7, 2017, 8:57pm
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
Because you add each board to the scene instead of to the sphere.
1 Like
jharv
November 7, 2017, 9:18pm
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.
Any error messages in the console?
jharv
November 20, 2017, 10:30pm
19
No only warnings about Texture loader
Jom
December 26, 2017, 12:49pm
20
Hi, Any update? I need the correct code for spinning earth with marker icons. Please help. I am new to three.js