Merging an entire Object3D/Mesh hierarchy together - javascript

I am working on a project that is dynamically generating trees. It's currently only in an early prototype stages, and so the branches and leaves are just simple cubes. The tree is made up of a hierarchy of the cubes, nested with the rotations and scaling down of the branches. I need to be able to add more branches/leaves to the tree, but can convert it to a static tree just for rendering purposes.
I am running into a problem when the tree gets too large, rendering many cubes slowing the program down.
After doing a lot of research, I discovered the THREE.GeometryUtils.merge() function, that would merge all the branches in my tree into one object that can be rendered/transformed much faster than before. However the problem I am encountering is the merge doesn't take into account all of the parent transforms, merging only it's vertices.
The basic code I am trying to get working is as follows. I have played around with applying the matrix to the geometry and a few other things, but have not got anything working properly yet.
var newGeo = new THREE.Geometry();
var newTree = tree.clone(); //Clones the tree so the original does not get altered
newTree.traverse(function(child){
if(child.parent){
child.applyMatrix( child.parent.matrixWorld);
}
THREE.GeometryUtils.merge(newGeo, child);
});
I have created a simple jsFiddle program for it:
http://jsfiddle.net/JeYhF/2/
The left object is 4 meshes parented inside each other and the right object is the mesh combination. As you can see, each component of the combination has its own transforms applied (translation in y axis by 11 units and rotation in z axis by PI/4), but they are not affected by the parent transforms.
The function in question is the MergeTree() function. This program would only work in chrome for me.
Any advice for how to solve this problem would be very much appreciated.
Thanks

The problem was the matrix world was not calculated before the merging. So the transforms were all just the identity matrix.
newTree.traverse(function(child){
if(child.parent){
child.updateMatrixWorld();
child.applyMatrix(child.parent.matrixWorld);
}
THREE.GeometryUtils.merge(newGeo, child);
});

Related

How to look at a vertices neighbor and the weight of the edge between the two?

I'm working on trying to implement Dijkstra's algorithm (in javascript) and I'm having some trouble in trying to figure out how to read a vertices neighbors and the weight of the edge between them.
I've created this graph here. Its nothing special, I plan on creating more graphs I just made this one for the initial test.
var graph1=
{
A:{B:1, C:2},
B:{A:1, D:4, E:1},
finish: Infinity
};
Thanks for the help!!
From what you've given, to view a vertices neighbor would be Object.keys(graph1['A']) for instance. Further, the weight would just be something like graph1['A']['B'].
Try famliarizing yourself with JavaScript Objects

3D Grid for multiple shapes

A few months ago I made a small terrain generator, like Minecraft, for a school project.
The way I did this was by using multiple chunks. Each chunk contained a 3-dimensional array that stored the blocks.
Every position in this array corresponded with the position of the block it contained.
blocks[x, y, z] = new Block();
Now I would like to add different sizes if blocks. However, I can't do that with the way I am storing the blocks right now, because bigger blocks would have to be spread over multiple positions in the 3-dimensional array.
An example of a game with different sizes of blocks (and different shapes) is LEGO Worlds. How does a game like this store all these little blocks?
I hope someone can help me with this.
The language I am using is Javascript in combination with WebGL.
Thanks in advance!
In my experience there are a few different ways of tackling an issue like this, but the one I'd recommend would depend on the amount of time you have to work on this and the scope (how big) you wanted to make this game.
Your Current Approach
At the moment I think your using what most people would consider the most straightforward approach by storing the voxels in a 3D grid
[Source].
But two problems you seem to be having is that there isn't an obvious way to create blocks that are bigger then 1x1 and that a 3D grid for a world space is fairly inefficient in terms of memory usage (As for an array you have to have memory allocated for every cell, including empty space. JavaScript is no different).
An Alternative Approach
An alternative to using a 3D array would be to instead use a different data structure, the full name being a sparse voxel octree.
This to put it simply is a tree data structure that works by subdividing an area of space until everything has been stored.
The 2D form of this where a square sub divides into four smaller quadrants is called a quad tree and likewise a 3D equivalent divides into eight quadrants, called an octree. This approach is generally preferable when possible as its much more efficient because the trees only occupy more memory when its absolutely essential and they can also be packed into a 1D array (Technically a 3D array can be too).
A common tactic used with quad/octrees in some block based games is to take a region of the same kind of voxel that fit into one larger quadrant of the tree is to simply stop sub division there, as there's no reason to go deeper if all the data is the same.
The other optimization they can make is called sparse where regions of empty space (air) are simply deleted since empty space doesn't do anything special and its location can be inferred.
[SVO Source]
[Z Order Curve Source]
Recommended Approach
Unless you have a few months to complete your game and you're at university I seriously wouldn't recommend an SVO (Though reading up about could impress any teachers you have). Instead I'd recommend taking the same approach that Minecraft appears to visibly has. E.G. A door is 1X2 but blocks can only be 1x1, then just make it two blocks.
In the example of a door you would have four unique blocks in total, two for the upper and lower half, and two variations of each being opened or closed.
E.G.
var cubeProgram; // shader program
var cubeVBO; // vertex buffer (I recommend combining vertex & UV coords)
var gl; // rendering context
// Preset list of block ID's
var BLOCK_TYPES = {
DOOR_LOWER_OPEN: 0,
DOOR_UPPER_OPEN: 1,
DOOR_LOWER_CLOSED: 2,
DOOR_UPPER_CLOSED: 3,
}
var BLOCK_MESHES = {
GENERIC_VBO: null,
DOOR_UPPER_VBO: null
DOOR_LOWER_VBO: null
}
// Declare a Door class using ES6 syntax
class Door {
// Assume X & Y are the lower half of the door
constructor(x,y,map) {
if (y - 1 > -1) {
console.error("Error: Top half of the door goes outside the map");
return;
}
this.x = x;
this.y = y;
map[x][y ] = BLOCK_TYPES.DOOR_LOWER_OPEN;
map[x][y-1] = BLOCK_TYPES.DOOR_UPPER_OPEN;
}
}

Three Js How to copy Object direction that it's facing

I'm currently making a 3d space fighter game for my school project, but I encounter a problem when I want to spawn a projectile according to my ship front face or direction it's facing.
I do find a way to spawn projectile according direction we are facing using vector in the following example
http://www.isaacsukin.com/news/2012/06/how-build-first-person-shooter-browser-threejs-and-webglhtml5-canvas
but I still does'nt undestand how this vector work. Can someone explain to me ?
I understand it is more an linear algebra question than programming. First you must fully understand, what Vector is, and what isn't.
Often mistake is, that a Vector is some coordinate in 3D space (x,y,z). This is no true and this thinking will not allow understand, how to correctly work with vectors in space and let's you ask questions like this one.
https://www.khanacademy.org/math/linear-algebra/vectors-and-spaces
https://www.khanacademy.org/math/linear-algebra/vectors-and-spaces/vectors/v/vector-introduction-linear-algebra
If you need only to copy object rotation, you can use obj2.rotation.set(obj1.rotation.x,obj1.rotation.y,obj1.rotation.z)
If you want so put something to the space object facing, you can use object as parent:
var my_vect = new THREE.Object3D(); // create vector
obj1.add(my_vect); // add to your object
obj1.rotation.set(1,2,3); // rotate object
my_vect.position.translateX(1); // move vector 1 unit before the object
obj1.localToWorld( my_vect.position); // get global coords from local coords
actually my_vect.position.x,my_vect.position.y,my_vect.position.z are the numbers in your scene before the object respecting object orientation.

resizing individual models in a single geometry

I have a 3D model of my home town. I would like to use real time data to change the height of the buildings. In my first try, I loaded the buildings as individual meshes and called scene.add(buildingMesh) during setup.
var threeObjects = []
var buildingMesh = new THREE.Mesh(geometry, material)
threeObjects.push(buildingMesh);
$.each(threeObjects,function(i, buildingMesh)
{
buildingMesh.rotation.x += -3.1415*0.5;
buildingMesh.castShadow = true;
buildingMesh.receiveShadow = true;
scene.add(buildingMesh);
});
Which is too slow as my dataset consists of roughly 10.000 building.
So I took the approach to add all the (geometries of the) meshes to a single geometry and wrap that in a mesh to be added to the scene
singleGeometry.merge(buildingMesh.geometry, buildingMesh.matrix); //in a loop
var faceColorMaterial = new THREE.MeshLambertMaterial( { color: 0xffffff, vertexColors: THREE.VertexColors } );
combinedMesh = new THREE.Mesh(singleGeometry, faceColorMaterial);
scene.add(combinedMesh);
Just to make a proof of concept, I'm trying to change the height of a building when I click it. Alas, this is not working.
By adding a new id field, I can get a reference to the faces and vertices and change the color of the building, but I can not for the life of me, get them to to change height.
In my first version, I would just use something like:
buildingMesh.scale.z=2;
But as I have no meshes anymore, I'm kinda lost.
Can anybody help?
disclaimer: I'm new to Three.js, so my question might be stupid...hope it's not :)
If you combine all of your buildings into a single geometry, you're obliterating everything that makes the buildings distinct from each other. Now you can't tell building A from building B because it's all one big geometry, and geometry at its basic level is literally just arrays of points and polygons with no way of telling any of it apart. So I think it's the wrong approach to merge it all together.
Instead, you should take advantage of three.js's efficient scene graph architecture. You had the right idea at first to just add all the buildings to a single root Object3D ("scene"). That way you get all the efficiencies of the scene graph but can still individually address the buildings.
To make it load more efficiently, instead of creating the scene graph in three.js every time you load the app, you should do it ahead of time in a 3D modeling program. Build the parent/child relationships there, and export it as a single model containing all of the buildings as child nodes. When you import it into three.js, it should retain its structure.
JCD: That was not quite the question I asked.
But anyhow, I found a solution to the problem.
What I did was to merge all the geometries, but in stead of using the standard clone function in geometry.merge() I used a shallow reference, which made it possible for me to use the reference in threeObjects to find the correct building and resize the part of the geometry using Mesh.scale, followed by a geometry.verticesNeedUpdate = true;
For further optimization, I split the model into 5 different geometries and only updated the geometry that contained the building

Split weakly-simple-polygon to true simple polygon or polygons

I want to divide weakly-simple polygons into simple polygons.
Background
The use case is to simplify polygons that are Simplified (Unioned) using Javascript Clipper. Javascript Clipper's as well as original Clipper's SimplifyPolygon() function removes self-intersections and combines common edges, but it cannot produce true simple polygons. The output is used in three.js, which has TriangulateShapes() which needs polygons to be simple. Three.js accepts polygon structures that have one contour and zero or multiple holes.
Input, weakly-simple polygons
Weakly-simple polygons cannot have sequential-duplicate-vertices (true duplicate points), nor holes (islands) nor self-intersections (edge crossing over other edge), but there can be non-sequential-multiple-vertices (vertices that have exactly the same coordinate but not as sequential). The input polygon can have either CW or CCW winding order, which means that CW input is outer polygon and CCW is a hole. The input is either CW or CCW polygon.
The input is an array of polygon points eg.:
// This is a true example of weakly-simple polygon:
var input = [{"X":270,"Y":520},{"X":130,"Y":490},{"X":210,"Y":250},{"X":60,"Y":170},{"X":130,"Y":490},{"X":20,"Y":410},{"X":60,"Y":300},{"X":60,"Y":20},{"X":780,"Y":40}, {"X":680,"Y":180},{"X":460,"Y":130},{"X":210,"Y":250},{"X":320,"Y":100},{"X":220,"Y":80}, {"X":210,"Y":250},{"X":520,"Y":250},{"X":680,"Y":180},{"X":770,"Y":480},{"X":540,"Y":470}, {"X":520,"Y":250},{"X":380,"Y":280},{"X":430,"Y":390},{"X":540,"Y":470},{"X":270,"Y":520},{"X":330,"Y":350},{"X":210,"Y":250}];
This is the above input polygon as an image:
And here are the points numbered, where you can easily see what points are duplicates:
As you see, the above polygon can be divided in multiple ways, eg.:
- One outer polygon with five holes
- five outer polygons of which one has one hole
Output, simple polygons as a exPolygon structure
Simple polygon is a polygon that have no self-intersections, no duplicate coordinates whether they were sequential or non-sequential, no holes. The output's simple polygon can have CW or CCW winding order. CW means outer and CCW holes.
The output can have (and in many times there will be) holes, but in certain cases the output has no holes. The output has always at least one outer polygon, but there can be also multiple outer polygons that have zero or more holes.
The output should be an array of exPolygon objects that have properties "outer" and "holes". "outer" is an array of point objects, "holes" is an array of arrays of point objects. If "holes" is populated, the holes in it have to be holes of "outer" polygon in the exPolygon object.
The example of output:
// This is an example of output, but the points are random:
[ { "outer": [{"X":54,"Y":4},{"X":2,"Y":50},{"X":30,"Y":5},{"X":10,"Y":50}],
"holes": [ [{"X":0,"Y":8},{"X":60,"Y":13},{"X":21,"Y":2},{"X":3,"Y":1}],
[{"X":21,"Y":2},{"X":50,"Y":2},{"X":6,"Y":1}] ] },
{ "outer": [{"X":54,"Y":4},{"X":2,"Y":50},{"X":30,"Y":5},{"X":10,"Y":50}],
"holes": [ [{"X":0,"Y":8},{"X":60,"Y":13},{"X":21,"Y":2},{"X":3,"Y":1}],
[{"X":21,"Y":2},{"X":50,"Y":2},{"X":6,"Y":1}] ] },
{ "outer": [{"X":54,"Y":4},{"X":2,"Y":50},{"X":30,"Y":5},{"X":10,"Y":50}],
"holes": [] }
];
Output's "outer" polygons are CW, and "holes" are CCW.
There is no limit for counts of points in polygons, count of exPolygons objects nor count of holes.
Here are other examples of weakly simple polygons:
Example of division
Here is an example of input polygon:
Here is how it could be divided:
Some other polygons can have multiple possible alternatives of ouput depending where are the pseudo-duplicate-points.
My question
How the polygons can be divided this way and the desired output structure achieved? I'm not asking full code (but if you have some spare time and want to show that it is possible). Thoughts of possible algorithms are also welcome.
I have searched hours a solution and tried to find an algorithm.
In case you want to try a solution, I have here a code which I have used to find the duplicates: http://jsbin.com/unuyev/7/edit. It shows the polygon in SVG and shows the points as red circles and an array index of each point (after pressing button "Run with JS").
Here is the same, but with 12 example polygons (change pindex in Javascript window to change the polygon):
http://jsbin.com/unuyev/4/edit
EDIT: Javascript Clipper 6 is available now and there is support for StrictlySimple. But according to the documentation "There's currently no guarantee that polygons will be strictly simple since 'simplifying' is still a work in progress". I have tested StrictlySimple and it fails in certain cases: Orientation problems and lack of rotation invariance. We hope these are fixed soon and StrictlySimple works as expected.
There may be something that I'm missing, but this looks like a classic problem of finding the articulation vertex of a graph. Essentially you're trying to find the weakest point in a graph such that when you cut the graph at that point, you end up with two separate graphs. So in your example, if you cut the polygon at that vertex, you end up with multiple polygons. You can represent your polygons quite easy as a graph, with each vertex representing a graph vertex, and the polygon edges as graph edges.
If I had to solve the problem, this is the approach that I would take. You can check out the following resources:
Articulation vertices from the Algorithm Design Manual - This is your best bet. He explains the algorithm in simple terms and also gives you C code that you can easily translate into JavaScript. If I had to start writing an algorithm, this is where I would start.
Biconnected component
Detection of Articulation Points (search for "articulation")
UPDATE
I'll try and give you a brief overview of the problem and the solution to point you in the right direction. An implementation of this algorithm using graphs will necessarily go into graph-algorithm terminologies, so if you are not familiar with graphs, you might want to read up on them.
The brute-force approach in your case would be to traverse the graph, temporarily delete each vetex and then see if the graph is connected when doing a DFS/BFS traversal on the modified graph. This is not very efficient and will run in quadratic time O(n(m + n)). But there is a linear-time algorithm that is based on classifying the edges of the resultant DFS tree that is formed from a DFS traversal.
In a DFS tree that doesn't contain any back-edges (edges connecting a "lower" node to a node "higher" in the tree [assuming "higher" nodes are those closer to the root]) leaf nodes are not articulation nodes, since deleting any one of them will still leave the graph connected. However, deleting any of the internal nodes will disconnect any nodes that follow it from the root.
Deleting the root of the tree depends on whether it has one or more children. If it has just one child, then it's more-or-less a leaf and so deleting it will have no effect. However, deleting a root node that has more than one child will disconnect the graph.
But in a general graph, you can have back-edges and so deleting any of the nodes in between will not disconnect the graph. So figuring out the articulation vertices boils down to figuring out which sections of the tree are linked to ancestor nodes by back edges (i.e., figuring out the "reachable ancestor" of a vertex).
In the page I linked to from the Algorithm Design Manual, Skiena describes three cases where a vertex can be an articulation vertex (root, bridge, and parent cut-nodes). Using the algorithm he describes, you can figure out if the vertex you are processing, meets any of those conditions. If it does, it is an articulation node.
Hopefully this helps you get started!

Categories

Resources