import { Renderer } from './beam' import { Camera } from './beam' import { vec2, vec3, mat4 } from './beam' import { Container, Mesh, Material, Texture, SphereGeometryBuffer } from './beam' import settings from './settings' // Shaders in strings import GlobeVS from './globe-vs' import GlobeFS from './globe-fs' function hexToRgb(hex) { var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); return result ? [ parseInt(result[1], 16) / 255, parseInt(result[2], 16) / 255, parseInt(result[3], 16) / 255 ] : [0,0,0]; } function lonLatToVector3(lng, lat) { var phi = (90-lat)*(Math.PI/180), theta = (lng+180)*(Math.PI/180), x = -( Math.sin(phi) * Math.cos(theta) ), z = Math.sin(phi) * Math.sin(theta), y = Math.cos(phi); return [x,y,z]; } class WebglGlobe { // Constructor constructor (options) { this.options = options; this.$el = options.el; this.cities = options.markers let gl; let canvas = document.createElement('canvas') try { gl = canvas.getContext("webgl"); } catch (x) { try { gl = canvas.getContext("experimental-webgl"); } catch (x) { gl = null; } } this.supportWebgl = gl !== null; if (this.supportWebgl) { this.buildWebglScene() this.resize() // this.initPointer() } } // Build buildWebglScene () { this.renderer = new Renderer({ alpha: this.alpha, antialias: this.antialias, }); this.$el.appendChild(this.renderer.canvas); this.texture = Texture.fromUrl(this.renderer.gl, this.options.texture) this.scene = new Container() this.camera = new Camera({ fov: settings.fov, near: 1, far: settings.cameraFar, type: 'perspective', orbitControl: true, firstPerson: false, lookAt: [0,0,0], position: [0,0, (3) / 2 / Math.tan(Math.PI * settings.fov / 360)], }); this.camera.lookAt = vec3.create() this.inverseViewProjectionMatrix = mat4.create() this.viewProjectionMatrix = mat4.create() this.cameraDirection = vec3.create(); this.cameraPosition = vec3.create(); this.globeMesh = new Mesh(); this.globeMesh.material = new Material(this.renderer.gl, { uniforms: { tInput: this.texture }, vertexShader: GlobeVS, fragmentShader: GlobeFS, // depthTest: true }) this.globeMesh.geometry = new SphereGeometryBuffer(this.renderer.gl, { radius: 1, widthSegments: 100, heightSegments: 100 }) this.scene.add( this.globeMesh ) this.markers = [] let markers = this.cities for (let i=0; i{ alert('click on ' + markers[i].name) }) el.classList.add('marker') this.$el.appendChild( el ) this.markers.push({ mesh: markerMesh, el: el, position: p, screenPosition: [0,0] }) } } // Resize method resize () { this.width = this.$el.clientWidth; this.height = this.$el.clientHeight; settings.resolution[0] = this.width //* settings.devicePixelRatio settings.resolution[1] = this.height //* settings.devicePixelRatio if (!this.supportWebgl) { return } this.renderer.setPixelRatio(settings.devicePixelRatio); this.renderer.resize(settings.resolution[0], settings.resolution[1]) this.camera.aspect = settings.resolution[0] / settings.resolution[1] this.camera.updateProjectionMatrix() this.camera.lookAt[0] = 0 this.camera.lookAt[1] = 0 this.camera.lookAt[2] = 0 this.camera.rotation[0] = 0 this.camera.rotation[1] = 0 this.camera.rotation[2] = 0 this.camera.position[0] = 0 this.camera.position[1] = 0 this.camera.position[2] = (3) / 2 / Math.tan(Math.PI * settings.fov / 360) this.camera.render(); vec3.set(this.cameraPosition, this.camera.worldMatrix[12], this.camera.worldMatrix[13], this.camera.worldMatrix[14]); vec3.copy(this.cameraDirection, this.camera.lookAt); vec3.subtract(this.cameraDirection, this.cameraDirection, this.cameraPosition); vec3.normalize(this.cameraDirection, this.cameraDirection); mat4.copy(this.viewProjectionMatrix, this.camera.projectionMatrix); mat4.multiply(this.viewProjectionMatrix, this.viewProjectionMatrix, this.camera.inverseWorldMatrix); let refPos = vec3.create() vec3.set(refPos, 0, 1, 0 ) vec3.transformMat4(refPos, refPos, this.viewProjectionMatrix); let refx = ( (refPos[0] + 1) / 2) * window.innerWidth let refy = (1. - (refPos[1] + 1) / 2) * window.innerHeight let dir2 = vec2.create() vec2.set( dir2, refx, refy ) let center2 = vec2.create() vec2.set( center2, window.innerWidth/2, window.innerHeight/2 ) let dir2d2 = vec2.clone(dir2, dir2) vec2.subtract( dir2d2, dir2d2, center2 ) this.circleScreenSize = vec2.length( dir2d2 ) * 1.04 } // Update update () { if (!this.supportWebgl){ return; } // this.currPointer[0] += ( this.pointerRatio[0] - this.currPointer[0]) * 0.05 // this.currPointer[1] += ( this.pointerRatio[1] - this.currPointer[1]) * 0.05 // this.globeMesh.rotation[1] = this.currPointer[0] // this.globeMesh.rotation[2] = this.currPointer[1] //manually call this as we prevent ithe camera from update between passes this.camera.update(); vec3.set(this.cameraPosition, this.camera.worldMatrix[12], this.camera.worldMatrix[13], this.camera.worldMatrix[14]); vec3.copy(this.cameraDirection, this.camera.lookAt); vec3.subtract(this.cameraDirection, this.cameraDirection, this.cameraPosition); vec3.normalize(this.cameraDirection, this.cameraDirection); mat4.copy(this.viewProjectionMatrix, this.camera.projectionMatrix); mat4.multiply(this.viewProjectionMatrix, this.viewProjectionMatrix, this.camera.inverseWorldMatrix); mat4.invert(this.inverseViewProjectionMatrix, this.viewProjectionMatrix); let screenPos = vec3.create() this.markers.forEach((marker, i)=>{ vec3.set(screenPos, marker.position[0], marker.position[1], marker.position[2] ) vec3.transformMat4(screenPos, screenPos, this.viewProjectionMatrix); let x = ( (screenPos[0] + 1) / 2) * window.innerWidth let y = (1. - (screenPos[1] + 1) / 2) * window.innerHeight let N = vec3.create() vec3.set( N, marker.position[0], marker.position[1], marker.position[2] ) vec3.normalize( N, N ) let V = vec3.create() vec3.set( V, marker.position[0], marker.position[1], marker.position[2] ) vec3.subtract( V, V, this.cameraPosition ) vec3.normalize( V, V ); //behind if ( vec3.dot( V, N ) * -1 < 0) { let dir = vec2.create() vec2.set( dir, x, y ) let center = vec2.create() vec2.set( center, window.innerWidth/2, window.innerHeight/2 ) let dir2d = vec2.clone(dir, dir) vec2.subtract( dir2d, dir2d, center ) vec2.normalize( dir2d, dir2d ); vec2.scale( dir2d, dir2d, this.circleScreenSize ); vec2.add(dir2d, dir2d, center) marker.el.style.transform = `translate(${dir2d[0]}px, ${dir2d[1]}px) translateZ(0)`; marker.el.classList.remove('is-active') } else { //vec3.dot( V, N ) * -1 < 0 ? (1 - vec3.dot( V, N ) / 0.1 ) : 1;//Math.max( 0, vec3.dot( N, V ) ); marker.el.style.transform = `translate(${x}px, ${y}px) translateZ(0)`; marker.el.classList.add('is-active') } // marker.el.style.opacity = 1. }) this.renderer.clearColor(0,0,0,0) this.renderer.clear() this.renderer.render(this.scene, this.camera); } // initPointer() { // this.currPointer = [0,0] // this.pointer = [0,0] // this.pointerRatio = [0,0] // this._onPointerDown = this._onPointerDown.bind(this) // this._onPointerMove = this._onPointerMove.bind(this) // this._onPointerUp = this._onPointerUp.bind(this) // this._handleOrientation = this._handleOrientation.bind(this) // document.addEventListener(support.pointerdown, this._onPointerDown, false); // document.addEventListener(support.pointermove, this._onPointerMove, false); // document.addEventListener(support.pointerup, this._onPointerUp, false); // window.addEventListener('deviceorientation', this._handleOrientation); // } // _handleOrientation(event) { // this.pointerRatio[0] = (event.gamma) / 25 // this.pointerRatio[1] = (event.beta-45) / 25 // } // _onPointerDown() { // this._isPointerDown = true; // } // _onPointerUp() { // this._isPointerDown = false // } // _onPointerMove(event) { // let pe = support.touch && event.type != 'mousemove' ? (event.touches[0] || event.changedTouches[0]) : event; // this.pointer[0] = pe.pageX; // this.pointer[1] = pe.pageY; // this.pointer[1] -= window.pageYOffset || document.documentElement.scrollTop // this.pointerRatio[0] = (this.pointer[0] / window.innerWidth - .5) * 2 // this.pointerRatio[1] = (this.pointer[1] / window.innerHeight - .5) * 2 // } } // window.WebglGlobe = WebglGlobe export default WebglGlobe