Three.js GIS Map (connect layers/attributive information) - three.js

Q: How to connect Three.js with any GIS map and place/process .JS (important .js) object there?
Description:
I have an app with .js model and 3D mesh model (tiles), now I need to retrieve the attributive information of the map (3D mesh) objects where ray intersects, e. I.: this is water, this is forest.
I got an idea to connect any open map and retrieve the information from there by layers (water layer, forest layer).
So far I found threebox + mapbox-gl to connect OpenStreetMap (seems like the one solution). But I cannot place the .js object. Moreover, there are two instances of three.js in the project (one is mine and one from threebox). Can anyone explain how to:
Use just one Three.js instance?
Place JS object in map?
Move object in map (in my own app I have manipulators, but seems like they won't work)?
Would be nice to hear #jscastro
No result:
tb.loadObj({
obj: 'projects/testProject/model/js/test.js',
type: 'custom',
scale: 1, /* same for 1000000000 */
units: 'meters',
rotation: { x: 90, y: 177, z: 0 },
anchor: 'auto'
}, function (model) {
console.log(model)
model.setCoords([25.2826859, 54.6718792, 1280]);
model.addTooltip("Blabla", true);
model.color = 0xffffff;
//model.selected = true;
tb.add(model);
})
up: no problem with loading .js in own app.

Related

Panning around globe until user interacts

Trying to loop around the globe until the user interacts with the map.
Locations are currently based on the flyTo example, as I'm still trying to get the functionality working. I'm struggling to make it animate smoothly, from point to point and loop.
Final version will ideally pan around the globe, and continue until user interacts.
map.on('load', () => {
for (const [index, coordinate] of cityCoordinates.entries()) {
setTimeout(() => {
map.easeTo({
center: coordinate,
duration: 10000
});
coordinate.push(coordinate.shift())
}, 2000 * index);
}
});
https://jsfiddle.net/r8fs2kbd/2/
I saw the animate along a path example, however I don't want the map to rotate or move altitude.

JeelizFaceFilter and THREEJS issue with gltf and texture models

Goal
I'm stuck since yesterday with an issue on modifying a JeelizFilterFace example. My goal is to create my own filters, so I started the the luffy's hat tutorial, which explains that : https://jeeliz.com/blog/creating-a-snapchat-like-filter-with-jeelizs-facefilter-api-part-1-creating-your-first-filter/
Quick description of the problem
My problem is simple : I can't have the glTF example working with glTF models. It always show me a black shape, without the texture.
Details of the problem
The tutorial explains that the model have to be generated with a Blender exporter addons, in order to create the json file which is the model. But the Blender exporter is not supported anymore.
This is why I try to use ThreeJS with the GLTF loader (which is the best solution according to all the tutorials).
My problem is that I can't see any texture on any of my models, when I load it with JeelizFaceFilter/Threejs. I only have the black shape.
Here is what I did :
First, I did all the tutorial to be sure I can run the FilterFace tool, except for the exporting model from Blender part. So, I just copied the exported resources from the Jeeliz repo. The FilterFace works well : the hat is visible, with the texture and I can play with the THREEJS params.
Because I couldn't export the JSON from blender, i wanted to try to use the GLTF 2.0 model, I tried this model, which is working in the gltf-viewer tool (see picture below) : https://s3.eu-west-3.amazonaws.com/com.julianlecalvez/LuffysHat.zip
So far everything seems ok, but when I try to use this glTF loader example in the glTF demos (https://github.com/jeeliz/jeelizFaceFilter/tree/master/demos/threejs/gltf_fullScreen), it displays my hat in black. I have the good shape, but no texture (or no light?). I just replaced the model URL in this file. And I'm not even sure that the default model (the helmet) is displaying any texture.
I tried with a model from SketchFab, and I have the same : Black shape, no texture.
I put here the code to init the view, when I was trying to redo it outside of the demo file :
let init_view = function(spec) {
const threeStuffs = THREE.JeelizHelper.init(spec, null);
const SETTINGS = {
gltfModelURL: 'objects/luffys_hat_gltf/luffys_hat.gltf',
offsetYZ: [1,0],
scale: 2.2
};
// const loader = new THREE.GLTFLoader();
const gltfLoader = new THREE.GLTFLoader();
gltfLoader.load( SETTINGS.gltfModelURL, function ( gltf ) {
gltf.scene.frustumCulled = false;
// center and scale the object:
const bbox = new THREE.Box3().expandByObject(gltf.scene);
// center the model:
const centerBBox = bbox.getCenter(new THREE.Vector3());
gltf.scene.position.add(centerBBox.multiplyScalar(-1));
gltf.scene.position.add(new THREE.Vector3(0,SETTINGS.offsetYZ[0], SETTINGS.offsetYZ[1]));
// scale the model according to its width:
const sizeX = bbox.getSize(new THREE.Vector3()).x;
gltf.scene.scale.multiplyScalar(SETTINGS.scale / sizeX);
// dispatch the model:
threeStuffs.faceObject.add(gltf.scene);
});
// CREATE THE CAMERA
THREECAMERA = THREE.JeelizHelper.create_camera();
}

A-frame: How to give a primitive like Ring or Cylinder depth?

Is it possible to give a 2D primitive like Ring thickness/depth? I'm trying to make a 3D door with primitives and I want to make either a ring that has some depth or a cylinder with a thicker mesh. Even if it's at the three.js layer I would like to learn how to do this so I don't have to rely on imported 3D objects for the whole design.
To extrude a shape, you will need to use THREE.js. Below is an example for how to do this.
https://threejs.org/examples/?q=extrude#webgl_geometry_extrude_shapes2
How to use THREE.js geometery inside AFrame?
You make a custom component that creates a new THREE.Geometry, and inside that component, you build your shape and extrude it (see the THREE.js example, click (<>) button in lower right to see the code).
Below is an example that makes a custom quad in a component.
You can see the glitch here.
https://glitch.com/edit/#!/custom-quad
Look in the quad.js for details.
You should be able to copy code from the three.js extrude demo, and place it into your custom component init function to build the extruded shape.
Then you can create parameters, like 'thickness', and put them in the schema, and then they can be accessed from the component name on the entity.
If you don't yet know how to write a custom component, you will need to practice this to understand how it works.
https://aframe.io/docs/0.9.0/introduction/writing-a-component.html
Here is a snippet from my glitch that makes a custom quad. It shows how to make THREE.Geometry in an AFrame custom component.
init: function (data) {
var geometry = new THREE.Geometry();
geometry.vertices = data.vertices.map(function (vertex) {
var points = vertex.split(' ').map(function(x){return parseFloat(x);});
return new THREE.Vector3(points[0], points[1], points[2], points[3]);
});
// Build the UVs on the faces.
geometry.faceVertexUvs[0].push(
[ new THREE.Vector2(1,0), new THREE.Vector2(0,1), new THREE.Vector2(1,1)
],
[ new THREE.Vector2(1,0), new THREE.Vector2(0,0), new THREE.Vector2(0,1)
]);
geometry.computeBoundingBox();
geometry.faces.push(new THREE.Face3(0, 2, 1), new THREE.Face3(0, 3, 2));
geometry.mergeVertices();
geometry.computeFaceNormals();
geometry.computeVertexNormals();
this.geometry = geometry;
//console.log(data);
}

how to implement complex models in aframe

I'm pretty new to aframe and the ECS-modeling technique, so I probably didn't fully grasp how the architecture should be used.
I want to model something like a robotic arm: in a simplified version that is a base, on top of that a rotator and the arm itself. The model is loaded from a single json-file and consist of several nested objects for the different parts.
How would something like this be implemented in aframe if I want to be able to control the different degrees of freedom independently (which means setting object.rotation-values on the different childs of the object itself)?
One thing I thought of was to implement the loading of the model-file as one component and each degree-of-freedom as a seperate component. So basically something like this:
<a-entity robot-model="..." base-rotation="123" arm-pitch="10" />
Or would it be a better way to use registerPrimitive for something like this?
My first take on it looks like this:
registerComponent('robot', {
schema: {type: 'asset'},
update() {
// - load and parse model using THREE.ObjectLoader
// - once ready, assign property this.parts with the various
// parts of the robot-arm
}
});
registerComponent('dof-1', {
schema: {type: 'number'},
dependencies: ['robot'],
init() {
this.robot = this.el.components.robot;
},
tick(t, dt) {
if (!this.robot.parts) { return; } // not ready yet
// update values (left out here: acceleration etc)
this.robot.parts.dof1.rotation.x = this.data;
}
});
// more parts / dof implemented likewise
I'm assuming you've already created and rigged a 3D model using software like Blender, Maya, or Cinema4D. If not, the article Animation from Blender to three.js is a good starting point.
Once you've done that, you can import the model into A-Frame with any format that supports skinning/rigging. THREE.ObjectLoader (.json) or THREE.GLTFLoader (.gltf) are good options, and there are already A-Frame components that wrap these loaders. Assuming you're using JSON and the object-model component from A-Frame Extras, you could do:
<a-entity object-model="src: url(my-model.json)"></a-entity>
At this point you should see a model in the scene, without having written any JavaScript, but it won't be animating yet. If you know what animation you want up front, you can create the animations in keyframes or morph targets using the same modeling software: Blender, Maya, or Cinema4D. Assuming you included the animations when you exported the model, you can use the animation-mixer component (also from A-Frame Extras) as follows:
<a-entity object-model="src: url(my-model.json)"
animation-mixer="clip: *;"></a-entity>
This will play all animations at once. You could use a clip name, instead of *, to play a specific animation.
If your animations need to be computed at runtime, and can't be baked into the model, you'll need to write a custom component. This gets complicated quickly, but the basics aren't too bad:
<a-entity object-model="src: url(my-model.json)"
custom-animation></a-entity>
And the JS:
AFRAME.registerComponent('custom-animation', {
tick: function (t, dt) {
var mesh = this.el.getObject3D('mesh');
// With complex models, you may need to loop over `mesh.children`
// in case the mesh you want to animate is a child of another
// object in your model file.
if (!mesh || !mesh.isSkinnedMesh) { return; }
mesh.traverse(function (node) {
if (node.isBone && node.name === 'arm') {
node.rotation.x += dt * Math.PI / 1000;
}
});
}
});

Three.js exports Blender model without texture

I am trying to export this https://www.dropbox.com/s/zz1g38xaci2ibod/sailor.blend?dl=1 Blender model using exporter from Three.js 73 (from github master branch).
But when I load it I see no texture:
var loader = new THREE.JSONLoader();
loader.load("assets/sailor.json",
function (geom, mat) {
console.log(mat);
var model = new THREE.Mesh(geom, mat[0]);
model.castShadow = true;
scene.add(model);
});
The model has two meshes (body and eyes) but looks like this exporter can export only one mesh... So for now I exported without eyes.
Exporter settings:
Exporter output file: sailor.json
io_three.export.log is empty with any logging level.
I'm not sure this will solve your problem but it might atleast give you a hint of where the problem is.
I compared my converted JSON files and compared to yours, and noticed that the JSON file that you use does not specify what texture the object should use.
Add:
"mapDiffuse" : "nameoftexture.png",
to your
"materials: [{
...,
...,
...
}]"
array.
Good luck.
EDIT
Your model seems to work with textures for me when I added this line to the materials property array.

Resources