geo-three icon indicating copy to clipboard operation
geo-three copied to clipboard

How to implement custom map nodes

Open farfromrefug opened this issue 4 years ago • 12 comments

I got your lib to run in my very specific mobile env and first thank you for that! Your GPU height shader is pretty awesome!

Now the aim of my project is to get something like PeakFinder. i already have the Three JS post processing effect using https://github.com/OmarShehata/webgl-outlines (which i need to change i guess to be able to use your height shader).

  • The first thing is that i dont need the "tile" provider, i simply need to render the height vertex using MeshBasicMaterial or something. Is that possible?
  • the second thing is tile loading. In my env (which is not that good perf wise) i can see that when i set the location and start rendering "closest" tiles are first rendered at low level then slowly renderer at higher level. Is there a way to make it load directly at the "final resolution"? It would greatly improve performance in my case. Is that the LOD handling that? maybe i can write a custom one.

Thanks
Screenshot 2021-04-28 at 15 08 24

farfromrefug avatar Apr 28 '21 13:04 farfromrefug

Hello

The TileProvider is just used to acess tiles by their coordinates it should be fairly simple create a tiler provider that does not return anything (to save on processing).

The LOD Control is responsible for deciding when to subdivide or simplify the tiles, im currently working on a system based on CancelablePromises to solve the problem that you are facing where you need to wait for intermediate tile level instead of going directly to the final LOD level.

Thanks a lot for your questions.

Cheers

tentone avatar Apr 28 '21 13:04 tentone

@tentone thank you :D are you in the three discord? maybe we could chat a bit more there. Would love to help you on that lib. Could really help me get the end result of my oss project

farfromrefug avatar Apr 28 '21 13:04 farfromrefug

No, but feel free to ask for help anytime here on github.

Cheers

tentone avatar Apr 28 '21 17:04 tentone

@tentone thanks so i ll ask :P 1/ I have looked at how to not using a "texture" on the 3d terrain but it was possible as is. The idea was to override the MapNode to not fetchTile in loadTexture and directly set textureLoaded and call nodeReady. No big deal as i think i will have to my own MapNode anyway. Which makes me ask: could you add a way to use a custom MapNode?

2/ i am trying to compute the normals in the vertex shader of MapHeightNodeShader. The idea is to render MapHeightNodeShader like MeshNormalMaterial (i need a normalBuffer for a post effect). as you see i am not there yet. Screenshot_1619630983 I have done something like this: But something seems wrong with my dz computation Would you have any idea on how to do that ?

EDIT: actually got it. Need to handle tiles borders now

var vertexShader = `
	varying vec2 vUv;
	
	uniform sampler2D heightMap;
	varying vec3 vNormal;

	float getElevation(vec2 coord, float bias) {
		// Convert encoded elevation value to meters
		vec4 e = texture2D(heightMap, clamp(coord, 0.0, 1.0));
		return ((e.r * 255.0 * 65536.0 + e.g * 255.0 * 256.0 + e.b * 255.0) * 0.1) - 10000.0;
	}
	
	void main() 
	{
		vUv = uv;

		// queried pixels:
		// +-----------+
		// |   |   |   |
		// | a | b | c |
		// |   |   |   |
		// +-----------+
		// |   |   |   |
		// | d | e | f |
		// |   |   |   |
		// +-----------+
		// |   |   |   |
		// | g | h | i |
		// |   |   |   |
		// +-----------+
		
		// vec4 theight = texture2D(heightMap, vUv);
		ivec2 size = textureSize(heightMap, 0);
		float offset = 1.0 / 256.0;
		float a = getElevation(vUv + vec2(-offset, -offset), 0.0);
		float b = getElevation(vUv + vec2(0, -offset), 0.0);
		float c = getElevation(vUv + vec2(offset, -offset), 0.0);
		float d = getElevation(vUv + vec2(-offset, 0), 0.0);
		float e = getElevation(vUv, 0.0);
		float f = getElevation(vUv + vec2(offset, 0), 0.0);
		float g = getElevation(vUv + vec2(-offset, offset), 0.0);
		float h = getElevation(vUv + vec2(0, offset), 0.0);
		float i = getElevation(vUv + vec2(offset,offset), 0.0);

		const float NormalLength = 0.001;

    	vec3 v0 = vec3(0.0, 0.0, 0.0);
		vec3 v1 = vec3(0.0, NormalLength, 0.0);
		vec3 v2 = vec3(NormalLength, 0.0, 0.0);
		v0.z = (e + d + g + h) / 4.0;
    	v1.z = (e+ b + a + d) / 4.0;
    	v2.z = (e+ h + i + f) / 4.0;

		vec3 transformed = position + e * normal;
		vec3 worldNormal = normalize ( mat3( modelMatrix[0].xyz, modelMatrix[1].xyz, modelMatrix[2].xyz ) * normal );

		vNormal = (normalize(cross(v2 - v0, v1 - v0)));
		gl_Position = projectionMatrix * modelViewMatrix * vec4(transformed, 1.0);
	}`;

farfromrefug avatar Apr 28 '21 17:04 farfromrefug

@tentone got most of what i need running. Still need to fix the normals are they are wrong on the "ground" Screenshot 2021-04-29 at 12 25 07

Now i had to make some changes to your lib to make it work (to allow more customisation). Are you ok with me creating PR with those?

farfromrefug avatar Apr 29 '21 10:04 farfromrefug

Yes please go ahead open a PR with your solution for custom map nodes.

I was starting to work on something too allow external implementation of MapNodes but probablt you already have something that can be used.

tentone avatar Apr 29 '21 12:04 tentone

@tentone ok will do. One question. is there any point where the childrenCache would be removed? If i look correctly at the code it wont. Wouldn't kill memory at one point? Would be nice to have a way to "destroy" meshes if they are far away

EDIT: @tentone you can see What i have so far at https://farfromrefug.github.io/geo-three/examples/

farfromrefug avatar Apr 29 '21 14:04 farfromrefug

@farfromrefug

The childcache has no mechanism for removing them currently. I want to introduce a mechanism for this eventually.

Your code seems quite nice 👍 Feel free to open PR maybe can be used as an example of custom nodes.

I will finish today the new mechanism for custom nodes and provide a simple example

tentone avatar May 02 '21 10:05 tentone

@tentone i made a lot of progress in my demo here https://farfromrefug.github.io/geo-three/examples/index.html. got almost everything working. Now i made quite a lot of changes that you can see here https://github.com/farfromrefug/geo-three/commits/master (tried to separate everything in understandable commits):

  • i work mostly with the lod frustum
  • the frustum dont rely on the provider max zoom anymore to compute the distance as it breaks when the maxZoom is not 20
  • i added an optional parameter to the MapView to have a callback on nodeReady. That way my map dont use animate anymore but just redraw as i move around (like most maps would).
  • i implemented a "one pass" lod. The updateLOD do all operations in one go (recursive). This is the biggest change but it also has the biggest impact. Now in my demo loadTexture is not called on node creation but only when needed (not subdivided, over minZoom and under maxZoom). The result is pretty big. Like now when you load the demo only 32 loadTexture are done again around 150 and 200 in the default implementation. However it might not be what everyone wants as you have to wait to see. You wont see level 0 while higher levels load. If you are interested about this we can try an make it an option of the MapView
  • no error when either the elevation or texture does not exist for a single tile. Right now it is failing hard and the tile is not showing at all. It also breaks subdivision and simplification.

I have not made PRs yet cause i think it would be better for you first to look at one i have done a bit. If you like something i can make PR and change things to your liking

farfromrefug avatar May 07 '21 15:05 farfromrefug

It would be cool if you could share those examples, they seem quite nice we can add an example page to the library.

Thanks a lot once again!

tentone avatar May 19 '21 09:05 tentone

@tentone when you say examples you mean the classes for LOD and and Nodes? or the example app using all that?

farfromrefug avatar May 19 '21 09:05 farfromrefug

Just the classes should be enough, i think we can add some running examples based on these.

Should be of help to other people trying to achieve similar goal ;)

tentone avatar May 19 '21 11:05 tentone