본문으로 바로가기

PCSS Light script

category Technical Report/Unity Scripts 2019. 9. 15. 22:02
반응형


원문 링크 : https://github.com/Heep042/Unity-Graphics-Demo/blob/master/Assets/GitHub/PCSS/Scripts/PCSSLight.cs




using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;

[ExecuteInEditMode]
public class PCSSLight : MonoBehaviour
{
    public int resolution = 4096;
    public bool customShadowResolution = false;

    [Space(20f)]
    [Range(1, 64)]
    public int Blocker_SampleCount = 16;
    [Range(1, 64)]
    public int PCF_SampleCount = 16;

    [Space(20f)]
    public bool RotateSamples = true;
    public bool UseNoiseTexture = true;
    public Texture2D noiseTexture;

    [Space(20f)]
    [Range(0f, 7.5f)]
    public float Softness = 1f;
    [Range(0f, 5f)]
    public float SoftnessFalloff = 4f;
    //[Range(0f, 1f)]
    //public float NearPlane = .1f;

    [Space(20f)]
    [Range(0f, 0.15f)]
    public float MaxStaticGradientBias = .05f;
    [Range(0f, 1f)]
    public float Blocker_GradientBias = 0f;
    [Range(0f, 1f)]
    public float PCF_GradientBias = 1f;

    /* Unity's Cascade Blending doesn't work quite right - Might be able to do something about it when I have time to research it more */
    [Space(20f)]
    [Range(0f, 1f)]
    public float CascadeBlendDistance = .5f;

    [Space(20f)]
    public bool supportOrthographicProjection;

    [Space(20f)]
    public RenderTexture shadowRenderTexture;
    public RenderTextureFormat format = RenderTextureFormat.RFloat;
    public FilterMode filterMode = FilterMode.Bilinear;
    private LightEvent lightEvent = LightEvent.AfterShadowMap;

    public string shaderName = "Hidden/PCSS";
    private Shader shader;
    private int shadowmapPropID;

    private CommandBuffer copyShadowBuffer;
    private Light _light;

    #region Initialization
    public void OnEnable ()
    {
        Setup();
    }

    public void OnDisable ()
    {
        ResetShadowMode();
    }

    [ContextMenu("Reinitialize")]
    public void Setup ()
    {
        _light = GetComponent<Light>();
        if (!_light)
            return;

        resolution = Mathf.ClosestPowerOfTwo(resolution);
        if (customShadowResolution)
            _light.shadowCustomResolution = resolution;
        else
            _light.shadowCustomResolution = 0;

        shader = Shader.Find(shaderName);
        shadowmapPropID = Shader.PropertyToID("_ShadowMap");

        copyShadowBuffer = new CommandBuffer();
        copyShadowBuffer.name = "PCSS Shadows";
        
        var buffers = _light.GetCommandBuffers(lightEvent);
        for (int i = 0; i < buffers.Length; i++)
        {
            if(buffers[i].name == "PCSS Shadows")
            {
                _light.RemoveCommandBuffer(lightEvent, buffers[i]);
            }
        }

        _light.AddCommandBuffer(lightEvent, copyShadowBuffer);
        GraphicsSettings.SetCustomShader(BuiltinShaderType.ScreenSpaceShadows, shader);
        GraphicsSettings.SetShaderMode(BuiltinShaderType.ScreenSpaceShadows, BuiltinShaderMode.UseCustom);

        CreateShadowRenderTexture();
        UpdateShaderValues();
        UpdateCommandBuffer();
    }

    public void CreateShadowRenderTexture ()
    {
        shadowRenderTexture = new RenderTexture(resolution, resolution, 0, format);
        shadowRenderTexture.filterMode = filterMode;
        shadowRenderTexture.useMipMap = false;
    }

    [ContextMenu("Reset Shadows To Default")]
    public void ResetShadowMode ()
    {
        GraphicsSettings.SetCustomShader(BuiltinShaderType.ScreenSpaceShadows, Shader.Find("Hidden/Internal-ScreenSpaceShadows"));
        GraphicsSettings.SetShaderMode(BuiltinShaderType.ScreenSpaceShadows, BuiltinShaderMode.Disabled);
        _light.shadowCustomResolution = 0;
        DestroyImmediate(shadowRenderTexture);
        GraphicsSettings.SetShaderMode(BuiltinShaderType.ScreenSpaceShadows, BuiltinShaderMode.UseBuiltin);

        if (!_light)
            return;

        _light.RemoveCommandBuffer(LightEvent.AfterShadowMap, copyShadowBuffer);
    }
    #endregion

    #region UpdateSettings
    public void UpdateShaderValues ()
    {
        Shader.SetGlobalInt("Blocker_Samples", Blocker_SampleCount);
        Shader.SetGlobalInt("PCF_Samples", PCF_SampleCount);

        if (shadowRenderTexture)
        {
            if (shadowRenderTexture.format != format)
                CreateShadowRenderTexture();
            else
                shadowRenderTexture.filterMode = filterMode;
        }

        Shader.SetGlobalFloat("Softness", Softness / 64f / Mathf.Sqrt(QualitySettings.shadowDistance));
        Shader.SetGlobalFloat("SoftnessFalloff", Mathf.Exp(SoftnessFalloff));
        SetFlag("USE_FALLOFF", SoftnessFalloff > Mathf.Epsilon);
        //Shader.SetGlobalFloat("NearPlane", NearPlane);

        Shader.SetGlobalFloat("RECEIVER_PLANE_MIN_FRACTIONAL_ERROR", MaxStaticGradientBias);
        Shader.SetGlobalFloat("Blocker_GradientBias", Blocker_GradientBias);
        Shader.SetGlobalFloat("PCF_GradientBias", PCF_GradientBias);

        SetFlag("USE_CASCADE_BLENDING", CascadeBlendDistance > 0);
        Shader.SetGlobalFloat("CascadeBlendDistance", CascadeBlendDistance);

        SetFlag("USE_STATIC_BIAS", MaxStaticGradientBias > 0);
        SetFlag("USE_BLOCKER_BIAS", Blocker_GradientBias > 0);
        SetFlag("USE_PCF_BIAS", PCF_GradientBias > 0);

        SetFlag("ROTATE_SAMPLES", RotateSamples);
        SetFlag("USE_NOISE_TEX", UseNoiseTexture);

        if (noiseTexture)
        {
            Shader.SetGlobalVector("NoiseCoords", new Vector4(1f / noiseTexture.width, 1f / noiseTexture.height, 0f, 0f));
            Shader.SetGlobalTexture("_NoiseTexture", noiseTexture);
        }

        SetFlag("ORTHOGRAPHIC_SUPPORTED", supportOrthographicProjection);

        int maxSamples = Mathf.Max(Blocker_SampleCount, PCF_SampleCount);

        SetFlag("POISSON_32", maxSamples < 33);
        SetFlag("POISSON_64", maxSamples > 33);
    }

    public void UpdateCommandBuffer ()
    {
        if (!_light)
            return;

        copyShadowBuffer.Clear();
        copyShadowBuffer.SetShadowSamplingMode(BuiltinRenderTextureType.CurrentActive, ShadowSamplingMode.RawDepth);
        copyShadowBuffer.Blit(BuiltinRenderTextureType.CurrentActive, shadowRenderTexture);
        copyShadowBuffer.SetGlobalTexture(shadowmapPropID, shadowRenderTexture);
    }
    #endregion

    public void SetFlag (string shaderKeyword, bool value)
    {
        if (value)
            Shader.EnableKeyword(shaderKeyword);
        else
            Shader.DisableKeyword(shaderKeyword);
    }
}








반응형

'Technical Report > Unity Scripts' 카테고리의 다른 글

Unity Scriptable RenderPipeline  (0) 2020.02.17
Demo script  (0) 2020.02.12
Unity Legacy shadow map resolution control  (0) 2019.09.15
Custom Material GUI  (0) 2019.08.14
Unity Custom tube, shere Light  (0) 2018.12.04