How to create multiple polygon into single geometry with three js - three.js

I have some countries polygon. I want to draw them on top of my sphere with three js, but when I'm trying to draw these polygons, fps drop down, at 3fps....
Someone told me to create juste ONE geometry and include all the polygons into it, did you have an example?
What I'm doing:
foreach countrie in countries
geometry = new THREE.shapeGeometry();
geometry.push(vectorArray);
var mesh = new Mesh(geometry);
globe.Add(mesh);
With over 250 countries, Three js just creates over 38k buffer. Strange behaviour, without any control, we shouldn't be able to create such buffers... so where am I wrong? I need help.

The three.js class THREE.GeometryUtils has a number of helpful methods for situations like these...
In particular, there is a merge method that will combine two Geometry objects into one. Assume that you have three geometry objects, country1, country2, country3. Then you could do something like:
temp = THREE.GeometryUtils.merge( country1, country2 );
allCountries = THREE.GeometryUtils.merge( temp, country3 );
Hope this helps!

Related

Aframe create shape from vectors

I'm doing something like this, How to create a custom square in a-frame but with custom shapes (i.e. drawing around an image to make a hotspot to make part of that image interactive)
I've got the line working and I'm now trying to convert this into a fill.
this._mesh = make('a-plane', {
geometry:"buffer: false"
}, this.el)
this._mesh.addEventListener('loaded', e => {
this._mesh.getObject3D('mesh').geometry.vertices = this._points
this._mesh.getObject3D('mesh').geometry.computeFaceNormals()
this._mesh.getObject3D('mesh').geometry.computeVertexNormals()
})
I'm getting close but it's only showing one triangle i.e. something like this
How do i get the shape to fill the whole area? I have done this before with a ConvexGeometry and Quick hull but it seems cumbersome.
I got the idea for updating the vertices of a plane from the above post.
If you create an array with Vector2 objects representing the contour of your shape in CCW order, you can use an instance of Shape and ShapeBufferGeometry to achieve the intended result. Just pass the array of points to the ctor of Shape. The following official three.js example demonstrates this approach:
https://threejs.org/examples/webgl_geometry_shapes
BTW: Instead of defining the contour by an array of points, you can also use the API of Shape to define shapes. A simple triangle would look like so:
var triangleShape = new THREE.Shape()
.moveTo( 80, 20 )
.lineTo( 40, 80 )
.lineTo( 120, 80 )
.lineTo( 80, 20 );
var geometry = new THREE.ShapeBufferGeometry( shape );
var mesh = new THREE.Mesh( geometry, material );
three.js R113

Applying different textures on a THREE.js OBJLoader loaded object

I have a square shape .obj model and 2 textures. How do I apply one texture on it's top face and another on rest of faces?
There are a ton of ways to do what you're asking all with varying complexity depending on your needs. It looks like you want to apply two materials to your object and not two textures.
It looks this way because it seems you want the textures to be interchangeable so there's no way you're going to combine the images and keep resolution and OBJ & THREE.Material only support one set of uv attributes so you can't use a single material and multiple textures. So multiple materials it is...
Multiple materials
If you have two materials (2 THREE.Materials which correlate to 2 WebGL programs) then each face needs to know what material it's assigned to.
While the THREE.js multi material API has been in flux for quite a while and there are differences between THREE.Geometry and THREE.BufferGeometry, fortunately for you THREE.OBJLoader supports material groups out of the box. To get this into THREE.js, you want to apply multiple materials in your 3D editor to your object and then export the OBJ to get everything. Doing it by hand is a little harder and requires calling addGroup as shown in the docs/the link above.
In THREE.js you simply pass in all the materials as an array to your object demonstrated in this answer. I also updated your fiddle to do the same thing. Relevant code shown below
var loadingManager = new THREE.LoadingManager();
var ObjLoader = new THREE.OBJLoader(loadingManager);
var textureLoader = new THREE.TextureLoader(loadingManager);
//Material 1 with first texture
var material = new THREE.MeshLambertMaterial({map: textureLoader.load('https://dl.dropboxusercontent.com/s/nvnacip8fhlrvm4/BoxUV.png?dl=0')});
//Material 2 with second texture
var material2 = new THREE.MeshLambertMaterial({map:
textureLoader.load('https://i.imgur.com/311w7oZ.png')});
ObjLoader.load(
'https://dl.dropboxusercontent.com/s/hiazgei0rxeirr4/cabinet30.obj?dl=0',
function ( object ) {
var geo = object.children[0].geometry;
var mats = [material, material2];
//These are just some random groups to demonstrate multi material, you need to set these up so they actually work for your object, either in code or in your 3D editor
geo.addGroup(0,geo.getAttribute("position").count/2,0);
geo.addGroup(geo.getAttribute("position").count/2,
geo.getAttribute("position").count/2,1);
//Mesh with multiple materials for material parameter
obj = new THREE.Mesh(geo, mats);
obj.position.y = 3;
});

How to set vertex colors of THREE.Points object in three.js

I am trying to write a function that creates a point cloud from mesh. I also want to control colors of every vertex of that point cloud. So far I tried to assign colors of geometry but colors doesnt being updated.
InteractablePointCloud_simug=function(object, editor){
var signals=editor.signals;
var vertexSize=0.3;
var pointMat= new THREE.PointsMaterial({size:vertexSize , vertexColors:THREE.VertexColors});
var colors=[];
var colorStep=0.1;
for (var i = 0; i < object.geometry.vertices.length; i++) {
colors.push(new
THREE.Color(colorStep*i,colorStep*i,colorStep*i));
};
//get points from mesh of original object
var points=new THREE.Points(object.geometry,pointMat);
//Update colors
points.geometry.colors=colors;
points.geometry.colorsNeedUpdate=true;
updatePosition();
//Add points object to scene
editor.addNoneObjectMesh(points);
}
I think this is probably doable on other video cards, but mine does not seem to like it.
Theoretically.. if your material color is white.. it should multiply times the vertex color ( which is basically like using the vertex color ), but since you did not specify black as your color, this is not the problem ).
If your code is not working on your computer ( not on mine either ), you will have to go nuclear... and just create a new selectedPointsGeometry and a new selectedPointsMesh
Grab a couple of vertices from the original.. copy them.. put them in a vertices array.. and run an update method ( you have to recreate the geo and mesh every time.. at least on my PC, I tried calling every single update method, and had to resort to recreating )
mind the coffee script. #anchor is the container
updateSelectedVertices: (vertices) ->
if #selectedParticles
#anchor.remove #selectedParticles
#pointGeometry = new THREE.Geometry()
#pointGeometry.vertices = vertices
#selectedParticles = new (THREE.PointCloud)(
#pointGeometry,
#selectedPointMaterial
)
#pointGeometry.verticesNeedUpdate = true
#pointGeometry.computeLineDistances()
#selectedParticles.scale.copy #particles.scale
#selectedParticles.sortParticles = true
#anchor.add #selectedParticles
selectedPointMaterial is defined elsewhere. Just use a different color ( and different size ).. than your non selected point cloud.
IE.. use black and size 5 for non selected point cloud , and use yellow and 10 for the selected one.
My other mesh is called #particles.. and I just have to copy the scale. (this is the non-selected point cloud)
Now my selected points show as yellow

how do I access the attributes of bufferGeometry from an an A-Frame component

I am writing a component that needs to access and modify position, normal, and uv attributes on a model read into A-Frame as an asset. I can get close to accessing the data, but can't quite get there. Using:
document.querySelector('a-entity').object3D.children
seems to give me an array, but trying to access the elements gives me an object with empty children and empty geometry.
My guess is that I'm trying to access the data through the wrong door and while:
console.log(document.querySelector('a-entity').object3D.children);
shows me an array size=1 with a populated Object element
console.log(document.querySelector('a-entity').object3D.children[0]);
gives me the element with the empty geo, etc. What is the right mechanism or syntax to use to get at the data?
There are two three.js classes you'll need to know about here: Geometry and BufferGeometry. The former already has properties for geometry.vertices and geometry.faces (see documentation there). Vertices are an array of THREE.Vertex3 objects, and easy to work with.
If you have a BufferGeometry, then instead you have geometry.attributes.position which is not an array of THREE.Vertex3, but instead contains a flat array of floats, like [x1, y1, z1, x2, y2, ...]. This is more efficient, but harder to modify manually.
If you have BufferGeometry but would rather work with Geometry, then you can convert either way:
var geometry = Geometry.fromBufferGeometry( mesh.geometry );
mesh.geometry = BufferGeometry.fromGeometry( geometry );
An A-Frame specific note, usually you'll get a reference to the mesh by doing el.getObject3D('mesh'). For custom models that might be a nested group, in which case:
el.object3D.traverse(function(node) {
if (node.geometry) { /* ... */ }
});
(three.js r84)

Outline object (normal scale + stencil mask) three.js

For some time, I've been trying to figure out how to do an object selection outline in my game. (So the player can see the object over everything else, on mouse-over)
This is how the result should look:
The solution I would like to use goes like this:
Layer 1: Draw model in regular shading.
Layer 2: Draw a copy in red color, scaled along normals using vertex shader.
Mask: Draw a black/white flat color of the model to use it as a stencil mask for the second layer, to hide insides and show layer 1.
And here comes the problem. I can't really find any good learning materials about masks. Can I subtract the insides from the outline shape? What am I doing wrong?
I can't figure out how to stack my render passes to make the mask work. :(
Here's a jsfiddle demo
renderTarget = new THREE.WebGLRenderTarget(window.innerWidth, window.innerHeight, renderTargetParameters)
composer = new THREE.EffectComposer(renderer, renderTarget)
// composer = new THREE.EffectComposer(renderer)
normal = new THREE.RenderPass(scene, camera)
outline = new THREE.RenderPass(outScene, camera)
mask = new THREE.MaskPass(maskScene, camera)
// mask.inverse = true
clearMask = new THREE.ClearMaskPass
copyPass = new THREE.ShaderPass(THREE.CopyShader)
copyPass.renderToScreen = true
composer.addPass(normal)
composer.addPass(outline)
composer.addPass(mask)
composer.addPass(clearMask)
composer.addPass(copyPass)
Also I have no idea whether to use render target or renderer for the source of the composer. :( Should I have the first pass in the composer at all? Why do I need the copy pass? So many questions, I know. But there are just not enough resources to learn from, I've been googling for days.
Thanks for any advice!
Here's a js fiddle with working solution. You're welcome. :)
http://jsfiddle.net/Eskel/g593q/6/
Update with only two render passes (credit to WestLangley):
http://jsfiddle.net/Eskel/g593q/9/
The pieces missing were these:
composer.renderTarget1.stencilBuffer = true
composer.renderTarget2.stencilBuffer = true
outline.clear = false
Now I think I've found a bit simpler solution, from the THREEx library. It pre-scales the mesh so you dont need a realtime shader for it.
http://jeromeetienne.github.io/threex.geometricglow/examples/geometricglowmesh.html

Resources