Search Unity

Dissolution Shader Shadow problem

Discussion in 'Shaders' started by Papnix, Mar 21, 2018.

  1. Papnix

    Papnix

    Joined:
    Apr 17, 2017
    Posts:
    3
    Hello everyone,

    I'm working on an implementation of the dissolution effect seen in the article Dissolve the world. I'm new to shader programming and I'm struggling a bit to understand what is really going on behind Unity pipeline.
    Unfortunately, I'm stuck with a shadow problem.



    As you can see on the picture above, shadow doesn't apply on hidden objects visible through my dissolution. I understand that it's because the shadow computation pass doesn't know that I will discard some pixel so shadows are not calculated behind them.


    This is the Shadows.CollectShadow image seen in my Frame Debugger and, off course, I see that the front wall hide the problematic area.

    So my questions is : How can I get my shadow ? Do I have to write my own shadow pass ? (If yes, how)
    I saw addshadow parameters for my surface shader but it didn't help or I didn't make it work.
    Can I ask to calculate shader after dissolving the object ?

    This is my proto shader :


    Shader "Custom/Dissolve" {
    Properties {
    _Color ("Color", Color) = (1,1,1,1)
    _MainTex ("Albedo (RGB)", 2D) = "white" {}
    _EllipseA("Factor A", Range(0.0,0.02)) = 0.01
    _EllipseB ("Factor B", Range(0.0,0.02)) = 0.01
    _DissolveColor("Dissolve Color", Color) = (1,1,1,1)
    }
    SubShader {
    Tags{ "RenderType" = "Opaque" }
    LOD 200
    CGPROGRAM
    // Physically based Standard lighting model, and enable shadows on all light types
    #pragma surface surf StandardSpecular addshadow
    // Use shader model 3.0 target, to get nicer looking lighting
    #pragma target 3.0
    #include "Assets/Shaders/3DPerlinNoise.cginc"

    sampler2D _MainTex;
    struct Input {
    float2 uv_MainTex;
    float4 screenPos;
    float3 worldPos;
    };
    half _EllipseA;
    half _EllipseB;

    uniform float _DisplayDistance;
    uniform float _TargetViewPointX;
    uniform float _TargetViewPointY;

    fixed4 _Color;
    fixed4 _DissolveColor;

    void surf(Input IN, inout SurfaceOutputStandardSpecular o) {

    float2 screenUV = IN.screenPos.xy / IN.screenPos.w;
    float dist = IN.worldPos.z - _WorldSpaceCameraPos.z;

    // Albedo comes from a texture tinted by color
    fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
    if (dist < _DisplayDistance)
    {
    float mask = pow(screenUV.x - _TargetViewPointX, 2) / _EllipseA + pow(screenUV.y - _TargetViewPointY, 2) / _EllipseB - 1 + Perlin3D(IN.worldPos);
    if (mask <= 0)
    {
    if (mask > -0.05)
    {
    o.Albedo = _DissolveColor.rgb * c.rgb;
    }
    else
    {
    clip(-1);
    }
    }
    else
    {
    o.Albedo = c.rgb;
    }
    }
    else
    {
    o.Albedo = c.rgb;
    }
    }
    ENDCG
    }
    }


    Thank you in advance for your help.
    Have a nice day
    Papnix
     
    Last edited: Mar 26, 2018
  2. Papnix

    Papnix

    Joined:
    Apr 17, 2017
    Posts:
    3
    Well, after research, this effect can't be done in forward rendering. It's only possible in deffered rendering.
     
  3. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    This is totally possible with forward rendering, in fact your addition of addshadow on the #pragma surface line is the solution. However it's possible your reliance on the screen position is the issue as there's no guarantee these will match between the shadow pass(es), depth pass, and forward pass. If you do all of your calculations in world space they'll match.
     
  4. Papnix

    Papnix

    Joined:
    Apr 17, 2017
    Posts:
    3
    Thanks for the reply, I'll try to make it works !