mirror of
https://github.com/maxartz15/VolumetricLighting.git
synced 2025-06-27 21:16:05 +02:00
Directional Light
- Directional light - Sponza sample scene
This commit is contained in:
@ -102,6 +102,7 @@ public partial class FogLight : LightOverride
|
||||
// This step should convert to ESM/VSM
|
||||
// m_BufGrabShadowmap.Blit(shadowmap, targetRT);
|
||||
m_BufGrabShadowmap.SetGlobalTexture("_DirShadowmap", shadowmap);
|
||||
m_BufGrabShadowmap.SetGlobalVector("_ZParams", GetZParams());
|
||||
m_BufGrabShadowmap.Blit(null, targetRT, m_BlurShadowmapMaterial, /*sample & convert to VSM*/ 4);
|
||||
}
|
||||
else
|
||||
@ -118,6 +119,14 @@ public partial class FogLight : LightOverride
|
||||
//m_BufGrabShadowmap.SetGlobalTexture(directionalShadowmapBlurred, directionalShadowmapBlurred);
|
||||
}
|
||||
|
||||
private Vector4 GetZParams()
|
||||
{
|
||||
Light light = GetComponent<Light>();
|
||||
float n = light.shadowNearPlane;
|
||||
float f = light.range;
|
||||
return new Vector4((n - f) / n, f / n, (n - f) / (n * f), 1 / n);
|
||||
}
|
||||
|
||||
void CleanupDirectionalShadowmap()
|
||||
{
|
||||
if (m_BufGrabShadowmap != null)
|
||||
|
@ -4,12 +4,9 @@ using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
[ExecuteInEditMode]
|
||||
[RequireComponent (typeof(Camera))]
|
||||
[RequireComponent(typeof(Camera))]
|
||||
public class VolumetricFog : MonoBehaviour
|
||||
{
|
||||
Material m_DebugMaterial;
|
||||
[HideInInspector]
|
||||
public Shader m_DebugShader;
|
||||
[HideInInspector]
|
||||
public Shader m_ShadowmapShader;
|
||||
[HideInInspector]
|
||||
@ -24,11 +21,6 @@ public class VolumetricFog : MonoBehaviour
|
||||
public Shader m_BlurShadowmapShader;
|
||||
[HideInInspector]
|
||||
public Texture2D m_Noise;
|
||||
[HideInInspector]
|
||||
public bool m_Debug = false;
|
||||
[HideInInspector]
|
||||
[Range(0.0f, 1.0f)]
|
||||
public float m_Z = 1.0f;
|
||||
|
||||
[Header("Size")]
|
||||
[MinValue(0.1f)]
|
||||
@ -43,7 +35,8 @@ public class VolumetricFog : MonoBehaviour
|
||||
Vector3i m_ScatterNumThreads = new Vector3i(32, 2, 1);
|
||||
RenderTexture m_VolumeInject;
|
||||
RenderTexture m_VolumeScatter;
|
||||
Vector3i m_VolumeResolution = new Vector3i(160, 90, 128);
|
||||
[SerializeField]
|
||||
private Vector3Int froxelResolution = new Vector3Int(160, 90, 128);
|
||||
Camera m_Camera;
|
||||
|
||||
// Density
|
||||
@ -68,6 +61,18 @@ public class VolumetricFog : MonoBehaviour
|
||||
public float m_AmbientLightIntensity = 0.0f;
|
||||
public Color m_AmbientLightColor = Color.white;
|
||||
|
||||
[Header("Debug")]
|
||||
private Material m_DebugMaterial;
|
||||
[HideInInspector]
|
||||
public Shader m_DebugShader;
|
||||
[HideInInspector]
|
||||
public bool m_Debug = false;
|
||||
[HideInInspector]
|
||||
[Range(0.0f, 1.0f)]
|
||||
public float m_Z = 1.0f;
|
||||
public int m_VolumeAA = 0;
|
||||
public FilterMode m_FilterMode = FilterMode.Bilinear;
|
||||
|
||||
struct Vector3i
|
||||
{
|
||||
public int x, y, z;
|
||||
@ -90,43 +95,6 @@ public class VolumetricFog : MonoBehaviour
|
||||
PointLightParams[] m_PointLightParams;
|
||||
ComputeBuffer m_PointLightParamsCB;
|
||||
|
||||
struct TubeLightParams
|
||||
{
|
||||
public Vector3 start;
|
||||
public float range;
|
||||
public Vector3 end;
|
||||
public float radius;
|
||||
public Vector3 color;
|
||||
float padding;
|
||||
}
|
||||
|
||||
TubeLightParams[] m_TubeLightParams;
|
||||
ComputeBuffer m_TubeLightParamsCB;
|
||||
|
||||
struct TubeLightShadowPlaneParams
|
||||
{
|
||||
public Vector4 plane0;
|
||||
public Vector4 plane1;
|
||||
public float feather0;
|
||||
public float feather1;
|
||||
float padding0;
|
||||
float padding1;
|
||||
}
|
||||
|
||||
TubeLightShadowPlaneParams[] m_TubeLightShadowPlaneParams;
|
||||
ComputeBuffer m_TubeLightShadowPlaneParamsCB;
|
||||
|
||||
struct AreaLightParams
|
||||
{
|
||||
public Matrix4x4 mat;
|
||||
public Vector4 pos;
|
||||
public Vector3 color;
|
||||
public float bounded;
|
||||
}
|
||||
|
||||
AreaLightParams[] m_AreaLightParams;
|
||||
ComputeBuffer m_AreaLightParamsCB;
|
||||
|
||||
struct FogEllipsoidParams
|
||||
{
|
||||
public Vector3 pos;
|
||||
@ -148,14 +116,14 @@ public class VolumetricFog : MonoBehaviour
|
||||
|
||||
ComputeBuffer m_DummyCB;
|
||||
|
||||
Camera cam{ get { if (m_Camera == null) m_Camera = GetComponent<Camera>(); return m_Camera; }}
|
||||
Camera cam { get { if (m_Camera == null) m_Camera = GetComponent<Camera>(); return m_Camera; } }
|
||||
|
||||
float nearClip { get { return Mathf.Max(0, m_NearClip); } }
|
||||
float farClip { get { return Mathf.Min(cam.farClipPlane, m_FarClipMax); } }
|
||||
|
||||
void ReleaseComputeBuffer(ref ComputeBuffer buffer)
|
||||
{
|
||||
if(buffer != null)
|
||||
if (buffer != null)
|
||||
buffer.Release();
|
||||
buffer = null;
|
||||
}
|
||||
@ -175,9 +143,6 @@ public class VolumetricFog : MonoBehaviour
|
||||
DestroyImmediate(m_VolumeInject);
|
||||
DestroyImmediate(m_VolumeScatter);
|
||||
ReleaseComputeBuffer(ref m_PointLightParamsCB);
|
||||
ReleaseComputeBuffer(ref m_TubeLightParamsCB);
|
||||
ReleaseComputeBuffer(ref m_TubeLightShadowPlaneParamsCB);
|
||||
ReleaseComputeBuffer(ref m_AreaLightParamsCB);
|
||||
ReleaseComputeBuffer(ref m_FogEllipsoidParamsCB);
|
||||
ReleaseComputeBuffer(ref m_DummyCB);
|
||||
m_VolumeInject = null;
|
||||
@ -227,121 +192,12 @@ public class VolumetricFog : MonoBehaviour
|
||||
m_InjectLightingAndDensity.SetBuffer(kernel, "_PointLights", m_PointLightParamsCB);
|
||||
}
|
||||
|
||||
TubeLightShadowPlane.Params[] sppArr;
|
||||
|
||||
void SetUpTubeLightBuffers(int kernel)
|
||||
{
|
||||
int count = m_TubeLightParamsCB == null ? 0 : m_TubeLightParamsCB.count;
|
||||
m_InjectLightingAndDensity.SetFloat("_TubeLightsCount", count);
|
||||
if (count == 0)
|
||||
{
|
||||
// Can't not set the buffer
|
||||
m_InjectLightingAndDensity.SetBuffer(kernel, "_TubeLights", m_DummyCB);
|
||||
m_InjectLightingAndDensity.SetBuffer(kernel, "_TubeLightShadowPlanes", m_DummyCB);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_TubeLightParams == null || m_TubeLightParams.Length != count)
|
||||
m_TubeLightParams = new TubeLightParams[count];
|
||||
|
||||
if (m_TubeLightShadowPlaneParams == null || m_TubeLightShadowPlaneParams.Length != count)
|
||||
m_TubeLightShadowPlaneParams = new TubeLightShadowPlaneParams[count];
|
||||
|
||||
HashSet<FogLight> fogLights = LightManagerFogLights.Get();
|
||||
|
||||
int j = 0;
|
||||
for (var x = fogLights.GetEnumerator(); x.MoveNext();)
|
||||
{
|
||||
var fl = x.Current;
|
||||
if (fl == null || fl.type != FogLight.Type.Tube || !fl.isOn)
|
||||
continue;
|
||||
|
||||
TubeLight light = fl.tubeLight;
|
||||
Transform t = light.transform;
|
||||
Vector3 pos = t.position;
|
||||
Vector3 halfLength = 0.5f * t.up * light.m_Length;
|
||||
|
||||
// Tube lights
|
||||
m_TubeLightParams[j].start = pos + halfLength;
|
||||
m_TubeLightParams[j].end = pos - halfLength;
|
||||
float range = light.m_Range * fl.m_RangeMult;
|
||||
m_TubeLightParams[j].range = 1.0f / (range * range);
|
||||
m_TubeLightParams[j].color = new Vector3(light.m_Color.r, light.m_Color.g, light.m_Color.b) * light.m_Intensity * fl.m_IntensityMult;
|
||||
m_TubeLightParams[j].radius = light.m_Radius;
|
||||
|
||||
// Tube light shadow planes
|
||||
var p = light.GetShadowPlaneParams(ref sppArr);
|
||||
m_TubeLightShadowPlaneParams[j].plane0 = p[0].plane;
|
||||
m_TubeLightShadowPlaneParams[j].plane1 = p[1].plane;
|
||||
m_TubeLightShadowPlaneParams[j].feather0 = p[0].feather;
|
||||
m_TubeLightShadowPlaneParams[j].feather1 = p[1].feather;
|
||||
|
||||
j++;
|
||||
}
|
||||
|
||||
m_TubeLightParamsCB.SetData(m_TubeLightParams);
|
||||
m_InjectLightingAndDensity.SetBuffer(kernel, "_TubeLights", m_TubeLightParamsCB);
|
||||
m_TubeLightShadowPlaneParamsCB.SetData(m_TubeLightShadowPlaneParams);
|
||||
m_InjectLightingAndDensity.SetBuffer(kernel, "_TubeLightShadowPlanes", m_TubeLightShadowPlaneParamsCB);
|
||||
}
|
||||
|
||||
void SetUpAreaLightBuffers(int kernel)
|
||||
{
|
||||
int count = m_AreaLightParamsCB == null ? 0 : m_AreaLightParamsCB.count;
|
||||
m_InjectLightingAndDensity.SetFloat("_AreaLightsCount", count);
|
||||
if (count == 0)
|
||||
{
|
||||
// Can't not set the buffers/textures
|
||||
m_InjectLightingAndDensity.SetBuffer(kernel, "_AreaLights", m_DummyCB);
|
||||
m_InjectLightingAndDensity.SetTexture(kernel, "_AreaLightShadowmap", Texture2D.whiteTexture);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_AreaLightParams == null || m_AreaLightParams.Length != count)
|
||||
m_AreaLightParams = new AreaLightParams[count];
|
||||
|
||||
HashSet<FogLight> fogLights = LightManagerFogLights.Get();
|
||||
|
||||
int shadowedAreaLightIndex = -1;
|
||||
int j = 0;
|
||||
for (var x = fogLights.GetEnumerator(); x.MoveNext();)
|
||||
{
|
||||
var fl = x.Current;
|
||||
if (fl == null || fl.type != FogLight.Type.Area || !fl.isOn)
|
||||
continue;
|
||||
|
||||
AreaLight light = fl.areaLight;
|
||||
|
||||
m_AreaLightParams[j].mat = light.GetProjectionMatrix(true);
|
||||
m_AreaLightParams[j].pos = light.GetPosition();
|
||||
m_AreaLightParams[j].color = new Vector3(light.m_Color.r, light.m_Color.g, light.m_Color.b) * light.m_Intensity * fl.m_IntensityMult;
|
||||
m_AreaLightParams[j].bounded = fl.m_Bounded ? 1 : 0;
|
||||
|
||||
if (fl.m_Shadows)
|
||||
{
|
||||
RenderTexture shadowmap = light.GetBlurredShadowmap();
|
||||
if (shadowmap != null)
|
||||
{
|
||||
m_InjectLightingAndDensity.SetTexture(kernel, "_AreaLightShadowmap", shadowmap);
|
||||
m_InjectLightingAndDensity.SetFloat("_ESMExponentAreaLight", fl.m_ESMExponent);
|
||||
shadowedAreaLightIndex = j;
|
||||
}
|
||||
}
|
||||
|
||||
j++;
|
||||
}
|
||||
m_AreaLightParamsCB.SetData(m_AreaLightParams);
|
||||
m_InjectLightingAndDensity.SetBuffer(kernel, "_AreaLights", m_AreaLightParamsCB);
|
||||
m_InjectLightingAndDensity.SetFloat("_ShadowedAreaLightIndex", shadowedAreaLightIndex < 0 ? fogLights.Count : shadowedAreaLightIndex);
|
||||
if (shadowedAreaLightIndex < 0)
|
||||
m_InjectLightingAndDensity.SetTexture(kernel, "_AreaLightShadowmap", Texture2D.whiteTexture);
|
||||
}
|
||||
|
||||
void SetUpFogEllipsoidBuffers(int kernel)
|
||||
{
|
||||
int count = 0;
|
||||
HashSet<FogEllipsoid> fogEllipsoids = LightManagerFogEllipsoids.Get();
|
||||
for (var x = fogEllipsoids.GetEnumerator(); x.MoveNext();) {
|
||||
for (var x = fogEllipsoids.GetEnumerator(); x.MoveNext();)
|
||||
{
|
||||
var fe = x.Current;
|
||||
if (fe != null && fe.enabled && fe.gameObject.activeSelf)
|
||||
count++;
|
||||
@ -370,7 +226,7 @@ public class VolumetricFog : MonoBehaviour
|
||||
m_FogEllipsoidParams[j].pos = t.position;
|
||||
m_FogEllipsoidParams[j].radius = fe.m_Radius * fe.m_Radius;
|
||||
m_FogEllipsoidParams[j].axis = -t.up;
|
||||
m_FogEllipsoidParams[j].stretch = 1.0f/fe.m_Stretch - 1.0f;
|
||||
m_FogEllipsoidParams[j].stretch = 1.0f / fe.m_Stretch - 1.0f;
|
||||
m_FogEllipsoidParams[j].density = fe.m_Density;
|
||||
m_FogEllipsoidParams[j].noiseAmount = fe.m_NoiseAmount;
|
||||
m_FogEllipsoidParams[j].noiseSpeed = fe.m_NoiseSpeed;
|
||||
@ -446,19 +302,29 @@ public class VolumetricFog : MonoBehaviour
|
||||
m_dirLightDir[1] = dir.y;
|
||||
m_dirLightDir[2] = dir.z;
|
||||
m_InjectLightingAndDensity.SetFloats("_DirLightDir", m_dirLightDir);
|
||||
|
||||
|
||||
}
|
||||
|
||||
float[] m_fogParams;
|
||||
float[] m_windDir;
|
||||
float[] m_ambientLight;
|
||||
float[] m_froxelResolution;
|
||||
|
||||
void SetUpForScatter(int kernel)
|
||||
{
|
||||
SanitizeInput();
|
||||
InitResources();
|
||||
SetFrustumRays();
|
||||
|
||||
|
||||
if (m_froxelResolution == null)
|
||||
{
|
||||
m_froxelResolution = new float[3];
|
||||
m_froxelResolution[0] = froxelResolution.x;
|
||||
m_froxelResolution[1] = froxelResolution.y;
|
||||
m_froxelResolution[2] = froxelResolution.z;
|
||||
}
|
||||
m_Scatter.SetFloats("_FroxelResolution", m_froxelResolution);
|
||||
m_InjectLightingAndDensity.SetFloats("_FroxelResolution", m_froxelResolution);
|
||||
// Compensate for more light and density being injected in per world space meter when near and far are closer.
|
||||
// TODO: Not quite correct yet.
|
||||
float depthCompensation = (farClip - nearClip) * 0.01f;
|
||||
@ -489,7 +355,7 @@ public class VolumetricFog : MonoBehaviour
|
||||
m_windDir[2] = windDir.z;
|
||||
m_InjectLightingAndDensity.SetFloats("_WindDir", m_windDir);
|
||||
m_InjectLightingAndDensity.SetFloat("_Time", Time.time);
|
||||
m_InjectLightingAndDensity.SetFloat("_NearOverFarClip", nearClip/farClip);
|
||||
m_InjectLightingAndDensity.SetFloat("_NearOverFarClip", nearClip / farClip);
|
||||
Color ambient = m_AmbientLightColor * m_AmbientLightIntensity * 0.1f;
|
||||
m_ambientLight[0] = ambient.r;
|
||||
m_ambientLight[1] = ambient.g;
|
||||
@ -497,8 +363,6 @@ public class VolumetricFog : MonoBehaviour
|
||||
m_InjectLightingAndDensity.SetFloats("_AmbientLight", m_ambientLight);
|
||||
|
||||
SetUpPointLightBuffers(kernel);
|
||||
SetUpTubeLightBuffers(kernel);
|
||||
SetUpAreaLightBuffers(kernel);
|
||||
SetUpFogEllipsoidBuffers(kernel);
|
||||
SetUpDirectionalLight(kernel);
|
||||
}
|
||||
@ -506,16 +370,15 @@ public class VolumetricFog : MonoBehaviour
|
||||
void Scatter()
|
||||
{
|
||||
// Inject lighting and density
|
||||
int kernel = 0;
|
||||
|
||||
int kernel = m_InjectLightingAndDensity.FindKernel("CSMain");
|
||||
SetUpForScatter(kernel);
|
||||
|
||||
m_InjectLightingAndDensity.Dispatch(kernel, m_VolumeResolution.x/m_InjectNumThreads.x, m_VolumeResolution.y/m_InjectNumThreads.y, m_VolumeResolution.z/m_InjectNumThreads.z);
|
||||
m_InjectLightingAndDensity.Dispatch(kernel, froxelResolution.x / m_InjectNumThreads.x, froxelResolution.y / m_InjectNumThreads.y, froxelResolution.z / m_InjectNumThreads.z);
|
||||
|
||||
// Solve scattering
|
||||
m_Scatter.SetTexture(0, "_VolumeInject", m_VolumeInject);
|
||||
m_Scatter.SetTexture(0, "_VolumeScatter", m_VolumeScatter);
|
||||
m_Scatter.Dispatch(0, m_VolumeResolution.x/m_ScatterNumThreads.x, m_VolumeResolution.y/m_ScatterNumThreads.y, 1);
|
||||
kernel = m_Scatter.FindKernel("CSMain");
|
||||
m_Scatter.SetTexture(kernel, "_VolumeInject", m_VolumeInject);
|
||||
m_Scatter.SetTexture(kernel, "_VolumeScatter", m_VolumeScatter);
|
||||
m_Scatter.Dispatch(kernel, froxelResolution.x / m_ScatterNumThreads.x, froxelResolution.y / m_ScatterNumThreads.y, 1);
|
||||
}
|
||||
|
||||
void DebugDisplay(RenderTexture src, RenderTexture dest)
|
||||
@ -535,7 +398,7 @@ public class VolumetricFog : MonoBehaviour
|
||||
{
|
||||
Shader.SetGlobalTexture("_VolumeScatter", m_VolumeScatter);
|
||||
Shader.SetGlobalVector("_Screen_TexelSize", new Vector4(1.0f / width, 1.0f / height, width, height));
|
||||
Shader.SetGlobalVector("_VolumeScatter_TexelSize", new Vector4(1.0f / m_VolumeResolution.x, 1.0f / m_VolumeResolution.y, 1.0f / m_VolumeResolution.z, 0));
|
||||
Shader.SetGlobalVector("_VolumeScatter_TexelSize", new Vector4(1.0f / froxelResolution.x, 1.0f / froxelResolution.y, 1.0f / froxelResolution.z, 0));
|
||||
Shader.SetGlobalFloat("_CameraFarOverMaxFar", cam.farClipPlane / farClip);
|
||||
Shader.SetGlobalFloat("_NearOverFarClip", nearClip / farClip);
|
||||
}
|
||||
@ -551,7 +414,7 @@ public class VolumetricFog : MonoBehaviour
|
||||
return;
|
||||
}
|
||||
|
||||
if(m_Debug)
|
||||
if (m_Debug)
|
||||
{
|
||||
DebugDisplay(src, dest);
|
||||
return;
|
||||
@ -573,7 +436,7 @@ public class VolumetricFog : MonoBehaviour
|
||||
|
||||
void OnPostRender()
|
||||
{
|
||||
VolumetricFogInForward(false);
|
||||
VolumetricFogInForward(false);
|
||||
}
|
||||
|
||||
void VolumetricFogInForward(bool enable)
|
||||
@ -590,8 +453,8 @@ public class VolumetricFog : MonoBehaviour
|
||||
return t.InverseTransformPoint(c.ViewportToWorldPoint(p));
|
||||
}
|
||||
|
||||
static readonly Vector2[] frustumUVs =
|
||||
new Vector2[] {new Vector2(0, 0), new Vector2(1, 0), new Vector2(1, 1), new Vector2(0, 1)};
|
||||
static readonly Vector2[] frustumUVs =
|
||||
new Vector2[] { new Vector2(0, 0), new Vector2(1, 0), new Vector2(1, 1), new Vector2(0, 1) };
|
||||
static float[] frustumRays = new float[16];
|
||||
|
||||
void SetFrustumRays()
|
||||
@ -603,10 +466,10 @@ public class VolumetricFog : MonoBehaviour
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
Vector3 ray = cam.ViewportToWorldPoint(new Vector3(uvs[i].x, uvs[i].y, far)) - cameraPos;
|
||||
frustumRays[i*4+0] = ray.x;
|
||||
frustumRays[i*4+1] = ray.y;
|
||||
frustumRays[i*4+2] = ray.z;
|
||||
frustumRays[i*4+3] = 0;
|
||||
frustumRays[i * 4 + 0] = ray.x;
|
||||
frustumRays[i * 4 + 1] = ray.y;
|
||||
frustumRays[i * 4 + 2] = ray.z;
|
||||
frustumRays[i * 4 + 3] = 0;
|
||||
}
|
||||
|
||||
m_InjectLightingAndDensity.SetVector("_CameraPos", cameraPos);
|
||||
@ -615,13 +478,15 @@ public class VolumetricFog : MonoBehaviour
|
||||
|
||||
void InitVolume(ref RenderTexture volume)
|
||||
{
|
||||
if(volume)
|
||||
if (volume)
|
||||
return;
|
||||
|
||||
volume = new RenderTexture (m_VolumeResolution.x, m_VolumeResolution.y, 0, RenderTextureFormat.ARGBHalf);
|
||||
volume.volumeDepth = m_VolumeResolution.z;
|
||||
volume = new RenderTexture(froxelResolution.x, froxelResolution.y, 0, RenderTextureFormat.ARGBHalf);
|
||||
volume.volumeDepth = froxelResolution.z;
|
||||
volume.dimension = UnityEngine.Rendering.TextureDimension.Tex3D;
|
||||
volume.enableRandomWrite = true;
|
||||
volume.antiAliasing = m_VolumeAA;
|
||||
volume.filterMode = m_FilterMode;
|
||||
volume.Create();
|
||||
}
|
||||
|
||||
@ -630,7 +495,7 @@ public class VolumetricFog : MonoBehaviour
|
||||
if (buffer != null && buffer.count == count)
|
||||
return;
|
||||
|
||||
if(buffer != null)
|
||||
if (buffer != null)
|
||||
{
|
||||
buffer.Release();
|
||||
buffer = null;
|
||||
@ -642,13 +507,12 @@ public class VolumetricFog : MonoBehaviour
|
||||
buffer = new ComputeBuffer(count, stride);
|
||||
}
|
||||
|
||||
void InitResources ()
|
||||
void InitResources()
|
||||
{
|
||||
// Volume
|
||||
InitVolume(ref m_VolumeInject);
|
||||
InitVolume(ref m_VolumeScatter);
|
||||
|
||||
|
||||
// Compute buffers
|
||||
int pointLightCount = 0, tubeLightCount = 0, areaLightCount = 0;
|
||||
HashSet<FogLight> fogLights = LightManagerFogLights.Get();
|
||||
@ -660,21 +524,20 @@ public class VolumetricFog : MonoBehaviour
|
||||
|
||||
bool isOn = fl.isOn;
|
||||
|
||||
switch(fl.type)
|
||||
switch (fl.type)
|
||||
{
|
||||
case FogLight.Type.Point: if (isOn) pointLightCount++; break;
|
||||
case FogLight.Type.Tube: if (isOn) tubeLightCount++; break;
|
||||
case FogLight.Type.Area: if (isOn) areaLightCount++; break;
|
||||
case FogLight.Type.Point: if (isOn) pointLightCount++; break;
|
||||
case FogLight.Type.Tube: if (isOn) tubeLightCount++; break;
|
||||
case FogLight.Type.Area: if (isOn) areaLightCount++; break;
|
||||
}
|
||||
}
|
||||
|
||||
CreateBuffer(ref m_PointLightParamsCB, pointLightCount, Marshal.SizeOf(typeof(PointLightParams)));
|
||||
CreateBuffer(ref m_TubeLightParamsCB, tubeLightCount, Marshal.SizeOf(typeof(TubeLightParams)));
|
||||
CreateBuffer(ref m_TubeLightShadowPlaneParamsCB, tubeLightCount, Marshal.SizeOf(typeof(TubeLightShadowPlaneParams)));
|
||||
CreateBuffer(ref m_AreaLightParamsCB, areaLightCount, Marshal.SizeOf(typeof(AreaLightParams)));
|
||||
HashSet<FogEllipsoid> fogEllipsoids = LightManagerFogEllipsoids.Get();
|
||||
CreateBuffer(ref m_FogEllipsoidParamsCB, fogEllipsoids == null ? 0 : fogEllipsoids.Count, Marshal.SizeOf(typeof(FogEllipsoidParams)));
|
||||
CreateBuffer(ref m_DummyCB, 1, 4);
|
||||
|
||||
//
|
||||
}
|
||||
|
||||
void ReleaseTemporary(ref RenderTexture rt)
|
||||
@ -715,7 +578,7 @@ public class VolumetricFog : MonoBehaviour
|
||||
|
||||
public static string GetUnsupportedErrorMessage()
|
||||
{
|
||||
return "Volumetric Fog requires compute shaders and this platform doesn't support them. Disabling. \nDetected device type: " +
|
||||
return "Volumetric Fog requires compute shaders and this platform doesn't support them. Disabling. \nDetected device type: " +
|
||||
SystemInfo.graphicsDeviceType + ", version: " + SystemInfo.graphicsDeviceVersion;
|
||||
}
|
||||
}
|
||||
|
@ -98,7 +98,7 @@ Shader "Hidden/BlurShadowmap" {
|
||||
z.b = tex2D (_DirShadowmap, i.uv22).r;
|
||||
z.a = tex2D (_DirShadowmap, i.uv23).r;
|
||||
|
||||
return z.r;
|
||||
// return z.r;
|
||||
|
||||
// Transform to linear z, 0 at near, 1 at far
|
||||
// z = z * 2 - 1;
|
||||
|
@ -6,7 +6,7 @@
|
||||
{
|
||||
CGPROGRAM
|
||||
#pragma target 5.0
|
||||
#pragma only_renderers d3d11
|
||||
//#pragma only_renderers d3d11
|
||||
#pragma vertex vert
|
||||
#pragma fragment frag
|
||||
#include "UnityCG.cginc"
|
||||
|
@ -44,8 +44,8 @@ CGPROGRAM
|
||||
{
|
||||
half depth = Linear01Depth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv));
|
||||
|
||||
// return i.uv.xyyy;
|
||||
return tex2D(_BoxLightShadowmap, i.uv);
|
||||
//return i.uv.xyyy;
|
||||
//return tex2D(_BoxLightShadowmap, i.uv);
|
||||
//return log(tex2D(_ShadowmapBlurred, i.uv))/80.0;
|
||||
return tex3D(_VolumeInject, half3(i.uv.x, i.uv.y, _Z)).a;// * tex2D(_MainTex, float2(i.uv.x, i.uv.y));
|
||||
}
|
||||
|
@ -1,15 +1,6 @@
|
||||
#pragma kernel CSMain TUBE_LIGHTS TUBE_LIGHT_SHADOW_PLANES FOG_ELLIPSOIDS ANISOTROPY AREA_LIGHTS POINT_LIGHTS
|
||||
|
||||
// Directional light support not quite ready yet
|
||||
// #pragma kernel CSMain TUBE_LIGHTS TUBE_LIGHT_SHADOW_PLANES FOG_ELLIPSOIDS ANISOTROPY AREA_LIGHTS POINT_LIGHTS DIR_LIGHT
|
||||
|
||||
#define TUBE_LIGHT_ATTENUATION_LEGACY 1
|
||||
#include "..\..\TubeLight\Shaders\TubeLightAttenuation.cginc"
|
||||
|
||||
#ifdef TUBE_LIGHT_SHADOW_PLANES
|
||||
#include "..\..\TubeLight\Shaders\TubeLightShadowPlanes.cginc"
|
||||
#endif
|
||||
#pragma kernel CSMain /*FOG_ELLIPSOIDS*/ ANISOTROPY POINT_LIGHTS DIR_LIGHT DIR_LIGHT_SHADOWS /*FOG_BOMB*/ /*ATTENUATION_LEGACY*/
|
||||
|
||||
float3 _FroxelResolution;
|
||||
RWTexture3D<half4> _VolumeInject;
|
||||
float4 _FrustumRays[4];
|
||||
float4 _CameraPos;
|
||||
@ -30,6 +21,7 @@ Texture2D _LightTextureB0;
|
||||
SamplerState sampler_LightTextureB0;
|
||||
float _NearOverFarClip;
|
||||
float3 _AmbientLight;
|
||||
|
||||
#ifdef FOG_BOMB
|
||||
float _FogBombRadius;
|
||||
float3 _FogBombPos;
|
||||
@ -65,43 +57,6 @@ StructuredBuffer<PointLight> _PointLights;
|
||||
float _PointLightsCount;
|
||||
#endif
|
||||
|
||||
#ifdef TUBE_LIGHTS
|
||||
struct TubeLight
|
||||
{
|
||||
float3 start;
|
||||
float range;
|
||||
float3 end;
|
||||
float radius;
|
||||
float3 color;
|
||||
float padding;
|
||||
};
|
||||
StructuredBuffer<TubeLight> _TubeLights;
|
||||
float _TubeLightsCount;
|
||||
|
||||
#ifdef TUBE_LIGHT_SHADOW_PLANES
|
||||
// Same count as _TubeLightsCount
|
||||
StructuredBuffer<TubeLightShadowPlane> _TubeLightShadowPlanes;
|
||||
#endif
|
||||
|
||||
#endif // TUBE_LIGHTS
|
||||
|
||||
#ifdef AREA_LIGHTS
|
||||
struct AreaLight
|
||||
{
|
||||
float4x4 mat;
|
||||
float4 pos; // only needed for anisotropy. w: 0 ortho, 1 proj
|
||||
float3 color;
|
||||
float bounded;
|
||||
};
|
||||
StructuredBuffer<AreaLight> _AreaLights;
|
||||
float _AreaLightsCount;
|
||||
Texture2D _AreaLightShadowmap;
|
||||
SamplerState sampler_AreaLightShadowmap;
|
||||
float _ShadowedAreaLightIndex;
|
||||
float4 _AreaLightShadowmapZParams;
|
||||
float _ESMExponentAreaLight;
|
||||
#endif
|
||||
|
||||
#ifdef FOG_ELLIPSOIDS
|
||||
struct FogEllipsoid
|
||||
{
|
||||
@ -142,7 +97,7 @@ float noise(float3 x)
|
||||
float3 f = frac(x);
|
||||
f = f * f * (3.0 - 2.0 * f);
|
||||
float2 uv = (p.xy + float2(37.0,17.0) * p.z) + f.xy;
|
||||
float2 rg = _Noise.SampleLevel(sampler_Noise, (uv + 0.5) / 256.0, 0).yx;
|
||||
float2 rg = _Noise.SampleLevel(sampler_Noise, (uv + 0.5) / 128.0, 0).yx;
|
||||
return -1.0 + 2.0 * lerp(rg.x, rg.y, f.z);
|
||||
}
|
||||
|
||||
@ -167,6 +122,58 @@ float ScrollNoise(float3 pos, float speed, float scale, float3 dir, float amount
|
||||
return lerp(1.0, f, amount);
|
||||
}
|
||||
|
||||
#if ATTENUATION_LEGACY
|
||||
|
||||
float Attenuation(float distNorm)
|
||||
{
|
||||
return 1.0 / (1.0 + 25.0 * distNorm);
|
||||
}
|
||||
|
||||
float AttenuationToZero(float distNorm)
|
||||
{
|
||||
float att = Attenuation(distNorm);
|
||||
|
||||
// Replicating unity light attenuation - pulled to 0 at range
|
||||
// if (distNorm > 0.8 * 0.8)
|
||||
// att *= 1 - (distNorm - 0.8 * 0.8) / (1 - 0.8 * 0.8);
|
||||
// Same, simplified
|
||||
float oneDistNorm = 1.0 - distNorm;
|
||||
att *= lerp(1.0, oneDistNorm * 2.78, step(0.64, distNorm));
|
||||
|
||||
att *= step(0.0, oneDistNorm);
|
||||
|
||||
return att;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
float Attenuation(float distSqr)
|
||||
{
|
||||
float d = sqrt(distSqr);
|
||||
float kDefaultPointLightRadius = 0.25;
|
||||
return 1.0 / pow(1.0 + d / kDefaultPointLightRadius, 2);
|
||||
}
|
||||
|
||||
float AttenuationToZero(float distSqr)
|
||||
{
|
||||
// attenuation = 1 / (1 + distance_to_light / light_radius)^2
|
||||
// = 1 / (1 + 2*(d/r) + (d/r)^2)
|
||||
// For more details see: https://imdoingitwrong.wordpress.com/2011/01/31/light-attenuation/
|
||||
float d = sqrt(distSqr);
|
||||
float kDefaultPointLightRadius = 0.25;
|
||||
float atten = 1.0 / pow(1.0 + d / kDefaultPointLightRadius, 2);
|
||||
float kCutoff = 1.0 / pow(1.0 + 1.0 / kDefaultPointLightRadius, 2); // cutoff equal to attenuation at distance 1.0
|
||||
|
||||
// Force attenuation to fall towards zero at distance 1.0
|
||||
atten = (atten - kCutoff) / (1.f - kCutoff);
|
||||
if (d >= 1.f)
|
||||
atten = 0.f;
|
||||
|
||||
return atten;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef FOG_ELLIPSOIDS
|
||||
void FogEllipsoids(float3 pos, inout float density)
|
||||
{
|
||||
@ -245,9 +252,8 @@ float anisotropy(float costheta)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if AREA_LIGHTS || DIR_LIGHT_SHADOWS
|
||||
#define VSM 1
|
||||
#if VSM
|
||||
#if DIR_LIGHT
|
||||
#if DIR_LIGHT_SHADOWS
|
||||
float ChebyshevUpperBound(float2 moments, float mean)
|
||||
{
|
||||
// Compute variance
|
||||
@ -260,13 +266,9 @@ float ChebyshevUpperBound(float2 moments, float mean)
|
||||
float pMax = variance / (variance + (d * d));
|
||||
|
||||
// One-tailed Chebyshev
|
||||
return (mean <= moments.x ? 1.0f : pMax);
|
||||
return (mean >= moments.x ? 1.0f : pMax);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if DIR_LIGHT
|
||||
#if DIR_LIGHT_SHADOWS
|
||||
float4 getCascadeWeights_splitSpheres(float3 pos)
|
||||
{
|
||||
float3 fromCenter0 = pos - _ShadowParams[0].shadowSplitSpheres[0].xyz;
|
||||
@ -286,27 +288,22 @@ float4 getShadowCoord(float3 pos, float4 cascadeWeights)
|
||||
|
||||
float3 DirectionalLight(float3 pos)
|
||||
{
|
||||
if (!any(_DirLightColor))
|
||||
return 0;
|
||||
|
||||
float att = 1;
|
||||
|
||||
#if DIR_LIGHT_SHADOWS
|
||||
if (_DirLightShadows > 0.0)
|
||||
{
|
||||
float4 cascadeWeights = getCascadeWeights_splitSpheres(pos);
|
||||
//bool inside = dot(cascadeWeights, float4(1,1,1,1)) < 4;
|
||||
float3 samplePos = getShadowCoord(pos, cascadeWeights).xyz;
|
||||
//occlusion += inside ? UNITY_SAMPLE_SHADOW(u_CascadedShadowMap, samplePos) : 1.f;
|
||||
#if 1
|
||||
att *= _DirectionalShadowmap.SampleLevel(sampler_DirectionalShadowmap, samplePos.xy, 0).r > samplePos.z;
|
||||
#else
|
||||
float2 shadowmap = _DirectionalShadowmap.SampleLevel(sampler_DirectionalShadowmap, samplePos, 0).xy;
|
||||
att *= ChebyshevUpperBound(shadowmap.xy, samplePos.z);
|
||||
|
||||
// float depth = exp(-40.0 * samplePos.z);
|
||||
// att = saturate(shadowmap.r * depth);
|
||||
#endif
|
||||
float4 samplePos = getShadowCoord(pos, cascadeWeights).xyzw;
|
||||
//---
|
||||
//att *= _DirectionalShadowmap.SampleLevel(sampler_DirectionalShadowmap, samplePos.xy, 0).r < samplePos.z;
|
||||
//---
|
||||
float2 shadowmap = _DirectionalShadowmap.SampleLevel(sampler_DirectionalShadowmap, samplePos.xy, 0).xy;
|
||||
att *= ChebyshevUpperBound(shadowmap.xy, samplePos.z / samplePos.w);
|
||||
//---
|
||||
//float depth = exp(-40.0 * samplePos.z);
|
||||
//att = saturate(shadowmap.r * depth);
|
||||
//---
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -342,195 +339,31 @@ float3 PointLights(float3 pos)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef TUBE_LIGHTS
|
||||
float almostIdentity(float x, float m, float n)
|
||||
{
|
||||
if (x > m)
|
||||
return x;
|
||||
|
||||
float a = 2.0f*n - m;
|
||||
float b = 2.0f*m - 3.0f*n;
|
||||
float t = x/m;
|
||||
|
||||
return (a*t + b)*t*t + n;
|
||||
}
|
||||
|
||||
float3 TubeLights(float3 pos)
|
||||
{
|
||||
float3 color = 0;
|
||||
for (int i = 0; i < _TubeLightsCount; i++)
|
||||
{
|
||||
float3 L0 = _TubeLights[i].start - pos;
|
||||
float3 L1 = _TubeLights[i].end - pos;
|
||||
float distNorm = 0.5f * (length(L0) * length(L1) + dot(L0, L1)) * _TubeLights[i].range;
|
||||
float att = Attenuation(distNorm);
|
||||
|
||||
#if ANISOTROPY
|
||||
// Just like when calculating specular for area lights:
|
||||
// assume forward scattering lobe -> the point on the light that's the closest to
|
||||
// the view direction is representative
|
||||
float3 posToCamera = normalize(pos - _CameraPos.xyz);
|
||||
float3 r = -posToCamera;
|
||||
float3 Ld = L1 - L0;
|
||||
float L0oL0 = dot(L0, L0);
|
||||
float RoL0 = dot(r, L0);
|
||||
float RoLd = dot(r, Ld);
|
||||
float L0oLd = dot(L0, Ld);
|
||||
float LdoLd = dot(Ld, Ld);
|
||||
float distLd = sqrt(LdoLd);
|
||||
|
||||
#if 1
|
||||
// Smallest angle to ray
|
||||
float t = (L0oLd * RoL0 - L0oL0 * RoLd) / (L0oLd * RoLd - LdoLd * RoL0);
|
||||
t = saturate(t);
|
||||
|
||||
// As r becomes parallel to Ld and then points away, t flips from 0 to 1 (or vv) and a discontinuity shows up.
|
||||
// Counteract by detecting that relative angle/position and flip t. The discontinuity in t moves to the back side.
|
||||
float3 L0xLd = cross(L0, Ld);
|
||||
float3 LdxR = cross(Ld, r);
|
||||
float RAtLd = dot(L0xLd, LdxR);
|
||||
|
||||
// RAtLd is negative if R points away from Ld.
|
||||
// TODO: check if lerp below is indeed cheaper.
|
||||
// if (RAtLd < 0)
|
||||
// t = 1 - t;
|
||||
t = lerp(1 - t, t, step(0, RAtLd));
|
||||
|
||||
#else
|
||||
// Original by Karis
|
||||
// Closest distance to ray
|
||||
float t = (RoL0 * RoLd - L0oLd) / (distLd * distLd - RoLd * RoLd);
|
||||
t = saturate(t);
|
||||
|
||||
#endif
|
||||
float3 closestPoint = L0 + Ld * t;
|
||||
float3 centerToRay = dot(closestPoint, r) * r - closestPoint;
|
||||
// closestPoint = closestPoint + centerToRay * saturate(_TubeLights[i].radius / length(centerToRay));
|
||||
float centerToRayNorm = length(centerToRay) / _TubeLights[i].radius;
|
||||
// The last param should in theory be 1
|
||||
centerToRayNorm = almostIdentity(centerToRayNorm, 2, 1.2);
|
||||
closestPoint = closestPoint + centerToRay / centerToRayNorm;
|
||||
|
||||
// Attenuation from the closest point looks really good if there's anisotropy, but breaks
|
||||
// for (close to) isotropic medium. Probably because there's no forward lobe anymore, so
|
||||
// the closest point to the view direction is not representative? But artifacts look like
|
||||
// smth else is going on too.
|
||||
// att = Attenuation(dot(closestPoint, closestPoint) * _TubeLights[i].range);
|
||||
|
||||
float costheta = dot(posToCamera, normalize(closestPoint));
|
||||
att *= anisotropy(costheta);
|
||||
#endif
|
||||
|
||||
#ifdef TUBE_LIGHT_SHADOW_PLANES
|
||||
att *= ShadowPlanes(pos, _TubeLightShadowPlanes[i]);
|
||||
#endif
|
||||
|
||||
// GDC hack
|
||||
att = isnan(att) || isinf(att) ? 0 : att;
|
||||
|
||||
color += _TubeLights[i].color * att;
|
||||
}
|
||||
return color;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef AREA_LIGHTS
|
||||
float3 AreaLights(float3 pos)
|
||||
{
|
||||
float3 color = 0;
|
||||
uint count = _AreaLightsCount;
|
||||
uint shadowedAreaLightIndex = _ShadowedAreaLightIndex;
|
||||
for (uint i = 0; i < count; i++)
|
||||
{
|
||||
float4 pClip = mul(_AreaLights[i].mat, float4(pos, 1));
|
||||
float3 p = float3(pClip.x / pClip.w, pClip.y / pClip.w, pClip.z);
|
||||
float z = p.z * 0.5 + 0.5;
|
||||
|
||||
float att = 1;
|
||||
|
||||
if (_AreaLights[i].bounded)
|
||||
{
|
||||
att *= saturate(AttenuationToZero(z * z));
|
||||
|
||||
// Magic tweaks to the shape
|
||||
float corner = 0.4;
|
||||
float outset = 0.8;
|
||||
float smooth = 0.7;
|
||||
|
||||
float d = length(max(abs(p.xy) - 1 + corner*outset, 0.0)) - corner;
|
||||
att *= saturate(1 - smoothstep(-smooth, 0, d));
|
||||
att *= smoothstep(-0.01, 0.01, z);
|
||||
}
|
||||
|
||||
#if ANISOTROPY
|
||||
float3 cameraToPos = normalize(pos - _CameraPos.xyz);
|
||||
float4 lightPos = _AreaLights[i].pos;
|
||||
float3 posToLight = lerp(lightPos.xyz, lightPos.xyz - pos, lightPos.w);
|
||||
float costheta = dot(cameraToPos, normalize(posToLight));
|
||||
att *= anisotropy(costheta);
|
||||
#endif
|
||||
|
||||
if (i == shadowedAreaLightIndex && all(abs(p) < 1))
|
||||
{
|
||||
#if VSM
|
||||
float2 shadowmap = _AreaLightShadowmap.SampleLevel(sampler_AreaLightShadowmap, p.xy * 0.5 + 0.5, 0).xy;
|
||||
att *= ChebyshevUpperBound(shadowmap.xy, z);
|
||||
#else
|
||||
float shadowmap = _AreaLightShadowmap.SampleLevel(sampler_AreaLightShadowmap, p.xy * 0.5 + 0.5, 0);
|
||||
float depth = exp(-_ESMExponentAreaLight * z);
|
||||
att *= saturate(shadowmap * depth);
|
||||
#endif
|
||||
}
|
||||
|
||||
color += _AreaLights[i].color * att;
|
||||
}
|
||||
return color;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
[numthreads(16,2,16)]
|
||||
void CSMain (uint3 id : SV_DispatchThreadID)
|
||||
{
|
||||
float3 color = _AmbientLight;
|
||||
float2 uv = float2(id.x/159.0, id.y/89.0);
|
||||
float z = id.z/127.0;
|
||||
float2 uv = float2(id.x / (_FroxelResolution.x - 1), id.y / (_FroxelResolution.y - 1));
|
||||
float z = id.z / (_FroxelResolution.z - 1);
|
||||
z = _NearOverFarClip + z * (1 - _NearOverFarClip);
|
||||
float3 pos = FrustumRay(uv, _FrustumRays) * z + _CameraPos.xyz;
|
||||
|
||||
|
||||
// Directional light
|
||||
#ifdef DIR_LIGHT
|
||||
color += DirectionalLight(pos);
|
||||
#endif
|
||||
|
||||
|
||||
// Point lights
|
||||
#ifdef POINT_LIGHTS
|
||||
color += PointLights(pos);
|
||||
#endif
|
||||
|
||||
|
||||
// Tube lights
|
||||
#ifdef TUBE_LIGHTS
|
||||
color += TubeLights(pos);
|
||||
#endif
|
||||
|
||||
|
||||
// Area lights
|
||||
#ifdef AREA_LIGHTS
|
||||
color += AreaLights(pos);
|
||||
#endif
|
||||
|
||||
|
||||
// Density
|
||||
float density = Density(pos);
|
||||
|
||||
|
||||
// Output
|
||||
float4 output;
|
||||
output.rgb = _Intensity * density * color;
|
||||
output.a = density;
|
||||
_VolumeInject[id] = output;
|
||||
}
|
||||
|
||||
}
|
@ -2,15 +2,15 @@
|
||||
// https://bartwronski.com/publications/
|
||||
|
||||
#pragma kernel CSMain
|
||||
#define VOLUME_DEPTH 128.0
|
||||
|
||||
float3 _FroxelResolution;
|
||||
Texture3D _VolumeInject;
|
||||
RWTexture3D<float4> _VolumeScatter;
|
||||
|
||||
float4 ScatterStep(float3 accumulatedLight, float accumulatedTransmittance, float3 sliceLight, float sliceDensity)
|
||||
{
|
||||
sliceDensity = max(sliceDensity, 0.000001);
|
||||
float sliceTransmittance = exp(-sliceDensity / VOLUME_DEPTH);
|
||||
float sliceTransmittance = exp(-sliceDensity / _FroxelResolution.z);
|
||||
|
||||
// Seb Hillaire's improved transmission by calculating an integral over slice depth instead of
|
||||
// constant per slice value. Light still constant per slice, but that's acceptable. See slide 28 of
|
||||
@ -30,7 +30,7 @@ void CSMain (uint3 id : SV_DispatchThreadID)
|
||||
// Store transmission in .a, as opposed to density in _VolumeInject
|
||||
float4 accum = float4(0, 0, 0, 1);
|
||||
uint3 pos = uint3(id.xy, 0);
|
||||
uint steps = VOLUME_DEPTH;
|
||||
uint steps = _FroxelResolution.z;
|
||||
|
||||
for(uint z = 0; z < steps; z++)
|
||||
{
|
||||
|
@ -1,32 +1,33 @@
|
||||
Shader "Hidden/Shadowmap" {
|
||||
SubShader {
|
||||
Tags { "RenderType"="Opaque" }
|
||||
Pass
|
||||
{
|
||||
Fog { Mode Off }
|
||||
Cull Back
|
||||
CGPROGRAM
|
||||
#pragma vertex vert
|
||||
#pragma fragment frag
|
||||
#include "UnityCG.cginc"
|
||||
SubShader{
|
||||
Tags {
|
||||
"RenderType" = "Opaque"
|
||||
}
|
||||
Pass {
|
||||
Fog { Mode Off }
|
||||
Cull Back
|
||||
CGPROGRAM
|
||||
#pragma vertex vert
|
||||
#pragma fragment frag
|
||||
#include "UnityCG.cginc"
|
||||
|
||||
struct v2f
|
||||
{
|
||||
float4 pos : SV_POSITION;
|
||||
};
|
||||
struct v2f
|
||||
{
|
||||
float4 pos : SV_POSITION;
|
||||
};
|
||||
|
||||
v2f vert (appdata_base v)
|
||||
{
|
||||
v2f o;
|
||||
o.pos = UnityObjectToClipPos (v.vertex);
|
||||
return o;
|
||||
}
|
||||
v2f vert(appdata_base v)
|
||||
{
|
||||
v2f o;
|
||||
o.pos = UnityObjectToClipPos(v.vertex);
|
||||
return o;
|
||||
}
|
||||
|
||||
float4 frag(v2f i) : COLOR
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
ENDCG
|
||||
}
|
||||
}
|
||||
float4 frag(v2f i) : COLOR
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
ENDCG
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user