using UnityEngine;
|
|
using UnityEngine.Profiling;
|
|
[ExecuteInEditMode]
|
|
public class ShadowCamera : MonoBehaviour
|
|
{
|
|
Camera ThisCamera = null;
|
|
GameObject Dad = null;
|
|
FogVolume Fog = null;
|
|
public RenderTexture RT_Opacity, RT_OpacityBlur, RT_PostProcess;
|
|
public RenderTexture GetOpacityRT()
|
|
{
|
|
return RT_Opacity;
|
|
}
|
|
public RenderTexture GetOpacityBlurRT()
|
|
{
|
|
return RT_OpacityBlur;
|
|
}
|
|
|
|
[System.Serializable]
|
|
public enum TextureSize
|
|
{
|
|
_64 = 64,
|
|
_128 = 128,
|
|
_256 = 256,
|
|
_512 = 512,
|
|
_1024 = 1024
|
|
};
|
|
|
|
public TextureSize SetTextureSize
|
|
{
|
|
set
|
|
{
|
|
if (value != textureSize)
|
|
SetQuality(value);
|
|
}
|
|
get
|
|
{
|
|
return textureSize;
|
|
}
|
|
}
|
|
public TextureSize textureSize = TextureSize._128;
|
|
/// Blur iterations - larger number means more blur.
|
|
[Range(0, 10)]
|
|
public int iterations = 3;
|
|
|
|
/// Blur spread for each iteration. Lower values
|
|
/// give better looking blur, but require more iterations to
|
|
/// get large blurs. Value is usually between 0.5 and 1.0.
|
|
[Range(0.0f, 1)]
|
|
public float blurSpread = 0.6f;
|
|
public int Downsampling = 2;
|
|
void SetQuality(TextureSize value)
|
|
{
|
|
textureSize = value;
|
|
// print((int)textureSize);
|
|
}
|
|
Shader blurShader = null;
|
|
Shader PostProcessShader = null;
|
|
Material blurMaterial = null;
|
|
Material postProcessMaterial = null;
|
|
protected Material BlurMaterial
|
|
{
|
|
get
|
|
{
|
|
if (blurMaterial == null)
|
|
{
|
|
blurMaterial = new Material(blurShader);
|
|
blurMaterial.hideFlags = HideFlags.DontSave;
|
|
}
|
|
return blurMaterial;
|
|
}
|
|
}
|
|
protected Material PostProcessMaterial
|
|
{
|
|
get
|
|
{
|
|
if (postProcessMaterial == null)
|
|
{
|
|
postProcessMaterial = new Material(PostProcessShader);
|
|
postProcessMaterial.hideFlags = HideFlags.DontSave;
|
|
}
|
|
return postProcessMaterial;
|
|
}
|
|
}
|
|
protected void GetRT(ref RenderTexture rt, int size, string name)
|
|
{
|
|
// Release existing one
|
|
ReleaseRT(rt);
|
|
rt = RenderTexture.GetTemporary(size, size, 0, RenderTextureFormat.R8, RenderTextureReadWrite.Linear);
|
|
rt.filterMode = FilterMode.Bilinear;
|
|
rt.name = name;
|
|
rt.wrapMode = TextureWrapMode.Repeat;
|
|
|
|
}
|
|
public void ReleaseRT(RenderTexture rt)
|
|
{
|
|
if (rt != null)
|
|
{
|
|
RenderTexture.ReleaseTemporary(rt);
|
|
rt = null;
|
|
}
|
|
}
|
|
|
|
// Performs one blur iteration.
|
|
public void FourTapCone(RenderTexture source, RenderTexture dest, int iteration)
|
|
{
|
|
float off = 0.5f + iteration * blurSpread;
|
|
Graphics.BlitMultiTap(source, dest, BlurMaterial,
|
|
new Vector2(-off, -off),
|
|
new Vector2(-off, off),
|
|
new Vector2(off, off),
|
|
new Vector2(off, -off)
|
|
);
|
|
}
|
|
|
|
// Downsamples the texture to a quarter resolution.
|
|
private void DownSample(RenderTexture source, RenderTexture dest)
|
|
{
|
|
float off = 1.0f;
|
|
Graphics.BlitMultiTap(source, dest, BlurMaterial,
|
|
new Vector2(-off, -off),
|
|
new Vector2(-off, off),
|
|
new Vector2(off, off),
|
|
new Vector2(off, -off)
|
|
);
|
|
}
|
|
|
|
void Blur(RenderTexture Input, int BlurRTSize)
|
|
{
|
|
RenderTexture RT_OpacityBlur2 = null;
|
|
GetRT(ref RT_OpacityBlur, BlurRTSize, "Shadow blurred");
|
|
GetRT(ref RT_OpacityBlur2, BlurRTSize, "Shadow blurred");
|
|
// Copy source to the smaller texture.
|
|
DownSample(Input, RT_OpacityBlur);
|
|
//Graphics.Blit(Input, RT_OpacityBlur);
|
|
|
|
// Blur the small texture
|
|
for (int i = 0; i < iterations; i++)
|
|
{
|
|
FourTapCone(RT_OpacityBlur, RT_OpacityBlur2, i);
|
|
FogVolumeUtilities.ExtensionMethods.Swap(ref RT_OpacityBlur, ref RT_OpacityBlur2);
|
|
}
|
|
|
|
|
|
Shader.SetGlobalTexture("RT_OpacityBlur", RT_OpacityBlur);
|
|
Fog.RT_OpacityBlur = RT_OpacityBlur;
|
|
}
|
|
|
|
|
|
|
|
void RenderShadowMap()
|
|
{
|
|
//ideally, a cheaper version should be rendered here.
|
|
//So lets render a version with no lighting stuff
|
|
Profiler.BeginSample(Fog.name + " shadows");
|
|
Fog.FogVolumeShader.maximumLOD = 100;
|
|
|
|
SetQuality(textureSize);
|
|
GetRT(ref RT_Opacity, (int)textureSize, "Opacity");
|
|
ThisCamera.targetTexture = RT_Opacity;
|
|
// print(Fog.ShadowCameraSkippedFrames);
|
|
ThisCamera.Render();
|
|
Fog.RT_Opacity = RT_Opacity;
|
|
|
|
// Shader.SetGlobalTexture("RT_Opacity", RT_Opacity);
|
|
if (RT_Opacity != null)
|
|
{
|
|
GetRT(ref RT_PostProcess, (int)textureSize, "Shadow PostProcess");
|
|
PostProcessMaterial.SetFloat("ShadowColor", Fog.ShadowColor.a);
|
|
// PostProcessMaterial.SetFloat("_jitter", Fog._jitter);
|
|
Graphics.Blit(RT_Opacity, RT_PostProcess, PostProcessMaterial);
|
|
// ThisCamera.targetTexture = null;
|
|
Graphics.Blit(RT_PostProcess, RT_Opacity);
|
|
//RenderTexture.ReleaseTemporary(RT_Opacity);
|
|
if (iterations > 0)
|
|
{
|
|
Blur(RT_Opacity, (int)textureSize >> Downsampling);
|
|
}
|
|
else
|
|
{
|
|
Shader.SetGlobalTexture("RT_OpacityBlur", RT_Opacity);
|
|
Fog.RT_OpacityBlur = RT_Opacity;
|
|
}
|
|
Fog.RT_Opacity = RT_Opacity;
|
|
}
|
|
//Shader.SetGlobalTexture("RT_Opacity", RT_Opacity);
|
|
BlurMaterial.SetFloat("ShadowColor", Fog.ShadowColor.a);
|
|
|
|
// back to normal
|
|
Fog.FogVolumeShader.maximumLOD = 600;
|
|
|
|
Profiler.EndSample();
|
|
}
|
|
|
|
void ShaderLoad()
|
|
{
|
|
blurShader = Shader.Find("Hidden/Fog Volume/BlurEffectConeTap");
|
|
if (blurShader == null) print("Hidden / Fog Volume / BlurEffectConeTap #SHADER ERROR#");
|
|
|
|
PostProcessShader = Shader.Find("Hidden/Fog Volume/Shadow Postprocess");
|
|
if (PostProcessShader == null) print("Hidden/Fog Volume/Shadow Postprocess #SHADER ERROR#");
|
|
}
|
|
|
|
void OnEnable()
|
|
{
|
|
ShaderLoad();
|
|
Dad = transform.parent.gameObject;
|
|
Fog = Dad.GetComponent<FogVolume>();
|
|
ThisCamera = gameObject.GetComponent<Camera>();
|
|
ThisCamera.depthTextureMode = DepthTextureMode.Depth;
|
|
CameraTransform();
|
|
}
|
|
|
|
public void CameraTransform()
|
|
{
|
|
if (ThisCamera != null)
|
|
{
|
|
ThisCamera.orthographicSize = Dad.GetComponent<FogVolume>().fogVolumeScale.x / 2;
|
|
ThisCamera.transform.position = Dad.transform.position;
|
|
ThisCamera.farClipPlane = Fog.fogVolumeScale.y + Fog.shadowCameraPosition;
|
|
// print(ThisCamera.farClipPlane);
|
|
Vector3 VerticalTranslate = new Vector3(0, 0, Fog.fogVolumeScale.y / 2 - Fog.shadowCameraPosition);
|
|
// print(Fog.ShadowCameraPosition);
|
|
|
|
ThisCamera.transform.Translate(VerticalTranslate, Space.Self);
|
|
Quaternion target = Quaternion.Euler(90, 0, 0);
|
|
ThisCamera.transform.rotation = Dad.transform.rotation * target;
|
|
|
|
ThisCamera.enabled = false;
|
|
|
|
if (Fog.SunAttached)
|
|
{
|
|
Fog.Sun.transform.rotation = Dad.transform.rotation * target;
|
|
}
|
|
}
|
|
}
|
|
// Update is called once per frame
|
|
void Update()
|
|
{
|
|
// print(Fog.name + " visibility: " + Fog.IsVisible);
|
|
if (Fog.IsVisible && Fog.CastShadows)//3.1.7
|
|
{
|
|
if (FogVolumeUtilities.ExtensionMethods.TimeSnap(Fog.ShadowCameraSkippedFrames))
|
|
RenderShadowMap();
|
|
#if UNITY_EDITOR
|
|
CameraTransform();
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void OnDisable()
|
|
{
|
|
RenderTexture.active = null;
|
|
ThisCamera.targetTexture = null;
|
|
if (RT_Opacity) DestroyImmediate(RT_Opacity);
|
|
if (RT_OpacityBlur) DestroyImmediate(RT_OpacityBlur);
|
|
if (RT_PostProcess) DestroyImmediate(RT_PostProcess);
|
|
if (blurMaterial) DestroyImmediate(blurMaterial);
|
|
if (postProcessMaterial) DestroyImmediate(postProcessMaterial);
|
|
}
|
|
}
|