Closed lslzl3000 closed 4 years ago
@lslzl3000 thanks for reaching out.
That's an interesting request. Is this something you could potentially achieve by manipulating the globe wrapping material, accessible via .globeMaterial()
?
Alternatively you could create a custom layer that renders another sphere (or fraction of a sphere) with a video texture on.
Globe material example: https://github.com/vasturiano/three-globe/blob/master/example/custom-material/index.html#L23-L27
Custom layer example: https://github.com/vasturiano/three-globe/blob/master/example/custom/index.html#L24-L34
Thanks for your reply. I've successfully created surface image/video labels in the custom layer. So I'll close this issue
@lslzl3000 nice! Do you have a demo you could share? 😃
@vasturiano here is a simple demo, hope to add image/video with given lat/lng and given size.
// create a blank sphere with given w&h
function addSurfacePanel(lat, lng, alt, width, height) {
let R = 100 * (1 + alt)
let geometry = new THREE.SphereBufferGeometry(R, 160, 160, Math.PI / 180 * (90 - width / 2), Math.PI / 180 * width, Math.PI / 180 * (90 - height / 2), Math.PI / 180 * height)
let material = new THREE.MeshBasicMaterial()
let sphere = new THREE.Mesh(geometry, material)
// added in a group, easy rotation
let group = new THREE.Group()
group.add(sphere)
// I don't use lat/lng here, cause we need to update location in customThreeObjectUpdate anyway
return group
}
// load texture
function loadTexture(url, onProgress) {
return new Promise((resolve, reject) => {
new THREE.TextureLoader().load(url, resolve, onProgress, reject)
})
}
// e.g. load a image at (0,0), a video at(0,180)
const customLayerData = [
{ type: 'image', id: 't1', lat: 0, lng: 0, alt:0.01, width: 60, height: 40, url: '/image/earth-day.jpg' },
{ type: 'video', id: 't2', lat: 0, lng: 180, alt:0.01, width: 60, height: 40, url: '/video/demo.mp4', autoplay: false }
]
globe.customLayerData(customLayerData)
.customThreeObject(d => {
switch (d.type) {
case 'image':
return addSurfacePanel(d.lat, d.lng, d.alt, d.width, d.height)
break
case 'video':
// for video, create a video element first
let video = document.createElement('video')
video.id = d.id
video.src = d.url
video.style.display = 'none'
document.body.appendChild(video)
// this will be easier when use Vue/React/.. to manage dom
return addSurfacePanel(d.lat, d.lng, d.alt, d.width, d.height)
break
// other types
}
}).customThreeObjectUpdate(async (group, d) => {
// first, update lat/lng, I used group here, maybe you can come up with a better solution
let obj = group.children[0]
// make sure group is at origin
group.position.set(0, 0, 0)
// rotate sphere along with x as lat
obj.rotation.x = Math.PI / 180 * -d.lat
// then rotate group along with y as lng
group.rotation.y = Math.PI / 180 * d.lng
// then update texture
let texture
switch (d.type) {
case 'image':
texture = await loadTexture(d.url)
obj.material.map = texture
obj.material.needsUpdate = true
break
case 'video':
let video = document.querySelector('video#'+d.id) // could access easily in Vue/React...
if (d.autoplay)
video.play()
else
video.currentTime = 1
// replace texture with videoTexture
texture = new THREE.VideoTexture(video)
texture.minFilter = THREE.LinearFilter
texture.magFilter = THREE.LinearFilter
texture.format = THREE.RGBFormat
obj.material.map = texture
obj.material.needsUpdate = true
break
case 'text': // could also make curved text label
...
break
}
}).onCustomLayerClick(obj => {
if (obj.type == 'video') {
let video = document.querySelector('video#'+d.id) // could access easily in Vue/React...
video.paused ? video.play() : video.pause()
}
})
It works fine: e.g. Static image
e.g Live video play
Maybe we could make new image/video layers in this project. I think it would be a good feature
The video layer is potentially very useful.
It can be used to visualize different kinds of animated data from
Here is a water vapor example (it uses video overlay but on top of a 2d map)
https://user-images.githubusercontent.com/6873202/152752302-339eb1d7-5e7a-479f-a621-58c500803b6d.mp4
@bumbeishvili thanks for your pointer.
Also worth noting that this can now more easily be achieved with the tiles layer. See docs here: https://github.com/vasturiano/three-globe#tiles-layer
Essentially each custom positioned tile can be setup with its own tileMaterial
which can be linked to a video, using Three's VideoTexture.
Alternatively the same thing could potentially be achieved in the same manner as the clouds example, by extending the existing scene with a globe wide object showing the water vapor. That is even a more flexible approach for some custom use cases. You can see the relevant code here: https://github.com/vasturiano/globe.gl/blob/3e3140fdf9595439d15ebbd3a198948dd071af59/example/clouds/index.html#L29-L40
Is your feature request related to a problem? Please describe. My project requires very complex dynamic effects on the globe surface, it's hard to code in three.js, but we cloud make a 2:1 globe video to simulate all effects. Three.js has a video texture demo, so is there possible to render video texture on the globe?
Describe the solution you'd like Like the demo, we cloud customize a video texture in globeMaterial()
In addition, like #9, support image/video content on the globe with particular location would be a nice feature