Search Unity

Hiding parts of terrain

Discussion in 'Editor & General Support' started by Maker16, Oct 7, 2009.

  1. Maker16

    Maker16

    Joined:
    Mar 4, 2009
    Posts:
    779
    I was reading up on the Depthmask Shader, but I'm not sure how to apply it. The example is a boat where the water inside of the boat is not rendered. How do you selectively say, "apply the shader to this part of the water only"?

    I'm trying to hide the terrain that is inside a cave, so I can use a model for the floor of the cave. By placing a trigger at the cave entrance that will "shut off" collisions between terrain and player when the cave is entered, this allows me to let the player go deep into the ground by simply passing through the terrain. The thing is, it only works if I can hide the parts of the terrain that are inside of the cave.

    Or, should the cave get the shader, instead? I'm just not sure how the depthmask shader works.
     
  2. Daniel_Brauer

    Daniel_Brauer

    Unity Technologies

    Joined:
    Aug 11, 2006
    Posts:
    3,355
    Here's how the depth shader works in the boat example:

    • First, everything but the water is rendered.

    • Second, a cover is rendered over the boat. However, the cover is entirely transparent. The only thing that happens when it is rendered is that it goes into the depth buffer, preventing anything from being drawn behind it.

    • Finally, the water is rendered. Because of the cover over the boat, no water is rendered inside the boat.

    With terrain, you need to render everything but the terrain, then render the opening of the cave with the depth mask shader, and finally render the train.

    To force rendering order, you'll want to use Material.renderQueue or shader tags. If you can modify the terrain shader, it's probably easier to have it render later than to explicitly render everything else earlier.

    Note that the depth mask approach causes problems with realtime shadows viewed through the mask.
     
  3. Maker16

    Maker16

    Joined:
    Mar 4, 2009
    Posts:
    779
    Thanks Daniel. 1 point of clarification. You said to place the "cover" over the cave entrance. My cave will be modeled into a rock outcropping model (they will essentially be one model, the cave being an interior portion of the outcropping). The interior tunnels will be intersecting the terrain object in multiple places, at all of which the terrain should not be visible. So, given that, do I just place the the depthmask shader on the entire cave system?
     
  4. Daniel_Brauer

    Daniel_Brauer

    Unity Technologies

    Joined:
    Aug 11, 2006
    Posts:
    3,355
    The depth mask shader itself produces an invisible result. You should use a regular shader to render the caves, and the depth mask shader on geometry that just covers the entrances to the caves.

    You might get a better understanding of the depth mask shader's functionality by downloading the project from the wiki, and tearing the cover off the boat, and then moving the camera around it.
     
  5. Maker16

    Maker16

    Joined:
    Mar 4, 2009
    Posts:
    779
    Is it possible to change the terrain shader? More specifically, is it possible to change the shader so that you can use a transparent texture to paint holes in the terrain? I have the collision part handled. It just seems that it would be easier to do it that way.

    And, while I am on the subject, is it possible to change the way terrain textures are handled to include a 5th texture? If I understand correctly, you currently can only use 4.
     
  6. DocSWAB

    DocSWAB

    Joined:
    Aug 28, 2006
    Posts:
    615
    You can use as many splats as you want technically. It's just that each fraction of a group of 4 greater than 4 (5-8, 9-12, etc.) add another pass to the rendering, which will bog down Intel or other integrated graphics.

    Real graphics cards can handle 8 splats without any problem, but Intel is killed by the second pass. So if you are targeting integrated graphics, you have to keep it to 4 splats.
     
  7. Fribble

    Fribble

    Joined:
    Dec 3, 2009
    Posts:
    56
    I know this is a bit of a Thread Revival, but this really great guy came up with a solution to the cave problem:

    http://forum.unity3d.com/viewtopic.php?p=272009#272009[/quote]

    You simply bring the terrain down to ground level, and model a cliff wall or whatever in (insert favorite modeling program here), Line it up with your pre-made cave model, and voila, you just "faked the entrance," as he put it.

    P.S. Check out the other pics in the thread. His stuff is amazing.
     
  8. Wox

    Wox

    Joined:
    Dec 14, 2009
    Posts:
    93
  9. Fribble

    Fribble

    Joined:
    Dec 3, 2009
    Posts:
    56
    Yeah, I've taken a look at that post many times.

    I'm just not too keen on that method for some reason :?
     
  10. Kragh

    Kragh

    Joined:
    Jan 22, 2008
    Posts:
    657
    Another and non tested approach may be changing the inbuild terrain shader a bit to support alpha, and then use the alpha channel of the lightmap to feed the alpha info to the shader. I made this quick mod of the inbuild FirstPassLightmap.shader file. I have not tested it for sorting issues and such, but maybe it could give some ideas to someone.
    What you need to do to get it to work, is saving this shader in your project, and then quit and re-open Unity.
    And then, obviously, make sure to use lightmap as your type of lighting of the terrain :D
    This is how the test looked:


    Code (csharp):
    1.  
    2. Shader "Hidden/TerrainEngine/Splatmap/Lightmap-FirstPass" {
    3. Properties {
    4.     _Control ("Control (RGBA)", 2D) = "red" {}
    5.     _LightMap ("LightMap (RGB)", 2D) = "white" {}
    6.     _Splat3 ("Layer 3 (A)", 2D) = "white" {}
    7.     _Splat2 ("Layer 2 (B)", 2D) = "white" {}
    8.     _Splat1 ("Layer 1 (G)", 2D) = "white" {}
    9.     _Splat0 ("Layer 0 (R)", 2D) = "white" {}
    10.     _BaseMap ("BaseMap (RGB)", 2D) = "white" {}
    11. }
    12.  
    13. Category {
    14.     // Fragment program, 4 splats per pass
    15.     SubShader {
    16.         Tags { "SplatCount" = "4" }
    17.         Pass {
    18.             Tags { "LightMode" = "Always" }
    19.             Blend SrcAlpha OneMinusSrcAlpha
    20.             CGPROGRAM
    21.             #pragma vertex LightmapSplatVertex
    22.             #pragma fragment LightmapSplatFragment
    23.             #pragma fragmentoption ARB_fog_exp2
    24.             #pragma fragmentoption ARB_precision_hint_fastest
    25.             #define TEXTURECOUNT 4
    26.  
    27.             #include "UnityCG.cginc"
    28.  
    29. uniform float4 _Splat0_ST,_Splat1_ST,_Splat2_ST,_Splat3_ST,_Splat4_ST;
    30. uniform float4 _Splat5_ST,_Splat6_ST,_Splat7_ST,_Splat8_ST,_Splat9_ST;
    31.  
    32. struct v2f {
    33.     float4 pos : POSITION;
    34.     float fog : FOGC;
    35.     float4 uv[(TEXTURECOUNT+1)/2 + 1] : TEXCOORD0;
    36.     float4 color : COLOR;
    37. };
    38.  
    39.  
    40. uniform sampler2D _Control;
    41. uniform sampler2D _Control1;
    42. uniform sampler2D _Splat0,_Splat1,_Splat2,_Splat3;
    43. uniform sampler2D _Splat4,_Splat5,_Splat6,_Splat7;
    44.  
    45.  
    46. float4 CalculateVertexLights (float3 objSpaceNormal) {
    47.     float3 normal = mul (objSpaceNormal, (float3x3)glstate.matrix.transpose.modelview[0]);
    48.    
    49.     // Do vertex light calculation
    50.     float4 lightColor = glstate.lightmodel.ambient;
    51.     for (int i = 0; i < 4; i++) {
    52.         float3 lightDir = glstate.light[i].position.xyz;
    53.         float lightAmt = saturate( dot (normal, lightDir) );
    54.         lightColor += glstate.light[i].diffuse * lightAmt;
    55.     }
    56.  
    57.     return lightColor;
    58. }
    59.  
    60. void CalculateSplatUV (float2 baseUV, inout v2f o) {
    61.     o.uv[0].xy = baseUV;   
    62.     #if TEXTURECOUNT >= 1
    63.     o.uv[1].xy = TRANSFORM_TEX (baseUV, _Splat0);  
    64.     #endif
    65.     #if TEXTURECOUNT >= 2
    66.     o.uv[1].zw = TRANSFORM_TEX (baseUV, _Splat1);  
    67.     #endif
    68.     #if TEXTURECOUNT >= 3
    69.     o.uv[2].xy = TRANSFORM_TEX (baseUV, _Splat2);  
    70.     #endif
    71.     #if TEXTURECOUNT >= 4
    72.     o.uv[2].zw = TRANSFORM_TEX (baseUV, _Splat3);  
    73.     #endif
    74.     #if TEXTURECOUNT >= 5
    75.     o.uv[3].xy = TRANSFORM_TEX (baseUV, _Splat4);  
    76.     #endif
    77.     #if TEXTURECOUNT >= 6
    78.     o.uv[3].zw = TRANSFORM_TEX (baseUV, _Splat5);  
    79.     #endif
    80.     #if TEXTURECOUNT >= 7
    81.     o.uv[4].xy = TRANSFORM_TEX (baseUV, _Splat6);  
    82.     #endif
    83.     #if TEXTURECOUNT >= 8
    84.     o.uv[4].zw = TRANSFORM_TEX (baseUV, _Splat7);  
    85.     #endif 
    86. }
    87.  
    88. half4 CalculateSplat (v2f i) {
    89.     half4 color;
    90.     #if TEXTURECOUNT >= 1
    91.     half4 control = tex2D (_Control, i.uv[0].xy);
    92.     color = control.r * tex2D (_Splat0, i.uv[1].xy);
    93.     #endif
    94.     #if TEXTURECOUNT >= 2
    95.     color += control.g * tex2D (_Splat1, i.uv[1].zw);
    96.     #endif
    97.     #if TEXTURECOUNT >= 3
    98.     color += control.b * tex2D (_Splat2, i.uv[2].xy);
    99.     #endif
    100.     #if TEXTURECOUNT >= 4
    101.     color += control.a * tex2D (_Splat3, i.uv[2].zw);
    102.     #endif
    103.     #if TEXTURECOUNT >= 5
    104.     control = tex2D (_Control1, i.uv[0].xy);
    105.     color = control.r * tex2D (_Splat4, i.uv[3].xy);
    106.     #endif
    107.     #if TEXTURECOUNT >= 6
    108.     color += control.g * tex2D (_Splat5, i.uv[3].zw);
    109.     #endif
    110.     #if TEXTURECOUNT >= 7
    111.     color += control.b * tex2D (_Splat6, i.uv[4].xy);
    112.     #endif
    113.     #if TEXTURECOUNT >= 8
    114.     color += control.a * tex2D (_Splat7, i.uv[4].zw);
    115.     #endif
    116.    
    117.     return color;  
    118. }
    119.  
    120. float4 VertexlitSplatFragment (v2f i) : COLOR {
    121.     half4 col = CalculateSplat (i) * i.color;
    122.     col *= float4 (2,2,2,0);
    123.     return col;
    124. }
    125.  
    126. v2f VertexlitSplatVertex (appdata_base v) {
    127.     v2f o;
    128.    
    129.     o.pos = mul(glstate.matrix.mvp, v.vertex);
    130.     o.fog = o.pos.z;
    131.     o.color = CalculateVertexLights (v.normal);
    132.     CalculateSplatUV (v.texcoord, o);
    133.  
    134.     return o;
    135. }
    136.  
    137. uniform sampler2D _LightMap;
    138.  
    139. float4 LightmapSplatFragment (v2f i) : COLOR {
    140.     half4 lightmapTex = tex2D (_LightMap, i.uv[0].xy);
    141.     half4 col = CalculateSplat (i) * lightmapTex;
    142.     col *= float4 (2,2,2,0);
    143.     col.a = lightmapTex.a;
    144.     return col;
    145. }
    146.  
    147. v2f LightmapSplatVertex (appdata_base v) {
    148.     v2f o;
    149.    
    150.     o.pos = mul(glstate.matrix.mvp, v.vertex);
    151.     o.fog = o.pos.z;
    152.     CalculateSplatUV (v.texcoord, o);
    153.  
    154.     return o;
    155. }
    156.  
    157.  
    158.             ENDCG
    159.         }
    160.     }
    161.    
    162.     // ATI texture shader, 4 splats per pass
    163.     SubShader {    
    164.         Tags { "SplatCount" = "4" }
    165.         Pass {
    166.             Tags { "LightMode" = "Always" }
    167.            
    168.             Program "" {
    169.                 SubProgram {
    170. "!!ATIfs1.0
    171. StartConstants;
    172.     CONSTANT c0 = {0};
    173. EndConstants;
    174.  
    175. StartOutputPass;
    176.     SampleMap r0, t0.str;   # splat0
    177.     SampleMap r1, t1.str;   # splat1   
    178.     SampleMap r2, t2.str;   # splat2   
    179.     SampleMap r3, t3.str;   # splat3   
    180.     SampleMap r4, t4.str;   # control
    181.     SampleMap r5, t5.str;   # lightmap
    182.  
    183.     MUL r0.rgb, r0, r4.r;
    184.     MAD r0.rgb, r1, r4.g, r0;
    185.     MAD r0.rgb, r2, r4.b, r0;
    186.     MAD r0.rgb, r3, r4.a, r0;
    187.     MUL r0.rgb, r0.2x, r5;
    188.     MOV r0.a, c0;
    189. EndPass;
    190. "
    191.                 }
    192.             }
    193.             SetTexture [_Splat0]
    194.             SetTexture [_Splat1]
    195.             SetTexture [_Splat2]
    196.             SetTexture [_Splat3]
    197.             SetTexture [_Control]
    198.             SetTexture [_LightMap]
    199.         }
    200.     }
    201. }
    202.  
    203. // Fallback to base map
    204. Fallback "Hidden/TerrainEngine/Splatmap/Lightmap-BaseMap"
    205. }
    206.  
    If you want to use more than four textures for the terrain, you will have to mod the AddPassLightmap.shader file as well... :wink:
     
  11. Fribble

    Fribble

    Joined:
    Dec 3, 2009
    Posts:
    56
    Looks pretty cool, but I think that would be better if you want subtle transparencies in terrain (for an invisible mountain ridge, or something), as you can still see the texture.

    You know what? That actually could work if you were to get a plain texture (like the default non-textured gray that is originally assigned to the terrain), but then what? The terrain would still be there physically, right? :?
     
  12. Kragh

    Kragh

    Joined:
    Jan 22, 2008
    Posts:
    657
    Oh, but that's just because my alpha channel isn't entirely black at that place...



    :)
     
  13. Fribble

    Fribble

    Joined:
    Dec 3, 2009
    Posts:
    56
    Ahh, much better. Very nice, sir.

    This could also be used to make invisible barriers, not like I'm really a fan of that idea, but sometimes it's necessary.


    [EDIT]:

    Now that I look at this for a while, it seems like the A-Transparency is making the skybox seem a little lighter...Or is it just me?
     
  14. Kragh

    Kragh

    Joined:
    Jan 22, 2008
    Posts:
    657
    It would probably be easier to just stick a box collider in front of people :wink:
    I have no idea how this works with other stuff, it just struck my mind that the alpha channel of the lightmap is unused by anything, and covers the entire terrain. Which is good for this use...
     
  15. Fribble

    Fribble

    Joined:
    Dec 3, 2009
    Posts:
    56
    Oh yeah, colliders.

    Colliders are the solution to everything. :D
     
  16. Kragh

    Kragh

    Joined:
    Jan 22, 2008
    Posts:
    657
    For the boat example my method would ofcourse be too hard to use, because it's hard to define it sharp enough, and dynamically enough for moving objects. But for other stuff it would maybe be more intuitive to just use an alpha map. And it doesn't remove the option to put on other ways on top, like an object blocking rendering of underlying geometry, like the terrain.
     
  17. JohannChristoph

    JohannChristoph

    Joined:
    Jun 21, 2009
    Posts:
    141
    Great idea!!! This is exactly what i am looking for (transparent parts/edges of terrain)
    But i couldn't get it to work.
    How do i change the inbuild terrain shader?

    I put a FirstPassLightmap.shader file (with your code) directly into my project folder (not in Assets or Library). But it also didn't work in Assets folder.
    I applied my LightMap.psd (with Alpha) as Lightmap to my terrain (in Project Tab).
    And reopened Unity.

    But there are no transparent parts in my terrain.
    I think i made something wrong (am not familiar with changing inbuild shaders).
     
  18. Kragh

    Kragh

    Joined:
    Jan 22, 2008
    Posts:
    657
    Seems you have done what has to be done. Did you actually change the terrain lighting setting to "lightmap"? Have you made the import format of the the lightmap a format that contains alpha information? (Look for formats with RGBA or ARGB). I use DXT5 myself. Originally you had to choose the ARGB 24 or 32 format, but I have had no troubles using the others in the newer versions of Unity.
    Other that that I have no idea what you do wrong. It works pretty straight forward here.

    Btw, my shader was just a quick test, and is actually based on an older version of the lightmap shader for terrains. You might want to download the latest shader code, and change that instead...
     
  19. JohannChristoph

    JohannChristoph

    Joined:
    Jun 21, 2009
    Posts:
    141
    currently it seems to work only on the Base Map.
    In 'Terrain Settings' i pulled up the 'Base Map Dist.' slider. And it works great when the camera is near enough.

    Unfortunately i have no time at the moment to work on the shader. So cause the terrain is not essential for my current job i decided to not use terrain at all for now to finish it in time.

    But generally the idea is really great!!!.
    Thanks a lot for the help
     
  20. Kragh

    Kragh

    Joined:
    Jan 22, 2008
    Posts:
    657
    But if you move the basemap distance up (make the distance where it takes over bigger), and then go near the terrain, wouldn't that mean you are not looking at the basemap? Or did I misunderstand your post? The basemap slider tells you at what distance the basemap will be shown.
    If you want this to work on the basemap as well, you need to put in the alpha extras on that shader also. I can maybe give you a modified basemap shader next week.
     
  21. JohannChristoph

    JohannChristoph

    Joined:
    Jun 21, 2009
    Posts:
    141
    i have to admit that i don't really know what a base map is. If i set the slider high enough i get transparency.

    It would be very cool to have it also working on the base map (or distance). But take your time to write it (i am anyway ultra busy for the rest of the month. And i can't pay you for your work).

    It would basically have the advantage that you can give the terrain a non rectangular shape and make a soft transition at sea shores.
    So you can look on the bottom of the sky cube (at deep water) and don't need to do such complicated stuff (like the 'fog thing' in the light map in island demo). The bottom of the island-demo-sky-cube looks quite good actually.

    It seems to work fine with the Pro Water
     

    Attached Files:

  22. MaleNancy

    MaleNancy

    Joined:
    May 14, 2011
    Posts:
    4
    Is the code still usable in Unity 3.3?
    I pasted the codes inside the shader file but it come out error that i don't what it is..
    any ideas?
     
  23. jc_lvngstn

    jc_lvngstn

    Joined:
    Jul 19, 2006
    Posts:
    1,508
    I'm a bit of a noob with shaders, but...
    couldn't someone modify the terrain shader, so that the first texture (or last, whatever) is always drawn transparently? Or is it not that easy?
     
  24. jister

    jister

    Joined:
    Oct 9, 2009
    Posts:
    1,749
    hey this is an awesome and very handy feature that should be build in!!

    could some one fix it for 3.5? and put it on the wiki with a small tutorial on how to implement?

    i need this bad and can't get it to work... :(
     
  25. George Coltart

    George Coltart

    Joined:
    Mar 14, 2012
    Posts:
    1
    I'm desperate for the shader as well, did anyone get it working in recent versions?
     
  26. PolyMad

    PolyMad

    Joined:
    Mar 19, 2009
    Posts:
    2,350
  27. Venryx

    Venryx

    Joined:
    Sep 25, 2012
    Posts:
    444
  28. Cascho01

    Cascho01

    Joined:
    Mar 19, 2010
    Posts:
    1,347
    I just tried this shader with Unity 4.1.2f1 but I don´t get any transparency but a warning:
    "Shader warning in "Nature/Terrain/Diffuse": Not enough temporary registers, needs 10(compiling for flash) at line 24
    (This should not be the problem, I am not compiling for flash.)

    Any help is welcomed!

    My aim is to render only the plants on the terrain and have the hole terrainobject invisible (no render at all), maybe the shader could be much easier?
     
    Last edited: Apr 22, 2013
  29. Venryx

    Venryx

    Joined:
    Sep 25, 2012
    Posts:
    444
    Are you sure you're using a transparent texture? I've tried it with Unity 4, and confirmed it works. Anyway, I think that shader error is only a problem if you're building the game for Flash. (which you aren't) I get that too, but it doesn't seem to cause any problems for Webplayer or Standalone builds. (or probably any, other than flash)

    Anyway...
    - - - - -
    Finally took the time to extend the shader given above, and turn it into an Asset Store Plugin! I put quite a bit of time into it, though, (a couple full days), so I decided to put it up for 5$. The major improvement is that it now comes with script that will let objects actually pass through the graphical holes made.

    There's a plugin for this on the Asset Store: Terrain Hole System

    Description: "This Unity extension lets you make holes in your terrain that characters and other objects can go through."

    More information can be found on the forum thread.