Unity 3d exporter missing terrain

I sent you a PM. :slight_smile:

Yo @manrix … I looked at the project in Classic Edition… I just see a large terrain and no navmesh setup… I dont know what MicroSplat is… I just export the internal unity nav mesh triangles… If this microsplat somehow effects the internal Unity nav mesh triangles before i export them… Kool.

The terrains in the Classic Edition are SCREWED … There has been a long going post about the texture amount and texture atlas and edge seams… But NO ONE ELSE in the whole community can or will go into Toolkit code and try and fix some things that i obviously cant get right. Like:

01… Terrain Splatmap Shader With Texture Atlas — AND NO EDGE SEAMS

02 … Skeletal Initial Bone Matrix Inverse Bind Poses — TAKING INTO ACCOUNT THE TRANSFORM Absolute Position

03… Some POLOR Space Coord Interpolation Game Math I need for Animation Blending Weights — BEEN BEGGING FOR THIS OVER A YEAR

and a couple other minor issues… But those are the main hold ups the Babylon Toolkit - Unity Exporter

BTW… I been trying to work on a Pro Terrain SDK that manages terrain and collision segments…

That terrain exceeds Unity 65,000 triangles and must be segmented (Unless you make the mesh yourself in code using the exported heightmap and layer textures)

I can only use the base texture right now because of texture atlas and edge seams… But this is what your seen looks like so far in my new Pro Toolkit:

And the Green Overlay is your NavigationMesh that you have setup directly on the terrain

Yo @manrix … The terrain based nav mesh looking good so far :slight_smile:

As far as raw terrain segments and mesh geometry running such a LARGE terrain for WebGL…

And rocking 60 FPS :slight_smile:

Got the the Unity Skybox vs Babylon Skybox Infinite Distance Magic Padding Number Worked out so you get the true Unity Lighting and Perspective Viewing but in a web friendly gltf scene file with unity metadata that the new Babylon Scene Manager will parse on load automatically:

Looking better and better… Just need to get the texture atlas shader with no edge seams going:

Unity Shot:

Babylon Shot (With just the base texture wrapped over entire terrain… for now):

Looks pretty close for one being a million dollar game engine and the other being the the Awesome Babylon WebGL Game Engine

You gotta luv it :slight_smile:

1 Like

Hey.
Really nice. :slight_smile:
Can’t wait to try the new exporter.
I’m using that big image as a placeholder to rebuild the map.
At end what i need is heightmap, splatmaps of textures and navmesh. For texturing the terrain i’m going to use the code here PBR texture splatting (up to 64 textures). The problem is the current version of exporter generates splatmap for only first 6 textures. I also had to remove the black color to make it work with that code.
I think at this point is the only way. I don’t see other solutions. It’s a bit sad because texturing a scene is one of most important things in a game.
Thanks for your nice work Mackey. :wink:

I am updating the classic edition… Depreciating the attemt at exporting terrain meshes and materials…

Just export the Layer Textures, Layer Normals, Splatmap Texture Atlas (up to 4 splatmap textures per atlas) and the terrain heightmap image…

Add up support for up to 12 Separate Layer Textures and Normals (Not in Texture Atlas)

If you get a splat map texture going… Please show me the EXACT SHADER CODE you used to get it to work…

What would you prefer for classic exporter to dump…

1… Each separate Layer Texture Image (up to 12)

or

2… A Terrain Image Layrer Atlas with up to images encoded in texture atlas (also a Normals Atlas)

Let me know if you can get texture Atlas working and i will make the classic edition pack the 12 separate layer textures into an atlas :slight_smile:

I’m using the code from the playground i linked you.
Shader code is quite difficult, i can’t help you much. I think you already know more than me. Choose you the best way to do it. :slight_smile:

That looks really good… I think i can see a tiny bit of edge seams… but is by far the best four tap implementation i have seen so far.

Who wrote that originally… ?

Do you understand everything going on in that shader… ?

I tried something like this before, but could never get it to work… ?

My initial issue i guess is what they are calling positions and scale… I use Unity PackTexture features… so i end up with RECT from 0 to 1 that specify each texture in the whole atlas…

I need to figure out how to convert that example to more of a Unity Prepared content…

Can you work with me on this… Not just making that PBRCustomMaterial (Which is great too, that why i created that class… But i wanna go DEEPER into the native unity workflow to use that shader)

If you work with me… over gotomeeting or something like that… So we can work on together… I will send you my new Pro Toolkit (not ready for public redist yet) and we can work on terrains together… but in the context of the New GLTF based Babylon Toolkit …

PM me and let me know if that is something would like to work on with me :slight_smile:

And btw… the classic edition you are currently using… I take it you want the Texture Atlas and not individual texture layer images ???

Yo @manrix … Got a question:

The atlas texture you are loading is nearest nearest… In unity would that be POINT filtermode

take a look at this code block please:

			if (texture.filterMode == FilterMode.Point)
			{
				sampler.MinFilter = MinFilterMode.NearestMipmapNearest;
				sampler.MagFilter = MagFilterMode.Nearest;
			}
			else if (texture.filterMode == FilterMode.Bilinear)
			{
				sampler.MinFilter = MinFilterMode.NearestMipmapLinear;
				sampler.MagFilter = MagFilterMode.Linear;
			}
			else
			{
				sampler.MinFilter = MinFilterMode.LinearMipmapLinear;
				sampler.MagFilter = MagFilterMode.Linear;
			}


Those are the filter modes for textures so the GLTF parser will apply the proper filter on GLTF load… I need to mark the Atlas Textures with the proper filter mode… Would that be POINT for the Texture Atlas

var atlas = new BABYLON.Texture("textures/4tapp2.jpg", scene, false, false, BABYLON.Texture.NEAREST_NEAREST_MIPNEAREST);

Hi Mackey.
I’m using the code posted here PBR texture splatting (up to 64 textures). As i said, i don’t understand shader code. I can’t help you understand how it works, because i don’t understand it either.
Strange nobody in this forum is able to explain it, there’re many skilled people here.
Maybe we’ll get more luck if we ask on unity forum.
If you need help testing, i’m available.

@Deltakosh, can you please explain me what is vAlbedoUV in shader ?
For example in this code:
vec2 uv1 = vec2((vAlbedoUV.x + 2.0) * 0.5, (vAlbedoUV.y * 1) + 1.0 * 1);
Thanks.

I think i might have it now… Once i fixed up the toolkit to properly export the right filter modes based on texture import settings… So all textures eight get exported as:

UPDATE

It has nothing to do with filter mode (except render quality).
Its actually in the the fracting with bilinear filtering and computing the mip map level and using the glsl texture2DExtLod to sample the texture.

Thats what made the difference :slight_smile:

That was my issue before… When using a texture atlas with Tiling and the fract caused edge seams . The POINT Filter mode helped alot but the Playground shader code stills has a bit of artifacts… especially in the distance…

This one look pretty darn good to me… No edge seams and no artifacts :slight_smile:

I still got working on the shader code properties… That shot was a hard coded rect… just to test read one of images out of the texture atlas and tiling it across the terrain

3 Likes

And my version (from articles i found around the internet about texture atlas and mipmap level) will be MUCH easier to use and understand:

    #ifdef TERRAINTEXTURES
        // JSON: "textureRect0": { "X": 0.0, "Y": 0.0, "Z": 0.25, "W": 0.5 },    
        vec4 textureRect0 = vec4(0.0, 0.0, 0.25, 0.5); 

        // JSON: "textureInfo0": { "X": 1.0, "Y": 1.0, "Z": 0.0, "W": 0.0 },
        vec2 textureScale0 = vec2(99.2, 75.36);
        vec2 textureOffset0 = vec2(0.0, 0.0);

        // TEST: Sample Test Texture Atlas Tile
        float tilelod = -1.0;
        float tilesize = 1024.0;
        vec2 tilecoord = vec2(0.0, 0.0);
        vec2 tilescaled = ((vAlbedoUV + textureOffset0) * textureScale0);
        vec4 tilepacked = vec4(textureRect0.z, textureRect0.w, tilesize, 10.0);

        // Sample texture tile from atlas
        vec4 textureAlbedo0 = sampleTextureAtlas2D(terrainTextures, tilescaled , tilecoord, tilepacked, tilelod);

        surfaceAlbedo.rgb = textureAlbedo0.rgb;
    #endif


@MackeyK24, nice. :slight_smile:

Holy Shit… I think i finally cracked terrain shaders. Its actually alot of shit to learn. But since i could not get anybody to actually contribute any real world terrain shader code for the toolkit… Finally … I said Fuck it… I had to go to the drawing board and figure this whole advanced terrain shader thing out for myself.

1… The Texture Atlas(s) Must be perfect. Can be any filter mode (Point, Bilinear or Trilinear). Each Tile Must be squared (Ex: 1024 x 1024) and the same resolution. DO NOT need to encode the entire mip chain into atlas either.

2… Must use a manual calculation for the desired mip map level in your shader. In a terrain shader. the further out should get more blurry. Have to use texture2DLodExt no way around that and keep it SIMPLE

3… Must use a fract for tiling. Cant get around that at all. The magic is in recalculating the uv after the fract using bilinear filtering.

4… The splatmap atlas also need to be just as perfect as the detail texture atlas. The higher the resolution the better. Up to a point. i like 1024 splatmap and 1024 detail resolution textures.

5… Sample tiles from the splatmap, detail and normal atlas(s) with the correct gamma correction and mip map level selection.

6… Mixing all the texture layer colors can be tricky. Everybody uses the mix glsl shader function. But that sucks for me. I cant get the fine grain detail like from a high res Unity Terrain. So i made my own color blending function that works like fucking charm

All my shader functions are short and sweet and very easy to understand and use

Mackey GLSL Terrain Shader Functions. These four simple functions i wrote are all you need

//////////////////////////////////////////////////////////////////////////////////////
/// CalculateMipmapLevel
//////////////////////////////////////////////////////////////////////////////////////
/// - uvs is the texture uv
/// - size is the texture size
//////////////////////////////////////////////////////////////////////////////////////
float calculateMipmapLevel(const in vec2 uvs, const in vec2 size)
{
    vec2 dx = dFdx(uvs * size.x);
    vec2 dy = dFdy(uvs * size.y);
    float d = max(dot(dx, dx), dot(dy, dy));
    return 0.4 * log2(d);
}
//////////////////////////////////////////////////////////////////////////////////////
/// SampleTextureAtlas2D
//////////////////////////////////////////////////////////////////////////////////////
/// - atlas is the texture atlas from which to sample a tile
/// - gamma is the desired gamma corection (NoCorrection = 1.0 - LinearCorrection = 2.2 - GammaCorrection = 0.454545)
/// - tile is the texture tile size in pixels and texture tile bits (ex.: a 1024 tile is 10 bits, a 512 tile is 9 Bits)
/// - rect is the position in atlas and the inverse of the number of horizontal tiles (ex.: 4 tiles -> 0.25 x 2 tiles -> 0.5)
/// - uvs are the texture coordinates of the pixel *inside the tile*
/// - lod is the desired mip map bluring (-1.0 for auto mip mapping bluring)
//////////////////////////////////////////////////////////////////////////////////////
vec4 sampleTextureAtlas2D(const in sampler2D atlas, const in float gamma, const in vec2 tile, const in vec4 rect, in vec2 uvs, in float lod)
{
	if (lod < 0.0) lod = clamp(calculateMipmapLevel(uvs, vec2(tile.x, tile.x)), 0.0, tile.y);   // Tile Info (tile.xy)
	float size = pow(2.0, tile.y - lod);                                                        // Tile Bits (tile.y)
	float sizex = size / rect.z;                                                                // Tile Width (rect.z)
	float sizey = size / rect.w;                                                                // Tile Height (rect.w)
	uvs = fract(uvs);                                                                           // Perfrom Tiling (fract)
	uvs.x = uvs.x * ((sizex * rect.z - 1.0) / sizex) + 0.5 / sizex + rect.z * rect.x;           // Tile Position X (rect.x)
	uvs.y = uvs.y * ((sizey * rect.w - 1.0) / sizey) + 0.5 / sizey + rect.w * rect.y;           // Tile Position Y (rect.y)
    vec4 color = texture2DLodEXT(atlas, uvs, lod);
    if (gamma != 1.0) {
        color.r = pow(color.r, gamma);
        color.g = pow(color.g, gamma);
        color.b = pow(color.b, gamma);
    }
    return color;
}
//////////////////////////////////////////////////////////////////////////////////////
/// SampleSplatmapAtlas2D
//////////////////////////////////////////////////////////////////////////////////////
/// - atlas is the texture atlas from which to sample a tile
/// - gamma is the desired gamma corection (NoCorrection = 1.0 - LinearCorrection = 2.2 - GammaCorrection = 0.454545)
/// - tile is the texture tile size in pixels and texture tile bits (ex.: a 1024 tile is 10 bits, a 512 tile is 9 Bits)
/// - rect is the position in atlas and the inverse of the number of horizontal tiles (ex.: 4 tiles -> 0.25 x 2 tiles -> 0.5)
/// - uvs are the texture coordinates of the pixel *inside the tile*
//////////////////////////////////////////////////////////////////////////////////////
vec4 sampleSplatmapAtlas2D(const in sampler2D atlas, const in float gamma, const in vec2 tile, const in vec4 rect, in vec2 uvs)
{
	float size = pow(2.0, tile.y);                                                              // Tile Bits (tile.y)
	float sizex = size / rect.z;                                                                // Tile Width (rect.z)
	float sizey = size / rect.w;                                                                // Tile Height (rect.w)
	uvs.x = uvs.x * ((sizex * rect.z - 1.0) / sizex) + 0.5 / sizex + rect.z * rect.x;           // Tile Position X (rect.x)
	uvs.y = uvs.y * ((sizey * rect.w - 1.0) / sizey) + 0.5 / sizey + rect.w * rect.y;           // Tile Position Y (rect.y)
    vec4 color = texture2D(atlas, uvs);
    if (gamma != 1.0) {
        color.r = pow(color.r, gamma);
        color.g = pow(color.g, gamma);
        color.b = pow(color.b, gamma);
    }
    return color;
}
//////////////////////////////////////////////////////////////////////////////////////
/// BlendSplatmapTileColors
//////////////////////////////////////////////////////////////////////////////////////
/// - splatmap is the mix color map
/// - color1 splatmap texture color 1
/// - color2 splatmap texture color 2
/// - color3 splatmap texture color 3
/// - color4 splatmap texture color 4
/// - mixbuffer is the final mixing buffer
//////////////////////////////////////////////////////////////////////////////////////
vec3 blendSplatmapTileColors(const in vec4 splatmap, in vec4 color1, in vec4 color2, in vec4 color3, in vec4 color4, in vec3 mixbuffer)
{
    mixbuffer += (color1.rgb * splatmap.r);
    mixbuffer += (color2.rgb * splatmap.g);
    mixbuffer += (color3.rgb * splatmap.b);
    mixbuffer += (color4.rgb * splatmap.a);
    return mixbuffer;
}
//////////////////////////////////////////////////////////////////////////////////////

Example Usage:

        splatmapBuffer = vec3(0.0, 0.0, 0.0);
        // ..
        // GLOBAL TILE INFO
        // ..
        float splatTileSize = 512.0;
        float splatTileBits = 9.0;
        float atlasTileSize = 1024.0;
        float atlasTileBits = 10.0;
        // ..
        // SPLATMAP TEXTURE 0
        // ..
        vec4 splatmapRect0 = vec4(0.0, 1.0, 0.5, 0.5);
        vec2 splatmapTileUV0 = (vAlbedoUV + uvOffset);
        vec4 splatmapAlbedo0 = sampleSplatmapAtlas2D(splatmapTextures, noCorrection, vec2(splatTileSize, splatTileBits), splatmapRect0, splatmapTileUV0);
      
        // ..
        vec4 textureRect0 = vec4(0.0, 3.0, 0.25, 0.25);
        vec2 textureScale0 = vec2(1.0, 1.0);
        vec2 textureOffset0 = vec2(0.0, 0.0);
        vec2 textureTileUV0 = ((vAlbedoUV + textureOffset0) * textureScale0);
        vec4 textureAlbedo0 = sampleTextureAtlas2D(terrainTextures, linearCorrection, vec2(atlasTileSize, atlasTileBits), textureRect0, textureTileUV0, autoMipLevel);
        
        // ..
        vec4 textureRect1 = vec4(1.0, 3.0, 0.25, 0.25);
        vec2 textureScale1 = vec2(100.0, 75.0);
        vec2 textureOffset1 = vec2(0.0, 0.0);
        vec2 textureTileUV1 = ((vAlbedoUV + textureOffset1) * textureScale1);
        vec4 textureAlbedo1 = sampleTextureAtlas2D(terrainTextures, linearCorrection, vec2(atlasTileSize, atlasTileBits), textureRect1, textureTileUV1, autoMipLevel);
        
        // ..
        vec4 textureRect2 = vec4(2.0, 3.0, 0.25, 0.25);
        vec2 textureScale2 = vec2(100.0, 75.0);
        vec2 textureOffset2 = vec2(0.0, 0.0);
        vec2 textureTileUV2 = ((vAlbedoUV + textureOffset2) * textureScale2);
        vec4 textureAlbedo2 = sampleTextureAtlas2D(terrainTextures, linearCorrection, vec2(atlasTileSize, atlasTileBits), textureRect2, textureTileUV2, autoMipLevel);

        // ..
        vec4 textureRect3 = vec4(3.0, 3.0, 0.25, 0.25);
        vec2 textureScale3 = vec2(100.0, 75.0);
        vec2 textureOffset3 = vec2(0.0, 0.0);
        vec2 textureTileUV3 = ((vAlbedoUV + textureOffset3) * textureScale3);
        vec4 textureAlbedo3 = sampleTextureAtlas2D(terrainTextures, linearCorrection, vec2(atlasTileSize, atlasTileBits), textureRect3, textureTileUV3, autoMipLevel);

        splatmapBuffer = blendSplatmapTileColors(splatmapAlbedo0, textureAlbedo0, textureAlbedo1, textureAlbedo2, textureAlbedo3, splatmapBuffer);
        surfaceAlbedo = splatmapBuffer.rgb;

Eazy Fuckin Peazy
(Yeah Right)
:slight_smile:

3 Likes

Underlying Base Terrain Without Splats:

Example Unity Terrain Shot With Splatmap Layers:

Upcoming Babyon Tookit: Pro Terrains SDK Shot: (Near Picture Fucking Perfect… The runtime lighting will always be a little different than the Unity Lighting Render Pipeline. But the terrain meshes, splating and mip map bluring is the shizznit)

Babylon Toolkit With Splatmap Layers:

Sweet :slight_smile:

4 Likes

Wow Mackey, you damn good. :smiley:
That should straight to babylon documentation at the top.
I remain tuned for the new version.
Meanwhile i’m fighting with the navigation to understand why it doesn’t work with my terrain. I imported the navmesh correctly but i can’t make that damn box move like in the example here: GitHub - wanadev/babylon-navigation-mesh: A library to move on navigation mesh with BABYLON.js.

1 Like

Send me the scene with your script … I’ll take a peek at it

1 Like

I sent you the scene in private message.