Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Tiling textures within an atlas? Possible?

Discussion in 'Formats & External Tools' started by Adam-Buckner, Mar 24, 2010.

  1. Adam-Buckner

    Adam-Buckner

    Joined:
    Jun 27, 2007
    Posts:
    5,664
    If one has tileable textures, and wants to take advantage of batching by putting them on an atlas (say 8 x 256 on a 1024) - Can you make your UV's tile over a small section of that atlas in Blender? To tile the UVs with one single image/material is easy, but I'm not sure if you can tile using a section of an image/material.

    Can you?
     
  2. Tysoe

    Tysoe

    Joined:
    Jul 6, 2009
    Posts:
    577
    To tile you basically need the texture to extend from one edge of the texture atlas to the opposite. Which means that you can tile on one direction and have strips of long tiling textures. They would have to be laid out as strips that tile across their length.

    Could be used for some things.

    The only other method I can think of is to slice your mesh into tiling sections, similar to per face mapping which does essentially the same thing. It's not very efficient or practical on anything but the simplest geometry so probably not what you wanted to hear.
     
  3. Adam-Buckner

    Adam-Buckner

    Joined:
    Jun 27, 2007
    Posts:
    5,664
    Unfortunately, that's what I thought.

    Regular structures ( like wall panels ) I can "tile" by hand, but there are enough irregular shapes in most designs where that's not possible without creating way too much geometry if I had to make one face per "tile" by hand. Oh well. Guess I'll have to keep watching that balance between design and practicality...

    (You'd think that if it works tiling from 0 - 255, you could tile from 256-511...)
     
  4. artzfx

    artzfx

    Joined:
    Apr 28, 2008
    Posts:
    572
    This s a flat plane being tiled 4x4 however as long as the geometry is the same and the UV's the same you should be able to tile a section of an Atlas.

    Below shows a 512x512 Atlas with only the grass section of the Atlas being used and tiled on my geometry 16 times.

    The bottom of the image is the scene played back in Unity. You have to have MIP maps turned off though.

     
  5. Adam-Buckner

    Adam-Buckner

    Joined:
    Jun 27, 2007
    Posts:
    5,664
    How do you set up the UVs for that?

    Here's a test example I was working with:







    The walls are hand placed UV's from a texture atlas, but the floor and dirt pile are tiled textures that are stand-alone. How would I set up the UV's (in Blender in my case) so it would pull from part the the same atlas as the wall?

    (And I assume that the mip maps would cause edging if you left them on...)
     
  6. Tysoe

    Tysoe

    Joined:
    Jul 6, 2009
    Posts:
    577
    Yeah thats what I meant by face mapping. It works well so long as you have fairly simple geometry.
     
  7. artzfx

    artzfx

    Joined:
    Apr 28, 2008
    Posts:
    572
    Ah sorry, I mis-understood your real issue of the irregular poly shapes.
     
  8. rungy

    rungy

    Joined:
    Oct 25, 2011
    Posts:
    23
    Yes you can do atlas tiling WITHOUT faking it with repeating geometry.

    There are "currently" some restrictions.

    1) unless the textures on your atlas have similar boundaries you will have to use point filtering.
    2) when using point filtering, your textures have to have laser accurate boundaries, not so much as a pixel width off of any edge.
    3) You will have to get a special mip map generator specifically made for texture atlases, or create your own, so that there is ZERO bleed over
    4) You will have to use the dds format for your textures so that Unity does not "process" them (causing bleed over)
    5) to batch effectively...you need to use vert colors to mark what tri's get what part of the atlas
    6) Last but not least...you need a custom shader to handle the tiling.

    It's basic math really, when the shader processes the pixels...it goes through each pixel used from your textures one pixel at a time.

    It gets ONE UV coordinate from where the pixel "should" be found, remember...it's one pixel at a time that gets fetched from the atlas(all shaders do this)
    So the trick is...to have to tell the shader...if the coordinate is outside your desired region, to "roll" the value.

    let's say we're talking about a texture atlas that is 256x256 right?
    And lets say it's a 2x2 atlas right?
    ok, so if you want the top left texture, then valid uv's are 0 to 0 .5 for u, and 1 to .5 for v (y space is inverted, zero is at the bottom)

    .............................................................................................................O <-current pixel U = 39.9, V = 18.2


    <-------------- U ------------->
    0,1'''''''''''''''''' .5,1 '''''''''''''''''' 1,1
    |xxxxxxxxxx|................|
    |xxxxxxxxxx|................|
    |xxxxxxxxxx|................|
    |xxxxxxxxxx|................|
    0,.5'''''''''''''''''' .5,.5'''''''''''''''''' 1,.5....V
    |.................|................|
    |.................|................|
    |.................|................|
    |.................|................|
    0,0 '''''''''''''''''' .5,0'''''''''''''''''' 1,0


    So you want to "MOD" the U value of you uv's from 0 to .5
    and you want to "MOD" your V value of your uv's from .5 to 1

    so...let's say your shader is drawing a tri you made in a modeling package

    ...and you tiled the f#$k out of your uvs....

    the current pixel its trying to fetch is way outside of normalized texture boundaries...

    like say U = 39.9, V = 18.2 ...way way way off of the sheet

    if you "modulo" the coordinate by your atlas cell width you get your new u coordinate
    39.9 mod 0.5 = 0.4

    the modulo instruction gets the remainder of a division before resulting to a fraction.

    and lucky for us shaders do support a mod instruction or this would be very messy stuff
    mod the V coordinate by .5 too ( if it was 18.2, then it would be .2 right?)
    because 18.2 mod 0.5 = 0.2

    so this pixel that was supposed to be fetched from your atlas at 39.9,18.2 is now going to be fetched from 0.4, 0.2

    All you have to do now is offset these coordinates by the atlas offset for U and V

    which if we want the top left...
    we add 0.0 to u (no offset required in this case but we're making a formula so we have to add something even if we're adding nothing, a zero
    we add 0.5 for V, because the top left texture starts half way up the V axis

    in shorthand...

    U = meshUV.U //UV coords for EACH pixel, remember, fragments get processed ONE pixel at a time
    V = meshUV.V
    tileScale = 0.5 // the width of each tile

    // use vert colors to mark every tri for where it uses which part of the atlas as an offset
    // vert colors have valid values from 0.0 to 1.0 for RGB&A
    UOffset = vertColor.R // the horizontal offset from the left edge of the atlas
    VOffest = vertColor.G // the vertical offset from the bottom of the atlas

    newU = U mod tileScale
    newU += UOffset

    newV = V mod tileScale
    newV += VOffset

    I know this works because I am doing it, can't release my code for legal reasons, but I can discuss the method I use.
     
    Last edited: Jul 22, 2012
    Zaelot likes this.
  9. rungy

    rungy

    Joined:
    Oct 25, 2011
    Posts:
    23
    Do we have full support for FP3.0 in our shaders?
    It would be extremely beneficial to have it...
    ULTRA ULTRA ULTRA cheap, fast and extremely efficient.

    I would buy Unity 4 JUST for this if it fully supported these inputs and outputs....

    COLOR Input primary color
    COLOR0
    COL
    COL0

    COLOR1 Input secondary color
    COL1

    TEX0 Input texture coordinate sets 0
    TEXCOORD0

    TEX1 Input texture coordinate sets 1
    TEXCOORD1

    TEX2 Input texture coordinate sets 2
    TEXCOORD2

    TEX3 Input texture coordinate sets 3
    TEXCOORD3

    TEX4 Input texture coordinate sets 4
    TEXCOORD4

    TEX5 Input texture coordinate sets 5
    TEXCOORD5

    TEX6 Input texture coordinate sets 6
    TEXCOORD6

    TEX7 Input texture coordinate sets 7
    TEXCOORD7

    FOGP Input fog color (XYZ) and factor (W)
    FOG

    Uniform Input Semantics

    Sixteen texture units are supported:

    Binding Semantic Name Corresponding Data

    TEXUNIT0 Texture unit 0
    TEXUNIT1 Texture unit 1
    ...
    TEXUNIT15 Texture unit 15
     
    Last edited: Jul 22, 2012
  10. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
  11. DorianF

    DorianF

    Joined:
    May 20, 2016
    Posts:
    3
    That should work, indeed, but that means we have a different Shader for each texture within our texture atlas. That means a different material to use a different shader for each texture, right?

    So... For, say 30 texture, with this solution we have
    30 materials, each with a different shader, all with the same texture atlas.
    I don't think it is more optimized than having
    30 materials, each with a different shader, each with a different texture.

    Because, from what I've read, it's the number of materials that has a high impact on draw calls :/

    Any better solution nowadays? This thread is 4 years old !
     
  12. DavidMarchessault

    DavidMarchessault

    Joined:
    Jan 8, 2016
    Posts:
    2
    You should be able to bypass that limitation by assigning the "texture" bounds via MaterialParamBlock! All objects would have the same material and be statically batcheable.