Jan
28
2014

Ray-traced Fake Soft Shadows (Shader)

raytrace_pointlight_shadows_unity_indie_1

Mooore fake shadows testing! (based on direct3D shaders)

Info:
– Works with unity indie/free!
– Just a shader with sphere intersect function (so it basically only works with spheres..)
– Point light & sphere positions are sent to the shader
– Each sphere requires invidual shadow collector flat plane (they are combined with blend modes)
– Options for: Soft shadows, Hard Shadows, Tinted shadows
– 1 or more spotlight positions

Maybe small bug, sphere radius should be half in shader, seems that the shadows is too big..

Webplayer:
http://unitycoder.com/upload/demos/RaytracedShadowShader/ (1 spotlight, 3 shader variations )
http://unitycoder.com/upload/demos/RaytracedShadowShader2/ (2 spotlights)

Shader source:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
 
Shader "Custom/RaytraceMultiShadowsHard" {
 
    Properties
    {
        _Color ("Main Color", Color) = (0,1,0,1)
        _BallPos("BallPos", Vector) = (0, 0, 0, 0)
        _LightPos("lightPos", Vector) = (1, 10, 0, 0)
        _LightPos2("lightPos2", Vector) = (1, 10, 0, 0)
        _BallRadius("ballRadius", Float) = 1.0
    }
 
    SubShader {
    Tags {"Queue"="Transparent" "RenderType"="Transparent"} //Change this
        Pass {
         
//Blend DstColor SrcColor
//Blend SrcAlpha OneMinusSrcAlpha    
        Blend SrcAlpha OneMinusSrcAlpha //Add This
         
            CGPROGRAM
// Upgrade NOTE: excluded shader from DX11 and Xbox360; has structs without semantics (struct v2f members wpos)
            #pragma exclude_renderers d3d11 xbox360
            #pragma vertex vert
            #pragma fragment frag alpha
            #pragma fragmentoption ARB_precision_hint_fastest
            //#pragma target 3.0
 
            #include "UnityCG.cginc"
 
     
        float4 _Color;
        float4 _BallPos;
        float4 _LightPos;
        float4 _LightPos2;
        float _BallRadius;
         
 
 
        //this function returns the distance of a point to a line:
        float dist_p2l(float3 pnt, float3 l0, float3 l1)
        {
            float3 v = l1 - l0;
            float3 w = pnt - l0;
          
            //determine the relations of the dot products of a triangle
            //formed by the vectors
            float c1 = dot(w,v);
            float c2 = dot(v,v);
            float b = c1/c2;
          
            //and use them to calculate the distance.
            float3 pb = l0 + b * v;
            return distance (pnt, pb);
        }
          
        float getSphereIntersect(float3 lightPos, float3 pixelPos, float3 ballPos, float ballRadius, out bool hit)
        {
            hit = true;
            float dist = dist_p2l(ballPos, pixelPos, lightPos);
            if (dist > ballRadius)
            {
                hit=false; return 0;
            }else
            {
                //prepare the shadow intensity here.
//                return 1-cos(1.0-(dist/ballRadius));
                return dist/ballRadius;
            }
        }
         
        struct a2v {
            float4 vertex : POSITION;
            //float4 texcoord : TEXCOORD0;
        };
 
        struct v2f {
            float4 pos : SV_POSITION;
            // Shader warning in 'Custom/RaytraceShadows': Program 'vert', 'vert': function return value missing semantics (compiling for d3d11_9x) at line 22
            // Shader warning in 'Custom/RaytraceShadows': Program 'vert', 'getSphereIntersect': implicit truncation of vector type (compiling for d3d11_9x) at line 87
            //float4 wpos;
            float3 wpos;
            //float2 uv : TEXCOORD0;
        };
         
        v2f vert(a2v v) {
            v2f o;
            o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
            o.wpos = mul(_Object2World, v.vertex);
               //o.uv = v.texcoord.xy;
            return o;
        }
 
        float4 frag(v2f i) : COLOR
        {
         
            bool hit;
            float shadowIntensity=10;
          
            shadowIntensity = getSphereIntersect(_LightPos,i.wpos, _BallPos, _BallRadius, hit);
          
//            float4 ret = _Color;
            float4 ret = float4(0,0,0,0);
             
            float a=0;
             
            if (hit)
            {
//                ret.rgb *= shadowIntensity;
//                ret.a = 1-shadowIntensity;
                a = 0.5f;
            }
 
            shadowIntensity = getSphereIntersect(_LightPos2,i.wpos, _BallPos, _BallRadius, hit);
            if (hit)
            {
//                ret.rgb *= shadowIntensity;
//                ret.a = 1-shadowIntensity;
                a += 0.25f;
            }
          
             ret.a = a;
                            
            return ret;
             
        //    fixed4 c = fixed4(1,0,0,1);
        //    return c;
        }
             
             
             
             
             
            ENDCG
        }
    }
}

 

 


4 Comments + Add Comment

Leave a comment to mgear

Connect

Twitter View LinkedIn profile Youtube Github Join Discord Twitch Instagram BlueSky

UnityLauncherPro

Get UnityLauncherPRO and work faster with Unity Projects!
*free unity hub alternative

@unitycoder_com

Subscribe to Blog via Email

Enter your email address to subscribe to this blog and receive notifications of new posts by email.