Search Unity

Need a quick way to turn model into a two-sided (cloth)

Discussion in 'Shaders' started by neginfinity, Dec 11, 2016.

  1. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,563
    Need a quick way to turn a model into two-sided geometry without manually remodeling it.

    That's for the purposes of using the model with unity cloth system.

    One would think it would be a fairly easy to slap a geometry shader but with surface shaders that's not the case.

    The question is valid till Monday 5:00 UTC+03.
     
  2. Martin_H

    Martin_H

    Joined:
    Jul 11, 2015
    Posts:
    4,436
    Can't you just duplicate the geometry, flip all normals, merge back into 1 mesh?
     
  3. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,336
    You can buy this asset.
    https://www.assetstore.unity3d.com/en/#!/content/42360

    Otherwise there are several examples on the forum already on how to do this. Search for two sided or double sided standard shader.

    The main parts are, Cull Off, VFACE, and flipping the normal on back faces.
     
  4. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,563
    There are mentions that this messes up cloth due to duplicate normals. Not sure if this is true, and I'm still too busy with other stuff to investigate.

    I don't need "legacy". I need standard PBR based built-in shader.

    Already searched, didn't find the sample I was looking for (with geometry shader + normal inversion).
     
  5. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,336
    That asset is actually "Double Sided Standard, Mobile, and Legacy Shaders", but the title is missing the commas and the "and", where the "Standard" is Unity's PBR shader. It includes double sided versions of all of the various "sets" of shaders that come with Unity.

    And the problem is you're looking for a solution using geometry shaders when none is needed.
     
  6. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,563
    Look, if you disable culling on standard shader, lighting on the other side will be, well, strange.

    The cleanest way would be to emit extra faces, which is done in geometry shader. Without that you'll need either hack standard shader (which will break after next update), or abandon idea with pbr and write both passes, shadowcasters and all that stuff.
     
  7. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,336
    The lighting is strange because the surface normals are facing away from you when looking at the back faces. The solution is to flip the normal direction in the surface shader based on the facing, and VFACE is the semantic for knowing if a tri is facing towards or away.

    Geometry shaders can be used to do the same thing, but at a greater cost.

    Again, search the forums for VFACE and you'll come across several examples of using it to flip the normal in a double sided surface shader. (Most probably written by me.)
     
    Martin_H likes this.
  8. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,563
    Found a solution.
    Code (csharp):
    1.  
    2. Shader "Custom/CloakShader" {
    3.     Properties {
    4.         _Color ("Color", Color) = (1,1,1,1)
    5.         _MainTex ("Albedo (RGB)", 2D) = "white" {}
    6.         _Glossiness ("Smoothness", Range(0,1)) = 0.5
    7.         _Metallic ("Metallic", Range(0,1)) = 0.0
    8.     }
    9.     SubShader {
    10.         Tags { "RenderType"="Opaque" "PreviewType"="Plane" }
    11.  
    12.         LOD 200
    13.         Cull Off
    14.  
    15.         CGPROGRAM
    16.         // Physically based Standard lighting model, and enable shadows on all light types
    17.  
    18.         #pragma surface surf Standard fullforwardshadows
    19.  
    20.         // Use shader model 3.0 target, to get nicer looking lighting
    21.         #pragma target 3.0
    22.  
    23.         sampler2D _MainTex;
    24.  
    25.         struct Input {
    26.             float2 uv_MainTex;
    27.             fixed facing: VFACE;
    28.         };
    29.  
    30.         half _Glossiness;
    31.         half _Metallic;
    32.         fixed4 _Color;
    33.  
    34.         void surf (Input IN, inout SurfaceOutputStandard o) {
    35.             // Albedo comes from a texture tinted by color
    36.             fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
    37.             o.Albedo = c.rgb;
    38.             // Metallic and smoothness come from slider variables
    39.             o.Metallic = _Metallic;
    40.             o.Smoothness = _Glossiness;
    41.             o.Alpha = c.a;
    42.             float tmp = IN.facing;
    43.             o.Normal = float3(0.0, 0.0, step(0.5f, IN.facing) * 2.0 - 1.0);
    44.         }
    45.         ENDCG
    46.     }
    47.     FallBack "Diffuse"
    48. }
    49.  
    50.  
    Requires "TwoSidedShadows" mode is shadowcasting is enabled.
    ------

    Unsubscribing from the thread.
     
    Martin_H likes this.
  9. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,336
    VFACE value is always a -1 or 1, the step() is unnecessary.

    You can add to the shader a custom shadow caster pass with culling off as well to avoid the need for setting two sided shadows on the renderer. I don't remember if just addshadow on the #pragma surface line is enough or if you need to add it manually.
     
  10. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,563
    Apparently the solution I posted earlier refuses to play nice with directional shadows. Even if the mesh has "Dual shadows" enabled.


    Grrr....

    Don't have the time to fix this right now. :-\
     
    iamthwee likes this.
  11. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,336
    The custom shadow caster pass fixes that. Or, again, that asset.
     
  12. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,563
    Quick and dirty fix:
    Code (csharp):
    1.  
    2. Shader "Custom/CloakShader" {
    3.     Properties {
    4.         _Color ("Color", Color) = (1,1,1,1)
    5.         _MainTex ("Albedo (RGB)", 2D) = "white" {}
    6.         _Glossiness ("Smoothness", Range(0,1)) = 0.5
    7.         _Metallic ("Metallic", Range(0,1)) = 0.0
    8.     }
    9.     SubShader {
    10.  
    11.         Pass {
    12.             Name "ShadowCaster"
    13.             Tags { "LightMode" = "ShadowCaster" }
    14.          
    15.             ZWrite On ZTest LEqual
    16.             Cull Off
    17.  
    18.             CGPROGRAM
    19.             #pragma target 3.0
    20.             // TEMPORARY: GLES2.0 temporarily disabled to prevent errors spam on devices without textureCubeLodEXT
    21.             #pragma exclude_renderers gles
    22.          
    23.             // -------------------------------------
    24.  
    25.  
    26.             #pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON
    27.             #pragma multi_compile_shadowcaster
    28.  
    29.             #pragma vertex vertShadowCaster
    30.             #pragma fragment fragShadowCaster
    31.  
    32.             #include "UnityStandardShadow.cginc"
    33.  
    34.             ENDCG
    35.         }
    36.  
    37.         Tags { "RenderType"="Opaque" "PreviewType"="Plane" }
    38.  
    39.         LOD 200
    40.         Cull Off
    41.  
    42.         CGPROGRAM
    43.         // Physically based Standard lighting model, and enable shadows on all light types
    44.  
    45.         #pragma surface surf Standard fullforwardshadows
    46.  
    47.         // Use shader model 3.0 target, to get nicer looking lighting
    48.         #pragma target 3.0
    49.  
    50.         sampler2D _MainTex;
    51.  
    52.         struct Input {
    53.             float2 uv_MainTex;
    54.             fixed facing: VFACE;
    55.         };
    56.  
    57.         half _Glossiness;
    58.         half _Metallic;
    59.         fixed4 _Color;
    60.  
    61.         void surf (Input IN, inout SurfaceOutputStandard o) {
    62.             // Albedo comes from a texture tinted by color
    63.             fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
    64.             o.Albedo = c.rgb;
    65.             // Metallic and smoothness come from slider variables
    66.             o.Metallic = _Metallic;
    67.             o.Smoothness = _Glossiness;
    68.             o.Alpha = c.a;
    69.             float tmp = IN.facing;
    70.             o.Normal = float3(0.0, 0.0, step(0.5f, IN.facing) * 2.0 - 1.0);
    71.             //o.Normal.z *= step(IN.facing, 0.5f) * 2.0 - 1.0;
    72.             //o.Normal = lerp(o.Normal, -o.Normal, step(IN.facing, 0.5f));
    73.         }
    74.         ENDCG
    75.     }
    76.     FallBack "Diffuse"
    77. }
    78.  
    That seems to be working
     
    tree_arb likes this.
  13. tree_arb

    tree_arb

    Joined:
    Dec 30, 2019
    Posts:
    323
    old thread but thanks for the shader! seems to be working quite well on my first google attempt to find a double sided cloth solution.