Search Unity

Multi-layer clothes through Z-test manipulation

Discussion in 'Shaders' started by korotkevich-md, Sep 8, 2012.

  1. korotkevich-md

    korotkevich-md

    Joined:
    Jun 10, 2011
    Posts:
    21
    Hi!
    I need to implement multi-layer dressing of clothes for my character. For example, for wearing suit jacket over shirt or simultaneously wearing shirt and pants.
    Variants with physics and collisions between clothes are too complicated and resource expensive.
    Colleague working on a similar project suggested that I can use manipulation with Z-test in shaders to determine the order of rendering.
    I tried to add line "ZTest Always"to the normal diffuse shader of the skirt, which weared over the blouse.
    In general, this is what I need - the skirt is rendered on the top of the blouse. But there are some problems that I do not know how to solve, because I never wrote shaders:
    1. belt of skirt does not fully cover the waist, it is especially evident when rotating camera, on the side views (see 1st picture)
    2. also on the side views - I need to drawn sleeves with hands over the skirt, now they are drawn under the skirt (see 2nd picture).


    Maybe I also need some changes of z-test in the shader of the lower layer?
     
    Last edited: Sep 8, 2012
  2. Martin-Kraus

    Martin-Kraus

    Joined:
    Feb 18, 2011
    Posts:
    617
    I guess you shouldn't use "ZTest Always" for this kind of problem because you run into troubles like the one with the hands.

    It might help to make sure that the layers are rendered from lower layers (skin) to higher layers (coat) with the Queue tag: http://docs.unity3d.com/Documentation/Components/SL-SubshaderTags.html .
    And then you could deactivate writing to the depth buffer (ZWrite Off : http://docs.unity3d.com/Documentation/Components/SL-Pass.html ) for those layers that stick out through higher layers. (But don't deactivate writing to the depth buffer for the skin.)
     
  3. korotkevich-md

    korotkevich-md

    Joined:
    Jun 10, 2011
    Posts:
    21
    Thanks for answer, Martin.
    I used "Queue" = "Geometry" in the shader of the lower layer (blouse) and "Queue" = "Geometry+1" in the shader of the higher layer (skirt). I also add line "ZWrite Off" to the lower layer shader. Problem with hands was solved. But I got another problems.
    Blouse looks partially transparent (see pict.1 - at the collar and around chest, pict.2 - around waist). Also, back of the blouse is too brightly lit (see pict. 2). I have 2 direct lights in the scene - back front.
    I would appreciate some help with it.
    Picture 1
    Picture 2
     
  4. Martin-Kraus

    Martin-Kraus

    Joined:
    Feb 18, 2011
    Posts:
    617
    I looks like the blouse should be over the skirt, doesn't it? I.e. the skirt is the lower layer and the blouse is the top-most layer.

    Is the skin in the same layer as the blouse? I think it would be better to have the skin only (without blouse) in the lowest Queue with(!) writing to the z buffer.
     
  5. korotkevich-md

    korotkevich-md

    Joined:
    Jun 10, 2011
    Posts:
    21
    No, blouse should be under skirt, so lowest layer - skin, then blouse, then skirt. I add "Queue" = "Geometry" to the skin shader, "...+1" to the blouse, "...+2" to the skirt. ZWrite is off only on middle layer (blouse). The picture remains the same, except of brightness on the back. Blouse is partially transparent as on the 1st picture. Also, there is some white artefacts on the blouse (see picture) - in the armpits and on the sleeves.
     
  6. Daniel_Brauer

    Daniel_Brauer

    Unity Technologies

    Joined:
    Aug 11, 2006
    Posts:
    3,355
    You should probably use Z-priming to handle intra-mesh overlaps. Z-priming is a technique where you first render a mesh with Colormask 0, which renders only to the depth buffer (nothing to RGBA). Then render normally with Z testing, and only the frontmost fragments will be rendered. A simple example of a Z-primed shader is on the wiki.

    Keep using renderqueues to handle inter-mesh overlaps, as distance from camera is not a good sorting metric in your case.
     
  7. korotkevich-md

    korotkevich-md

    Joined:
    Jun 10, 2011
    Posts:
    21
    Thanks, Daniel. I applied technic that you suggested. That removed all artefacts from lower layer.
    But...initially I made a mistake. I tried to manipulate Z-test and Z-buffer without "Pass" block. I simply added "ZWrite Off" straight after "Tags".
    As I understand now, all changing of Z-test should be in "Pass {...}"
    I did so and clothes looks like as I dont changed anything (see picture) - upper layer (skirt) doesnt cover lower layer (blouse).

    Please, see at the code of lower layer shader - its a normal diffuse shader with two "Pass" block added.
    Code (csharp):
    1. Shader "Diffuse ZTest Lower" {
    2. Properties {
    3.     _Color ("Main Color", Color) = (1,1,1,1)
    4.     _MainTex ("Base (RGB)", 2D) = "white" {}
    5. }
    6. SubShader {
    7.     Tags { "RenderType"="Opaque" }
    8.     Tags {"Queue" = "Geometry+1"}
    9.     LOD 200
    10.    
    11.     Pass {
    12.         ColorMask 0
    13.     }
    14.     Pass {
    15.         ZWrite Off
    16.         ColorMask RGB
    17.     }
    18.    
    19.    
    20. CGPROGRAM
    21. #pragma surface surf Lambert
    22.  
    23. sampler2D _MainTex;
    24. fixed4 _Color;
    25.  
    26. struct Input {
    27.     float2 uv_MainTex;
    28. };
    29.  
    30. void surf (Input IN, inout SurfaceOutput o) {
    31.     fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
    32.     o.Albedo = c.rgb;
    33.     o.Alpha = c.a;
    34. }
    35. ENDCG
    36. }
    37.  
    38. Fallback "VertexLit"
    39. }
     
  8. Daniel_Brauer

    Daniel_Brauer

    Unity Technologies

    Joined:
    Aug 11, 2006
    Posts:
    3,355
    That looks like your shaders are working correctly, but your geometry is intersecting in ugly ways. Can you change the blouse model to have it match up with the top of the skirt?
     
  9. Martin-Kraus

    Martin-Kraus

    Joined:
    Feb 18, 2011
    Posts:
    617
    Look at the picture at the waistline: the blouse clearly extends over the skirt. The blouse being under the skirt is only your wishful thinking: the geometry clearly isn't under the skirt.

    EDIT: But maybe I'm misunderstanding you: maybe you want the blouse being rendered below the skirt even though the geometry is not. Then we are talking about a much harder problem. (Maybe you should ask a wizard? ;) )
     
    Last edited: Sep 17, 2012
  10. korotkevich-md

    korotkevich-md

    Joined:
    Jun 10, 2011
    Posts:
    21
    To Daniel:
    Why clothes looks like as I used the same normal diffuse shader for each layer and don't changed anything with ZBuffer?
    I like more the picture that I received before, using "ZBuffer Off" without Pass-block (by mistake).
    I can change the blouse model to match the top of the skirt, in this particular case. But I have a plan of streaming manufacture a large number of clothes (using CAD), and I don't want to spend extra time on matching each clothes together. Besides, if I change the blouse to have match up with this skirt, not the fact that in other combinations, such as with pants, it will also be match up. If such non-compliance (as in the picture in your post) can be removed by using the render queues and setting "ZBuffer off" - this is what I need.

    To Martin:
    I am agree, in this particular case, blouse geometry isn't under the skirt. I'll try to change it around the waistline.
    But, is it real to render skirt over blouse in case as in my previous post?
     
    Last edited: Sep 18, 2012