How to get LatLng by clicking on rotating sphere (three.js)? - javascript

1) create earth object
self.earth = new THREE.Mesh(new THREE.SphereGeometry(50, 32, 32), new THREE.MeshBasicMaterial({map: tex}));
THREE.ImageUtils.crossOrigin = '';
self.obj = new THREE.Object3D();
self.obj.add(self.earth);
// self.obj.rotation.y = 34.3;
2) intersects
var mouse3D = new THREE.Vector3( );
var raycaster = new THREE.Raycaster();
mouse3D.set( ( (event.clientX) / window.innerWidth ) * 2 - 1, -( (event.clientY) / window.innerHeight ) * 2 + 1, 0.5 ).unproject(self.camera);raycaster.set(self.camera.position, mouse3D.sub(self.camera.position ).normalize());
var intersects = raycaster.intersectObject( self.earth );
if (intersects.length > 0) {
object = intersects[0];
r = 50; // radius
x = object.point.x ;
y = object.point.y ;
z = object.point.z ;
3) coords
var lat = ( 90 - (Math.acos(y / r)) * 180 / Math.PI ) - 10;
var lon = ((270 + (Math.atan2(x , z)) * 180 / Math.PI) % 360) - 10;
Its work, but rotating (self.obj.rotation.y = 34.3;) broke calculating, why?

Related

Create a BoxGeometry 16x16 Grid relative to viewport size with Three.js

The question goes as simple as it can, the title pretty much describes what I'm trying to do.
I'm new to Three.js and WebGL, I more or less understand the basics of creating a Cube but when it comes to what I'm trying to do I'm at loss.
I'm basically using this pen as reference while I learn: https://codepen.io/jackrugile/pen/vOEKzw as it does what I want without it being relative to screen size
var tick = 0,
smallestDimension = Math.min(window.innerWidth, window.innerHeight),
viewportWidth = smallestDimension,
viewportHeight = smallestDimension,
worldWidth = 100,
worldHeight = 100,
rows = 30,
cols = 30,
tileWidth = worldWidth / cols,
tileHeight = worldHeight / rows,
FOV = 90,
scene = new THREE.Scene(),
camera = new THREE.PerspectiveCamera(
FOV,
viewportWidth / viewportHeight,
0.1,
1000
),
renderer = new THREE.WebGLRenderer({
antialias: true
}),
plane = new THREE.Mesh(
new THREE.PlaneBufferGeometry(worldWidth, worldHeight, 1),
new THREE.MeshPhongMaterial({
color: 0x222222
})
),
cubes = new THREE.Object3D(),
spotLight = new THREE.SpotLight(0xffffff),
ambientLight = new THREE.AmbientLight(0x666666);
renderer.setSize(viewportWidth, viewportHeight);
renderer.shadowMapEnabled = true;
renderer.shadowMapType = THREE.PCFSoftShadowMap;
scene.add(plane);
scene.add(cubes);
scene.add(spotLight);
scene.add(ambientLight);
for (var x = 0; x < cols; x++) {
for (var y = 0; y < rows; y++) {
var width = tileWidth,
height = tileHeight,
dx = (cols / 2 - x),
dy = (rows / 2 - y),
depth = 1 + (20 - Math.sqrt(dx * dx + dy * dy)) / 4,
xBase = -worldWidth / 2 + x * tileWidth + tileWidth / 2,
yBase = -worldHeight / 2 + y * tileHeight + tileHeight / 2,
zBase = depth / 2,
cube = new THREE.Mesh(
new THREE.BoxGeometry(width, height, depth),
new THREE.MeshPhongMaterial({
color: 'rgb(' + ~~((y / rows) * 255) + ', ' + ~~((x / cols) * 255) + ', 255)',
shininess: 50
})
);
cube.position.set(
xBase,
yBase,
zBase
);
cube.castShadow = true;
cube.receiveShadow = true;
cube.zBase = zBase;
cube.zScaleTarget = 1;
cubes.add(cube);
}
}
plane.position.set(0, 0, 0);
plane.castShadow = false;
plane.receiveShadow = true;
camera.position.set(0, 0, 100);
spotLight.position.set(0, 0, 100);
spotLight.castShadow = true;
spotLight.shadowCameraNear = 0.1;
spotLight.shadowMapWidth = 2048;
spotLight.shadowMapHeight = 2048;
spotLight.shadowDarkness = 0.1;
function step() {
spotLight.position.x = Math.sin(tick / 100) * (worldWidth / 2);
spotLight.position.y = Math.cos(tick / 100) * (worldHeight / 2);
cubes.traverse(function(cube) {
if (cube instanceof THREE.Mesh) {
if (Math.abs(cube.scale.z - cube.zScaleTarget) > 0.001) {
cube.scale.z += (cube.zScaleTarget - cube.scale.z) * 0.05;
} else {
cube.zScaleTarget = 1 + Math.random() * 10;
}
cube.position.z = cube.geometry.parameters.depth / 2 * cube.scale.z;
}
});
tick++;
}
function render() {
renderer.render(scene, camera);
}
function loop() {
requestAnimationFrame(loop);
step();
render();
}
loop();
document.body.appendChild(renderer.domElement);
body {
background: #000;
overflow: hidden;
}
canvas {
bottom: 0;
display: block;
left: 0;
margin: auto;
position: absolute;
right: 0;
top: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r71/three.min.js"></script>
worldWidth = 100,
worldHeight = 100,
rows = 30,
cols = 30,
tileWidth = worldWidth / cols,
tileHeight = worldHeight / rows,
I see it uses this to set the size of the tiles that he lates uses in the loop:
...
var width = tileWidth,
height = tileHeight,
dx = ( cols / 2 - x ),
dy = ( rows / 2 - y ),
depth = 1 + ( 20 - Math.sqrt( dx * dx + dy * dy ) ) / 4,
xBase = -worldWidth / 2 + x * tileWidth + tileWidth / 2,
yBase = -worldHeight / 2 + y * tileHeight + tileHeight / 2,
...
How would I draw this tiles across the whole viewport so its similar to:
Thank you!
Rather then to take Math.min use this in line number 2 smallestDimension = Math.max( window.innerWidth, window.innerHeight )
It will automatically cover your screen size.
If you want you can change rows = 10 and col = 10

RENDER WARNING: there is no texture bound to the unit 0

I am trying to reproduce the three.js panaorama dualfisheye example using Three.js r71.
I need to stick to r71 because eventually I will use this code on autodesk forge viewer which is based on Three.js r71.
I made some progress, but I am facing an error message in the browser javascript console saying: RENDER WARNING: there is no texture bound to the unit 0
var camera, scene, renderer;
var isUserInteracting = false,
onMouseDownMouseX = 0, onMouseDownMouseY = 0,
lon = 0, onMouseDownLon = 0,
lat = 0, onMouseDownLat = 0,
phi = 0, theta = 0,
distance = 500;
init();
animate();
function init() {
var container, mesh;
container = document.getElementById('container');
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 2000);
scene = new THREE.Scene();
// var geometry = new THREE.SphereBufferGeometry( 500, 60, 40 ).toNonIndexed();
var geometry = new THREE.SphereGeometry(500, 60, 40);
// invert the geometry on the x-axis so that all of the faces point inward
// geometry.scale( - 1, 1, 1 );
geometry.applyMatrix(new THREE.Matrix4().makeScale(-1, 1, 1));
// Remap UVs
// var normals = geometry.attributes.normal.array;
var normals = [];
geometry.faces.forEach(element => {
normals.push(element.normal)
});
var uvs = geometry.faceVertexUvs
// var uvs = geometry.attributes.uv.array;
for (var i = 0, l = normals.length / 3; i < l; i++) {
var x = normals[i * 3 + 0];
var y = normals[i * 3 + 1];
var z = normals[i * 3 + 2];
if (i < l / 2) {
var correction = (x == 0 && z == 0) ? 1 : (Math.acos(y) / Math.sqrt(x * x + z * z)) * (2 / Math.PI);
uvs[i * 2 + 0] = x * (404 / 1920) * correction + (447 / 1920);
uvs[i * 2 + 1] = z * (404 / 1080) * correction + (582 / 1080);
} else {
var correction = (x == 0 && z == 0) ? 1 : (Math.acos(- y) / Math.sqrt(x * x + z * z)) * (2 / Math.PI);
uvs[i * 2 + 0] = - x * (404 / 1920) * correction + (1460 / 1920);
uvs[i * 2 + 1] = z * (404 / 1080) * correction + (582 / 1080);
}
}
geometry.applyMatrix(new THREE.Matrix4().makeRotationZ(-Math.PI / 2))
// geometry.rotateZ( - Math.PI / 2 );
//
// var texture = new THREE.TextureLoader().load( 'ricoh_theta_s.jpg' );
var texture = new THREE.TextureLoader('https://preview.ibb.co/hZXYmz/ricoh_theta_s.jpg');
this.texture = texture;
texture.format = THREE.RGBFormat;
var material = new THREE.MeshBasicMaterial({ map: texture });
material.map.repeat = { x: 0, y: 0 }
material.map.offset = { x: 0, y: 0 };
mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
container.appendChild(renderer.domElement);
document.addEventListener('mousedown', onDocumentMouseDown, false);
document.addEventListener('mousemove', onDocumentMouseMove, false);
document.addEventListener('mouseup', onDocumentMouseUp, false);
document.addEventListener('wheel', onDocumentMouseWheel, false);
//
window.addEventListener('resize', onWindowResize, false);
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function onDocumentMouseDown(event) {
event.preventDefault();
isUserInteracting = true;
onPointerDownPointerX = event.clientX;
onPointerDownPointerY = event.clientY;
onPointerDownLon = lon;
onPointerDownLat = lat;
}
function onDocumentMouseMove(event) {
if (isUserInteracting === true) {
lon = (onPointerDownPointerX - event.clientX) * 0.1 + onPointerDownLon;
lat = (onPointerDownPointerY - event.clientY) * 0.1 + onPointerDownLat;
}
}
function onDocumentMouseUp(event) {
isUserInteracting = false;
}
function onDocumentMouseWheel(event) {
distance += event.deltaY * 0.05;
distance = THREE.Math.clamp(distance, 400, 1000);
}
function animate() {
// requestAnimationFrame(animate);
update();
}
function update() {
if (isUserInteracting === false) {
lon += 0.1;
}
lat = Math.max(- 85, Math.min(85, lat));
phi = THREE.Math.degToRad(90 - lat);
theta = THREE.Math.degToRad(lon - 180);
camera.position.x = distance * Math.sin(phi) * Math.cos(theta);
camera.position.y = distance * Math.cos(phi);
camera.position.z = distance * Math.sin(phi) * Math.sin(theta);
camera.lookAt(scene.position);
renderer.render(scene, camera);
}
body {
background-color: #000000;
margin: 0px;
overflow: hidden;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/71/three.js"></script>
<div id="container"></div>
Thank you for your time.
There are a bunch of issues with the code
The loading code is wrong for r71. It should be something like this
THREE.ImageUtils.crossOrigin = '';
var texture = THREE.ImageUtils.loadTexture('https://preview.ibb.co/hZXYmz/ricoh_theta_s.jpg');
IIRC THREE r71 didn't pre-init textures with something renderable so you need to wait for the texture to load
var texture = THREE.ImageUtils.loadTexture(
'https://preview.ibb.co/hZXYmz/ricoh_theta_s.jpg',
undefined,
animate); // call animate after texture has loaded
and removed the call to animate at the top
That will get rid of the warning but continuing on
The code sets the repeat to 0
material.map.repeat = { x: 0, y: 0 };
material.map.offset = { x: 0, y: 0 };
Setting the repeat to 0 means you'll only see the first pixel of the texture since all UVs will be multiplied by 0
It code sets the repeat and offset incorrectly.
The correct way to set repeat and offset is with set
material.map.repeat.set(1, 1);
material.map.offset.set(0, 0);
It works the other way but only by luck. The 2 settings are THREE.Vector2
objects. The code using repeat and offset could change at any time to
use methods on THREE.Vector2 or pass the repeat and offset to functions
that expect a THREE.Vector2 so it's best not to replace them
note that there is no reason to set them though. 1 1 for repeat and 0 0 for offset are the defaults.
The code only renders once
requestAnimationFrame was commented out. Textures load asynchronously
so you won't see the texture for several frames. You either need to wait
for the texture to load before rendering, render again once it has finish
loading or, render continuously so that when it happens to load it's used
The code is using a cross domain image
This isn't actually a bug, just a warning. WebGL can't use cross domain
images unless the server itself gives permission. The one the code links
to does give that permission but I wasn't sure if you're aware of that
or were just lucky. The majority of images from servers not your own
are unlikely to work.
The code's uv math is wrong
You should ask another question for that. Commenting that out I can see the texture
var camera, scene, renderer;
var isUserInteracting = false,
onMouseDownMouseX = 0, onMouseDownMouseY = 0,
lon = 0, onMouseDownLon = 0,
lat = 0, onMouseDownLat = 0,
phi = 0, theta = 0,
distance = 500;
init();
function init() {
var container, mesh;
container = document.getElementById('container');
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 2000);
scene = new THREE.Scene();
// var geometry = new THREE.SphereBufferGeometry( 500, 60, 40 ).toNonIndexed();
var geometry = new THREE.SphereGeometry(500, 60, 40);
// invert the geometry on the x-axis so that all of the faces point inward
// geometry.scale( - 1, 1, 1 );
geometry.applyMatrix(new THREE.Matrix4().makeScale(-1, 1, 1));
// Remap UVs
// var normals = geometry.attributes.normal.array;
var normals = [];
geometry.faces.forEach(element => {
normals.push(element.normal)
});
var uvs = geometry.faceVertexUvs
// var uvs = geometry.attributes.uv.array;
for (var i = 0, l = normals.length / 3; i < l; i++) {
var x = normals[i * 3 + 0];
var y = normals[i * 3 + 1];
var z = normals[i * 3 + 2];
if (i < l / 2) {
var correction = (x == 0 && z == 0) ? 1 : (Math.acos(y) / Math.sqrt(x * x + z * z)) * (2 / Math.PI);
// uvs[i * 2 + 0] = x * (404 / 1920) * correction + (447 / 1920);
// uvs[i * 2 + 1] = z * (404 / 1080) * correction + (582 / 1080);
} else {
var correction = (x == 0 && z == 0) ? 1 : (Math.acos(- y) / Math.sqrt(x * x + z * z)) * (2 / Math.PI);
// uvs[i * 2 + 0] = - x * (404 / 1920) * correction + (1460 / 1920);
// uvs[i * 2 + 1] = z * (404 / 1080) * correction + (582 / 1080);
}
}
geometry.applyMatrix(new THREE.Matrix4().makeRotationZ(-Math.PI / 2))
// geometry.rotateZ( - Math.PI / 2 );
//
THREE.ImageUtils.crossOrigin = '';
var texture = THREE.ImageUtils.loadTexture('https://preview.ibb.co/hZXYmz/ricoh_theta_s.jpg', undefined, animate);
var material = new THREE.MeshBasicMaterial({ map: texture });
material.map.repeat.set(1, 1);
material.map.offset.set(0, 0);
mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
container.appendChild(renderer.domElement);
document.addEventListener('mousedown', onDocumentMouseDown, false);
document.addEventListener('mousemove', onDocumentMouseMove, false);
document.addEventListener('mouseup', onDocumentMouseUp, false);
document.addEventListener('wheel', onDocumentMouseWheel, false);
//
window.addEventListener('resize', onWindowResize, false);
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function onDocumentMouseDown(event) {
event.preventDefault();
isUserInteracting = true;
onPointerDownPointerX = event.clientX;
onPointerDownPointerY = event.clientY;
onPointerDownLon = lon;
onPointerDownLat = lat;
}
function onDocumentMouseMove(event) {
if (isUserInteracting === true) {
lon = (onPointerDownPointerX - event.clientX) * 0.1 + onPointerDownLon;
lat = (onPointerDownPointerY - event.clientY) * 0.1 + onPointerDownLat;
}
}
function onDocumentMouseUp(event) {
isUserInteracting = false;
}
function onDocumentMouseWheel(event) {
distance += event.deltaY * 0.05;
distance = THREE.Math.clamp(distance, 400, 1000);
}
function animate() {
requestAnimationFrame(animate);
update();
}
function update() {
if (isUserInteracting === false) {
lon += 0.1;
}
lat = Math.max(- 85, Math.min(85, lat));
phi = THREE.Math.degToRad(90 - lat);
theta = THREE.Math.degToRad(lon - 180);
camera.position.x = distance * Math.sin(phi) * Math.cos(theta);
camera.position.y = distance * Math.cos(phi);
camera.position.z = distance * Math.sin(phi) * Math.sin(theta);
camera.lookAt(scene.position);
renderer.render(scene, camera);
}
body {
background-color: #000000;
margin: 0px;
overflow: hidden;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/71/three.js"></script>
<div id="container"></div>
For those just looking for an answer to the warning
RENDER WARNING: there is no texture bound to the unit 0
It is issued by Chrome when:
The bound shader program expects a texture.
No texture is bound.
Source and further links:
https://github.com/NASAWorldWind/WebWorldWind/issues/302#issuecomment-346188472
The fix then, is to always bind a texture to the shader samplers, even when the shader won't use it.
As gman suggested in his longer answer, binding a white 1px texture when "there is no texture" is good practice because it won't consume much space or bandwidth and the shader code can use it to multiply with another colour without altering it.

three js - how to make a decagon

var vector = new THREE.Vector3();
var spherical = new THREE.Spherical();
for ( var i = 0, l = objects.length; i < l; i ++ ) {
var phi = Math.acos( -1 + ( 2 * i ) / l );
var theta = Math.sqrt( l * Math.PI ) * phi;
var object = new THREE.Object3D();
spherical.set(1000, phi, theta );
object.position.setFromSpherical( spherical );
vector.copy( object.position ).multiplyScalar( 2 );
object.lookAt( vector );
}
This code describes round three.js sphere. How to make a decagon out of it? Thanks

Multiple random points Three.js

I am constructing a point with a random x,y,z (in a certain min and max for x,y,z).
How can I multiply the point (e.g. 20 points), but the have different values (random)for x,y and z also.
//Math.random() * (max - min) + min
var x = Math.random() * (80 - 1) + 1
var y = Math.random() * (80 - 1) + 1
var z = Math.random() * (80 - 1) + 1
var dotGeometry = new THREE.Geometry();
dotGeometry.vertices.push(new THREE.Vector3( x, y, z));
var dotMaterial = new THREE.PointCloudMaterial( { size: 10, sizeAttenuation: false, color: 0xFF0000 } );
var dot = new THREE.PointCloud( dotGeometry, dotMaterial );
scene.add( dot );
I tried something, but the point multiplies at the same position over and over.
If you want to create 20 random points, you only have to do the same into a for loop. I've not used Three.js library, but I suppose that it has be something like this:
var NUM_POINTS = 20;
var dots = []; //If you want to use for other task
for (var i = 0 ; i < NUM_POINTS){
var x = Math.random() * (80 - 1) + 1
var y = Math.random() * (80 - 1) + 1
var z = Math.random() * (80 - 1) + 1
var dotGeometry = new THREE.Geometry();
dots.push(dotGeometry);
dotGeometry.vertices.push(new THREE.Vector3( x, y, z));
var dotMaterial = new THREE.PointCloudMaterial( { size: 10, sizeAttenuation: false, color: 0xFF0000 } );
var dot = new THREE.PointCloud( dotGeometry, dotMaterial );
scene.add(dot);
}
More info about for loop here
Good luck!

splines arc on three js globe not working

I've been following a couple of examples on mapping arcs around a three.js globe. I've nearly got this to work although I'm having trouble getting the math correct and the resulting projection is incorrect. I'd appreciate anyone taking a look at the code and telling me what I'm doing wrong. Thanks
import oHoverable from 'o-hoverable';
import d3 from 'd3';
import oHeader from 'o-header';
import THREE from 'three.js';
// var OrbitControls = require('three-orbit-controls')(THREE);
// console.log("orbitControls=",OrbitControls);
oHoverable.init(); // makes hover effects work on touch devices
document.addEventListener('DOMContentLoaded', function () {
oHoverable.init(); // makes hover effects work on touch devices
var dataset=spreadsheet.data
console.log(dataset)
// This let's you inspect the resulting image in the console.
//console.log(canvas.node().toDataURL()); //F
var startLon=45
var startLat=75
var endLon=0
var endLat=0
var posX = 200;
var posY = 600;
var posZ = 1800;
var width = document.getElementById('main').getBoundingClientRect().width;
var height = 600;
var FOV = 45;
var NEAR = 2;
var FAR = 4000;
var controls;
// some global variables and initialization code
// simple basic renderer
var renderer = new THREE.WebGLRenderer();
renderer.setSize(width,height);
renderer.setClearColor( 0x000000, 1);
// add it to the target element
var globeDiv = document.getElementById("globeDiv");
globeDiv.appendChild(renderer.domElement);
// setup a camera that points to the center
var camera = new THREE.PerspectiveCamera(FOV,width/height,NEAR,FAR);
camera.position.set(posX,posY, posZ);
camera.lookAt(new THREE.Vector3(0,0,0));
// create a basic scene and add the camera
var scene = new THREE.Scene();
scene.add(camera);
//spotlight set up in the same location as the camera
var light = new THREE.DirectionalLight(0xffffff, 1.0, 200 );
light.position.set(posX,posY,posZ);
scene.add(light);
//Add Earth
var radious=650
var line
// var earthGeo=new THREE.SphereGeometry(radious,100,100);
// var earthMat=new THREE.MeshPhongMaterial();
// earthMat.map=THREE.ImageUtils.loadTexture("images/world.jpg");
// earthMat.bumpMap=THREE.ImageUtils.loadTexture("images/bumpmap.jpg");
// earthMat.bumpScale=8;
// earthMat.shininess=10;
// var earthObject = new THREE.Mesh(earthGeo,earthMat);
// scene.add(earthObject);
// //Add clouds
// var cloudGeo=new THREE.SphereGeometry(radious,60,60);
// var cloudsMat=new THREE.MeshPhongMaterial({
// opacity: 0.5,
// transparent: true,
// color: 0xffffff
// });
// cloudsMat.map=THREE.ImageUtils.loadTexture("images/clouds.png");
// var meshClouds = new THREE.Mesh( cloudGeo, cloudsMat );
// meshClouds.scale.set(1.015, 1.015, 1.015 );
// scene.add(meshClouds);
//Add lines
var root = new THREE.Object3D();
for (var i = 0; i < dataset.length; i++) {
endLon=dataset[i].lng;
endLat=dataset[i].lat;
makeCurve(startLat,startLon,endLat,endLon);
root.add(line);
};
scene.add(root)
function makeCurve(startLon,startLat,endLon,endLat){
console.log("makeCurve",startLon,startLat,endLon,endLat);
var phiFrom = startLon * Math.PI / 180;
var thetaFrom = (startLat+90) * Math.PI / 180;
//calculates "from" point
var xF = radious * Math.cos(phiFrom) * Math.sin(thetaFrom);
var yF = radious * Math.sin(phiFrom);
var zF = radious * Math.cos(phiFrom) * Math.cos(thetaFrom);
phiFrom = endLon * Math.PI / 180;
thetaFrom = (endLat+90) * Math.PI / 180;
//calculates "from" point
var xT = radious * Math.cos(phiFrom) * Math.sin(thetaFrom);
var yT = radious * Math.sin(phiFrom);
var zT = radious * Math.cos(phiFrom) * Math.cos(thetaFrom);
//Sets up vectors
var vF = new THREE.Vector3(xF, yF, zF);
var vT = new THREE.Vector3(xT, yT, zT);
var dist = vF.distanceTo(vT);
// here we are creating the control points for the first ones.
// the 'c' in front stands for control.
var cvT = vT.clone();
var cvF = vF.clone();
// get the half point of the vectors points.
var xC = ( 0.5 * (vF.x + vT.x) );
var yC = ( 0.5 * (vF.y + vT.y) );
var zC = ( 0.5 * (vF.z + vT.z) );
// then we create a vector for the midpoints.
var subdivisions = 100;
var geometry = new THREE.Geometry();
var curve = new THREE.QuadraticBezierCurve3();
curve.v0 = new THREE.Vector3(xF, yF, zF);
curve.v1 = new THREE.Vector3(xT, yT, zT);
curve.v2 = new THREE.Vector3(xC, yC, zC);
for (var i = 0; i < subdivisions; i++) {
geometry.vertices.push( curve.getPoint(i / subdivisions) )
}
var material = new THREE.LineBasicMaterial( { color: 0xf2c0a4, linewidth: 2 } );
line = new THREE.Line(geometry, material);
}
// controls = new THREE.OrbitControls( camera );
render();
function render() {
var timer = Date.now() * 0.0001;
// camera.position.x=(Math.cos(timer)*1800);
// camera.position.z=(Math.sin(timer)*1800);
camera.lookAt( scene.position );
// light.position.x = (Math.cos(timer)*2000);
// light.position.z = (Math.sin(timer)*2000);
light.lookAt(scene.position);
//earthObject.rotation.y += 0.0014;
root.rotation.y += 0.0014;
//meshClouds.rotation.y += 0.001;
renderer.render(scene,camera);
requestAnimationFrame(render );
}
});
data sample is as follows and is loaded elsewhere
ftlabel,imfcode,lat,lng
Afghanistan,512,33,66
Albania,914,41,20
Algeria,612,28,3
Angola,614,-12.5,18.5
Argentina,213,-34,-64
Armenia,911,40,45
Aruba,314,12.5,-69.97
Australia,193,-25,135
Austria,122,47.33,13.33
Azerbaijan,912,40.5,47.5
Bahamas,313,24,-76
Bahrain,419,26,50.5
Bangladesh,513,24,90
Barbados,316,13.17,-59.53
Belarus,913,53,28
Belgium,124,50.83,4
Belize,339,17.25,-88.75
Benin,638,9.5,2.25
Bermuda,319,32.33,-64.75
Bolivia,218,-17,-65
Bosnia and Herzegovina,963,44.25,17.83
Brazil,223,-10,-55
Brunei,516,4.5,114.67
Bulgaria,918,43,25
Burkina Faso,748,13,-2
Burundi,618,-3.5,30
Cambodia,522,13,105
Cameroon,622,6,12
Canada,156,60,-96
Cape Verde,624,16,-24
Central African Republic,626,7,21
Chad,628,15,19
Chile,228,-30,-71
China,924,35,105
Colombia,233,4,-72
Comoros,632,-12.17,44.25
Costa Rica,238,10,-84
Cote d'Ivoire,662,8,-5
Croatia,960,45.17,15.5
Cuba,928,22,-79.5
Cleaned up the maths a bit but basically I was passing the lon and lat to the function which was receiving them the wrong way round. Code now working and looks like this
import oHoverable from 'o-hoverable';
import d3 from 'd3';
import oHeader from 'o-header';
import THREE from 'three.js';
oHoverable.init(); // makes hover effects work on touch devices
document.addEventListener('DOMContentLoaded', function () {
oHoverable.init(); // makes hover effects work on touch devices
var dataset=spreadsheet.data
//console.log(dataset)
var startLat=38
var startLon=-100
var endLon=0
var endLat=0
var posX = 200;
var posY = 600;
var posZ = 1800;
var width = document.getElementById('main').getBoundingClientRect().width;
var height = 600;
var FOV = 45;
var NEAR = 2;
var FAR = 4000;
var controls;
// some global variables and initialization code
// simple basic renderer
var renderer = new THREE.WebGLRenderer();
renderer.setSize(width,height);
renderer.setClearColor( 0x000000, 1);
// add it to the target element
var globeDiv = document.getElementById("globeDiv");
globeDiv.appendChild(renderer.domElement);
// setup a camera that points to the center
var camera = new THREE.PerspectiveCamera(FOV,width/height,NEAR,FAR);
camera.position.set(posX,posY, posZ);
camera.lookAt(new THREE.Vector3(0,0,0));
// create a basic scene and add the camera
var scene = new THREE.Scene();
scene.add(camera);
//spotlight set up in the same location as the camera
var light = new THREE.DirectionalLight(0xffffff, 1.0, 200 );
light.position.set(posX,posY,posZ);
scene.add(light);
//Add Earth
var radius=600
var curveObject
var earthGeo=new THREE.SphereGeometry(radius,100,100);
var earthMat=new THREE.MeshPhongMaterial();
earthMat.map=THREE.ImageUtils.loadTexture("images/world.jpg");
earthMat.bumpMap=THREE.ImageUtils.loadTexture("images/bumpmap.jpg");
earthMat.bumpScale=8;
earthMat.shininess=10;
var earthObject = new THREE.Mesh(earthGeo,earthMat);
scene.add(earthObject);
//Add clouds
var cloudGeo=new THREE.SphereGeometry(radius,60,60);
var cloudsMat=new THREE.MeshPhongMaterial({
opacity: 0.5,
transparent: true,
color: 0xffffff
});
cloudsMat.map=THREE.ImageUtils.loadTexture("images/clouds.png");
var meshClouds = new THREE.Mesh( cloudGeo, cloudsMat );
meshClouds.scale.set(1.015, 1.015, 1.015 );
scene.add(meshClouds);
//Add lines
var lineObject = new THREE.Object3D();
for (var i = 0; i < dataset.length; i++) {
endLon=dataset[i].lng;
endLat=dataset[i].lat;
makeCurve(startLon,startLat,endLon,endLat,i);
lineObject.add(curveObject);
};
scene.add(lineObject)
// takes lon lat and a radius and turns that into vector
function to3DVector(lon, lat, radius) {
var phi = lat * Math.PI / 180;
var theta = (lon + 90) * Math.PI / 180;
var xF = radius * Math.cos(phi) * Math.sin(theta);
var yF = radius * Math.sin(phi);
var zF = radius * Math.cos(phi) * Math.cos(theta);
return new THREE.Vector3(xF, yF, zF);
}
function makeCurve(startLon,startLat,endLon,endLat,i){
var widthScale = d3.scale.linear()
.domain([0, d3.max(dataset, function(d) { return d.imfcode; })])
.range([1, 12]);
var vF = to3DVector(startLon, startLat, radius);
var vT = to3DVector(endLon, endLat, radius);
// then you get the half point of the vectors points.
var xC = ( 0.5 * (vF.x + vT.x) );
var yC = ( 0.5 * (vF.y + vT.y) );
var zC = ( 0.5 * (vF.z + vT.z) );
// then we create a vector for the midpoints.
var mid = new THREE.Vector3(xC, yC, zC);
var dist = vF.distanceTo(vT);
// here we are creating the control points for the first ones.
// the 'c' in front stands for control.
var cvT = vT.clone();
var cvF = vF.clone();
var smoothDist = map(dist, 0, 10, 0, 15/dist );
console.log(smoothDist);
mid.setLength( radius * smoothDist );
cvT.add(mid);
cvF.add(mid);
cvT.setLength( radius * smoothDist );
cvF.setLength( radius * smoothDist );
var curve = new THREE.CubicBezierCurve3( vF, cvF, cvT, vT );
var geometry2 = new THREE.Geometry();
geometry2.vertices = curve.getPoints( 50 );
var material2 = new THREE.LineBasicMaterial( { transparent: true,opacity :0.6, color : 0xff0000,linewidth:widthScale(dataset[i].imfcode)} );
// Create the final Object3d to add to the scene
curveObject = new THREE.Line( geometry2, material2 );
function map(value, low1, high1, low2, high2) {
return low2 + (high2 - low2) * (value - low1) / (high1 - low1);
}
}
render();
function render() {
var timer = Date.now() * 0.0001;
// camera.position.x=(Math.cos(timer)*1800);
// camera.position.z=(Math.sin(timer)*1800);
camera.lookAt( scene.position );
// light.position.x = (Math.cos(timer)*2000);
// light.position.z = (Math.sin(timer)*2000);
light.lookAt(scene.position);
earthObject.rotation.y += 0.0005;
lineObject.rotation.y += 0.0005;
meshClouds.rotation.y += 0.0012;
renderer.render(scene,camera);
requestAnimationFrame(render );
}
});

Categories

Resources