Перейти ко вступительной информации

Видео+код: #2/12 THREEJS координаты земли в Vector3

Статья создана: Видео+код: #2/12 THREEJS координаты земли в Vector3

Видео: 14 THREEJS координаты земли

урок 14 по Three JS / урок 12 по планете

Codepen
Codepen копия Пашиного кода

Файлы из урока 12 по 3D планете

2-12-coordinates-to-vector3.zip

JS Код из видео (!на threejs-webpack-starter!)

Выделениями отмечены изменения в коде по сравнению с предыдущим уроком

import './style.css'
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'

import {BufferGeometryUtils} from 'three/examples/jsm/utils/BufferGeometryUtils'
import {TWEEN} from 'three/examples/jsm/libs/tween.module.min'

//import * as dat from 'dat.gui'

//const gui = new dat.GUI()
let o;
const scene = new THREE.Scene();
//scene.background = new THREE.Color('blue');
const camera = new THREE.PerspectiveCamera(45, innerWidth / innerHeight, 0.01, 50);
camera.position.set(0, 10, 10);
const renderer = new THREE.WebGLRenderer({antialias: true,alpha: true});
renderer.setSize(innerWidth, innerHeight);

renderer.setClearColor('#000', 0);

document.body.appendChild(renderer.domElement);

const controls = new OrbitControls(camera, renderer.domElement);
controls.enablePan = true;

// our codeconst group=new THREE.Group();// empty groupe for add all rotation object
const params = {
  colors: {
    base: "#ffffff",
    gradInner: "#ff0022",
    gradOuter: "#ff0000"
  },
  mapPoints:{
    sizeOfPoints:.3,// FLOAT ONLY | MIN: 0.1 , MAX: 0.4
    opacityOfOceanPoints:.1,// FLOAT ONLY ex. .1 | MIN: 0.1 - black, MAX: 0.9
    countOfPoints:25000,// INT ONLY ex. 1000 - 40000
  },
  reset: ()=>controls.reset()
}

const maxImpactAmount = 1;

const tmpFrom={lat:32.622876, lon:107.523152}//China//const tmpFrom={lat:8.499511, lon:77.617839}//INDIAconst tmpTo={lat:-26.164493,lon:134.742407}//-26.164493, 134.742407//const tmpTo={lat:-50.606498,lon:-70.9632}/* const new_arr=[    {lat:32.622876, lon:107.523152},    {lat:32.622876, lon:107.523152},    {lat:32.622876, lon:107.523152},    {lat:32.622876, lon:107.523152},] */
// init uniforms impacts and traces array
const impacts = new Array();
const trails = new Array();
for (let i = 0; i < maxImpactAmount; i++) {
  impacts.push({
    impactPosition: cTv(tmpTo),//Sydnay | Paris: lat:48.5112,lon:2.2055    prevPosition: cTv(tmpFrom),//NY    impactMaxRadius: 5 * THREE.Math.randFloat(.1, .7),
    impactRatio: 0,
    trailRatio: {value: 0},
    trailLength: {value: 0}
  });
  makeTrail(i);
}
const uniforms = {
  impacts: {value: impacts},
  maxSize: {value: 0.04},
  minSize: {value: 0.03},
  waveHeight: {value: 0.125},
  scaling: {value: 2},
  gradInner: {value: new THREE.Color(params.colors.gradInner)},
  gradOuter: {value: new THREE.Color(params.colors.gradOuter)}
}

const tweens = new Array();

for (let i = 0; i < maxImpactAmount; i++) {
  tweens.push({
    runTween: ()=> {
        const path = trails[i];
        const speed = 2;
        const len = path.geometry.attributes.lineDistance.array[99];
        const dur = len / speed;
    	  const tweenTrail = new TWEEN.Tween({value: 0})
      	.to({value: 1}, dur * 1000)
        .onUpdate( val => {
        	impacts[i].trailRatio.value = val.value;
        });
        const tweenImpact = new TWEEN.Tween({ value: 0 })
        .to({ value: 1 }, THREE.Math.randInt(2500, 5000))
        .onUpdate(val => {
          uniforms.impacts.value[i].impactRatio = val.value;
        })
        .onComplete(() => {
          impacts[i].prevPosition=cTv(tmpFrom)          impacts[i].impactPosition=cTv(tmpTo)          setPath(path, impacts[i].prevPosition, impacts[i].impactPosition, 1);
          uniforms.impacts.value[i].impactMaxRadius = 5 * THREE.Math.randFloat(.5, .75);
          tweens[i].runTween();
        });
        tweenTrail.chain(tweenImpact);
        tweenTrail.start();
    }
  });
}

tweens.forEach(t => t.runTween());
(()=>{
    const dummyObj = new THREE.Object3D()
    const p = new THREE.Vector3()
    const sph = new THREE.Spherical()
    const geoms = new Array()
    const tex = new THREE.TextureLoader().load('/map.jpg',()=>{
      // https://web.archive.org/web/20120107030109/http://cgafaq.info/wiki/Evenly_distributed_points_on_sphere#Spirals
      const counter = params.mapPoints.countOfPoints
      const rad = 5
    
      let r = 0
      const dlong = Math.PI * (3 - Math.sqrt(5))
      const dz = 2 / counter
      let long = 0
      let z = 1 - dz / 2
      for(let i = 0; i < counter; i++){
          r = Math.sqrt(1 - z * z);
          p.set( Math.cos(long) * r, z, -Math.sin(long) * r).multiplyScalar(rad);
          z = z - dz;
          long = long + dlong;
          sph.setFromVector3(p);
          dummyObj.lookAt(p);
          dummyObj.updateMatrix(); 
          const g =  new THREE.PlaneBufferGeometry(2, 2);
          g.applyMatrix4(dummyObj.matrix);
          g.translate(p.x, p.y, p.z);
          const centers = [
            p.x, p.y, p.z, 
            p.x, p.y, p.z, 
            p.x, p.y, p.z, 
            p.x, p.y, p.z
          ];
          const uv = new THREE.Vector2(
            (sph.theta + Math.PI) / (Math.PI * 2),
            1. - sph.phi / Math.PI
          );
          const uvs = [
            uv.x, uv.y,
            uv.x, uv.y,
            uv.x, uv.y,
            uv.x, uv.y
          ];
          g.setAttribute("center", new THREE.Float32BufferAttribute(centers, 3));
          g.setAttribute("bUv", new THREE.Float32BufferAttribute(uvs, 2));
          geoms.push(g);
      }
      const g = BufferGeometryUtils.mergeBufferGeometries(geoms);
// JFT      /* const tex_ = new THREE.TextureLoader().load(        "https://cywarr.github.io/small-shop/map-political1.gif"      );      const mew=new THREE.Mesh(        new THREE.IcosahedronBufferGeometry(5,5),        new THREE.MeshBasicMaterial({          map: tex_,          transparent:true,          opacity:.25,        })      )      mew.rotation.y=1.57      group.add(mew) */// \ JFT      const m = new THREE.MeshBasicMaterial({
        color: new THREE.Color(params.colors.base),
        side: THREE.DoubleSide,
        transparent:true,
        onBeforeCompile: shader => {
          shader.uniforms.impacts = uniforms.impacts;
          shader.uniforms.maxSize = uniforms.maxSize;
          shader.uniforms.minSize = uniforms.minSize;
          shader.uniforms.waveHeight = uniforms.waveHeight;
          shader.uniforms.scaling = uniforms.scaling;
          shader.uniforms.gradInner = uniforms.gradInner;
          shader.uniforms.gradOuter = uniforms.gradOuter;
          shader.uniforms.tex = {value: tex};
          shader.vertexShader = `
              struct impact {
              vec3 impactPosition;
              float impactMaxRadius;
              float impactRatio;
            };
              uniform impact impacts[${maxImpactAmount}];
            uniform sampler2D tex;
            uniform float maxSize;
            uniform float minSize;
            uniform float waveHeight;
            uniform float scaling;
            attribute vec3 center;
            attribute vec2 bUv;
            varying float vFinalStep;
            varying float vMap;
            ${shader.vertexShader}
          `.replace(
              `#include <begin_vertex>`,
            `#include <begin_vertex>
            float finalStep = 0.0;
            for (int i = 0; i < ${maxImpactAmount};i++){
              float dist = distance(center, impacts[i].impactPosition);
              float curRadius = impacts[i].impactMaxRadius * impacts[i].impactRatio;
              float sstep = smoothstep(0., curRadius, dist) - smoothstep(curRadius - ( 0.25 * impacts[i].impactRatio ), curRadius, dist);
              sstep *= 1. - impacts[i].impactRatio;
              finalStep += sstep;
            }
            finalStep = clamp(finalStep, 0., 1.);
            vFinalStep = finalStep;
            
            float map = texture(tex, bUv).g;
            vMap = map;
            float pSize = map < 0.5 ? maxSize : minSize;
            float scale = scaling;
    
            transformed = (position - center) * pSize * mix(1., scale * 1.25, finalStep) + center; // scale on wave
            transformed += normal * finalStep * waveHeight; // lift on wave
            `
          );
          shader.fragmentShader = `
            uniform vec3 gradInner;
            uniform vec3 gradOuter;
            varying float vFinalStep;
            varying float vMap;
            
            ${shader.fragmentShader}
            `.replace(
              `vec4 diffuseColor = vec4( diffuse, opacity );`,
            `// shaping the point, pretty much from The Book of Shaders
            vec2 hUv = (vUv - .1);
            int N = 8;
            float a = atan(hUv.x,hUv.y);
            float r = PI2/float(N);
            float d = cos(floor(.5+a/r)*r-a)*length(hUv);
            float f = cos(PI / float(N)) * .5;
            //if (d > f) discard;
            if (length(vUv - ${params.mapPoints.sizeOfPoints}) > ${params.mapPoints.sizeOfPoints}) discard;
            vec3 grad = mix(gradInner, gradOuter, clamp( d / f, 0., 1.)); // gradient
            vec3 diffuseMap = diffuse * ((vMap > .5) ? ${params.mapPoints.opacityOfOceanPoints} : 1.);
            vec3 col = mix(diffuseMap, grad, vFinalStep); // color on wave
            float opct=(vMap > .5)?${params.mapPoints.opacityOfOceanPoints}:1.;
            vec4 diffuseColor = vec4( col , opct );
            `);
        }
      });
      m.defines = {"USE_UV":""};
      o = new THREE.Mesh(g, m);
      //o.rotation.y=1.59      trails.forEach(t => group.add(t));
      group.add(o);    })
  })()

function makeTrail(idx){
  const pts = new Array(100 * 3).fill(0);
  const g = new THREE.BufferGeometry();
  g.setAttribute("position", new THREE.Float32BufferAttribute(pts, 3));
  const m = new THREE.LineDashedMaterial({
  	color: params.colors.gradOuter,
    transparent: true,
  	onBeforeCompile: shader => {
    	shader.uniforms.actionRatio = impacts[idx].trailRatio;
      shader.uniforms.lineLength = impacts[idx].trailLength;
      shader.fragmentShader = `
      	uniform float actionRatio;
        uniform float lineLength;
        ${shader.fragmentShader}
      `.replace(
      	`if ( mod( vLineDistance, totalSize ) > dashSize ) {
		discard;
	}`,
        `
        	float halfDash = dashSize * 0.5;
          float currPos = (lineLength + dashSize) * actionRatio;
        	float d = (vLineDistance + halfDash) - currPos;
        	if (abs(d) > halfDash ) discard;
          
          float grad = ((vLineDistance + halfDash) - (currPos - halfDash)) / halfDash;
        `
      )
      .replace(
      	`vec4 diffuseColor = vec4( diffuse, opacity );`,
        `
        vec4 diffuseColor = vec4( diffuse, grad );
        `
      );
      //console.log(shader.fragmentShader);
    }
  });

  const l = new THREE.Line(g, m);
  l.userData.idx = idx;

  setPath(l, impacts[idx].prevPosition, impacts[idx].impactPosition, 1);
  trails.push(l);
}

// based on https://jsfiddle.net/prisoner849/fu59aved/
function setPath(l, startPoint, endPoint, peakHeight, cycles) {
    const pos = l.geometry.attributes.position;
    const division = pos.count - 1;
    const cycle = cycles || 1;
    const peak = peakHeight || 1;
    const radius = startPoint.length();
    const angle = startPoint.angleTo(endPoint);
    const arcLength = radius * angle;
    const diameterMinor = arcLength / Math.PI;
    const radiusMinor = (diameterMinor * 0.5) / cycle;
    const peakRatio = peak / diameterMinor;
    const radiusMajor = startPoint.length() + radiusMinor;
    const basisMajor = new THREE.Vector3().copy(startPoint).setLength(radiusMajor);
    const basisMinor = new THREE.Vector3().copy(startPoint).negate().setLength(radiusMinor);


    // triangle (start, end, center)
    const tri = new THREE.Triangle(startPoint, endPoint, new THREE.Vector3());
    const nrm = new THREE.Vector3(); // normal
    tri.getNormal(nrm);

    // rotate startPoint around normal
    //let angleStep = angle / division;
    const v3Major = new THREE.Vector3();
    const v3Minor = new THREE.Vector3();
    const v3Inter = new THREE.Vector3();
    const vFinal = new THREE.Vector3();
    for (let i = 0; i <= division; i++) {
        const divisionRatio = i / division;
        const angleValue = angle * divisionRatio;
        v3Major.copy(basisMajor).applyAxisAngle(nrm, angleValue);
        v3Minor.copy(basisMinor).applyAxisAngle(nrm, angleValue + Math.PI * 2 * divisionRatio * cycle);
        v3Inter.addVectors(v3Major, v3Minor);
        const newLength = ((v3Inter.length() - radius) * peakRatio) + radius;
        vFinal.copy(v3Inter).setLength(newLength);
        pos.setXYZ(i, vFinal.x, vFinal.y, vFinal.z);
    }
    pos.needsUpdate = true;
    l.computeLineDistances();
    l.geometry.attributes.lineDistance.needsUpdate = true;
    impacts[l.userData.idx].trailLength.value = l.geometry.attributes.lineDistance.array[99];
    l.material.dashSize = 3;
    //l.material.gapSize = l.material.userData.lineLength.value;
    //return new THREE.BufferGeometry().setFromPoints(points);
}
  //LESS 2-12 function cTv(coordObj={lat:48.5125,lon:2.2055}/* ,color='red',sizes={a:.1,b:.1,c:.1} */){//coordinates to vector | Default: Paris  const parisSpherical = {    lat: THREE.Math.degToRad(90 - coordObj.lat),    lon: THREE.Math.degToRad(coordObj.lon)  };  const radius = 5;// соответствует радиусу карты планеты  const vector=new THREE.Vector3().setFromSphericalCoords(    radius,    parisSpherical.lat,    parisSpherical.lon  );  //console.log(vector);  // check we did it correctly  //const spherical = new THREE.Spherical().setFromVector3(vector);  //console.log(spherical,vector);  //const g_=new THREE.BoxBufferGeometry(.1,.1,.1)//sizes.a,sizes.b,sizes.c  //const m_0=new THREE.Mesh(  //        g_,  //      new THREE.MeshBasicMaterial({color:'red'})  //  )  //group.add(m_0)  //m_0.position.set(vector.x,vector.y,vector.z)  return vector} //cTv()//China 34.452711, 105.092530/* function convert(coord={  lat:8.442042,  lon:77.148370,}){  const parisSpherical = {    lat: THREE.Math.degToRad(90 - coord.lat),    lon: THREE.Math.degToRad(coord.lon)  };  const radius = 5;  const vector = new THREE.Vector3().setFromSphericalCoords(    radius,    parisSpherical.lat,    parisSpherical.lon  );  console.log(vector)  return vector} *///JFT/*     const lineGeom = new THREE.BufferGeometry().setFromPoints([convert(tmpTo), convert(tmpFrom)]);    const line = new THREE.Line(    lineGeom,    new THREE.LineBasicMaterial({ color: "yellow" })    );    //line.rotation.y=1.57//INDIA TO UAM    group.add(line) */// \ JFT//function getCoordinatesFromLatLng(coord={lat:40.4251, lon:74.0021},umnojit=1){//Default New-York//   const latitude_rad = coord.lat * Math.PI / 180;//   const longitude_rad = coord.lon * Math.PI / 180*umnojit;//   const radiusEarth=5.01//   const xPos= radiusEarth * Math.cos(latitude_rad) * Math.cos(longitude_rad);//   const zPos = radiusEarth * Math.cos(latitude_rad) * Math.sin(longitude_rad);//   const yPos = radiusEarth * Math.sin(latitude_rad);//   const vector= new THREE.Vector3(xPos,yPos,zPos);      //JFT/*    const coor={x: xPos, y: yPos, z: zPos};   const g_=new THREE.BoxBufferGeometry(.1,.1,.1)   const m_=new THREE.Mesh(g_,           new THREE.MeshBasicMaterial({color:new THREE.Color(THREE.Math.randFloat(0, 1),THREE.Math.randFloat(.5,1),THREE.Math.randFloat(.5,1))})       )   if(group)group.add(m_)   m_.position.set(coor.x,coor.y,coor.z) */   // \ JFT//   return vector//}//TEST FUNC//getCoordinatesFromLatLng();//new-york//getCoordinatesFromLatLng({lat:48.858854,lon:2.350368});//paris  // \ LESS 2-12scene.add(group)
// \ our code

window.addEventListener( 'resize', onWindowResize )

renderer.setAnimationLoop( () => {
  // our code
  TWEEN.update()
  group.rotation.y += 0.001// было if(o)o.rotation.y+=.001  // \
  renderer.render(scene, camera)
})

function onWindowResize() {

  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();

  renderer.setSize( window.innerWidth, window.innerHeight );

}

Код тестовой цены с линиями и кубами

import './style.css'
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import * as dat from 'dat.gui'

import { MeshLine, MeshLineMaterial } from 'three.meshline';
// Debug
const gui = new dat.GUI()

// Canvas
const canvas = document.querySelector('canvas.webgl')

// Scene
const scene = new THREE.Scene()

// Objects
const geometry = new THREE.IcosahedronBufferGeometry(1.05, 3);

// Materials

const material = new THREE.MeshBasicMaterial({
    transparent:true,
    opacity: .7,
})
material.color = new THREE.Color(0x333333)

// Mesh
const sphere = new THREE.Mesh(geometry,material)
scene.add(sphere)

const getRandPosition=()=>new THREE.Vector3().random().subScalar(.5).setLength(5);
//sphere.position.set(position_.x,position_.y,position_.z)

//console.log(position_);
function createCurve(q){
    // Эти штуки необходимы для позиционирования над поверхностью планеты
    const lonHelper = new THREE.Object3D();
    scene.add(lonHelper);
    // We rotate the latHelper on its X axis to the latitude
    const latHelper = new THREE.Object3D();
    lonHelper.add(latHelper);
    // The position helper moves the object to the edge of the sphere
    const positionHelper = new THREE.Object3D();
    positionHelper.position.z = .5;
    latHelper.add(positionHelper);
    // Used to move the center of the cube so it scales from the position Z axis
    const originHelper = new THREE.Object3D();
    originHelper.position.z = 0.5;
    positionHelper.add(originHelper);
    // QuadraticBezierCurve3 — создаёт из трёх и более точек кривую Безье
    const curve = new THREE.QuadraticBezierCurve3(
        new THREE.Vector3(q.q[0],q.q[1],q.q[2]),
        new THREE.Vector3(q.w[0],q.w[1],q.w[2]),
        new THREE.Vector3(q.e[0],q.e[1],q.e[2])
    );
    // Возвращаю константу, хотя можно было и просто возвратить результат. Здесь просто её можно залогировать, чтобы понять, что происходит
    const pointsCurve = curve.getPoints(24);
    // ... например, так:
    // console.log(pointsCurve)
    return pointsCurve;
  }//\Curve
  const lineMesh=new Array
function createMeshLine(dataFromCreateCurve,flat=null){
    // Строим геометрию
    // Здесь я делаю цвета линий немного разными, чтобы разнообразить их
    let color=new THREE.Color(.2,THREE.Math.randFloat(0,1),1);
    let dashRatio=.5,
        lineWidth=.005
    if(flat){// это линии, которые белые — летят из нашего центра в другие стороны, в отличии от синих линий, которые летят К ЦЕНТРУ (нашему условному центру)
        color=new THREE.Color(0xffffff);
        dashRatio=.9
        lineWidth=.003
    }
    const line = new MeshLine();// экземпляр MeshLine
    line.setGeometry(dataFromCreateCurve);// Передаём ему геометрию из функции выше
    const geometryl = line.geometry;
    // Построить материал с параметрами, чтобы оживить его.
    const materiall = new MeshLineMaterial({
        transparent: false, // Необходимо, чтобы была видна анимация, если false, то линия просто будет залита определённым цветом и не будет видна анимация
        lineWidth,
        color,
        dashArray: 2, // всегда должен быть
        dashOffset: 0, // начать с dash к zero
        dashRatio, // видимая минута ряда длины. Мин: 0.5, Макс: 0.99
    });
    // Построение сетки
    const lineMeshMat = new THREE.Mesh(geometryl, materiall);// Создаём саму линию (Mesh)
    lineMeshMat.lookAt(new THREE.Vector3())// Здесь можно и не писать это
    //parent.add(lineMeshMat); // Добавим её на сцену
    scene.add(lineMeshMat);
    lineMesh.push(lineMeshMat); // Добавим эту одну линию, созданную выше, в массив для их анимаций
}
function dataForFlatCurve(otkuda,cuda,mps=2){
    let o=new Object
    //o.const=[.64,.775,-.275];// Позиция главной (первой появляющейся) точки на карте

    //centered 0
    o.x=THREE.MathUtils.lerp(otkuda[0],cuda[0],.6)
    o.y=THREE.MathUtils.lerp(otkuda[1],cuda[1],.5)
    o.z=THREE.MathUtils.lerp(otkuda[2],cuda[2],.5)

    const nePA=new Array();
    const nePA2=new Array();
    const distance=new THREE.Vector3(cuda[0],cuda[1],cuda[2]).distanceTo(
        new THREE.Vector3(otkuda[0],otkuda[1],otkuda[2])
    );
    console.log("mps distance = "+distance);
/*    
 
    (distance<1)?console.log("distance = "+distance):null;
    mps=distance/3;
    if(mps<1.4){
        mps=1.2;
        console.log("DETECT < 1.4");
    }else if(mps>2){
        mps=1.4
    }
    
 */
    nePA.push(
        new THREE.Vector3(cuda[0],cuda[1],cuda[2]),
        new THREE.Vector3(o.x,o.y,o.z),
        new THREE.Vector3(otkuda[0],otkuda[1],otkuda[2])
    );
    nePA.forEach(e=>nePA2.push(e.normalize()))

    const curve = new THREE.QuadraticBezierCurve3(
        nePA2[0].multiplyScalar(1.075),
        nePA2[1].multiplyScalar(2),
        nePA2[2].multiplyScalar(1.075)
    );
    const pointsCurve = curve.getPoints(24);
    const geometryCurve = new THREE.BufferGeometry().setFromPoints( pointsCurve );
    const materialCurve = new THREE.LineBasicMaterial( { color : 0xffffff,opacity:.5,transparent:true } );
    const curveObject = new THREE.Line( geometryCurve, materialCurve );
    return curveObject.geometry.attributes.position.array
  }
/* const mainPos=[.662,.8,-.28];
const rand_=getRandPosition();
const rand_2=getRandPosition();

createMeshLine(dataForFlatCurve([
    rand_.x,
    rand_.y,
    rand_.z,
],[
    rand_2.x,
    rand_2.y,
    rand_2.z,
]))
const rand_3=getRandPosition();
const rand_4=getRandPosition();

createMeshLine(dataForFlatCurve([
    rand_3.x,
    rand_3.y,
    rand_3.z,
],[
    rand_4.x,
    rand_4.y,
    rand_4.z,
])) */


var paris = {
    lat: 40.4251,
    lon: 74.0021
  };
/*   console.log(paris);
  
  var parisSpherical = {
    lat: THREE.Math.degToRad(90 - paris.lat),
    lon: THREE.Math.degToRad(paris.lon)
  };


var parisVector = new THREE.Vector3().setFromSphericalCoords(
  radius,
  parisSpherical.lat,
  parisSpherical.lon
);
// check we did it correctly
var spherical = new THREE.Spherical().setFromVector3(parisVector);
 */

const radius = 1;


function getCoordinatesFromLatLng(latitude, longitude, radiusEarth,color='red')
{
   let latitude_rad = latitude * Math.PI / 180;
   let longitude_rad = longitude * Math.PI / 180;

   let xPos= radiusEarth * Math.cos(latitude_rad) * Math.cos(longitude_rad);
   let zPos = radiusEarth * Math.cos(latitude_rad) * Math.sin(longitude_rad);
   let yPos = radiusEarth * Math.sin(latitude_rad);
   
   const coor= {x: xPos, y: yPos, z: zPos};

   const g_=new THREE.BoxBufferGeometry(.1,.1,.1)
   const m_=new THREE.Mesh(g_,
           new THREE.MeshBasicMaterial({color})
       )
   scene.add(m_)
   m_.position.set(coor.x,coor.y,coor.z)


}

//console.log(getCoordinatesFromLatLng(paris.lat,paris.lon,radius));
getCoordinatesFromLatLng(33.5204,151.1226,radius);//Sydnay
getCoordinatesFromLatLng(48.864716,2.349014,radius,'green');//paris

createMeshLine(dataForFlatCurve([0,2,0,],[1,-2,0,]))
//createMeshLine(dataForFlatCurve([-1,.1,0,],[1,-.5,0,]))
//createMeshLine(dataForFlatCurve([-1,1,0,],[1,-0,0,]))
/* for(let i=0;i<60;i++){

    const rand_3=getRandPosition();
    const rand_4=getRandPosition();

    createMeshLine(dataForFlatCurve([
        rand_3.x,
        rand_3.y,
        rand_3.z,
    ],[
        rand_4.x,
        rand_4.y,
        rand_4.z,
    ]))
} */

/* const nre=sphere.clone()

const ve=new THREE.Vector3().random()
nre.position.set(position_.x,position_.y,position_.z)
scene.add(nre) */

// Lights

const pointLight = new THREE.PointLight(0xffffff, 0.1)
pointLight.position.x = 2
pointLight.position.y = 3
pointLight.position.z = 4
scene.add(pointLight)

/**
 * Sizes
 */
const sizes = {
    width: window.innerWidth,
    height: window.innerHeight
}


///

///


window.addEventListener('resize', () =>
{
    // Update sizes
    sizes.width = window.innerWidth
    sizes.height = window.innerHeight

    // Update camera
    camera.aspect = sizes.width / sizes.height
    camera.updateProjectionMatrix()

    // Update renderer
    renderer.setSize(sizes.width, sizes.height)
    renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
})

/**
 * Camera
 */
// Base camera
const camera = new THREE.PerspectiveCamera(75, sizes.width / sizes.height, 0.1, 100)
camera.position.x = 0
camera.position.y = 0
camera.position.z = 2
scene.add(camera)

// Controls
const controls = new OrbitControls(camera, canvas)
// controls.enableDamping = true

/**
 * Renderer
 */
const renderer = new THREE.WebGLRenderer({
    canvas: canvas
})
renderer.setSize(sizes.width, sizes.height)
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))

/**
 * Animate
 */

const clock = new THREE.Clock()

const tick = () =>
{

    const elapsedTime = clock.getElapsedTime()

    // Update objects
    //sphere.rotation.y = .5 * elapsedTime

    // Update Orbital Controls
    // controls.update()

    // Render
    renderer.render(scene, camera)

    // Call tick again on the next frame
    window.requestAnimationFrame(tick)
}

tick()

Расшифровка временных меток видео:

00:00-05:55 Guten Tag
05:56 Теоретическая часть: функция конвертации широты и долготы в Vector3 (ThreeJS)
16:44 Приступаю к переносу кода из готового к коду урока, поясняя его
17:49 Особенность кода. Берём картинку карты с сервера, а не JS переменной
18:56 Как формируется новая карта планеты
23:25 Поясняю новый код
31:29 Создаю доп-ные кубы, чтобы найти точки (JFT)
35:34 Поясняю за радиус сфера (или икосаэдра)
37:55 multiplyScalar в ThreeJS
39:17 ThreeJS методы Spherical(), setFromVector3()
40:18 Как вычисляется Vector3 из широты и долготы?
42:52 Тестовый куб (надо было добавить ко группе group.add(m_0))
44:41 Режим отладки, пытаюсь найти куб ^
55:17 Линия из координат сферы (глобуса) создаётся этим кодом в ThreeJS
59:03 Использование функции конвертации широты/долготы в Vector3 в ThreeJS
01:00:15 JFT: политическая карта мира на ThreeJS
01:01:56 Подвожу итоги
01:02:42 Важное замечание по загрузке map.jpg
01:05:12 Что будет дальше?
01:10:54 Auf Wiedersehen
copyleft 2023. we use: GatsbyJS, React, Google Analytics. Source code