Jump to content

Texture Atlas Tiling At the Shader


MackeyK24
 Share

Recommended Posts

Yo @Deltakosh ... I am having trouble with apply terrain texture atlas tiling (texture.uScale and texture.vScale) at the shader for texture atlas...

 

This is how i am having main UV coord offset for texture atlas:

I have a vec4 (atlas1UV) containing the rectangle of the texture within the texture atlas (x, y, height, width). I also have a vec2 (atlas1Scale) that is the texture offset/tiling

so atlasScale might be something like vec2(5,5)

now i assume the default way openGL texture() function works is anything outside the 0 - 1 for uv causes the texture2D to 'REPEAT' the texture giving use tiling... But using a texture atlas going outside the 0 to 1 by multiplying uvcoord * scaleTile causes the texture() function to return the OTHER parts of the splats...

This is the followingg snippet to get splat 1... WORKS except when i need scale or tiling:

 

vec2 atlas1UV = vec2((vTerrainUV.x * atlasRect1.w) + atlasRect1.x, (vTerrainUV.y * atlasRect1.z) + atlasRect1.y);

vec2 atlas1Scale = vec2(atlasInfo1.x, atlasInfo1.y);
vec4 atlas1Color = texture2D(albedoSampler, atlas1UV * atlas1Scale + uvOffset);

surfaceAlbedo = atlas1Color * baseColor1.r;

How can i offset the scale or limit the region the texture() function uses so it can REPEAT the section from texture atlas... Or something like that... Anything...

Otherwise i have to go back to using operate textures for each terrain splatmap (up to 4) and each texture splat (up to 12) and each normal splat (up to 12)...

Thats 28 ADDITIONAL texture i would have to load into my splatmap shader (on top of the standard PBR textures ... if being used.. light light maps and reflection)

So your browser would need at least 32 for the MAX_TEXTURE_IMAGE_UNITS (which are 16 on most browsers and 8 on iOS) for a fully loaded splatmap.

TextureAtlas is perfect, can do all of texture now with just 1 additional texture to the PBR pipeline...SPLATMAP TEXTURE... the actuals splats and normals are encoded to the regular Albedo and Bump texture from the PBR Materials... got working except for applying scale like shown above... Please.... Any help... I have been working on this for weeks now and i can't seem to figure this last bit of scaling/tiling :)

Pinging @Sebavan and @RaananW and @Wingnut ... This goes out to you guys as well.

 

My current shader code:

Terrain_Splatmap.fragment.fx

Terrain_Splatmap.vertex.fx

 

Please take a look at :)

 

Link to comment
Share on other sites

Hi M.  About the best I can do... is watch you do your work, Mackey.  You are quite a bit more advanced than I am.  But I sure enjoy reading about your issues and learning from you.  And, I appreciate what you are doing.  I'm honored that you think I matter... thanks!  Wish I could be more helpful, but I'm not a shaders guy, and I have no idea what a splat map is.

Ok. perhaps I do... now that I've read about it on the web.  :)  Yeah, blending over-layed textures - I'm definitely a fan of on-the-fly texture blending.

@NasimiAsl did a real nice shader-blending of 2 materials, recently, and I loved it, and possibly that is why you included me in your ping-list, Mack.  I appreciate that.  I hope you find quick assistance on this logjam.

Link to comment
Share on other sites

I think that is a perfect solution if I understand it well!
I think, first you have to get the fract() of uv. that gives you a 0..1 range.
And multiply that with atlas rect scale, and after that add atlas rect position.
I hope it helps.
And I (still) hope this splatmap material will be available somehow outside of unity exporter :)

Link to comment
Share on other sites

// Base splat colors
		vTerrainUV = fract(vTerrainUV);
		if (splatmapRects > 0.0) {
			vec2 baseUV1 = vec2(vTerrainUV.x * splatmapRect1.w) + splatmapRect1.x, (vTerrainUV.y * splatmapRect1.z) + splatmapRect1.y);
			baseColor1 = texture2D(splatmap, baseUV1 + uvOffset);
		}

Something like this I think.
 

Link to comment
Share on other sites

2 hours ago, MackeyK24 said:

Yo @NasimiAsl ... Any thoughts from you on how to do tiling when using a Texture Atlas ?

 

Note details above :)

http://www.babylonjs-playground.com/#1ODVTX#1 border problem

http://www.babylonjs-playground.com/#1ODVTX#7

vN2QxSo.jpg

 

we have this conversation but we don't continue that for find good result any way i am now on custom material 

for a few days after that i make full support for atlas texture 

 

 

Link to comment
Share on other sites

1 minute ago, MackeyK24 said:

I don't see any calculations in shader code where you take "uScale" and "vScale" into account...

This example above i don't see any shader code...

The very first one ... i just don't see you using a "Scaling or Tiling" code :(

 

this calculated under ShaderBuilder  and generated last result

this just support Square table

//

rowIndex: row  index for your wnated texture on table ,

columnIndex: coulmn index for your wnated texture on table ,

indexCount: row  and column count on table 

\\

i can share all calculate about that 

(if you want for real texture atlas ) 

Link to comment
Share on other sites

31 minutes ago, NasimiAsl said:

i can share all calculate about that 

(if you want for real texture atlas ) 

PLEASE...

this is want i need to happen... Using albedo WITHOUT texture atlas i would use 'albedoScale' which is a vec2 with the texture.uScale and texture.vScale just like in per material...

to make my terrain textures scale or tile or repeat or whatever you call it was this:

surfaceAlbedo = texture2D(albedoSampler, vAlbedoUV * albedoScale + uvOffset);

albedoScale might contain a value like vec2(5.0, 5.0)... So the texture would get 'tiled or repeated'

 

now i have PACKED all my textures into an atlas and assign to albedoSampler... I also send a free uniforms to hold the rect info for the texture within the texture atlas

so now to offset the vAlbedoUV ... I do this:

vec2 newUV = vec2((vAlbedoUV.x * splatmapRect1.w) + splatmapRect1.x, (vAlbedoUV.y * splatmapRect1.z) + splatmapRect1.y);

surfaceAlbedo = texture2D(albedoSampler, newUV * albedoScale + uvOffset);

 

now if scale is ALWAYS 1.0 it works OK... still see border a bit... but the real problem is when i try to multiply the newUV with albedoScale like i was doing for NON texture atlas version... But that does not work ... show the other texture from texture atlas that above 1.0...

 

So i MUST not supposed to APPLY scale at that line of code anymore... i guess it shout be already calculated into newUV ... I guess... That what i need help with...

Applying the uScale and vScale for tile and repeat just like you normally  for NON texture atlas:

Basically convert this code to use Texture Atlas with tiling support:

 

vec2 newUV = vec2((vAlbedoUV.x * splatmapRect1.w) + splatmapRect1.x, (vAlbedoUV.y * splatmapRect1.z) + splatmapRect1.y);

surfaceAlbedo = texture2D(albedoSampler, newUV * albedoScale + uvOffset);

 

Link to comment
Share on other sites

HMM :)

i dont know about albodo uv but you can convert any uv to atlas uv use with this :

1: 

SWAAA.png.33aaa93f744c7b0f26831dfb0a493f26.png

            float left = 128.;\  // sub Image position pixel 
            float top = 384.;\  //  sub Image position pixel 
            float width = 128.;\ // sub Image size pixel 
            float height = 64.;\ // sub Image size pixel 
            float WIDTH = 512.;\  // image size
            float HEIGHT = 512.;\ // image size
\
            float uv_w =  width / WIDTH;\
            float uv_h =  height / HEIGHT;\
            float uv_x =  left / WIDTH;\
            float uv_y =  1.-  top  / HEIGHT -uv_h;\
\
            float tile_x = 4.;\  // sub Image repeat pixel 
            float tile_y = 4.;\  // sub Image repeat pixel 
\
            vec2 newUvAtlas = vec2( mod( vuv.x*tile_x  , uv_w ) +uv_x  , mod(vuv.y*tile_y    ,uv_h)+uv_y  );')
		    

http://www.babylonjs-playground.com/#1ODVTX#14

or 

   float tile  = 4.;\
            vec2 newUvAtlas = vec2(uv_x,uv_y)+vec2(uv_w,uv_h)*   fract(vuv*tile); 
		  

http://www.babylonjs-playground.com/#1ODVTX#16

but you can see edges problem  

i have one way to fix that problem but i don't know that is good or not

for that 

1. : make new rep Photo from your old Pic

werr.jpg.176f563ca736cdb8daebca318990582e.jpg

2 : use new photo in your atlas 

SFDFWERFW.png.990d919637b8a6e952426e62e243b073.png

3.: find tile edge : 

http://www.babylonjs-playground.com/#1ODVTX#20

4 : find edge uvs and replace that in current 

that is more mathematical stuff but we can make it like easy function 

http://www.babylonjs-playground.com/#1ODVTX#21

 

 

 

 

 

Link to comment
Share on other sites

Wow that seems like a lot of EXTRA work to get Texture Atlas to work...

I can't just PHOTOSHOP the texture atlas to have those WRAPPING version of the texture either... these will be terrain textures used to paint the terrain splats with...

I can't believe GLSL does not have some texture2D() that we could pass a rect to difine the actual area within the texture as a VIEWPORT so to speak then we do texture coordinates like normal.

I guess i might just have to take BACK down the splatmapping down to 6 MAX splats (6 diffuse and 6 normals plus 1 mixmap for a total of 13 texture images units... plus 3 for PBR pipeline ) as separate textures this will MAX out the MAX_TEXTURE_IMAGE_UNITS ...

Texture Atlas would have been sweet for terrains :(

Link to comment
Share on other sites

BTW... This worked... Just has borders... hopefully can figure out a better way to get rid of borders.

But this DID work for tiling in the texture atlas:

// Primary splat textures
if (atlasInfos > 0.0 && atlasRects > 0.0) {
	float tile1 = 5.0;
    vec2 atlas1UV = vec2(atlasRect1.x, atlasRect1.y) + vec2(atlasRect1.w, atlasRect1.z) * fract(vTerrainUV * tile1); 			
	vec4 atlas1Color = texture2D(albedoSampler, atlas1UV + uvOffset);
	splatColor = atlas1Color * baseColor1.r;
}

Hope we get the border issue worked out WITHOUT some many manual steps to prepare the texture image :)

 

Link to comment
Share on other sites

17 hours ago, NasimiAsl said:

http://www.babylonjs-playground.com/#1ODVTX#7

vN2QxSo.jpg

 

we have this conversation but we don't continue that for find good result any way i am now on custom material 

 

This seems to be tiling ... i can't tell if there is border problem because the design of the texture... but if it is it is noticeable than the fract() version.

 

So is all the magic in this code... i can't tell what is going on because of all the shader builder and dynamic string building as apposed to separate vertex and fragment .fx files..

So what is this stuffing doing ?

Does it take a tile vale like tile = 4. into account ?

From playground #7

var plan = BABYLON.Mesh.CreateGround("a", 50, 50, 10, scene);
		plan.material = new BABYLONX.ShaderBuilder()
		.SetUniform('tileInd','vec4')
		.InLine('vec2 newUv =vec2( mod(  vuv.x*3.,1.0)/3.+1./3. , mod(  vuv.y*3.,1.0)/3.+2./3.);')
			.Map({ path: 'http://i.imgur.com/vN2QxSo.jpg' 
			,uv:'newUv ' })
			.InLine('\
			  float x_b = 0.;\
			   if(mod(newUv.x, 1. / 3.) < 0.1 / 3.0) x_b =  mod(newUv.x, 1. / 3.) * 3. * 10.; \
               else if(mod(newUv.x,1./3.) > 0.9 /3.0   ) x_b =  1.-(mod(newUv.x,1./3.)-0.9/3.)*3.*10.;\
			   else x_b = 1.;\
			   x_b = 1.-x_b;')
			   .Reference(1,BABYLONX.Helper().Map({ path: 'http://i.imgur.com/vN2QxSo.jpg' , uv:'vec2(  mod(  vuv.x*3.+0.5,1.0)/3.+1./3.  , mod(  vuv.y*3.,1.0)/3.+2./3.) '   }).Build())
	.InLine('\
			  float y_b = 0.;\
			   if(mod(newUv.y, 1. / 3.) < 0.1 / 3.0) y_b =  mod(newUv.y, 1. / 3.) * 3. * 10.; \
               else if(mod(newUv.y,1./3.) > 0.9 /3.0   ) y_b =  1.-(mod(newUv.y,1./3.)-0.9/3.)*3.*10.;\
			   else y_b = 1.;\
			   y_b = 1.-y_b;')
			   .Reference(2,BABYLONX.Helper().Map({ path: 'http://i.imgur.com/vN2QxSo.jpg' , uv:'vec2(  mod(  vuv.x*3. ,1.0)/3.+1./3.  , mod(  vuv.y*3.+0.5,1.0)/3.+2./3.) '   }).Build())
		.InLine('\
			  float xy_b = 0.;\
			   xy_b = min(x_b,y_b);')
			   .Reference(3,BABYLONX.Helper().Map({ path: 'http://i.imgur.com/vN2QxSo.jpg' , uv:'vec2(  mod(  vuv.x*3.+0.5 ,1.0)/3.+1./3.  , mod(  vuv.y*3.+0.5,1.0)/3.+2./3.) '   }).Build())
		
			.InLine('\
			 result = result*(1.-y_b)+result_2*y_b;\
			  result = result*(1.-x_b)+result_1*x_b;\
			  result = result*(1.-xy_b)+result_3*xy_b;\
			   ')
              //})
			.BuildMaterial(scene);

 

This seems to work... why did dis continue for good reason ???

:)

 

Link to comment
Share on other sites

18 hours ago, NasimiAsl said:

HMM :)

i dont know about albodo uv but you can convert any uv to atlas uv use with this :

1: 

SWAAA.png.33aaa93f744c7b0f26831dfb0a493f26.png


            float left = 128.;\  // sub Image position pixel 
            float top = 384.;\  //  sub Image position pixel 
            float width = 128.;\ // sub Image size pixel 
            float height = 64.;\ // sub Image size pixel 
            float WIDTH = 512.;\  // image size
            float HEIGHT = 512.;\ // image size
\
            float uv_w =  width / WIDTH;\
            float uv_h =  height / HEIGHT;\
            float uv_x =  left / WIDTH;\
            float uv_y =  1.-  top  / HEIGHT -uv_h;\
\
            float tile_x = 4.;\  // sub Image repeat pixel 
            float tile_y = 4.;\  // sub Image repeat pixel 
\
            vec2 newUvAtlas = vec2( mod( vuv.x*tile_x  , uv_w ) +uv_x  , mod(vuv.y*tile_y    ,uv_h)+uv_y  );')
		    

http://www.babylonjs-playground.com/#1ODVTX#14

or 


   float tile  = 4.;\
            vec2 newUvAtlas = vec2(uv_x,uv_y)+vec2(uv_w,uv_h)*   fract(vuv*tile); 
		  

http://www.babylonjs-playground.com/#1ODVTX#16

but you can see edges problem  

i have one way to fix that problem but i don't know that is good or not

for that 

1. : make new rep Photo from your old Pic

werr.jpg.176f563ca736cdb8daebca318990582e.jpg

2 : use new photo in your atlas 

SFDFWERFW.png.990d919637b8a6e952426e62e243b073.png

3.: find tile edge : 

http://www.babylonjs-playground.com/#1ODVTX#20

4 : find edge uvs and replace that in current 

that is more mathematical stuff but we can make it like easy function 

http://www.babylonjs-playground.com/#1ODVTX#21

 

 

 

 

 

Yo @NasimiAsl ...

Whatever your doing in here http://www.babylonjs-playground.com/#1ODVTX#21

looks like its working, but i still can really tell whats going on in all the ShaderBuilder text string building of the actual shader... can you send me the .fx files for this so i can study what is what... mayday put a few param names instead of all the HARD CODED values... had to tell what is supposed to be what?

I actually have an array of all the texture right before i pack them in texture atlas... could i just take pixels from left edge and put them on right edge and take pixel from top edge and put on bottom edge...

Is there some algorithm to iterate thru the pixels of an image and do that... and most of all WOULD THAT WORK i could image if something like that could work... would make the shader faster by not having to do as much math for each pixel at runtime instead of encoding that into the texture when i pack into texture map... What do you think?

@Deltakosh What do think as well...

 

Link to comment
Share on other sites

hi again 

in github : 

https://github.com/BabylonJS/Extensions/tree/master/ShaderBuilder

documentation : 

http://cdn.rawgit.com/RNasimiAsl/Extensions/master/ShaderBuilder/Documentation/ShaderBuilderReferences.html

you can find the shader in BABYLON.Effect.ShaderStore

BABYLON.Effect.ShadersStore["ShaderBuilder_1PixelShader"]

BABYLON.Effect.ShadersStore["ShaderBuilder_1VertexShader"]

and about other way i think i need test a not blur texture ( like ddr or bmp ) maybe  for the border problem

all hard terms define in this class 

export class ShaderMaterialHelperStatics {
   
  static Dark = false;
  static Light = true;
   
  static PrecisionHighMode = 'highp';
  static PrecisionMediumMode = 'mediump';
   
   
  static face_back = "!gl_FrontFacing";
  static face_front = "gl_FrontFacing";
   
  static AttrPosition = 'position';
  static AttrNormal = 'normal';
  static AttrUv = 'uv';
  static AttrUv2 = 'uv2';
   
  static AttrTypeForPosition = 'vec3';
  static AttrTypeForNormal = 'vec3';
  static AttrTypeForUv = 'vec2';
  static AttrTypeForUv2 = 'vec2';
   
  static uniformView = "view";
  static uniformWorld = "world";
  static uniformWorldView = "worldView";
  static uniformViewProjection = "viewProjection";
  static uniformWorldViewProjection = "worldViewProjection";
   
  static uniformStandardType = "mat4";
  static uniformFlags = "flags";
   
  static Mouse = "mouse";
  static Screen = "screen";
  static Camera = "camera";
  static Look = "look";
   
  static Time = "time";
  static GlobalTime = "gtime";
  static Position = "pos";
  static WorldPosition = "wpos";
   
  static Normal = "nrm";
  static WorldNormal = "wnrm";
  static Uv = "vuv";
  static Uv2 = "vuv2";
  static Center = 'center';
   
  static ReflectMatrix = "refMat";
   
  static Texture2D = "txtRef_";
  static TextureCube = "cubeRef_";
   
  static IdentityHelper: number;
   
  constructor() {
   
 

}

}

Link to comment
Share on other sites

55 minutes ago, NasimiAsl said:

and about other way i think i need test a not blur texture ( like ddr or bmp ) maybe  for the border problem

.png cleared up the blur... even the blending between splats look good.... ALTHOUGH I STILL HAVE BORDER PROBLEM... i don't understand your fixing up the image approach... can i do that i code since i have the width and height of each texture and an array to the actual pixels ???

Here is shot (WITH BORDER PROBLEM) but everything ELSE looks good to me

Here is Unity Version of terrain in game editor:

58e9dbedba62b_ScreenShot2017-04-08at8_58_55PM.thumb.png.25b09a9cd3ab054c1fa4d2d2c108a60d.png

 

Here is my BabylonJS Toolkit Made Export of that terrain (STILL HAS BORDER PROBLEM... But everything else looks good):

58e9dc2952d70_ScreenShot2017-04-08at8_59_13PM.thumb.png.4926229014e1b1134912da15a5cbddfc.png

 

Not bad ehh :)

All splatmaps packed in a single 4K texture atlas (small in size)

All terrain splat textures encoded into another texture atlas 4k

All normal maps encoded into another texture atlas 4k as well

The old way... if you have a fully splatted with normal maps... that would require 28 texture just to have the actual splat mapping of the terrain (not to mention the light map and environment reflection textures too).. so up 30 separate textures would have to load and your browser would have to support at least 32 MAX_TEXTURE_IMAGE_UNITS (i think only 64-bit windows Chrome support 32... most others support 16 and IOS support 8)

But now i only and 1 additional texture to the normal PBR pipeline used to render the terrain... and is 'SplatmapTexture' 

I stick the terrain texture atlas in 'albedoSampler' and the normals texture atlas in 'bumpSampler'

and now only 3 total textures for the splatting and 2 or 3 for the PBR light map and reflection coming from the environment...

for a total of only 6 MAX_TEXTURE_IMAGE_UNITS was used to produced the splatmap terrain you see above :)

Just gotta figure out the border thing :)

ANYBODY ... ANY THOUGHTS ON THE TEXTURE ATLAS TILING BORDER ISSUE ... PLEASE ... CHIME IN :)

 

Link to comment
Share on other sites

I think you have two options:

1. Padding
When getting the texture data with Texture2D, the value it returns depends on the mipmap level (from 4k down to 2x2pixels), and trilinear filtering.
This reads not one but from many texture values.
So when u or v is near 1.0 or 0.0, you get the texture value from the edge of the other texture rectangle.
And because of mipmapping, this is not one pixel (texel), can be many more nto the other texture rectangle.

I think the only way this will work is padding the textures by some pixels, like in your 4k textures, use 1016x1016 rectangles with 4 pixel padding on every side (with the textures "mirrored out" on the sides)
This works down to the 4th mipmap level, wich may be far enough.

2. Clamping
You can clamp the u,v values like this

vTerrainUV = clamp(fract(vTerrainUV),vec2(0.00390625),vec2(0.9960935));

This will dampen the border effect a bit (u,v stays within the texture in the first few mipmaps), but it will cause a 8 texel "band" in the texture.

values are 4/1024, 1.0-4/1024
Or you can try this with 1/1024.
 

Link to comment
Share on other sites

1 hour ago, BitOfGold said:

I think you have two options:

1. Padding
When getting the texture data with Texture2D, the value it returns depends on the mipmap level (from 4k down to 2x2pixels), and trilinear filtering.
This reads not one but from many texture values.
So when u or v is near 1.0 or 0.0, you get the texture value from the edge of the other texture rectangle.
And because of mipmapping, this is not one pixel (texel), can be many more nto the other texture rectangle.

I think the only way this will work is padding the textures by some pixels, like in your 4k textures, use 1018x1018 rectangles with 4 pixel padding on every side (with the textures "mirrored out" on the sides)
This works down to the 4th mipmap level, wich may be far enough.

2. Clamping
You can clamp the u,v values like this

vTerrainUV = clamp(fract(vTerrainUV),vec2(0.00390625),vec2(0.9960935));

This will dampen the border effect a bit (u,v stays within the texture in the first few mipmaps), but it will cause a 8 texel "band" in the texture.

values are 4/1024, 1.0-4/1024
Or you can try this with 1/1024.
 

 

Yo @BitOfGold ... Check this out... This is my texture packing code in c# that i use to encoding all my texture... I add a section where i loop thru and have a source pixel buffer and a dest pixel buffer.... Can you please show me to add the image and mirror the edges ... this is the perfect spot to do that pixel work:

                // Encode Texture Atlas Padding
                List<Texture2D> paddingBuffer = new List<Texture2D>();
                if (scalingBuffer.Count > 0)
                {
                    foreach (var sourceTexture in scalingBuffer)
                    {
                        Color[] sourcePixels = sourceTexture.GetPixels();
                        Color[] paddingPixels = new Color[sourcePixels.Length];
                        Texture2D paddingTexture = new Texture2D(sourceTexture.width, sourceTexture.height, sourceTexture.format, false);
                        
                        
                        
                        // TODO: Encode Source Texture Pixel Buffer Into Padding Buffer With Padding And Mirrored Edges
                        int index = 0;
                        for (int y=0; y < sourceTexture.height; y++) 
                        {
                            for (int x=0; x < sourceTexture.width; x++) 
                            {
                                paddingPixels[index] = sourcePixels[index];
                                index++;
                            }
                        }



                        paddingTexture.SetPixels(paddingPixels);
                        paddingTexture.Apply();
                        paddingBuffer.Add(paddingTexture);
                    }
                }
                if (paddingBuffer.Count > 0)
                {
                    result = source.PackTextures(paddingBuffer.ToArray(), texturePadding, textureAtlasSize, false);
                    source.Apply();
                }

 

Right now i just copy the exact pixel from source to dest... but this are (even if not this looping structure ... please change it to work)

 

// TODO: Encode Source Texture Pixel Buffer Into Padding Buffer With Padding And Mirrored Edges
                        int index = 0;
                        for (int y=0; y < sourceTexture.height; y++) 
                        {
                            for (int x=0; x < sourceTexture.width; x++) 
                            {
                                paddingPixels[index] = sourcePixels[index];
                                index++;
                            }
                        }

 

Dude... I would be your best friend :)

 

Link to comment
Share on other sites

Just for reference... Here is my Whole texture packing static function:

        public static Rect[] PackTextureAtlas(Texture2D source, Texture2D[] textures, int textureAtlasSize = 4096, int maxTextureImageSize = 0, bool bilinearScaling = true, int texturePadding = 0)
        {
            Rect[] result = null;
            if (textures != null && textures.Length > 0)
            {
                // Enforce Texture Packing Scale
                List<Texture2D> scalingBuffer = new List<Texture2D>();
                foreach (var texture in textures)
                {
                    Texture2D item = texture.Copy();
                    if (maxTextureImageSize > 0 && (item.width > maxTextureImageSize || item.height > maxTextureImageSize))
                    {
                        if (bilinearScaling) {
                            TextureScale.Bilinear(item, maxTextureImageSize, maxTextureImageSize);
                        } else {
                            TextureScale.Point(item, maxTextureImageSize, maxTextureImageSize);
                        }
                    }
                    scalingBuffer.Add(item);
                }
                // Encode Texture Atlas Padding
                List<Texture2D> paddingBuffer = new List<Texture2D>();
                if (scalingBuffer.Count > 0)
                {
                    foreach (var sourceTexture in scalingBuffer)
                    {
                        Color[] sourcePixels = sourceTexture.GetPixels();
                        Color[] paddingPixels = new Color[sourcePixels.Length];
                        Texture2D paddingTexture = new Texture2D(sourceTexture.width, sourceTexture.height, sourceTexture.format, false);
                        
                        
                        
                        // TODO: Encode Source Texture Pixel Buffer Into Padding Buffer With Padding And Mirrored Edges
                        int index = 0;
                        for (int y=0; y < sourceTexture.height; y++) 
                        {
                            for (int x=0; x < sourceTexture.width; x++) 
                            {
                                paddingPixels[index] = sourcePixels[index];
                                index++;
                            }
                        }



                        paddingTexture.SetPixels(paddingPixels);
                        paddingTexture.Apply();
                        paddingBuffer.Add(paddingTexture);
                    }
                }
                if (paddingBuffer.Count > 0)
                {
                    result = source.PackTextures(paddingBuffer.ToArray(), texturePadding, textureAtlasSize, false);
                    source.Apply();
                }
            }
            return result;
        }

 

Link to comment
Share on other sites

19 hours ago, BitOfGold said:

1. Padding
When getting the texture data with Texture2D, the value it returns depends on the mipmap level (from 4k down to 2x2pixels), and trilinear filtering.
This reads not one but from many texture values.
So when u or v is near 1.0 or 0.0, you get the texture value from the edge of the other texture rectangle.
And because of mipmapping, this is not one pixel (texel), can be many more nto the other texture rectangle.

I think the only way this will work is padding the textures by some pixels, like in your 4k textures, use 1016x1016 rectangles with 4 pixel padding on every side (with the textures "mirrored out" on the sides)
This works down to the 4th mipmap level, wich may be far enough.

 @BitOfGold are you around... ?

Can you explain this a little more...

so when you use 1016 instead of 1024 ...

A... Are you saying actually scale the whole image down from 1024 to 1016

B... Are you say just "wipe out" the first 4 pixels all around the 1024 image and then replace those wiped out pixel with copies from the the other side of the image..

Are you say i can just open a texture in paint program gram the first few pixels on the left edege copy them ... flip them... them move to the far right edge...

What about over lapping corners ?

BTW ... i only have the 1 base mip map level... I never encode any pixels in the other mipmap level... All my GetPixel and SetPixel code from unity only uses mipmap level 0... So i don't see there there could ever be more than 1 mipmap from the terrain splats coming from unity.

I have access to the pixel data but don't quite understand what are saying i have to do to the image :(

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...