Unity 3d exporter missing terrain

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.