Search Unity

FourSplatBlendWrapShader from wiki

Discussion in 'Shaders' started by priceap, May 28, 2009.

  1. priceap

    priceap

    Joined:
    Apr 18, 2009
    Posts:
    274
    Has anyone gotten the FourSplatBlendWrapShader on the wiki to work?

    I am using 2.5 pro on xp, and it only gives me errors of too many arguments to a function (GetTileWrapColor)
    and there are undefined variables as well.

    I am interested in seeing this shader work as I would like to figure out how to sample different quadrants of one texture sheet and repeat each of those textures across the shader. This is the only shaderlab example I know of so far that does that.

    thanks for any suggestions
    ap
     
  2. priceap

    priceap

    Joined:
    Apr 18, 2009
    Posts:
    274
    bump and rephrasing the question:

    Has anyone tried the FourSplatBlendWrapShader on the wiki and did it work?

    thanks
    ap
     
  3. Daniel_Brauer

    Daniel_Brauer

    Unity Technologies

    Joined:
    Aug 11, 2006
    Posts:
    3,355
    I don't see how it would work, and I honestly don't really understand what it's trying to do in the first place. The description is lacking and the four textures being blended in the image don't show you what's going on because they all look the same. There are enough errors at first glance that trying to dig deeper doesn't seem like a good idea.

    If all you're after is retrieving textures from an atlas, you're probably better off starting with the original, five-texture version and seeing if you can offset the UV arguments used in the tex2D() calls: http://www.unifycommunity.com/wiki/index.php?title=TerrainFourLayer
     
  4. priceap

    priceap

    Joined:
    Apr 18, 2009
    Posts:
    274
    Thanks for the reply Daniel. This seemed to be the case, and I wonder why it has lasted on the wiki.

    In any case, regardless of the variety of non-working code in it, it seemed like something was being done there to take a region of a texture and repeat that across the geometry.

    I think you know what I am talking about, but just to be clear I have added a fast illustration of the concept. The texture source would be like the square on the left, with a number of separate textures (four in this case) laid out within it.

    I can scale and set offsets to display just one quarter of the texture on the model, but can't quite figure out how to make it repeat without showing the other parts of the textures also. The objective would be to have a layered texture just like the fourLayer shader you note, but instead of four seperate textures, it would use just one, and then allow for repeats of each region as shown on the two perspective planes on the right (I only did two out of laziness, but they would be layers blended together in the end result.)

    Do you know of any examples that do this, or what the approach might be like? I start to think a region of the texture would have to be sampled into a new texture slot or array or something. The initial thought was as a means to avoid the register limit I was hitting when doing multi-texture layers with bumps in another post, so it may not fix what I was hoping it would.
    thanks
    ap
     

    Attached Files:

  5. tgraupmann

    tgraupmann

    Joined:
    Sep 14, 2007
    Posts:
    828
    It's already late for me. Initially, I thought you were talking about the FourTextureWrapBlend shader I added to the wiki. http://www.unifycommunity.com/wiki/index.php?title=FourSplatBlendWrapShader

    What kind of errors are you getting?

    You have a 2x2 splat array up there. In my example I was using 4x4.
     
  6. priceap

    priceap

    Joined:
    Apr 18, 2009
    Posts:
    274
    Hello - Yes I have been referring to the "FourSplatBlendWrapShader".

    My example image above is a 2x2 (four splats) to show what I am interested in doing, and hoping your shader would reveal how it is done.

    The wiki page is difficult to interpret, the first line description says "The following shader blends four textures while wrapping the textures by a power of two times."
    There is also a block in the code:
    //define the splat colors
    float4 tile1Color;
    float4 tile2Color;
    float4 tile3Color;
    float4 tile4Color;

    and various other blocks that seem to indicate the use of just four colors or splats, not sixteen.
    Also the example image appears to show four textures at each corner and the result blended on the center plane - at least it appears that to be the intent but it is not clear.

    But I do see the line that says "The main texture sheet should contain 4x4 splats. I.e. 128x128 splats in a 512x512 texture."

    The errors that I get are:

    "Cg in program 'vert': error C1104: too many parameters in function call at line 107"

    this is because the frag program is sending 5 arguments to a function "GetTileWrapColor" that only accepts 4 arguments.

    If I alter the function calls in order to match the definition like this:

    Code (csharp):
    1.  
    2. //from this:
    3.  tile1Color = GetTileWrapColor(i.color.r, (1-i.texcoord.x) * (1-i.texcoord.y), uv, wrapX, wrapZ);
    4.  
    5. //changed to this:
    6. tile1Color = GetTileWrapColor(i.color.r, (1-i.texcoord.x) * (1-i.texcoord.y), uv, float2(wrapX, wrapZ));
    7.  
    then I get:
    "Cg in program 'frag': error C1008: undefined variable "wrapX" at line 101"

    because neither "wrapX" or "wrapZ" are defined anywhere in the shader.

    So I stop there as far as errors.
     
  7. tgraupmann

    tgraupmann

    Joined:
    Sep 14, 2007
    Posts:
    828
    If you search the forums you can find a more recent version with a very detailed explanation of how it works.

    http://forum.unity3d.com/viewtopic.php?p=119769#119769

    Look for this part:

    I use RenderMonkey first to write the shader to make sure it works on the machine that I'm working with. I wrote some porting notes on how to get the shader to Unity.

    http://www.unifycommunity.com/wiki/index.php?title=ShaderPortingNotes

    Related:

    [Workaround] Fragment prog alpha channel precision per card - http://forum.unity3d.com/viewtopic.php?p=128915&sid=992f6193f5e8adb3b1cc7da906b5a376

    [Resolved] Shader Compile Failed in web player (RM example) - http://forum.unity3d.com/viewtopic.php?t=19440&highlight=shader
     
  8. priceap

    priceap

    Joined:
    Apr 18, 2009
    Posts:
    274
    I read through the first threads which seem to culminate in unresolved problems or many other things not directly related to the question of repeating regions of a single texture. The last link you listed where I understand you to say is the more recent version that works, but it is called "FourSplatBlendWireframeShader" doing a wireframe overlay, but even with that one, if I try a 2x2 texture sheet, it only displays the top right quarter of the texture across a plane and nothing else of the texture source. I can fiddle with the values hard-coded in the code (like 15.99, etc.) and see the texture offset, but nothing to do with repeating a region only.

    I will keep trying to understand your approach to repeating a smaller region of a texture source across a surface, but I can't see how it is trying to do so in your last example or in the visual result, but I suppose the last note I would make is to invite you to update the wiki entry with the one you consider a working example and its explanation, and any dependencies it relies on in terms of the hard-coded values you have in the shader, etc., and/or remove the one that is there.

    thanks
    ap
     
  9. ToreTank

    ToreTank

    Joined:
    Jun 23, 2008
    Posts:
    165
    Here is my take at the "repeat-only-part-of-a-texture". I'm not sure if this is what you had in mind? It is not perfect, but you should get the idea. The TODO comment in there is sort of important - you don't want the bleeding from neighbouring pixels, so a border around each tile is probably a good idea, along with a small scale/offset to keep the sampling within the safe area.

    Here is the shader:

    Code (csharp):
    1. Shader "Texture Array with Blendmap" {
    2.  
    3. Properties {
    4.     _MainTex ("Base (RGB)", 2D) = "white" {}
    5.     _BlendTex("Blend (RGB)", 2D) = "red" {}
    6.  
    7. }
    8.  
    9. Category {
    10.     Fog { Color [_AddFog] }
    11.  
    12. // ------------------------------------------------------------------
    13.     // ARB fragment program
    14.  
    15. SubShader {
    16.         Pass {
    17.             Tags { "LightMode" = "Always" }
    18.                
    19. CGPROGRAM
    20. #pragma vertex vert
    21. #pragma fragment frag
    22.  
    23. #include "UnityCG.cginc"
    24.  
    25. struct v2f {
    26.    float4 pos:POSITION;
    27.    float2 uv_diffuse;
    28.    float2 uv_blend;
    29. };
    30.  
    31. float4 _MainTex_ST, _BlendTex_ST;
    32.      
    33. v2f vert (appdata_base v) {
    34.    v2f o;
    35.    o.pos = mul( glstate.matrix.mvp, v.vertex );
    36.    o.uv_diffuse = TRANSFORM_TEX(v.texcoord, _MainTex);
    37.    o.uv_blend = TRANSFORM_TEX(v.texcoord, _BlendTex);
    38.    return o;
    39. }
    40.  
    41.  
    42. uniform sampler2D _MainTex;
    43. uniform sampler2D _BlendTex;
    44.  
    45. float4 frag (v2f i) : COLOR
    46. {
    47.     half4 blend = tex2D(_BlendTex, i.uv_blend);
    48.    
    49.     //TODO: Scale and offset sampling area so it is one pixel in from all
    50.     //      sides - this will prevent bleeding from neighbour textures.
    51.     //      That will become more difficult for lower mips, though.
    52.     float2 sampleScaled = float2(frac(i.uv_diffuse.x) * 0.5, frac(i.uv_diffuse.y) * 0.5);
    53.    
    54.     half4 array_00 = tex2D(_MainTex, sampleScaled);
    55.     half4 array_01 = tex2D(_MainTex, sampleScaled + float2(0.0, 0.5));
    56.     half4 array_10 = tex2D(_MainTex, sampleScaled + float2(0.5, 0.0));
    57.    
    58.     half4 color = array_00 * blend.r + array_01 * blend.g + array_10 * blend.b;
    59.    
    60.     return color;
    61.    
    62. }
    63. ENDCG            
    64.         }
    65.     }
    66.    
    67.  
    68. }
    69.  
    70. FallBack "VertexLit"
    71.  
    72. }
    I wouldn't be surprised if this looks slightly different on Windows, as the texture coordinates in OpenGL and D3D are "upside-down" - unless this is compensated for somewhere in the pipeline (my head is not up for the mental task of thinking out if this will work on both or not right now), it will sample from different tiles. I added an image of what it looks like on my computer. Also, note that I turned off mip-maps and used point sampling for the base texture in the screenshot to prevent the bleeding I mentioned above.
     

    Attached Files:

  10. priceap

    priceap

    Joined:
    Apr 18, 2009
    Posts:
    274
    ToreTank - this is _exactly_ what I have in mind!!! Very impressive - thanks so much for sharing!

    I tried it on my pc and it looks good - I see the need for ensuring texture borders / scaling inward, but this is it!

    OK, so I stared at the "frac()" function for a while, and found it in HLSL docs on msdn, and I think I get it: If you set the texture to repeat (10 in your example), frac(uv.x)*0.5 will still always return 0 to 0.5 each time as it steps across the uv space, and so places the same region of the texture each time. Yay!

    Thanks again - I hope you find this of use also, unless it has already been part of your toolset - It has helped me learn a lot.
    ap
     
  11. ToreTank

    ToreTank

    Joined:
    Jun 23, 2008
    Posts:
    165
    I'm glad to hear! I'm thinking it might become useful, but the issues noted will need some attention for that to happen :)

    Yes, the frac-function is key here. It will take the fractional part of a float, and thus keep the uv in the [0,1> range. By scaling it to the relative size of the tiles (in this case 0.5) and offset it by tileindex * tilesize, it will stay within the texture area of a given tile.

    The code as is will not, as far as I can see, help on texture samplings or register usage compared to the other shader using several textures, but I was thinking that it might be possible to calculate the offset into the texture atlas (or texture array, if you want) by using the color strength of the blendmap - for example, color.r < 0.25 would sample from the upper-left, color.r < 0.5 would sample from the upper-right etc, but I haven't thought of a good way to do smooth transitions between texture tiles this way.

    Another option might be to compile a simplified version and tweak the result assembly manually to sample from a couple of extra textures and reuse registers. Not the most readable solution though, I'm sure :)
     
  12. sladuuch

    sladuuch

    Joined:
    Jan 5, 2007
    Posts:
    51
    All right, this is great stuff guys! Now how about adding support for a 2x2 splatmap of bump textures?