Skip to content

Commit 6804e54

Browse files
Simple volume spot light
1 parent dfeea31 commit 6804e54

File tree

2 files changed

+163
-0
lines changed

2 files changed

+163
-0
lines changed

VolumeSpotLight.cs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// Add script to Main Camera. Volume spot light will be rendered in world position (0,0,0).
2+
// Script will be improved in future.
3+
4+
using UnityEngine;
5+
6+
public class VolumeSpotLight: MonoBehaviour
7+
{
8+
public Shader VolumeLightShader;
9+
Material _Material;
10+
Camera _Camera;
11+
12+
private Matrix4x4 GetFrustumCorners(Camera cam)
13+
{
14+
Matrix4x4 frustumCorners = Matrix4x4.identity;
15+
float fovWHalf = cam.fieldOfView * 0.5f;
16+
float tan_fov = Mathf.Tan(fovWHalf * Mathf.Deg2Rad);
17+
Vector3 toRight = Vector3.right * tan_fov * cam.aspect;
18+
Vector3 toTop = Vector3.up * tan_fov;
19+
Vector3 topLeft = (-Vector3.forward - toRight + toTop);
20+
Vector3 topRight = (-Vector3.forward + toRight + toTop);
21+
Vector3 bottomRight = (-Vector3.forward + toRight - toTop);
22+
Vector3 bottomLeft = (-Vector3.forward - toRight - toTop);
23+
frustumCorners.SetRow(0, topLeft);
24+
frustumCorners.SetRow(1, topRight);
25+
frustumCorners.SetRow(2, bottomRight);
26+
frustumCorners.SetRow(3, bottomLeft);
27+
return frustumCorners;
28+
}
29+
30+
void Blit(RenderTexture source, RenderTexture dest, Material fxMaterial, int passNr)
31+
{
32+
RenderTexture.active = dest;
33+
fxMaterial.SetTexture("_MainTex", source);
34+
GL.PushMatrix();
35+
GL.LoadOrtho();
36+
fxMaterial.SetPass(passNr);
37+
GL.Begin(GL.QUADS);
38+
GL.MultiTexCoord2(0, 0.0f, 0.0f);
39+
GL.Vertex3(0.0f, 0.0f, 3.0f);
40+
GL.MultiTexCoord2(0, 1.0f, 0.0f);
41+
GL.Vertex3(1.0f, 0.0f, 2.0f);
42+
GL.MultiTexCoord2(0, 1.0f, 1.0f);
43+
GL.Vertex3(1.0f, 1.0f, 1.0f);
44+
GL.MultiTexCoord2(0, 0.0f, 1.0f);
45+
GL.Vertex3(0.0f, 1.0f, 0.0f);
46+
GL.End();
47+
GL.PopMatrix();
48+
}
49+
50+
void Start ()
51+
{
52+
_Camera = Camera.main;
53+
_Material = new Material(VolumeLightShader);
54+
}
55+
56+
void OnRenderImage(RenderTexture source, RenderTexture destination)
57+
{
58+
_Material.SetMatrix("_FrustumCornersES", GetFrustumCorners(_Camera));
59+
_Material.SetMatrix("_CameraInvViewMatrix", _Camera.cameraToWorldMatrix);
60+
_Material.SetVector("_CameraWS", _Camera.transform.position);
61+
Blit(source, destination, _Material, 0);
62+
}
63+
64+
}

VolumeSpotLight.shader

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
Shader "VolumeSpotLight"
2+
{
3+
SubShader
4+
{
5+
Cull Off ZWrite Off ZTest Always
6+
Pass
7+
{
8+
CGPROGRAM
9+
#pragma vertex VSMain
10+
#pragma fragment PSMain
11+
12+
sampler2D _CameraDepthTexture;
13+
sampler2D _MainTex;
14+
float4x4 _CameraInvViewMatrix;
15+
float4x4 _FrustumCornersES;
16+
float4 _CameraWS;
17+
18+
bool cone(float3 org, float3 dir, out float near, out float far, float d)
19+
{
20+
org.x += 0.5;
21+
float s = 0.5;
22+
org.x *= s;
23+
dir.x *= s;
24+
float a = dir.y * dir.y + dir.z * dir.z - dir.x * dir.x;
25+
float b = org.y * dir.y + org.z * dir.z - org.x * dir.x;
26+
float c = org.y * org.y + org.z * org.z - org.x * org.x;
27+
float cap = (s - org.x) / dir.x;
28+
if( a == 0.0 )
29+
{
30+
near = -0.5 * c/b;
31+
float x = org.x + near * dir.x;
32+
if( x < 0.0 || x > s ) return false;
33+
far = cap;
34+
float temp = min(far, near);
35+
far = max(far, near);
36+
near = temp;
37+
return far > 0.0;
38+
}
39+
float delta = b * b - a * c;
40+
if( delta < 0.0 ) return false;
41+
float deltasqrt = sqrt(delta);
42+
float arcp = 1.0 / a;
43+
near = (-b - deltasqrt) * arcp;
44+
far = (-b + deltasqrt) * arcp;
45+
float temp = min(far, near);
46+
far = max(far, near);
47+
near = temp;
48+
float xnear = org.x + near * dir.x;
49+
float xfar = org.x + far * dir.x;
50+
if( xnear < 0.0 )
51+
{
52+
if( xfar < 0.0 || xfar > s ) return false;
53+
near = far;
54+
far = cap;
55+
}
56+
else if( xnear > s )
57+
{
58+
if( xfar < 0.0 || xfar > s ) return false;
59+
near = cap;
60+
}
61+
else if( xfar < 0.0 )
62+
{
63+
far = near;
64+
near = cap;
65+
}
66+
else if( xfar > s )
67+
{
68+
far = cap;
69+
}
70+
if (far>d) return false;
71+
return far > 0.0;
72+
}
73+
74+
void VSMain (inout float4 vertex : POSITION, inout float2 uv : TEXCOORD0, out float3 ray:TEXCOORD1)
75+
{
76+
half index = vertex.z;
77+
vertex.z = 0.1;
78+
vertex = UnityObjectToClipPos(vertex);
79+
ray = _FrustumCornersES[(int)index].xyz;
80+
ray /= abs(ray.z);
81+
ray = mul(_CameraInvViewMatrix, ray);
82+
}
83+
84+
float4 PSMain (float4 vertex : POSITION, float2 uv : TEXCOORD0, float3 ray:TEXCOORD1) : SV_Target
85+
{
86+
float far=0.0, near=0.0;
87+
float depth = 1.0 / (_ZBufferParams.z * tex2D(_CameraDepthTexture,uv).r + _ZBufferParams.w) * length(ray);
88+
float4 color = tex2D(_MainTex,uv);
89+
if (cone (_CameraWS, normalize(ray), near, far, depth))
90+
{
91+
float k = far - max(near, 0.0);
92+
color += float4(k,k,0.9*k,k);
93+
}
94+
return color;
95+
}
96+
ENDCG
97+
}
98+
}
99+
}

0 commit comments

Comments
 (0)