Help with globe extrusion

@Keeger This one combines some of your work with some of mine https://www.babylonjs-playground.com/#5I9JSA#8

Map sphere points to a plane somewhat parallel to country.

Rotate points to horizontal, form a polygon (not extruded). Check relative size of each triangular facet, if greater than 10% of total area add extra points inside the triangle. These extra points will act as singularities ( ie that will be used as holes in making a new polygon but as each hole is a single point no hole is formed but the extra points are used to create more triangles)

Dispose of original polygon and create a new polygon with the singularities.

Rotate polygon back to somewhat parallel to country and map plane points to above sphere using given depth storing the upper edge of the raised country outline. Form a ribbon from the original country outline as one path and the upper edge as the other path.

Merge ribbon and polygon to form a landMass.

4 Likes

wow.

that is pretty amazing John. a lot less triangles than the method i was working on now.

I remember thinking “man i want to add points inside the poly, but that will ruin the shape” and I had no idea I could use single points as holes to achieve part of that logic.

You are awesome!

Looking at the rendered output, I think i’m going to keep the ribbon unmerged from the cap. I think I’ll end up using a slightly darker material for the ribbon, to give it more depth look.

now to morph this to a flat plane, with depth. so basically i go from a globe to a flat paper, but the masses are still extruded.

i am working on that now via the googles and reading some docs. I was wondering about your code. in it, you take the 3d points and create a horizontal plane with no depth, and then use that for the area and finding / adding holes.

if I take the sphere, and I want to flatten it, do I do something similar as this code?

    planePoints = [];
centerDistance = 2 * radius;
pointOnPlane = planeNormal.scale(centerDistance);

for (let i = 0; i < nbCoords; i++) {
  let unitVect = outerCoordinates[i].clone().normalize();
  let d = centerDistance / BABYLON.Vector3.Dot(unitVect, planeNormal);
  planePoints.push(unitVect.scale(d));
}

planeX = (planePoints[0].subtract(pointOnPlane)).normalize();
planeY = planeNormal;
planeZ = BABYLON.Vector3.Cross(planeX, planeY).normalize();

let M = new BABYLON.Matrix();
BABYLON.Matrix.FromXYZAxesToRef(planeX, planeY, planeZ, M);

let MT = new BABYLON.Matrix();
M.invertToRef(MT);

let horzPlane = [];
let horzPosition = 0;
for (let i = 0; i < nbCoords; i++) {
  horzPlane[i] = BABYLON.Vector3.TransformCoordinates(planePoints[i], MT);
  horzPosition += horzPlane[i].y;
  horzPlane[i].y = 0;
}

horzPosition /= nbCoords;
//create polygon plane - no depth
let polygon = BABYLON.MeshBuilder.CreatePolygon("polygon", { shape: horzPlane, updatable: true }, scene);

just wondering if that’s a good approach. the extrusion will still be visible, so the 3d isn’t going away, it’s just the world is moving to a flat plane vs a sphere.

First of all for a flat projection you will not need to work about large triangles since there is no possibility of a curved surface cutting through the plane.

Secondly wanting to project the whole globe rather than part of it is completely different. The way my method works is because I am projecting a section of the sphere onto a plane near “parallel” to the section. You cannot have a plane that is any sense “parallel” to the whole globe. global projections are listed here List of map projections - Wikipedia with Equirectangular projection - Wikipedia probably the most straight forward.

Whole new ball game.

Here is a start but not right yet. I think I will leave this for you to play with for a while.

ah, that makes sense.

I appreciate all of your help, and the link to the wiki article. You are the supreme Jedi Leader sir :slight_smile:

2 Likes

ok ran into some issues.

when i load the full world, I get these errors in console.

[.WebGL-000001F7D72422A0] GL_INVALID_OPERATION: Error: 0x00000502, in …/…/third_party/angle/src/libANGLE/renderer/d3d/VertexDataManager.cpp, reserveSpaceForAttrib:514. Internal error: 0x00000502: Vertex buffer is not big enough for the draw call.

this happens after all polygons have been dawn. do i need to increase vertex buffer capacity?

the sphere right now, i can drive the camera through it. however I dont want that. is there a way to tell the webgl to treat the sphere as a blockable solid for rendering?

I’m also noticing holes in Brazil, Russia, and Australia. I tried changing the area to add points for > 1%. this fixes Brazil, but not russia or australia, and that’s kind of weird. the hole in russia is huge. but i’m not sure if the holes are from the vertexbuffer errors, like maybe it freaked out trying to render them?

[edit]
ok i fixed the error by calling forceSharedVertices() on the finished polygon and ribbon. it changes the look of the cap a little bit, but if i play with lighting, it’s not too bad.

and it turns out the error is not why i have holes still in the large countries. so weird. looking at brazil, the largest area value is below 0.1. it is like .08. so that’s why changing to .01 works. however i guess Russia is even smaller? i guess that makes sense cuz of the large landmass. hmm

[edit2]
ok, if I change the number of points to higher (like 10), and a lower area (0.01) it works. so i think i’ll add specific checks for russia, australia, and brazil, and leave the rest of the code alone.

2 Likes

This is amazing.

1 Like

Sorry to circle back to this post. but i’m running into some weirdness with the holes logic and am confused.

In general, the hole logic works well, and I had to do a few manual tweaks for Russia, Australia, and Brazil. i just adjusted the percent comparison and the number of points generated, and found a balance that worked.

However, Argentina is just blowing my mind. There’s a small hole in the country, which I originally thought was a lake, but turns out is a hole. When I use the hole logic code to try and close it…it is generating points outside of the border???

I’ve made a playground to demo, rotate the globe to see Argentina. set normalexp = true to see the hole, which is pretty close to center of the country.

So I’ve also had issues with the triangles crossing dips, so like 2 points are way east, and the 3rd is a coast line west of them, and it basically covers that dip with a triangle.

this is leading me to think i should manually create my hole points and store them, and not have to do the calculation. however, when I try to manually fix Argentina by adding holes, it doesn’t seem to work at all for me.

Is there something special I need to do? do the holes need to be in a specific order, like left hand rule?

https://www.babylonjs-playground.com/#5I9JSA#12

argentina pic

if I don’t draw holes, the triangles covering dips goes away. and looking at the indices, i think the issue may just be something in the addedPoints method. maybe the bug with points outside the triangle is the key.

it’s weird, if I request 1 point, i get 0. if i request 2, i get 1. if i request 3…i get 4 points. trying to figure out what the function is doing exactly. i know what it’s attempting to do, i just wonder…if we add 1 point as a hole, does that change the indice logic, so that it causes my ‘overlap the dips’ issue? should we add 3 points at a time inside?

I believe I have found a solution. although I have not yet tested it against the world.

Basically I re-wrote the addedPoints function in a way I understood. :slight_smile: I take the number of points I want to add, and I bisect the triangle down the middle as many times as I need. With argentina, I think the issue was the normals of the vectors were pointing away, so the vector add or subtract math was going in the wrong direction. however i was unable to figure out how to handle that.

and this also fixes the issue of crossing the dip so far, because i am guaranteeing the holes are inside the existing triangles, so no one is exiting the borders. will see how it goes against the world.

here’s a playground in case anyone is interesting n the code.

https://www.babylonjs-playground.com/#5I9JSA#14

The problems @Keeger was having with Russia, etc was due to mistakes I made in the addedPoints function in #8. Hope these are now corrected in https://www.babylonjs-playground.com/#5I9JSA#17

3 Likes

Johns code works better than mine, lol. and faster too.

Now you need to add some particles… :slight_smile:

hah. soon. :slight_smile: I do have it projecting to a plane using the Van Der Gritten projection method. I find that makes a nice rectangle shape without weird stretching of the main continents.

I never realized how many tris it must take to cover a coastline.
Really excellent project.

Did you ever try reducing the resolution for shits? Not sure the granularity of your data set if it would make any difference.

this is a pretty reduced size actually. I’ve tried using larger sets to see if they reduce the large areas, but no joy.

1 Like

Hopefully the last PG I posted is working for you. However I am not completely happy with it, for one thing it produces many long very thin triangles and secondly I am pretty sure that mathematically line 32 should be

let d = p0.add(p.scale(i * lambda).add(q.scale(i * lambda * j * mu)));

however correcting it produces holes. ???

Anyway if you are happy with things how they are then you need not use this alternative (whose coding is simpler) - Whenever there are holes use the increaseVertices property on the polygon until the holes disappear. An extra parameter on drawCountry function is the number of extra points per triangle side, just work out the smallest number that gives no holes.

https://www.babylonjs-playground.com/#5I9JSA#18

The drawback ( and why I didn’t do it in the first place) is that all triangles no matter how small are split into smaller triangles and for n points per side the increase in triangles is of the order (n + 1 ) * (n + 1). Russia goes from 455 vertices to 2722 vertices

I did try to split just the larger triangles but then you have to split adjacent triangles and those adjacent to them and so on and it got too complicated.

So at the end we shall get something like that?

image

It’s funny. The last update you posted before this only really works well because you bumped the radius by 0.1. however, despite that being such a small distance, it’s visually noticeable! boo. (country doesn’t rest on surface of sphere). I raised depth by 0.1 instead and that returned to a better result. although Argentina still has a tiny slit. I am not a fan of “just make it taller and its fixed.”

the issue with a pure increaseVertices solution, is we are extruding to a spherical look, and that will end up with some countries taller than others, which wont be sexy.

Feature Request! One major issue really, is I have no concept right now if a hole exists or not programmatically. I’ve tried to use Mesh IntersectMeshes to help determine that, and unfortunately there’s no way to make it work with the bounding box / bounding sphere. It would be cool if Babylon created a bounding arc, so intersections could be analyzed more accurately than a bounding box on an item. I feel the logic would mimic the sphere, but I could be wrong haha.

Yesterday i ventured into the world of PDFs of algorithms, looking at CSG subtract type stuff. I was thinking I could draw a sphere at the depth height (radius+depth), with 128 segments (produces good sized triangles), and then subtract the border ribbon out of the sphere. this would return me the vertices from the sphere inside the borders, and then I’d just render those.This would solve holes and give me sweet curvature.

that … did not work in Babylon haha (cpu whimpered and died). (course, the outer shell sphere is like, 32k vertices or 64k, something crazy big). I am thinking of trying this with a csg.js library i found, but I feel it might die too. I tried to use the CreateSphere routine with an arc, to reduce vertices, but I couldn’t find a way to box in the border.

Found a paper on doing it for meshes, but sadly could not find any code, and the paper was juust vague enough i couldn’t pull it out.

As it stands right now, I have 3 functional approaches that I’ve used with varying success.

  1. Return Center and Incenter of triangle. just add those 2 as holes. works great for Canada and Brazil.
  2. Return midpoints of triangle legs, basically I’m attempting to create 4 triangles. got the idea from a Delauney triangulation article, section 1 Although on re-reading it, apparently I read it wrong. so may have to revisit (I was trying to do 4T-LE). My current code works great when i have a narrow triangle such as Argentina. in fact, i think this is the only one that solves it well and simply.
  3. JohnK’s addedPoint logic based on area. this works really well for super large triangles like Russia. but less well for Canada and Australia, and that’s not a tiny triangle! kinda interesting.

Interesting notes: i tried to make (1) and (2) subdivide, thinking if the area is big enough, multiples will be needed. did not work! although that may be programmer error. especially (2)

so I am considering looking at the area of a triangle (i have a function that gets me the true triangle area, using the vertices not a bounding box), and some logic to figure out if the triangle approaches equilateral (canada), narrow (argentina), or superlarge (Russia), and uses one of the above algorithms for it.

I am considering also looking at the longest leg length of the triangle in relation to the sphere. the issue is the curve of the sphere surface. so if my leg is 0.5 length on a radius 2 sphere, that needs to be reduced. I feel like I should be able to mathematically calculate the distance at which the curve intersects a fixed line, and use that as a guide.

This is fairly interesting project haha.

similar. no grid system for me on my render.

If you look at some of the earlier Playground examples, you can set the material to wireframe and see the mesh triangles.

example: mat1.wireframe = true;

Ok, so I cannot find any sort of mathematical formula to help me. I was trying to do some horizon calculation to see if one end of a line can see the opposite end, and I was unable to find one that worked right for me.

in the end, i simply created an array of objects for the hole countries. these are just Canada, Russia, Brazil, Argentina, and Australia.

i think the line length is the key, but given the location of the country on the globe, different values apply. so I just use my mid points for most of them, argentina is only solvable with the 4T LE approach.

a PG with the code:

https://www.babylonjs-playground.com/#5I9JSA#19