Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Extrude Shader

Discussion in 'Made With Unity' started by tomaszek, Aug 15, 2012.

  1. tomaszek

    tomaszek

    Joined:
    Jun 18, 2009
    Posts:
    3,861
    I've been working for some time on kind of extrusion shader. It's something similar to relief mapping shader, but gets only two states (shape/hole).





    http://www.stobierski.pl/unity/ExtrudeShader/WebPlayer.html


    It will be used in my racing game (braking disks like in example), but I'm thinking about exposing it in AssetStore for a few $. For now I'd like to know any possible feedback. Such shader gives us opportunity to extrude any shape from heightmap (grayscale) which is treated as alpha>0.5 (volume) alpha<=0.5 (hole). This way, depending on shape we need, heightmap could be lowpass filtered (smoothed) and of low resolution while extruded edges could be still very sharp.

    Extrusion is realised in tangent space, so shape doesn't need to be "flat". We could extrude wavy shapes along mesh normals, etc.

    As this is special case of relief mapping I'm doing the job special way.

    First I use the "distance map" (I made tool for making distance maps from grayscale height map). Distance map is RGBA encoded "hollow boxes" for every pixel on height map. This way we know how far we can safely travel in each direction (think of it - cube instead of cone mapping as this is sharp extrusion, not smooth relief) and 3 steps (3 x tex2D+some simple math) seems to be OK for this initial guess, although there are still pesimistic cases - like in any other relief algorithm, no matter how would you try...no holy grail :(. After such initialisation traced ray gets close to the potential "wall". Due to using distance map, marching ray is potentialy able to travel very large empty spaces quickly depending on situation.

    Second - as we're likely close to the edge we can perform classic binary search to refine exact rayhit position. I use 6 steps for it in example above.

    Third (optional) - I use reverse travel similar to the initial step (by distance map) from hit point toward light for realising self-shadowing. Again - 3 steps looks OKish even without exact search (for better selfshadowing we should perform another binary search at the end). Then I'm smoothing the self-shadow (costs nothing and looks better).

    Number of steps for nice effect would depend on used heightmap.

    Take into account that in position of ray hit I compute exact normal, perpendicular to the surface, so that lighting is OK where vertical (extruded) walls are rendered. It's realised by normalmap - easily generated from source heightmap (normalmap can be also tiny if you don't need very small details to be extruded).

    Presented shader is not fully optimized and computes reflection + some other things. In case of another coloring or application, shader could be considerably simplier.

    I put some effort to make it compatible with Unity's lighting/shadow system (which is often problem with other implementations of relief shaders). Shadow casting of extruded volume is realised by custom ShadowCaster pass (simple alpha cutout), to speed-up things as in most cases we won't need that precise shadow caster from our extruded shape. For unknown reason I can't force my shader to cast shadows in forward redering, but I hope I'll make it soon (any hints what I could do wrong way ?)

    One positive thing is I was able to mess around alpha values to improve edges - we can get them smoothly extruded w/o aliasing, for almost no additional cost. No matter deferred or not - it's something like "soft vegetation" in 3D :). We can very precisely extrude complex shapes while maintaining low poly count. Altough extruding too many pixels (even optimized fragment shader isn't very performance-friendly) could cost too much, I can think of this shader application as quick geometry detail refinement. Like in example - brake disks are rendered rather in small scale, no close-ups in standard camera position. The same time making them flat alpha-cut wouldn't look good when observing along their surface. On the other hand I don't want to spend 2000k+ polys on every brake disk (or sprocket, ietc.) to make them look nice from any direction.

    If one use only "one side" of extrusion when object is seen from one side and we don't see extruded edge from the side direction nor back surface, then shader could be considerably simpler (less math and conditions), but of course number of tex lookups and ray tracing steps can't be considerably reduced for good looking results. Another idea is to put extruded object onto another mesh surface so we can see it thru our extruded "holes". This way we could make sharp reliefs on surfaces as an alternative to bump maping. Theoretically we could extrude whole cylinders (from circle as heightmap) or objects like this, but one should consider that for very deep extrusions we would probably need more ray marching steps to get better results.

    Please - any ideas, thoughts would be very appreciated.
     
    Last edited: Aug 15, 2012
  2. ScienceFiction

    ScienceFiction

    Joined:
    May 28, 2008
    Posts:
    393
    Wow, very nice. Cutting edge as usual. What is the likelyhood of this shader working on iOS or android? :eek:
     
  3. Fishypants

    Fishypants

    Joined:
    Jan 25, 2009
    Posts:
    444
    That is really damn cool! Could this shader sample vertex colors on the mesh and use that to light the rendered result?
     
  4. tomaszek

    tomaszek

    Joined:
    Jun 18, 2009
    Posts:
    3,861
    Sure, depending on what you exactly want to do. Shading pixels in fragment program we can use interpolated info from vertices, but we don't have info of _any_ vertice color (instead we can access textures). For some special cases we could dont use any height texture but compute it realtime in fragment program (for example for regular circle bumps or kind of noise).
     
  5. tomaszek

    tomaszek

    Joined:
    Jun 18, 2009
    Posts:
    3,861
    We can do simplier mobile version (no mipmaps as we need tex2D_grad) but we need consider performance issues. Do you can access 10+ texture + math ? I can't tell as I'm not much into mobile devices. If you don't extrude too deep you should be able to get reasonable results in less ray marching iterations
     
  6. Finjitzu

    Finjitzu

    Joined:
    Sep 8, 2011
    Posts:
    160
    Very cool. Let us know when it's up on the asset store.
     
  7. imaginaryhuman

    imaginaryhuman

    Joined:
    Mar 21, 2010
    Posts:
    5,834
    Impressive that you got that all 3D-like from a single texture surface.
     
  8. TiG

    TiG

    Joined:
    Feb 28, 2011
    Posts:
    311
    Wonderful. This can save lots of polygons. The things that can be done with shaders always amaze me.
     
  9. larsbertram1

    larsbertram1

    Joined:
    Oct 7, 2008
    Posts:
    6,850
    very nice – but how fast is it compared to render complex geometry?

    lars
     
  10. tomaszek

    tomaszek

    Joined:
    Jun 18, 2009
    Posts:
    3,861
    Good point as it may seem like doing art for art's sake :). As I said - it's no good to try render scene all with that kind of stuff as shader isn't lighting fast. I can imagine using such shader where we need quickly extrude complex details for example fancy decors on objects. Doing it via geometry could take many polys and weight more than a few lo-res textures (my shader needs heightmap - alpha8, normalmap - DXTnm, distancemap for improved raymarch - RGBA, color map if you need it).

    This is question of balancing GPU vertex vs. fragment. Heavy hi-poly when rendered as a small object would hit vertex GPU units considerably while rendering only a small part of view. On the other hand - using very complex fragment shaders for too many pixels would also result in bad ballance. Demo above shows the method (256x256 heightmap). Brake disk, however not that complex geometry as we can easily imagine much more detailed height map, is generaly seen as a small part of object. Extreme close-ups are rare. In real application I guess ending up with 128x64 bitmaps (my shader for brake disk is special case of mirror). Doing it via hi-poly could costs more. In this particular case I'm not THAT sure if really, but I'm just taking my chance :). Another issue in my case is motion blur of quickly rotating object - hard to achieve when rendered as poly instead of texture when we can smear it radialy inside shader or use a few spare textures.

    I'm not that interested in implementing classic relief mapping as this case is well studied and other people already done it in Unity. I took special case of extrusion because of its interesting properties (for example cube space leaping optimization instead of cone). It's not done for the reason it couldn't be done another way (pushing maaany polygons), but more for fun of researching which in many situations proved to lead into results beyond original idea of researcher. In fact - now I'm thinking about doing a few versions of my shader so that pepole can use it in particular cases, tailored to their needs where only a basic functionalities are needed and shader could be simplier. That solution would be good for developers that need it. I'm _not_ thinking about packing it into kind of bundle and selling at higher price. I belive then, let's say $5-$8 would be fine ? What do you think ?

    Next step of reserach could be kind of procedural extrusion where we needn't use textures at all and shader could get really fast while giving a set of fine results (circle, bump, checker extrusion, etc.). But this is another story...
     
    Last edited: Aug 15, 2012