diff --git a/IronToad_UnityProject/Assets/Art/Models/lightHouse_LOW.obj.meta b/IronToad_UnityProject/Assets/Art/Models/lightHouse_LOW.obj.meta deleted file mode 100644 index d94fc60..0000000 --- a/IronToad_UnityProject/Assets/Art/Models/lightHouse_LOW.obj.meta +++ /dev/null @@ -1,82 +0,0 @@ -fileFormatVersion: 2 -guid: 919eb0dba9aa0da44aec3a80f1cf98ea -timeCreated: 1485000000 -licenseType: Free -ModelImporter: - serializedVersion: 19 - fileIDToRecycleName: - 100000: lighthouse - 100002: //RootNode - 400000: lighthouse - 400002: //RootNode - 2300000: lighthouse - 3300000: lighthouse - 4300000: lighthouse - materials: - importMaterials: 1 - materialName: 0 - materialSearch: 1 - animations: - legacyGenerateAnimations: 4 - bakeSimulation: 0 - resampleCurves: 1 - optimizeGameObjects: 0 - motionNodeName: - animationImportErrors: - animationImportWarnings: - animationRetargetingWarnings: - animationDoRetargetingWarnings: 0 - animationCompression: 1 - animationRotationError: 0.5 - animationPositionError: 0.5 - animationScaleError: 0.5 - animationWrapMode: 0 - extraExposedTransformPaths: [] - clipAnimations: [] - isReadable: 1 - meshes: - lODScreenPercentages: [] - globalScale: 1 - meshCompression: 0 - addColliders: 0 - importBlendShapes: 1 - swapUVChannels: 0 - generateSecondaryUV: 0 - useFileUnits: 1 - optimizeMeshForGPU: 1 - keepQuads: 0 - weldVertices: 1 - secondaryUVAngleDistortion: 8 - secondaryUVAreaDistortion: 15.000001 - secondaryUVHardAngle: 88 - secondaryUVPackMargin: 4 - useFileScale: 1 - tangentSpace: - normalSmoothAngle: 60 - normalImportMode: 0 - tangentImportMode: 3 - importAnimation: 1 - copyAvatar: 0 - humanDescription: - serializedVersion: 2 - human: [] - skeleton: [] - armTwist: 0.5 - foreArmTwist: 0.5 - upperLegTwist: 0.5 - legTwist: 0.5 - armStretch: 0.05 - legStretch: 0.05 - feetSpacing: 0 - rootMotionBoneName: - rootMotionBoneRotation: {x: 0, y: 0, z: 0, w: 1} - hasTranslationDoF: 0 - hasExtraRoot: 0 - skeletonHasParents: 1 - lastHumanDescriptionAvatarSource: {instanceID: 0} - animationType: 0 - humanoidOversampling: 1 - additionalBone: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Scripts/AlertController.cs b/IronToad_UnityProject/Assets/Scripts/AlertController.cs index 605023d..96f1d04 100644 --- a/IronToad_UnityProject/Assets/Scripts/AlertController.cs +++ b/IronToad_UnityProject/Assets/Scripts/AlertController.cs @@ -9,21 +9,21 @@ public class AlertController : MonoBehaviour public Slider slider; public float hideTime = 5f; - private Vector3 originalPos; - private float lastSpotted; +// private Vector3 originalPos; +// private float lastSpotted; void Start () { NotificationServer.register("spotted boat", spottedBoat); NotificationServer.register("lost boat", lostBoat); - originalPos = text.rectTransform.anchoredPosition3D; +// originalPos = text.rectTransform.anchoredPosition3D; } public void spottedBoat() { LeanTween.cancel(text.gameObject, false); LeanTween.cancel(slider.gameObject, false); - lastSpotted = Time.timeSinceLevelLoad; +// lastSpotted = Time.timeSinceLevelLoad; NotificationServer.notify("show AlertText"); text.text = "hide!"; setTimer(0f); diff --git a/IronToad_UnityProject/Assets/Scripts/Boulder.cs b/IronToad_UnityProject/Assets/Scripts/Boulder.cs new file mode 100644 index 0000000..6669270 --- /dev/null +++ b/IronToad_UnityProject/Assets/Scripts/Boulder.cs @@ -0,0 +1,16 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +public class Boulder : HeavyObject +{ + + + public override void OnWaterStay(WaterController water,float waveHeight) + { + } + + public override void OnWaterExit(WaterController water) + { + } +} diff --git a/IronToad_UnityProject/Assets/Scripts/Boulder.cs.meta b/IronToad_UnityProject/Assets/Scripts/Boulder.cs.meta new file mode 100644 index 0000000..d71ea63 --- /dev/null +++ b/IronToad_UnityProject/Assets/Scripts/Boulder.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: b17436874f6d74be884f5af7ebabda8a +timeCreated: 1485018292 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Scripts/Catapult.cs b/IronToad_UnityProject/Assets/Scripts/Catapult.cs new file mode 100644 index 0000000..dd85e0c --- /dev/null +++ b/IronToad_UnityProject/Assets/Scripts/Catapult.cs @@ -0,0 +1,85 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +using BansheeGz.BGSpline.Components; +using BansheeGz.BGSpline.Curve; + +public class Catapult : MonoBehaviour +{ + public BGCurve splineCurve; + public float speed = 600f; + public float rotateSpeed = 200f; + public float timePadding = 0.5f; + public float timeBetweenLaunches = 0.5f; + public float minScale = 0.3f; + public float maxScale = 1f; + public float randomFactor = 50f; + public AnimationCurve animationCurve; + public Transform player; + + private bool isLaunching = false; + private BGCcCursor splineCursor; + private BGCcCursorObjectTranslate splineObjectTranslate; + private Vector3 originalScale; + private MeshRenderer meshRenderer; + + void Start () + { + splineCursor = splineCurve.GetComponent(); + splineObjectTranslate = splineCurve.GetComponent(); + meshRenderer = splineObjectTranslate.ObjectToManipulate.GetComponent(); + meshRenderer.enabled = false; + + originalScale = splineCurve.transform.parent.localScale; + + NotificationServer.register("statechange Searchlight", searchlightStateChanged); + } + + void Update() + { + splineObjectTranslate.ObjectToManipulate.Rotate(Vector3.forward, Time.deltaTime * rotateSpeed); + } + + public void searchlightStateChanged() + { + LeanTween.cancel(splineObjectTranslate.ObjectToManipulate.parent.gameObject, true); + if (Searchlight.state == Searchlight.SearchState.Chasing) + launchBoulder(); + } + + public void launchBoulder() + { + if (Searchlight.state != Searchlight.SearchState.Chasing || isLaunching) + { + isLaunching = false; + return; + } + + isLaunching = true; + LeanTween.delayedCall(splineObjectTranslate.ObjectToManipulate.parent.gameObject, timeBetweenLaunches, ()=>{ + if (Searchlight.state != Searchlight.SearchState.Chasing) + { + isLaunching = false; + return; + } + meshRenderer.enabled = true; + splineCursor.DistanceRatio = 0f; + splineCurve.transform.parent.position = player.position + + Vector3.right * Random.Range(-randomFactor, randomFactor) + + Vector3.forward * Random.Range(-randomFactor, randomFactor); + splineCurve.transform.parent.localEulerAngles = Vector3.up * Random.Range(0f, 360f); + splineCurve.transform.parent.localScale = new Vector3(Random.Range(minScale * originalScale.x, maxScale * originalScale.x), originalScale.y, originalScale.z); + LeanTween.value(splineObjectTranslate.ObjectToManipulate.gameObject, 0f, 1f, splineCursor.Math.GetDistance() / speed) + .setEase(animationCurve) + .setOnUpdate((float val)=>{ + splineCursor.DistanceRatio = val; + }).setOnComplete(()=>{ + splineCursor.DistanceRatio = 0f; + isLaunching = false; + meshRenderer.enabled = false; + launchBoulder(); + }); + }); + } +} diff --git a/IronToad_UnityProject/Assets/Scripts/Catapult.cs.meta b/IronToad_UnityProject/Assets/Scripts/Catapult.cs.meta new file mode 100644 index 0000000..c0ee060 --- /dev/null +++ b/IronToad_UnityProject/Assets/Scripts/Catapult.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 8d68d4df0b2854bf6bc9e40235372a0f +timeCreated: 1485013470 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Scripts/Lighthouse.cs b/IronToad_UnityProject/Assets/Scripts/Lighthouse.cs index 256ecf8..3805c6f 100644 --- a/IronToad_UnityProject/Assets/Scripts/Lighthouse.cs +++ b/IronToad_UnityProject/Assets/Scripts/Lighthouse.cs @@ -32,7 +32,7 @@ public class Lighthouse : MonoBehaviour { BGCurvePointI point = splineCurve.Points[i]; float distance = 0f; - Vector3 temp = splineCursor.Math.CalcPositionByClosestPoint(point.PositionWorld, out distance); + splineCursor.Math.CalcPositionByClosestPoint(point.PositionWorld, out distance); splineDistantPoints.Add(distance); } splineDistantPoints.Add(splineCursor.Math.GetDistance()); diff --git a/IronToad_UnityProject/Assets/Scripts/ScreenEffects.cs b/IronToad_UnityProject/Assets/Scripts/ScreenEffects.cs new file mode 100644 index 0000000..8537e45 --- /dev/null +++ b/IronToad_UnityProject/Assets/Scripts/ScreenEffects.cs @@ -0,0 +1,52 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityStandardAssets.CinematicEffects; + +public class ScreenEffects : MonoBehaviour +{ + public DepthOfField depthOfField; + + private float originalNearRadius; + private float originalFarRadius; + + void Start () + { + depthOfField = GetComponent(); + if (depthOfField == null) + depthOfField = gameObject.AddComponent(); + originalNearRadius = depthOfField.focus.nearBlurRadius; + originalFarRadius = depthOfField.focus.farBlurRadius; + + NotificationServer.register("show GameUI", showGame); + NotificationServer.register("hide GameUI", hideGame); + } + + public void showGame() + { + LeanTween.cancel(gameObject, false); + float startNear = depthOfField.focus.nearBlurRadius; + float startFar = depthOfField.focus.farBlurRadius; + DepthOfField.FocusSettings focus = depthOfField.focus; + LeanTween.value(gameObject, 1f, 0f, 0.5f).setEaseInOutQuad().setOnUpdate((float val)=>{ + focus.nearBlurRadius = startNear * val; + focus.farBlurRadius = startFar * val; + }).setOnComplete(()=>{ + depthOfField.enabled = false; + }).setIgnoreTimeScale(true); + } + + public void hideGame() + { + LeanTween.cancel(gameObject, false); + depthOfField.enabled = true; + float startNear = depthOfField.focus.nearBlurRadius; + float startFar = depthOfField.focus.farBlurRadius; + DepthOfField.FocusSettings focus = depthOfField.focus; + LeanTween.value(gameObject, 0f, 1f, 0.5f).setEaseInOutQuad().setOnUpdate((float val)=>{ + focus.nearBlurRadius = startNear + (originalNearRadius-startNear) * val; + focus.farBlurRadius = startFar + (originalFarRadius-startFar) * val; + }).setIgnoreTimeScale(true); + } + +} diff --git a/IronToad_UnityProject/Assets/Scripts/ScreenEffects.cs.meta b/IronToad_UnityProject/Assets/Scripts/ScreenEffects.cs.meta new file mode 100644 index 0000000..04c5a10 --- /dev/null +++ b/IronToad_UnityProject/Assets/Scripts/ScreenEffects.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 0bbf215cb5bca4fa09f6547f0a24f318 +timeCreated: 1485020054 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Scripts/Searchlight.cs b/IronToad_UnityProject/Assets/Scripts/Searchlight.cs index f113fae..0b1f08b 100644 --- a/IronToad_UnityProject/Assets/Scripts/Searchlight.cs +++ b/IronToad_UnityProject/Assets/Scripts/Searchlight.cs @@ -36,7 +36,6 @@ public class Searchlight : MonoBehaviour void Awake() { - NotificationServer.register("statechange Searchlight", stateChanged); NotificationServer.register("statechange Searchlight safe", stateSafe); NotificationServer.register("statechange Searchlight returning", stateReturning); if (!instants.Contains(this)) @@ -56,6 +55,8 @@ public class Searchlight : MonoBehaviour NotificationServer.notify("statechange Searchlight"); NotificationServer.notify("chasing boat"); } + LeanTween.cancel(gameObject, false); + LeanTween.move(gameObject, chased.transform.position, 0.5f).setEase(animationCurve).setOnComplete(chase); NotificationServer.notify("spotted boat"); } @@ -88,8 +89,8 @@ public class Searchlight : MonoBehaviour public void stateChanged() { LeanTween.cancel(gameObject, false); - if (state == SearchState.Chasing) - LeanTween.move(gameObject, chased.transform.position, 0.5f).setEase(animationCurve).setOnComplete(chase); +// if (state == SearchState.Chasing) +// LeanTween.move(gameObject, chased.transform.position, 0.5f).setEase(animationCurve).setOnComplete(chase); } public void chase() diff --git a/IronToad_UnityProject/Assets/Scripts/UIPanel.cs b/IronToad_UnityProject/Assets/Scripts/UIPanel.cs index 5e7c4b1..3135ea3 100644 --- a/IronToad_UnityProject/Assets/Scripts/UIPanel.cs +++ b/IronToad_UnityProject/Assets/Scripts/UIPanel.cs @@ -30,7 +30,7 @@ public class UIPanel : MonoBehaviour private RectTransform rectTransform; private CanvasGroup canvasGroup; private Vector3 originalPos; - private bool isShowing = false; +// private bool isShowing = false; void Awake () { @@ -143,7 +143,7 @@ public class UIPanel : MonoBehaviour canvasGroup.alpha = 1f; rectTransform.anchoredPosition3D = originalPos; transform.localScale = Vector3.one; - isShowing = true; +// isShowing = true; } public void setHideState() @@ -151,7 +151,7 @@ public class UIPanel : MonoBehaviour canvasGroup.interactable = false; canvasGroup.blocksRaycasts = false; canvasGroup.alpha = 0f; - isShowing = false; +// isShowing = false; } public void quitApplication() diff --git a/IronToad_UnityProject/Assets/Sound.meta b/IronToad_UnityProject/Assets/Sound.meta new file mode 100644 index 0000000..359da3b --- /dev/null +++ b/IronToad_UnityProject/Assets/Sound.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 0fbabcae9313543ffbf1429aeac3664d +folderAsset: yes +timeCreated: 1485006712 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion.meta new file mode 100644 index 0000000..e556049 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: ed6d7947a564a4dd1987f60392be4349 +folderAsset: yes +timeCreated: 1457326591 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/AmbientOcclusion.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/AmbientOcclusion.cs new file mode 100644 index 0000000..1093cbc --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/AmbientOcclusion.cs @@ -0,0 +1,360 @@ +using UnityEngine; +using UnityEngine.Rendering; + +namespace UnityStandardAssets.CinematicEffects +{ + [ExecuteInEditMode] + [RequireComponent(typeof(Camera))] + [AddComponentMenu("Image Effects/Cinematic/Ambient Occlusion")] +#if UNITY_5_4_OR_NEWER + [ImageEffectAllowedInSceneView] +#endif + public partial class AmbientOcclusion : MonoBehaviour + { + #region Public Properties + + /// Effect settings. + [SerializeField] + public Settings settings = Settings.defaultSettings; + + /// Checks if the ambient-only mode is supported under the current settings. + public bool isAmbientOnlySupported + { + get { return targetCamera.hdr && occlusionSource == OcclusionSource.GBuffer; } + } + + /// Checks if the G-buffer is available + public bool isGBufferAvailable + { + get { return targetCamera.actualRenderingPath == RenderingPath.DeferredShading; } + } + + #endregion + + #region Private Properties + + // Properties referring to the current settings + + float intensity + { + get { return settings.intensity; } + } + + float radius + { + get { return Mathf.Max(settings.radius, 1e-4f); } + } + + SampleCount sampleCount + { + get { return settings.sampleCount; } + } + + int sampleCountValue + { + get + { + switch (settings.sampleCount) + { + case SampleCount.Lowest: return 3; + case SampleCount.Low: return 6; + case SampleCount.Medium: return 12; + case SampleCount.High: return 20; + } + return Mathf.Clamp(settings.sampleCountValue, 1, 256); + } + } + + OcclusionSource occlusionSource + { + get + { + if (settings.occlusionSource == OcclusionSource.GBuffer && !isGBufferAvailable) + // An unavailable source was chosen: fallback to DepthNormalsTexture. + return OcclusionSource.DepthNormalsTexture; + else + return settings.occlusionSource; + } + } + + bool downsampling + { + get { return settings.downsampling; } + } + + bool ambientOnly + { + get { return settings.ambientOnly && !settings.debug && isAmbientOnlySupported; } + } + + // Texture format used for storing AO + RenderTextureFormat aoTextureFormat + { + get + { + if (SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.R8)) + return RenderTextureFormat.R8; + else + return RenderTextureFormat.Default; + } + } + + // AO shader + Shader aoShader + { + get + { + if (_aoShader == null) + _aoShader = Shader.Find("Hidden/Image Effects/Cinematic/AmbientOcclusion"); + return _aoShader; + } + } + + [SerializeField] Shader _aoShader; + + // Temporary aterial for the AO shader + Material aoMaterial + { + get + { + if (_aoMaterial == null) + _aoMaterial = ImageEffectHelper.CheckShaderAndCreateMaterial(aoShader); + return _aoMaterial; + } + } + + Material _aoMaterial; + + // Command buffer for the AO pass + CommandBuffer aoCommands + { + get + { + if (_aoCommands == null) + { + _aoCommands = new CommandBuffer(); + _aoCommands.name = "AmbientOcclusion"; + } + return _aoCommands; + } + } + + CommandBuffer _aoCommands; + + // Target camera + Camera targetCamera + { + get { return GetComponent(); } + } + + // Property observer + PropertyObserver propertyObserver { get; set; } + + // Reference to the quad mesh in the built-in assets + // (used in MRT blitting) + Mesh quadMesh + { + get { return _quadMesh; } + } + + [SerializeField] Mesh _quadMesh; + + #endregion + + #region Effect Passes + + // Build commands for the AO pass (used in the ambient-only mode). + void BuildAOCommands() + { + var cb = aoCommands; + + var tw = targetCamera.pixelWidth; + var th = targetCamera.pixelHeight; + var ts = downsampling ? 2 : 1; + var format = aoTextureFormat; + var rwMode = RenderTextureReadWrite.Linear; + var filter = FilterMode.Bilinear; + + // AO buffer + var m = aoMaterial; + var rtMask = Shader.PropertyToID("_OcclusionTexture"); + cb.GetTemporaryRT(rtMask, tw / ts, th / ts, 0, filter, format, rwMode); + + // AO estimation + cb.Blit((Texture)null, rtMask, m, 2); + + // Blur buffer + var rtBlur = Shader.PropertyToID("_OcclusionBlurTexture"); + + // Primary blur filter (large kernel) + cb.GetTemporaryRT(rtBlur, tw, th, 0, filter, format, rwMode); + cb.SetGlobalVector("_BlurVector", Vector2.right * 2); + cb.Blit(rtMask, rtBlur, m, 4); + cb.ReleaseTemporaryRT(rtMask); + + cb.GetTemporaryRT(rtMask, tw, th, 0, filter, format, rwMode); + cb.SetGlobalVector("_BlurVector", Vector2.up * 2 * ts); + cb.Blit(rtBlur, rtMask, m, 4); + cb.ReleaseTemporaryRT(rtBlur); + + // Secondary blur filter (small kernel) + cb.GetTemporaryRT(rtBlur, tw, th, 0, filter, format, rwMode); + cb.SetGlobalVector("_BlurVector", Vector2.right * ts); + cb.Blit(rtMask, rtBlur, m, 6); + cb.ReleaseTemporaryRT(rtMask); + + cb.GetTemporaryRT(rtMask, tw, th, 0, filter, format, rwMode); + cb.SetGlobalVector("_BlurVector", Vector2.up * ts); + cb.Blit(rtBlur, rtMask, m, 6); + cb.ReleaseTemporaryRT(rtBlur); + + // Combine AO to the G-buffer. + var mrt = new RenderTargetIdentifier[] { + BuiltinRenderTextureType.GBuffer0, // Albedo, Occ + BuiltinRenderTextureType.CameraTarget // Ambient + }; + cb.SetRenderTarget(mrt, BuiltinRenderTextureType.CameraTarget); + cb.SetGlobalTexture("_OcclusionTexture", rtMask); + cb.DrawMesh(quadMesh, Matrix4x4.identity, m, 0, 8); + + cb.ReleaseTemporaryRT(rtMask); + } + + // Execute the AO pass immediately (used in the forward mode). + void ExecuteAOPass(RenderTexture source, RenderTexture destination) + { + var tw = source.width; + var th = source.height; + var ts = downsampling ? 2 : 1; + var format = aoTextureFormat; + var rwMode = RenderTextureReadWrite.Linear; + var useGBuffer = settings.occlusionSource == OcclusionSource.GBuffer; + + // AO buffer + var m = aoMaterial; + var rtMask = RenderTexture.GetTemporary(tw / ts, th / ts, 0, format, rwMode); + + // AO estimation + Graphics.Blit((Texture)null, rtMask, m, (int)occlusionSource); + + // Primary blur filter (large kernel) + var rtBlur = RenderTexture.GetTemporary(tw, th, 0, format, rwMode); + m.SetVector("_BlurVector", Vector2.right * 2); + Graphics.Blit(rtMask, rtBlur, m, useGBuffer ? 4 : 3); + RenderTexture.ReleaseTemporary(rtMask); + + rtMask = RenderTexture.GetTemporary(tw, th, 0, format, rwMode); + m.SetVector("_BlurVector", Vector2.up * 2 * ts); + Graphics.Blit(rtBlur, rtMask, m, useGBuffer ? 4 : 3); + RenderTexture.ReleaseTemporary(rtBlur); + + // Secondary blur filter (small kernel) + rtBlur = RenderTexture.GetTemporary(tw, th, 0, format, rwMode); + m.SetVector("_BlurVector", Vector2.right * ts); + Graphics.Blit(rtMask, rtBlur, m, useGBuffer ? 6 : 5); + RenderTexture.ReleaseTemporary(rtMask); + + rtMask = RenderTexture.GetTemporary(tw, th, 0, format, rwMode); + m.SetVector("_BlurVector", Vector2.up * ts); + Graphics.Blit(rtBlur, rtMask, m, useGBuffer ? 6 : 5); + RenderTexture.ReleaseTemporary(rtBlur); + + // Combine AO with the source. + m.SetTexture("_OcclusionTexture", rtMask); + + if (!settings.debug) + Graphics.Blit(source, destination, m, 7); + else + Graphics.Blit(source, destination, m, 9); + + RenderTexture.ReleaseTemporary(rtMask); + } + + // Update the common material properties. + void UpdateMaterialProperties() + { + var m = aoMaterial; + m.SetFloat("_Intensity", intensity); + m.SetFloat("_Radius", radius); + m.SetFloat("_TargetScale", downsampling ? 0.5f : 1); + m.SetInt("_SampleCount", sampleCountValue); + } + + #endregion + + #region MonoBehaviour Functions + + void OnEnable() + { + // Check if the shader is supported in the current platform. + if (!ImageEffectHelper.IsSupported(aoShader, true, false, this)) + { + enabled = false; + return; + } + + // Register the command buffer if in the ambient-only mode. + if (ambientOnly) + targetCamera.AddCommandBuffer(CameraEvent.BeforeReflections, aoCommands); + + // Enable depth textures which the occlusion source requires. + if (occlusionSource == OcclusionSource.DepthTexture) + targetCamera.depthTextureMode |= DepthTextureMode.Depth; + + if (occlusionSource != OcclusionSource.GBuffer) + targetCamera.depthTextureMode |= DepthTextureMode.DepthNormals; + } + + void OnDisable() + { + // Destroy all the temporary resources. + if (_aoMaterial != null) DestroyImmediate(_aoMaterial); + _aoMaterial = null; + + if (_aoCommands != null) + targetCamera.RemoveCommandBuffer(CameraEvent.BeforeReflections, _aoCommands); + _aoCommands = null; + } + + void Update() + { + if (propertyObserver.CheckNeedsReset(settings, targetCamera)) + { + // Reinitialize all the resources by disabling/enabling itself. + // This is not very efficient way but just works... + OnDisable(); + OnEnable(); + + // Build the command buffer if in the ambient-only mode. + if (ambientOnly) + { + aoCommands.Clear(); + BuildAOCommands(); + } + + propertyObserver.Update(settings, targetCamera); + } + + // Update the material properties (later used in the AO commands). + if (ambientOnly) UpdateMaterialProperties(); + } + + [ImageEffectOpaque] + void OnRenderImage(RenderTexture source, RenderTexture destination) + { + if (ambientOnly) + { + // Do nothing in the ambient-only mode. + Graphics.Blit(source, destination); + } + else + { + // Execute the AO pass. + UpdateMaterialProperties(); + ExecuteAOPass(source, destination); + } + } + + #endregion + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/AmbientOcclusion.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/AmbientOcclusion.cs.meta new file mode 100644 index 0000000..c2329f9 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/AmbientOcclusion.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: e89654dcf6db746d2a57aeaaa14f5e83 +timeCreated: 1457327177 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: + - _aoShader: {fileID: 4800000, guid: 65e203e5acda447acbf9dc1ef78c4a39, type: 3} + - _quadMesh: {fileID: 10210, guid: 0000000000000000e000000000000000, type: 0} + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Editor.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Editor.meta new file mode 100644 index 0000000..024d19a --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Editor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: c1589efc0706e448d9a0af709e2c99cc +folderAsset: yes +timeCreated: 1457326964 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Editor/AmbientOcclusionEditor.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Editor/AmbientOcclusionEditor.cs new file mode 100644 index 0000000..636c650 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Editor/AmbientOcclusionEditor.cs @@ -0,0 +1,89 @@ +using UnityEngine; +using UnityEditor; + +namespace UnityStandardAssets.CinematicEffects +{ + [CanEditMultipleObjects] + [CustomEditor(typeof(AmbientOcclusion))] + public class AmbientOcclusionEditor : Editor + { + SerializedProperty _intensity; + SerializedProperty _radius; + SerializedProperty _sampleCount; + SerializedProperty _sampleCountValue; + SerializedProperty _downsampling; + SerializedProperty _occlusionSource; + SerializedProperty _ambientOnly; + SerializedProperty _debug; + + static GUIContent _textValue = new GUIContent("Value"); + + static string _textNoGBuffer = + "G-buffer is currently unavailable. " + + "Change Renderring Path in camera settings to Deferred."; + + static string _textNoAmbientOnly = + "The ambient-only mode is currently disabled; " + + "it requires G-buffer source and HDR rendering."; + + static string _textGBufferNote = + "Forward opaque objects don't go in the G-buffer. " + + "This may lead to artifacts."; + + void OnEnable() + { + _intensity = serializedObject.FindProperty("settings.intensity"); + _radius = serializedObject.FindProperty("settings.radius"); + _sampleCount = serializedObject.FindProperty("settings.sampleCount"); + _sampleCountValue = serializedObject.FindProperty("settings.sampleCountValue"); + _downsampling = serializedObject.FindProperty("settings.downsampling"); + _occlusionSource = serializedObject.FindProperty("settings.occlusionSource"); + _ambientOnly = serializedObject.FindProperty("settings.ambientOnly"); + _debug = serializedObject.FindProperty("settings.debug"); + } + + public override void OnInspectorGUI() + { + var targetInstance = (AmbientOcclusion)target; + + serializedObject.Update(); + + EditorGUILayout.PropertyField(_intensity); + EditorGUILayout.PropertyField(_radius); + EditorGUILayout.PropertyField(_sampleCount); + + if (_sampleCount.hasMultipleDifferentValues || + _sampleCount.enumValueIndex == (int)AmbientOcclusion.SampleCount.Variable) + { + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(_sampleCountValue, _textValue); + EditorGUI.indentLevel--; + } + + EditorGUILayout.PropertyField(_downsampling); + EditorGUILayout.PropertyField(_occlusionSource); + + if (!_occlusionSource.hasMultipleDifferentValues && + _occlusionSource.enumValueIndex == (int)AmbientOcclusion.OcclusionSource.GBuffer) + { + if (!targetInstance.isGBufferAvailable) + EditorGUILayout.HelpBox(_textNoGBuffer, MessageType.Warning); + else if (!_ambientOnly.hasMultipleDifferentValues && !_ambientOnly.boolValue) + EditorGUILayout.HelpBox(_textGBufferNote, MessageType.Info); + } + + EditorGUILayout.PropertyField(_ambientOnly); + + if (!_ambientOnly.hasMultipleDifferentValues && + _ambientOnly.boolValue && + !targetInstance.isAmbientOnlySupported) + { + EditorGUILayout.HelpBox(_textNoAmbientOnly, MessageType.Warning); + } + + EditorGUILayout.PropertyField(_debug); + + serializedObject.ApplyModifiedProperties(); + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Editor/AmbientOcclusionEditor.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Editor/AmbientOcclusionEditor.cs.meta new file mode 100644 index 0000000..5ef27d2 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Editor/AmbientOcclusionEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 05ea8e27ed8e74e67a9220b4f4119e51 +timeCreated: 1457327141 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Helpers.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Helpers.meta new file mode 100644 index 0000000..168a0c9 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Helpers.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 1d775599023574a39befabe47bdfddde +folderAsset: yes +timeCreated: 1457326936 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Helpers/PropertyObserver.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Helpers/PropertyObserver.cs new file mode 100644 index 0000000..270368f --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Helpers/PropertyObserver.cs @@ -0,0 +1,44 @@ +using UnityEngine; + +namespace UnityStandardAssets.CinematicEffects +{ + public partial class AmbientOcclusion : MonoBehaviour + { + // Observer class that detects changes on properties + struct PropertyObserver + { + // AO properties + bool _downsampling; + OcclusionSource _occlusionSource; + bool _ambientOnly; + bool _debug; + + // Camera properties + int _pixelWidth; + int _pixelHeight; + + // Check if it has to reset itself for property changes. + public bool CheckNeedsReset(Settings setting, Camera camera) + { + return + _downsampling != setting.downsampling || + _occlusionSource != setting.occlusionSource || + _ambientOnly != setting.ambientOnly || + _debug != setting.debug || + _pixelWidth != camera.pixelWidth || + _pixelHeight != camera.pixelHeight; + } + + // Update the internal state. + public void Update(Settings setting, Camera camera) + { + _downsampling = setting.downsampling; + _occlusionSource = setting.occlusionSource; + _ambientOnly = setting.ambientOnly; + _debug = setting.debug; + _pixelWidth = camera.pixelWidth; + _pixelHeight = camera.pixelHeight; + } + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Helpers/PropertyObserver.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Helpers/PropertyObserver.cs.meta new file mode 100644 index 0000000..21830ef --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Helpers/PropertyObserver.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 1d9548d9a173a40e4b758ecf6e4fed49 +timeCreated: 1457326885 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Helpers/Settings.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Helpers/Settings.cs new file mode 100644 index 0000000..9d96d26 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Helpers/Settings.cs @@ -0,0 +1,85 @@ +using System; +using UnityEngine; + +namespace UnityStandardAssets.CinematicEffects +{ + public partial class AmbientOcclusion : MonoBehaviour + { + /// Values for Settings.sampleCount, determining the number of sample points. + public enum SampleCount + { + Lowest, Low, Medium, High, Variable + } + + /// Values for Settings.occlusionSource, determining the source buffer of occlusion. + public enum OcclusionSource + { + DepthTexture, DepthNormalsTexture, GBuffer + } + + /// Class used for storing settings of AmbientOcclusion. + [Serializable] + public class Settings + { + /// Degree of darkness produced by the effect. + [SerializeField, Range(0, 4)] + [Tooltip("Degree of darkness produced by the effect.")] + public float intensity; + + /// Radius of sample points, which affects extent of darkened areas. + [SerializeField] + [Tooltip("Radius of sample points, which affects extent of darkened areas.")] + public float radius; + + /// Number of sample points, which affects quality and performance. + [SerializeField] + [Tooltip("Number of sample points, which affects quality and performance.")] + public SampleCount sampleCount; + + /// Determines the sample count when SampleCount.Variable is used. + [SerializeField] + [Tooltip("Determines the sample count when SampleCount.Variable is used.")] + public int sampleCountValue; + + /// Halves the resolution of the effect to increase performance. + [SerializeField] + [Tooltip("Halves the resolution of the effect to increase performance.")] + public bool downsampling; + + /// Enables the ambient-only mode in that the effect only affects + /// ambient lighting. This mode is only available with G-buffer + /// source and HDR rendering. + [SerializeField] + [Tooltip("If checked, the effect only affects ambient lighting.")] + public bool ambientOnly; + + /// Source buffer on which the occlusion estimator is based. + [SerializeField] + [Tooltip("Source buffer on which the occlusion estimator is based.")] + public OcclusionSource occlusionSource; + + /// Displays occlusion for debug purpose. + [SerializeField] + [Tooltip("Displays occlusion for debug purpose.")] + public bool debug; + + /// Returns the default settings. + public static Settings defaultSettings + { + get + { + return new Settings + { + intensity = 1, + radius = 0.3f, + sampleCount = SampleCount.Medium, + sampleCountValue = 24, + downsampling = false, + ambientOnly = false, + occlusionSource = OcclusionSource.DepthNormalsTexture + }; + } + } + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Helpers/Settings.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Helpers/Settings.cs.meta new file mode 100644 index 0000000..438495e --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Helpers/Settings.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: e952a344c72354904a417d27abe6f55e +timeCreated: 1457331804 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Resources.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Resources.meta new file mode 100644 index 0000000..4c04e73 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Resources.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: ae08100d29090452888e1b6a7b5a7170 +folderAsset: yes +timeCreated: 1457326958 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Resources/AmbientOcclusion.cginc b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Resources/AmbientOcclusion.cginc new file mode 100644 index 0000000..ef722db --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Resources/AmbientOcclusion.cginc @@ -0,0 +1,409 @@ +// Upgrade NOTE: commented out 'float4x4 _WorldToCamera', a built-in variable +// Upgrade NOTE: replaced '_WorldToCamera' with 'unity_WorldToCamera' + +// -------- +// Additional options for further customization +// -------- + +// By default, a fixed sampling pattern is used in the AO estimator. +// Although this gives preferable results in most cases, a completely +// random sampling pattern could give aesthetically good results in some +// cases. Comment out the line below to use the random pattern instead of +// the fixed one. +#define FIXED_SAMPLING_PATTERN 1 + +// The constant below determines the contrast of occlusion. Altough this +// allows intentional over/under occlusion, currently is not exposed to the +// editor, because it’s thought to be rarely useful. +static const float kContrast = 0.6; + +// The constant below controls the geometry-awareness of the blur filter. +// The higher value, the more sensitive it is. +static const float kGeom = 50; + +// The constants below are used in the AO estimator. Beta is mainly used +// for suppressing self-shadowing noise, and Epsilon is used to prevent +// calculation underflow. See the paper (Morgan 2011 http://goo.gl/2iz3P) +// for further details of these constants. +static const float kBeta = 0.002; +static const float kEpsilon = 1e-4; + +// -------- + +#include "UnityCG.cginc" + +// Global shader properties +sampler2D _CameraGBufferTexture2; +sampler2D_float _CameraDepthTexture; +sampler2D _CameraDepthNormalsTexture; +// float4x4 _WorldToCamera; + +// Sample count +// Use a constant on GLES2 (basically it doesn't support dynamic looping). +#if SHADER_API_GLES +static const int _SampleCount = 5; +#else +int _SampleCount; +#endif + +sampler2D _MainTex; +float4 _MainTex_TexelSize; +sampler2D _OcclusionTexture; + +// Material shader properties +half _Intensity; +float _Radius; +float _TargetScale; +float2 _BlurVector; + +// Utility for sin/cos +float2 CosSin(float theta) +{ + float sn, cs; + sincos(theta, sn, cs); + return float2(cs, sn); +} + +// Gamma encoding function for AO value +// (do nothing if in the linear mode) +half EncodeAO(half x) +{ + // Gamma encoding + half x_g = 1 - pow(1 - x, 1 / 2.2); + // ColorSpaceLuminance.w is 0 (gamma) or 1 (linear). + return lerp(x_g, x, unity_ColorSpaceLuminance.w); +} + +// Pseudo random number generator with 2D argument +float UVRandom(float u, float v) +{ + float f = dot(float2(12.9898, 78.233), float2(u, v)); + return frac(43758.5453 * sin(f)); +} + +// Interleaved gradient function from Jimenez 2014 http://goo.gl/eomGso +float GradientNoise(float2 uv) +{ + uv = floor(uv * _ScreenParams.xy); + float f = dot(float2(0.06711056f, 0.00583715f), uv); + return frac(52.9829189f * frac(f)); +} + +// Boundary check for depth sampler +// (returns a very large value if it lies out of bounds) +float CheckBounds(float2 uv, float d) +{ + float ob = any(uv < 0) + any(uv > 1); +#if defined(UNITY_REVERSED_Z) + ob += (d <= 0.00001); +#else + ob += (d >= 0.99999); +#endif + return ob * 1e8; +} + +// Depth/normal sampling functions +float SampleDepth(float2 uv) +{ +#if SOURCE_GBUFFER || SOURCE_DEPTH + float d = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, uv); + return LinearEyeDepth(d) + CheckBounds(uv, d); +#else + float4 cdn = tex2D(_CameraDepthNormalsTexture, uv); + float d = DecodeFloatRG(cdn.zw); + return d * _ProjectionParams.z + CheckBounds(uv, d); +#endif +} + +float3 SampleNormal(float2 uv) +{ +#if SOURCE_GBUFFER + float3 norm = tex2D(_CameraGBufferTexture2, uv).xyz; + norm = norm * 2 - any(norm); // gets (0,0,0) when norm == 0 + return mul((float3x3)unity_WorldToCamera, norm); +#else + float4 cdn = tex2D(_CameraDepthNormalsTexture, uv); + return DecodeViewNormalStereo(cdn) * float3(1, 1, -1); +#endif +} + +float SampleDepthNormal(float2 uv, out float3 normal) +{ +#if SOURCE_GBUFFER || SOURCE_DEPTH + normal = SampleNormal(uv); + return SampleDepth(uv); +#else + float4 cdn = tex2D(_CameraDepthNormalsTexture, uv); + normal = DecodeViewNormalStereo(cdn) * float3(1, 1, -1); + float d = DecodeFloatRG(cdn.zw); + return d * _ProjectionParams.z + CheckBounds(uv, d); +#endif +} + +// Reconstruct view-space position from UV and depth. +// p11_22 = (unity_CameraProjection._11, unity_CameraProjection._22) +// p13_31 = (unity_CameraProjection._13, unity_CameraProjection._23) +float3 ReconstructViewPos(float2 uv, float depth, float2 p11_22, float2 p13_31) +{ + return float3((uv * 2 - 1 - p13_31) / p11_22, 1) * depth; +} + +// Normal vector comparer (for geometry-aware weighting) +half CompareNormal(half3 d1, half3 d2) +{ + return pow((dot(d1, d2) + 1) * 0.5, kGeom); +} + +// Final combiner function +half3 CombineOcclusion(half3 src, half3 ao) +{ + return lerp(src, 0, EncodeAO(ao)); +} + +// Sample point picker +float3 PickSamplePoint(float2 uv, float index) +{ + // Uniformaly distributed points on a unit sphere http://goo.gl/X2F1Ho +#if FIXED_SAMPLING_PATTERN + float gn = GradientNoise(uv * _TargetScale); + float u = frac(UVRandom(0, index) + gn) * 2 - 1; + float theta = (UVRandom(1, index) + gn) * UNITY_PI * 2; +#else + float u = UVRandom(uv.x + _Time.x, uv.y + index) * 2 - 1; + float theta = UVRandom(-uv.x - _Time.x, uv.y + index) * UNITY_PI * 2; +#endif + float3 v = float3(CosSin(theta) * sqrt(1 - u * u), u); + // Make them distributed between [0, _Radius] + float l = sqrt((index + 1) / _SampleCount) * _Radius; + return v * l; +} + +// Occlusion estimator function +float EstimateOcclusion(float2 uv) +{ + // Parameters used in coordinate conversion + float3x3 proj = (float3x3)unity_CameraProjection; + float2 p11_22 = float2(unity_CameraProjection._11, unity_CameraProjection._22); + float2 p13_31 = float2(unity_CameraProjection._13, unity_CameraProjection._23); + + // View space normal and depth + float3 norm_o; + float depth_o = SampleDepthNormal(uv, norm_o); + +#if SOURCE_DEPTHNORMALS + // Offset the depth value to avoid precision error. + // (depth in the DepthNormals mode has only 16-bit precision) + depth_o -= _ProjectionParams.z / 65536; +#endif + + // Reconstruct the view-space position. + float3 vpos_o = ReconstructViewPos(uv, depth_o, p11_22, p13_31); + + // Distance-based AO estimator based on Morgan 2011 http://goo.gl/2iz3P + float ao = 0.0; + + for (int s = 0; s < _SampleCount; s++) + { + // Sample point +#if SHADER_API_D3D11 + // This 'floor(1.0001 * s)' operation is needed to avoid a NVidia + // shader issue. This issue is only observed on DX11. + float3 v_s1 = PickSamplePoint(uv, floor(1.0001 * s)); +#else + float3 v_s1 = PickSamplePoint(uv, s); +#endif + v_s1 = faceforward(v_s1, -norm_o, v_s1); + float3 vpos_s1 = vpos_o + v_s1; + + // Reproject the sample point + float3 spos_s1 = mul(proj, vpos_s1); + float2 uv_s1 = (spos_s1.xy / vpos_s1.z + 1) * 0.5; + + // Depth at the sample point + float depth_s1 = SampleDepth(uv_s1); + + // Relative position of the sample point + float3 vpos_s2 = ReconstructViewPos(uv_s1, depth_s1, p11_22, p13_31); + float3 v_s2 = vpos_s2 - vpos_o; + + // Estimate the obscurance value + float a1 = max(dot(v_s2, norm_o) - kBeta * depth_o, 0); + float a2 = dot(v_s2, v_s2) + kEpsilon; + ao += a1 / a2; + } + + ao *= _Radius; // intensity normalization + + // Apply other parameters. + return pow(ao * _Intensity / _SampleCount, kContrast); +} + +// Geometry-aware separable blur filter (large kernel) +half SeparableBlurLarge(sampler2D tex, float2 uv, float2 delta) +{ +#if !SHADER_API_MOBILE + // 9-tap Gaussian blur with adaptive sampling + float2 uv1a = uv - delta; + float2 uv1b = uv + delta; + float2 uv2a = uv - delta * 2; + float2 uv2b = uv + delta * 2; + float2 uv3a = uv - delta * 3.2307692308; + float2 uv3b = uv + delta * 3.2307692308; + + half3 n0 = SampleNormal(uv); + + half w0 = 0.37004405286; + half w1a = CompareNormal(n0, SampleNormal(uv1a)) * 0.31718061674; + half w1b = CompareNormal(n0, SampleNormal(uv1b)) * 0.31718061674; + half w2a = CompareNormal(n0, SampleNormal(uv2a)) * 0.19823788546; + half w2b = CompareNormal(n0, SampleNormal(uv2b)) * 0.19823788546; + half w3a = CompareNormal(n0, SampleNormal(uv3a)) * 0.11453744493; + half w3b = CompareNormal(n0, SampleNormal(uv3b)) * 0.11453744493; + + half s = tex2D(_MainTex, uv).r * w0; + s += tex2D(_MainTex, uv1a).r * w1a; + s += tex2D(_MainTex, uv1b).r * w1b; + s += tex2D(_MainTex, uv2a).r * w2a; + s += tex2D(_MainTex, uv2b).r * w2b; + s += tex2D(_MainTex, uv3a).r * w3a; + s += tex2D(_MainTex, uv3b).r * w3b; + + return s / (w0 + w1a + w1b + w2a + w2b + w3a + w3b); +#else + // 9-tap Gaussian blur with linear sampling + // (less quality but slightly fast) + float2 uv1a = uv - delta * 1.3846153846; + float2 uv1b = uv + delta * 1.3846153846; + float2 uv2a = uv - delta * 3.2307692308; + float2 uv2b = uv + delta * 3.2307692308; + + half3 n0 = SampleNormal(uv); + + half w0 = 0.2270270270; + half w1a = CompareNormal(n0, SampleNormal(uv1a)) * 0.3162162162; + half w1b = CompareNormal(n0, SampleNormal(uv1b)) * 0.3162162162; + half w2a = CompareNormal(n0, SampleNormal(uv2a)) * 0.0702702703; + half w2b = CompareNormal(n0, SampleNormal(uv2b)) * 0.0702702703; + + half s = tex2D(_MainTex, uv).r * w0; + s += tex2D(_MainTex, uv1a).r * w1a; + s += tex2D(_MainTex, uv1b).r * w1b; + s += tex2D(_MainTex, uv2a).r * w2a; + s += tex2D(_MainTex, uv2b).r * w2b; + + return s / (w0 + w1a + w1b + w2a + w2b); +#endif +} + +// Geometry-aware separable blur filter (small kernel) +half SeparableBlurSmall(sampler2D tex, float2 uv, float2 delta) +{ + float2 uv1 = uv - delta; + float2 uv2 = uv + delta; + + half3 n0 = SampleNormal(uv); + + half w0 = 2; + half w1 = CompareNormal(n0, SampleNormal(uv1)); + half w2 = CompareNormal(n0, SampleNormal(uv2)); + + half s = tex2D(_MainTex, uv).r * w0; + s += tex2D(_MainTex, uv1).r * w1; + s += tex2D(_MainTex, uv2).r * w2; + + return s / (w0 + w1 + w2); +} + +// Occlusion estimation pass +half4 frag_ao(v2f_img i) : SV_Target +{ + return EstimateOcclusion(i.uv); +} + +// Noise reduction pass (large kernel) +half4 frag_blur1(v2f_img i) : SV_Target +{ + float2 delta = _MainTex_TexelSize.xy * _BlurVector; + return SeparableBlurLarge(_MainTex, i.uv, delta); +} + +// Noise reduction pass (small kernel) +half4 frag_blur2(v2f_img i) : SV_Target +{ + float2 delta = _MainTex_TexelSize.xy * _BlurVector; + return SeparableBlurSmall(_MainTex, i.uv, delta); +} + +// Combiner pass for the forward mode +struct v2f_multitex +{ + float4 pos : SV_POSITION; + float2 uv0 : TEXCOORD0; + float2 uv1 : TEXCOORD1; +}; + +v2f_multitex vert_multitex(appdata_img v) +{ + // Handles vertically-flipped case. + float vflip = sign(_MainTex_TexelSize.y); + + v2f_multitex o; + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv0 = v.texcoord.xy; + o.uv1 = (v.texcoord.xy - 0.5) * float2(1, vflip) + 0.5; + return o; +} + +half4 frag_combine(v2f_multitex i) : SV_Target +{ + half4 src = tex2D(_MainTex, i.uv0); + half ao = tex2D(_OcclusionTexture, i.uv1).r; + return half4(CombineOcclusion(src.rgb, ao), src.a); +} + +// Combiner pass for the ambient-only mode +v2f_img vert_gbuffer(appdata_img v) +{ + v2f_img o; + o.pos = v.vertex * float4(2, 2, 0, 0) + float4(0, 0, 0, 1); +#if UNITY_UV_STARTS_AT_TOP + o.uv = v.texcoord * float2(1, -1) + float2(0, 1); +#else + o.uv = v.texcoord; +#endif + return o; +} + +#if !SHADER_API_GLES // excluding the MRT pass under GLES2 + +struct CombinerOutput +{ + half4 gbuffer0 : SV_Target0; + half4 gbuffer3 : SV_Target1; +}; + +CombinerOutput frag_gbuffer_combine(v2f_img i) +{ + half ao = tex2D(_OcclusionTexture, i.uv).r; + CombinerOutput o; + o.gbuffer0 = half4(0, 0, 0, ao); + o.gbuffer3 = half4((half3)EncodeAO(ao), 0); + return o; +} + +#else + +fixed4 frag_gbuffer_combine(v2f_img i) : SV_Target0 +{ + return 0; +} + +#endif + +// Debug blit +half4 frag_blit_ao(v2f_multitex i) : SV_Target +{ + half4 src = tex2D(_MainTex, i.uv0); + half ao = tex2D(_OcclusionTexture, i.uv1).r; + return half4(CombineOcclusion(1, ao), src.a); +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Resources/AmbientOcclusion.cginc.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Resources/AmbientOcclusion.cginc.meta new file mode 100644 index 0000000..81f16c6 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Resources/AmbientOcclusion.cginc.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 7bbc8f354c22e447dbd9deb502530d91 +timeCreated: 1463553768 +licenseType: Store +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Resources/AmbientOcclusion.shader b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Resources/AmbientOcclusion.shader new file mode 100644 index 0000000..bd330a2 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Resources/AmbientOcclusion.shader @@ -0,0 +1,129 @@ +Shader "Hidden/Image Effects/Cinematic/AmbientOcclusion" +{ + Properties + { + _MainTex("", 2D) = ""{} + _OcclusionTexture("", 2D) = ""{} + } + SubShader + { + // 0: Occlusion estimation with CameraDepthTexture + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #define SOURCE_DEPTH 1 + #include "AmbientOcclusion.cginc" + #pragma vertex vert_img + #pragma fragment frag_ao + #pragma target 3.0 + ENDCG + } + // 1: Occlusion estimation with CameraDepthNormalsTexture + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #define SOURCE_DEPTHNORMALS 1 + #include "AmbientOcclusion.cginc" + #pragma vertex vert_img + #pragma fragment frag_ao + #pragma target 3.0 + ENDCG + } + // 2: Occlusion estimation with G-Buffer + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #define SOURCE_GBUFFER 1 + #include "AmbientOcclusion.cginc" + #pragma vertex vert_img + #pragma fragment frag_ao + #pragma target 3.0 + ENDCG + } + // 3: Noise reduction (first pass) with CameraDepthNormalsTexture + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #define SOURCE_DEPTHNORMALS 1 + #include "AmbientOcclusion.cginc" + #pragma vertex vert_img + #pragma fragment frag_blur1 + #pragma target 3.0 + ENDCG + } + // 4: Noise reduction (first pass) with G Buffer + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #define SOURCE_GBUFFER 1 + #include "AmbientOcclusion.cginc" + #pragma vertex vert_img + #pragma fragment frag_blur1 + #pragma target 3.0 + ENDCG + } + // 5: Noise reduction (second pass) with CameraDepthNormalsTexture + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #define SOURCE_DEPTHNORMALS 1 + #include "AmbientOcclusion.cginc" + #pragma vertex vert_img + #pragma fragment frag_blur2 + #pragma target 3.0 + ENDCG + } + // 6: Noise reduction (second pass) with G Buffer + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #define SOURCE_GBUFFER 1 + #include "AmbientOcclusion.cginc" + #pragma vertex vert_img + #pragma fragment frag_blur2 + #pragma target 3.0 + ENDCG + } + // 7: Occlusion combiner + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #include "AmbientOcclusion.cginc" + #pragma vertex vert_multitex + #pragma fragment frag_combine + #pragma target 3.0 + ENDCG + } + // 8: Occlusion combiner for the ambient-only mode + Pass + { + Blend Zero OneMinusSrcColor, Zero OneMinusSrcAlpha + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #include "AmbientOcclusion.cginc" + #pragma vertex vert_gbuffer + #pragma fragment frag_gbuffer_combine + #pragma target 3.0 + ENDCG + } + // 9: Debug blit + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #include "AmbientOcclusion.cginc" + #pragma vertex vert_multitex + #pragma fragment frag_blit_ao + #pragma target 3.0 + ENDCG + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Resources/AmbientOcclusion.shader.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Resources/AmbientOcclusion.shader.meta new file mode 100644 index 0000000..f4022b7 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AmbientOcclusion/Resources/AmbientOcclusion.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 65e203e5acda447acbf9dc1ef78c4a39 +timeCreated: 1457327141 +licenseType: Store +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing.meta new file mode 100644 index 0000000..1139bce --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 4b15f777774297b4f91455d3353a0c40 +folderAsset: yes +timeCreated: 1454589502 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/AntiAliasing.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/AntiAliasing.cs new file mode 100644 index 0000000..71c093c --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/AntiAliasing.cs @@ -0,0 +1,90 @@ +using UnityEngine; + +namespace UnityStandardAssets.CinematicEffects +{ + [ExecuteInEditMode] + [RequireComponent(typeof(Camera))] + [AddComponentMenu("Image Effects/Anti-aliasing")] +#if UNITY_5_4_OR_NEWER + [ImageEffectAllowedInSceneView] +#endif + public class AntiAliasing : MonoBehaviour + { + public enum Method + { + Smaa, + Fxaa + } + + [SerializeField] + private SMAA m_SMAA = new SMAA(); + + [SerializeField] + private FXAA m_FXAA = new FXAA(); + + [SerializeField, HideInInspector] + private int m_Method = (int)Method.Smaa; + public int method + { + get { return m_Method; } + + set + { + if (m_Method == value) + return; + + m_Method = value; + } + } + + public IAntiAliasing current + { + get + { + if (method == (int)Method.Smaa) + return m_SMAA; + else + return m_FXAA; + } + } + + private Camera m_Camera; + public Camera cameraComponent + { + get + { + if (m_Camera == null) + m_Camera = GetComponent(); + + return m_Camera; + } + } + + private void OnEnable() + { + m_SMAA.OnEnable(this); + m_FXAA.OnEnable(this); + } + + private void OnDisable() + { + m_SMAA.OnDisable(); + m_FXAA.OnDisable(); + } + + private void OnPreCull() + { + current.OnPreCull(cameraComponent); + } + + private void OnPostRender() + { + current.OnPostRender(cameraComponent); + } + + private void OnRenderImage(RenderTexture source, RenderTexture destination) + { + current.OnRenderImage(cameraComponent, source, destination); + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/AntiAliasing.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/AntiAliasing.cs.meta new file mode 100644 index 0000000..ad964f3 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/AntiAliasing.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: fdc35e0180670ab4e8d2f9439137791f +timeCreated: 1454589503 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/Editor.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/Editor.meta new file mode 100644 index 0000000..e6a1c7a --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/Editor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 738f82ccf57b5974cb672f8032c72169 +folderAsset: yes +timeCreated: 1454595975 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/Editor/AntiAliasingEditor.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/Editor/AntiAliasingEditor.cs new file mode 100644 index 0000000..aafe0e3 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/Editor/AntiAliasingEditor.cs @@ -0,0 +1,64 @@ +using System; +using UnityEditor; + +namespace UnityStandardAssets.CinematicEffects +{ + [CustomEditor(typeof(AntiAliasing))] + public class AntiAliasingEditor : Editor + { + private string[] methodNames = + { + "Subpixel Morphological Anti-aliasing", + "Fast Approximate Anti-aliasing" + }; + + private int m_SelectedMethod; + + private SMAAEditor m_SMAAEditor = new SMAAEditor(); + private FXAAEditor m_FXAAEditor = new FXAAEditor(); + + IAntiAliasingEditor m_AntiAliasingEditor; + + private void OnEnable() + { + m_SMAAEditor.OnEnable(serializedObject, "m_SMAA"); + m_FXAAEditor.OnEnable(serializedObject, "m_FXAA"); + } + + public override void OnInspectorGUI() + { + var antiAliasingTarget = (AntiAliasing)target; + + m_SelectedMethod = antiAliasingTarget.method; + + EditorGUI.BeginChangeCheck(); + m_SelectedMethod = EditorGUILayout.Popup("Method", m_SelectedMethod, methodNames); + + bool dirty = false; + + if (EditorGUI.EndChangeCheck()) + { + if (m_SelectedMethod < 0) + m_SelectedMethod = 0; + else if (m_SelectedMethod > 1) + m_SelectedMethod = 1; + + antiAliasingTarget.method = m_SelectedMethod; + dirty = true; + } + + if (m_SelectedMethod == 0) + m_AntiAliasingEditor = m_SMAAEditor; + else + m_AntiAliasingEditor = m_FXAAEditor; + + dirty |= m_AntiAliasingEditor.OnInspectorGUI(antiAliasingTarget.current); + + if (dirty) + { + EditorUtility.SetDirty(antiAliasingTarget); + serializedObject.ApplyModifiedProperties(); + } + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/Editor/AntiAliasingEditor.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/Editor/AntiAliasingEditor.cs.meta new file mode 100644 index 0000000..1b65d6f --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/Editor/AntiAliasingEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 6bd9375ab74a65448b556b0452e8c6af +timeCreated: 1454593885 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/Editor/IAntiAliasingEditor.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/Editor/IAntiAliasingEditor.cs new file mode 100644 index 0000000..fbc262b --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/Editor/IAntiAliasingEditor.cs @@ -0,0 +1,10 @@ +using UnityEditor; + +namespace UnityStandardAssets.CinematicEffects +{ + public interface IAntiAliasingEditor + { + void OnEnable(SerializedObject serializedObject, string path); + bool OnInspectorGUI(IAntiAliasing target); + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/Editor/IAntiAliasingEditor.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/Editor/IAntiAliasingEditor.cs.meta new file mode 100644 index 0000000..e3af631 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/Editor/IAntiAliasingEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 015ee83e537e9e4438f403e2149c69ae +timeCreated: 1454595240 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA.meta new file mode 100644 index 0000000..51a1389 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 7629f5693f26f34448aa9c713d257e26 +folderAsset: yes +timeCreated: 1453733554 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Editor.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Editor.meta new file mode 100644 index 0000000..64e44f1 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Editor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 880813d23951c624d9d5c3e6d2a4e93c +folderAsset: yes +timeCreated: 1454331861 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Editor/FXAAEditor.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Editor/FXAAEditor.cs new file mode 100644 index 0000000..cfeb868 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Editor/FXAAEditor.cs @@ -0,0 +1,57 @@ +using UnityEditor; + +namespace UnityStandardAssets.CinematicEffects +{ + public class FXAAEditor : IAntiAliasingEditor + { + private string[] presetNames = + { + "Extreme performance", + "Performance", + "Default", + "Quality", + "Extreme quality" + }; + + + public void OnEnable(SerializedObject serializedObject, string path) + { + } + + public bool OnInspectorGUI(IAntiAliasing target) + { + var fxaaTarget = (FXAA)target; + + if (!fxaaTarget.validSourceFormat) + EditorGUILayout.HelpBox("FXAA should be used at the end of the post-processing stack after conversion to LDR (after Tonemapping) to maximize quality and avoid artifacts.", MessageType.Warning); + + int selectedPreset = 2; + + if (fxaaTarget.preset.Equals(FXAA.Preset.extremePerformancePreset)) + selectedPreset = 0; + else if (fxaaTarget.preset.Equals(FXAA.Preset.performancePreset)) + selectedPreset = 1; + else if (fxaaTarget.preset.Equals(FXAA.Preset.defaultPreset)) + selectedPreset = 2; + else if (fxaaTarget.preset.Equals(FXAA.Preset.qualityPreset)) + selectedPreset = 3; + else if (fxaaTarget.preset.Equals(FXAA.Preset.extremeQualityPreset)) + selectedPreset = 4; + + EditorGUI.BeginChangeCheck(); + selectedPreset = EditorGUILayout.Popup("Preset", selectedPreset, presetNames); + + if (EditorGUI.EndChangeCheck()) + { + if (selectedPreset < 0) + selectedPreset = 0; + else if (selectedPreset > 4) + selectedPreset = 4; + + fxaaTarget.preset = FXAA.availablePresets[selectedPreset]; + return true; + } + return false; + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Editor/FXAAEditor.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Editor/FXAAEditor.cs.meta new file mode 100644 index 0000000..26b7b2a --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Editor/FXAAEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 60bfb637c85e3e04ea76962349fee327 +timeCreated: 1454331861 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/FXAA.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/FXAA.cs new file mode 100644 index 0000000..8e5a29c --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/FXAA.cs @@ -0,0 +1,255 @@ +using UnityEngine; +using System; + +using Object = UnityEngine.Object; + +namespace UnityStandardAssets.CinematicEffects +{ + [Serializable] + public class FXAA : IAntiAliasing + { + private Shader m_Shader; + private Shader shader + { + get + { + if (m_Shader == null) + m_Shader = Shader.Find("Hidden/Fast Approximate Anti-aliasing"); + + return m_Shader; + } + } + + private Material m_Material; + public Material material + { + get + { + if (m_Material == null) + m_Material = ImageEffectHelper.CheckShaderAndCreateMaterial(shader); + + return m_Material; + } + } + + [Serializable] + public struct QualitySettings + { + [Tooltip("The amount of desired sub-pixel aliasing removal. Effects the sharpeness of the output.")] + [Range(0.0f, 1.0f)] + public float subpixelAliasingRemovalAmount; + + [Tooltip("The minimum amount of local contrast required to qualify a region as containing an edge.")] + [Range(0.063f, 0.333f)] + public float edgeDetectionThreshold; + + [Tooltip("Local contrast adaptation value to disallow the algorithm from executing on the darker regions.")] + [Range(0.0f, 0.0833f)] + public float minimumRequiredLuminance; + } + + [Serializable] + public struct ConsoleSettings + { + [Tooltip("The amount of spread applied to the sampling coordinates while sampling for subpixel information.")] + [Range(0.33f, 0.5f)] + public float subpixelSpreadAmount; + + [Tooltip("This value dictates how sharp the edges in the image are kept; a higher value implies sharper edges.")] + [Range(2.0f, 8.0f)] + public float edgeSharpnessAmount; + + [Tooltip("The minimum amount of local contrast required to qualify a region as containing an edge.")] + [Range(0.125f, 0.25f)] + public float edgeDetectionThreshold; + + [Tooltip("Local contrast adaptation value to disallow the algorithm from executing on the darker regions.")] + [Range(0.04f, 0.06f)] + public float minimumRequiredLuminance; + } + + [Serializable] + public struct Preset + { + [AttributeUsage(AttributeTargets.Field)] + public class LayoutAttribute : PropertyAttribute + {} + + [Layout] + public QualitySettings qualitySettings; + + [Layout] + public ConsoleSettings consoleSettings; + + private static readonly Preset s_ExtremePerformance = new Preset + { + qualitySettings = new QualitySettings + { + subpixelAliasingRemovalAmount = 0.0f, + edgeDetectionThreshold = 0.333f, + minimumRequiredLuminance = 0.0833f + }, + + consoleSettings = new ConsoleSettings + { + subpixelSpreadAmount = 0.33f, + edgeSharpnessAmount = 8.0f, + edgeDetectionThreshold = 0.25f, + minimumRequiredLuminance = 0.06f + } + }; + + private static readonly Preset s_Performance = new Preset + { + qualitySettings = new QualitySettings + { + subpixelAliasingRemovalAmount = 0.25f, + edgeDetectionThreshold = 0.25f, + minimumRequiredLuminance = 0.0833f + }, + + consoleSettings = new ConsoleSettings + { + subpixelSpreadAmount = 0.33f, + edgeSharpnessAmount = 8.0f, + edgeDetectionThreshold = 0.125f, + minimumRequiredLuminance = 0.06f + } + }; + + private static readonly Preset s_Default = new Preset + { + qualitySettings = new QualitySettings + { + subpixelAliasingRemovalAmount = 0.75f, + edgeDetectionThreshold = 0.166f, + minimumRequiredLuminance = 0.0833f + }, + + consoleSettings = new ConsoleSettings + { + subpixelSpreadAmount = 0.5f, + edgeSharpnessAmount = 8.0f, + edgeDetectionThreshold = 0.125f, + minimumRequiredLuminance = 0.05f + } + }; + + private static readonly Preset s_Quality = new Preset + { + qualitySettings = new QualitySettings + { + subpixelAliasingRemovalAmount = 1.0f, + edgeDetectionThreshold = 0.125f, + minimumRequiredLuminance = 0.0625f + }, + + consoleSettings = new ConsoleSettings + { + subpixelSpreadAmount = 0.5f, + edgeSharpnessAmount = 4.0f, + edgeDetectionThreshold = 0.125f, + minimumRequiredLuminance = 0.04f + } + }; + + private static readonly Preset s_ExtremeQuality = new Preset + { + qualitySettings = new QualitySettings + { + subpixelAliasingRemovalAmount = 1.0f, + edgeDetectionThreshold = 0.063f, + minimumRequiredLuminance = 0.0312f + }, + + consoleSettings = new ConsoleSettings + { + subpixelSpreadAmount = 0.5f, + edgeSharpnessAmount = 2.0f, + edgeDetectionThreshold = 0.125f, + minimumRequiredLuminance = 0.04f + } + }; + + public static Preset extremePerformancePreset + { + get { return s_ExtremePerformance; } + } + + public static Preset performancePreset + { + get { return s_Performance; } + } + + public static Preset defaultPreset + { + get { return s_Default; } + } + + public static Preset qualityPreset + { + get { return s_Quality; } + } + + public static Preset extremeQualityPreset + { + get { return s_ExtremeQuality; } + } + } + + [SerializeField, HideInInspector] + public Preset preset = Preset.defaultPreset; + + public static Preset[] availablePresets = + { + Preset.extremePerformancePreset, + Preset.performancePreset, + Preset.defaultPreset, + Preset.qualityPreset, + Preset.extremeQualityPreset + }; + + public bool validSourceFormat { get; private set; } + + public void OnEnable(AntiAliasing owner) + { + if (!ImageEffectHelper.IsSupported(shader, true, false, owner)) + owner.enabled = false; + } + + public void OnDisable() + { + if (m_Material != null) + Object.DestroyImmediate(m_Material); + } + + public void OnPreCull(Camera camera) + { + } + + public void OnPostRender(Camera camera) + { + } + + public void OnRenderImage(Camera camera, RenderTexture source, RenderTexture destination) + { +#if UNITY_EDITOR + validSourceFormat = true; + + if (source.format == RenderTextureFormat.ARGBHalf + || source.format == RenderTextureFormat.ARGBFloat + || source.format == RenderTextureFormat.ARGB2101010) + validSourceFormat = false; +#endif + + material.SetVector("_QualitySettings", new Vector3(preset.qualitySettings.subpixelAliasingRemovalAmount, + preset.qualitySettings.edgeDetectionThreshold, preset.qualitySettings.minimumRequiredLuminance)); + + material.SetVector("_ConsoleSettings", new Vector4(preset.consoleSettings.subpixelSpreadAmount, + preset.consoleSettings.edgeSharpnessAmount, preset.consoleSettings.edgeDetectionThreshold, + preset.consoleSettings.minimumRequiredLuminance)); + + Graphics.Blit(source, destination, material, 0); + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/FXAA.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/FXAA.cs.meta new file mode 100644 index 0000000..e9f0eab --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/FXAA.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: 8ca0fe85db4ef594fb0771b250c00e23 +timeCreated: 1453738651 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: + - shader: {fileID: 4800000, guid: 3eaaee164ee0fed4d9a0bbe8434805a6, type: 3} + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Resources.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Resources.meta new file mode 100644 index 0000000..fb2603e --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Resources.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 3f7cc4a9005f5f846957997471c28f2b +folderAsset: yes +timeCreated: 1455022968 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Resources/FXAA.shader b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Resources/FXAA.shader new file mode 100644 index 0000000..69a1ba3 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Resources/FXAA.shader @@ -0,0 +1,104 @@ +Shader "Hidden/Fast Approximate Anti-aliasing" +{ + Properties + { + _MainTex ("Texture", 2D) = "white" {} + } + + CGINCLUDE + #pragma fragmentoption ARB_precision_hint_fastest + + #if defined(SHADER_API_PS3) + #define FXAA_PS3 1 + + // Shaves off 2 cycles from the shader + #define FXAA_EARLY_EXIT 0 + #elif defined(SHADER_API_XBOX360) + #define FXAA_360 1 + + // Shaves off 10ms from the shader's execution time + #define FXAA_EARLY_EXIT 1 + #else + #define FXAA_PC 1 + #endif + + #define FXAA_HLSL_3 1 + #define FXAA_QUALITY__PRESET 39 + + #define FXAA_GREEN_AS_LUMA 1 + + #pragma target 3.0 + #include "FXAA3.cginc" + + float4 _MainTex_TexelSize; + + float3 _QualitySettings; + float4 _ConsoleSettings; + + struct Input + { + float4 position : POSITION; + float2 uv : TEXCOORD0; + }; + + struct Varying + { + float4 position : SV_POSITION; + float2 uv : TEXCOORD0; + }; + + Varying vertex(Input input) + { + Varying output; + + output.position = mul(UNITY_MATRIX_MVP, input.position); + output.uv = input.uv; + + return output; + } + + sampler2D _MainTex; + + float calculateLuma(float4 color) + { + return color.g * 1.963211 + color.r; + } + + fixed4 fragment(Varying input) : SV_Target + { + const float4 consoleUV = input.uv.xyxy + .5 * float4(-_MainTex_TexelSize.xy, _MainTex_TexelSize.xy); + const float4 consoleSubpixelFrame = _ConsoleSettings.x * float4(-1., -1., 1., 1.) * + _MainTex_TexelSize.xyxy; + + const float4 consoleSubpixelFramePS3 = float4(-2., -2., 2., 2.) * _MainTex_TexelSize.xyxy; + const float4 consoleSubpixelFrameXBOX = float4(8., 8., -4., -4.) * _MainTex_TexelSize.xyxy; + + #if defined(SHADER_API_XBOX360) + const float4 consoleConstants = float4(1., -1., .25, -.25); + #else + const float4 consoleConstants = float4(0., 0., 0., 0.); + #endif + + return FxaaPixelShader(input.uv, consoleUV, _MainTex, _MainTex, _MainTex, _MainTex_TexelSize.xy, + consoleSubpixelFrame, consoleSubpixelFramePS3, consoleSubpixelFrameXBOX, + _QualitySettings.x, _QualitySettings.y, _QualitySettings.z, _ConsoleSettings.y, _ConsoleSettings.z, + _ConsoleSettings.w, consoleConstants); + } + ENDCG + + SubShader + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + Pass + { + CGPROGRAM + #pragma vertex vertex + #pragma fragment fragment + + #include "UnityCG.cginc" + ENDCG + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Resources/FXAA.shader.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Resources/FXAA.shader.meta new file mode 100644 index 0000000..e1523d1 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Resources/FXAA.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 3eaaee164ee0fed4d9a0bbe8434805a6 +timeCreated: 1453736553 +licenseType: Store +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Resources/FXAA3.cginc b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Resources/FXAA3.cginc new file mode 100644 index 0000000..d5ee34b --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Resources/FXAA3.cginc @@ -0,0 +1,2047 @@ +/*============================================================================ + + + NVIDIA FXAA 3.11 by TIMOTHY LOTTES + + +------------------------------------------------------------------------------ +COPYRIGHT (C) 2010, 2011 NVIDIA CORPORATION. ALL RIGHTS RESERVED. +------------------------------------------------------------------------------ +TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THIS SOFTWARE IS PROVIDED +*AS IS* AND NVIDIA AND ITS SUPPLIERS DISCLAIM ALL WARRANTIES, EITHER EXPRESS +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL NVIDIA +OR ITS SUPPLIERS BE LIABLE FOR ANY SPECIAL, INCIDENTAL, INDIRECT, OR +CONSEQUENTIAL DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR +LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, +OR ANY OTHER PECUNIARY LOSS) ARISING OUT OF THE USE OF OR INABILITY TO USE +THIS SOFTWARE, EVEN IF NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + +------------------------------------------------------------------------------ + INTEGRATION CHECKLIST +------------------------------------------------------------------------------ +(1.) +In the shader source, setup defines for the desired configuration. +When providing multiple shaders (for different presets), +simply setup the defines differently in multiple files. +Example, + + #define FXAA_PC 1 + #define FXAA_HLSL_5 1 + #define FXAA_QUALITY__PRESET 12 + +Or, + + #define FXAA_360 1 + +Or, + + #define FXAA_PS3 1 + +Etc. + +(2.) +Then include this file, + + #include "Fxaa3_11.h" + +(3.) +Then call the FXAA pixel shader from within your desired shader. +Look at the FXAA Quality FxaaPixelShader() for docs on inputs. +As for FXAA 3.11 all inputs for all shaders are the same +to enable easy porting between platforms. + + return FxaaPixelShader(...); + +(4.) +Insure pass prior to FXAA outputs RGBL (see next section). +Or use, + + #define FXAA_GREEN_AS_LUMA 1 + +(5.) +Setup engine to provide the following constants +which are used in the FxaaPixelShader() inputs, + + FxaaFloat2 fxaaQualityRcpFrame, + FxaaFloat4 fxaaConsoleRcpFrameOpt, + FxaaFloat4 fxaaConsoleRcpFrameOpt2, + FxaaFloat4 fxaaConsole360RcpFrameOpt2, + FxaaFloat fxaaQualitySubpix, + FxaaFloat fxaaQualityEdgeThreshold, + FxaaFloat fxaaQualityEdgeThresholdMin, + FxaaFloat fxaaConsoleEdgeSharpness, + FxaaFloat fxaaConsoleEdgeThreshold, + FxaaFloat fxaaConsoleEdgeThresholdMin, + FxaaFloat4 fxaaConsole360ConstDir + +Look at the FXAA Quality FxaaPixelShader() for docs on inputs. + +(6.) +Have FXAA vertex shader run as a full screen triangle, +and output "pos" and "fxaaConsolePosPos" +such that inputs in the pixel shader provide, + + // {xy} = center of pixel + FxaaFloat2 pos, + + // {xy__} = upper left of pixel + // {__zw} = lower right of pixel + FxaaFloat4 fxaaConsolePosPos, + +(7.) +Insure the texture sampler(s) used by FXAA are set to bilinear filtering. + + +------------------------------------------------------------------------------ + INTEGRATION - RGBL AND COLORSPACE +------------------------------------------------------------------------------ +FXAA3 requires RGBL as input unless the following is set, + + #define FXAA_GREEN_AS_LUMA 1 + +In which case the engine uses green in place of luma, +and requires RGB input is in a non-linear colorspace. + +RGB should be LDR (low dynamic range). +Specifically do FXAA after tonemapping. + +RGB data as returned by a texture fetch can be non-linear, +or linear when FXAA_GREEN_AS_LUMA is not set. +Note an "sRGB format" texture counts as linear, +because the result of a texture fetch is linear data. +Regular "RGBA8" textures in the sRGB colorspace are non-linear. + +If FXAA_GREEN_AS_LUMA is not set, +luma must be stored in the alpha channel prior to running FXAA. +This luma should be in a perceptual space (could be gamma 2.0). +Example pass before FXAA where output is gamma 2.0 encoded, + + color.rgb = ToneMap(color.rgb); // linear color output + color.rgb = sqrt(color.rgb); // gamma 2.0 color output + return color; + +To use FXAA, + + color.rgb = ToneMap(color.rgb); // linear color output + color.rgb = sqrt(color.rgb); // gamma 2.0 color output + color.a = dot(color.rgb, FxaaFloat3(0.299, 0.587, 0.114)); // compute luma + return color; + +Another example where output is linear encoded, +say for instance writing to an sRGB formated render target, +where the render target does the conversion back to sRGB after blending, + + color.rgb = ToneMap(color.rgb); // linear color output + return color; + +To use FXAA, + + color.rgb = ToneMap(color.rgb); // linear color output + color.a = sqrt(dot(color.rgb, FxaaFloat3(0.299, 0.587, 0.114))); // compute luma + return color; + +Getting luma correct is required for the algorithm to work correctly. + + +------------------------------------------------------------------------------ + BEING LINEARLY CORRECT? +------------------------------------------------------------------------------ +Applying FXAA to a framebuffer with linear RGB color will look worse. +This is very counter intuitive, but happends to be true in this case. +The reason is because dithering artifacts will be more visiable +in a linear colorspace. + + +------------------------------------------------------------------------------ + COMPLEX INTEGRATION +------------------------------------------------------------------------------ +Q. What if the engine is blending into RGB before wanting to run FXAA? + +A. In the last opaque pass prior to FXAA, + have the pass write out luma into alpha. + Then blend into RGB only. + FXAA should be able to run ok + assuming the blending pass did not any add aliasing. + This should be the common case for particles and common blending passes. + +A. Or use FXAA_GREEN_AS_LUMA. + +============================================================================*/ + +/*============================================================================ + + INTEGRATION KNOBS + +============================================================================*/ +// +// FXAA_PS3 and FXAA_360 choose the console algorithm (FXAA3 CONSOLE). +// FXAA_360_OPT is a prototype for the new optimized 360 version. +// +// 1 = Use API. +// 0 = Don't use API. +// +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_PS3 + #define FXAA_PS3 0 +#endif +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_360 + #define FXAA_360 0 +#endif +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_360_OPT + #define FXAA_360_OPT 0 +#endif +/*==========================================================================*/ +#ifndef FXAA_PC + // + // FXAA Quality + // The high quality PC algorithm. + // + #define FXAA_PC 0 +#endif +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_PC_CONSOLE + // + // The console algorithm for PC is included + // for developers targeting really low spec machines. + // Likely better to just run FXAA_PC, and use a really low preset. + // + #define FXAA_PC_CONSOLE 0 +#endif +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_GLSL_120 + #define FXAA_GLSL_120 0 +#endif +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_GLSL_130 + #define FXAA_GLSL_130 0 +#endif +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_HLSL_3 + #define FXAA_HLSL_3 0 +#endif +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_HLSL_4 + #define FXAA_HLSL_4 0 +#endif +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_HLSL_5 + #define FXAA_HLSL_5 0 +#endif +/*==========================================================================*/ +#ifndef FXAA_GREEN_AS_LUMA + // + // For those using non-linear color, + // and either not able to get luma in alpha, or not wanting to, + // this enables FXAA to run using green as a proxy for luma. + // So with this enabled, no need to pack luma in alpha. + // + // This will turn off AA on anything which lacks some amount of green. + // Pure red and blue or combination of only R and B, will get no AA. + // + // Might want to lower the settings for both, + // fxaaConsoleEdgeThresholdMin + // fxaaQualityEdgeThresholdMin + // In order to insure AA does not get turned off on colors + // which contain a minor amount of green. + // + // 1 = On. + // 0 = Off. + // + #define FXAA_GREEN_AS_LUMA 0 +#endif +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_EARLY_EXIT + // + // Controls algorithm's early exit path. + // On PS3 turning this ON adds 2 cycles to the shader. + // On 360 turning this OFF adds 10ths of a millisecond to the shader. + // Turning this off on console will result in a more blurry image. + // So this defaults to on. + // + // 1 = On. + // 0 = Off. + // + #define FXAA_EARLY_EXIT 1 +#endif +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_DISCARD + // + // Only valid for PC OpenGL currently. + // Probably will not work when FXAA_GREEN_AS_LUMA = 1. + // + // 1 = Use discard on pixels which don't need AA. + // For APIs which enable concurrent TEX+ROP from same surface. + // 0 = Return unchanged color on pixels which don't need AA. + // + #define FXAA_DISCARD 0 +#endif +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_FAST_PIXEL_OFFSET + // + // Used for GLSL 120 only. + // + // 1 = GL API supports fast pixel offsets + // 0 = do not use fast pixel offsets + // + #ifdef GL_EXT_gpu_shader4 + #define FXAA_FAST_PIXEL_OFFSET 1 + #endif + #ifdef GL_NV_gpu_shader5 + #define FXAA_FAST_PIXEL_OFFSET 1 + #endif + #ifdef GL_ARB_gpu_shader5 + #define FXAA_FAST_PIXEL_OFFSET 1 + #endif + #ifndef FXAA_FAST_PIXEL_OFFSET + #define FXAA_FAST_PIXEL_OFFSET 0 + #endif +#endif +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_GATHER4_ALPHA + // + // 1 = API supports gather4 on alpha channel. + // 0 = API does not support gather4 on alpha channel. + // + #if (FXAA_HLSL_5 == 1) + #define FXAA_GATHER4_ALPHA 1 + #endif + #ifdef GL_ARB_gpu_shader5 + #define FXAA_GATHER4_ALPHA 1 + #endif + #ifdef GL_NV_gpu_shader5 + #define FXAA_GATHER4_ALPHA 1 + #endif + #ifndef FXAA_GATHER4_ALPHA + #define FXAA_GATHER4_ALPHA 0 + #endif +#endif + +/*============================================================================ + FXAA CONSOLE PS3 - TUNING KNOBS +============================================================================*/ +#ifndef FXAA_CONSOLE__PS3_EDGE_SHARPNESS + // + // Consoles the sharpness of edges on PS3 only. + // Non-PS3 tuning is done with shader input. + // + // Due to the PS3 being ALU bound, + // there are only two safe values here: 4 and 8. + // These options use the shaders ability to a free *|/ by 2|4|8. + // + // 8.0 is sharper + // 4.0 is softer + // 2.0 is really soft (good for vector graphics inputs) + // + #if 1 + #define FXAA_CONSOLE__PS3_EDGE_SHARPNESS 8.0 + #endif + #if 0 + #define FXAA_CONSOLE__PS3_EDGE_SHARPNESS 4.0 + #endif + #if 0 + #define FXAA_CONSOLE__PS3_EDGE_SHARPNESS 2.0 + #endif +#endif +/*--------------------------------------------------------------------------*/ +#ifndef FXAA_CONSOLE__PS3_EDGE_THRESHOLD + // + // Only effects PS3. + // Non-PS3 tuning is done with shader input. + // + // The minimum amount of local contrast required to apply algorithm. + // The console setting has a different mapping than the quality setting. + // + // This only applies when FXAA_EARLY_EXIT is 1. + // + // Due to the PS3 being ALU bound, + // there are only two safe values here: 0.25 and 0.125. + // These options use the shaders ability to a free *|/ by 2|4|8. + // + // 0.125 leaves less aliasing, but is softer + // 0.25 leaves more aliasing, and is sharper + // + #if 1 + #define FXAA_CONSOLE__PS3_EDGE_THRESHOLD 0.125 + #else + #define FXAA_CONSOLE__PS3_EDGE_THRESHOLD 0.25 + #endif +#endif + +/*============================================================================ + FXAA QUALITY - TUNING KNOBS +------------------------------------------------------------------------------ +NOTE the other tuning knobs are now in the shader function inputs! +============================================================================*/ +#ifndef FXAA_QUALITY__PRESET + // + // Choose the quality preset. + // This needs to be compiled into the shader as it effects code. + // Best option to include multiple presets is to + // in each shader define the preset, then include this file. + // + // OPTIONS + // ----------------------------------------------------------------------- + // 10 to 15 - default medium dither (10=fastest, 15=highest quality) + // 20 to 29 - less dither, more expensive (20=fastest, 29=highest quality) + // 39 - no dither, very expensive + // + // NOTES + // ----------------------------------------------------------------------- + // 12 = slightly faster then FXAA 3.9 and higher edge quality (default) + // 13 = about same speed as FXAA 3.9 and better than 12 + // 23 = closest to FXAA 3.9 visually and performance wise + // _ = the lowest digit is directly related to performance + // _ = the highest digit is directly related to style + // + #define FXAA_QUALITY__PRESET 12 +#endif + + +/*============================================================================ + + FXAA QUALITY - PRESETS + +============================================================================*/ + +/*============================================================================ + FXAA QUALITY - MEDIUM DITHER PRESETS +============================================================================*/ +#if (FXAA_QUALITY__PRESET == 10) + #define FXAA_QUALITY__PS 3 + #define FXAA_QUALITY__P0 1.5 + #define FXAA_QUALITY__P1 3.0 + #define FXAA_QUALITY__P2 12.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 11) + #define FXAA_QUALITY__PS 4 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 3.0 + #define FXAA_QUALITY__P3 12.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 12) + #define FXAA_QUALITY__PS 5 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 4.0 + #define FXAA_QUALITY__P4 12.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 13) + #define FXAA_QUALITY__PS 6 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 4.0 + #define FXAA_QUALITY__P5 12.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 14) + #define FXAA_QUALITY__PS 7 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 4.0 + #define FXAA_QUALITY__P6 12.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 15) + #define FXAA_QUALITY__PS 8 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 2.0 + #define FXAA_QUALITY__P6 4.0 + #define FXAA_QUALITY__P7 12.0 +#endif + +/*============================================================================ + FXAA QUALITY - LOW DITHER PRESETS +============================================================================*/ +#if (FXAA_QUALITY__PRESET == 20) + #define FXAA_QUALITY__PS 3 + #define FXAA_QUALITY__P0 1.5 + #define FXAA_QUALITY__P1 2.0 + #define FXAA_QUALITY__P2 8.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 21) + #define FXAA_QUALITY__PS 4 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 8.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 22) + #define FXAA_QUALITY__PS 5 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 8.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 23) + #define FXAA_QUALITY__PS 6 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 8.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 24) + #define FXAA_QUALITY__PS 7 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 3.0 + #define FXAA_QUALITY__P6 8.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 25) + #define FXAA_QUALITY__PS 8 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 2.0 + #define FXAA_QUALITY__P6 4.0 + #define FXAA_QUALITY__P7 8.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 26) + #define FXAA_QUALITY__PS 9 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 2.0 + #define FXAA_QUALITY__P6 2.0 + #define FXAA_QUALITY__P7 4.0 + #define FXAA_QUALITY__P8 8.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 27) + #define FXAA_QUALITY__PS 10 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 2.0 + #define FXAA_QUALITY__P6 2.0 + #define FXAA_QUALITY__P7 2.0 + #define FXAA_QUALITY__P8 4.0 + #define FXAA_QUALITY__P9 8.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 28) + #define FXAA_QUALITY__PS 11 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 2.0 + #define FXAA_QUALITY__P6 2.0 + #define FXAA_QUALITY__P7 2.0 + #define FXAA_QUALITY__P8 2.0 + #define FXAA_QUALITY__P9 4.0 + #define FXAA_QUALITY__P10 8.0 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_QUALITY__PRESET == 29) + #define FXAA_QUALITY__PS 12 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 2.0 + #define FXAA_QUALITY__P6 2.0 + #define FXAA_QUALITY__P7 2.0 + #define FXAA_QUALITY__P8 2.0 + #define FXAA_QUALITY__P9 2.0 + #define FXAA_QUALITY__P10 4.0 + #define FXAA_QUALITY__P11 8.0 +#endif + +/*============================================================================ + FXAA QUALITY - EXTREME QUALITY +============================================================================*/ +#if (FXAA_QUALITY__PRESET == 39) + #define FXAA_QUALITY__PS 12 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.0 + #define FXAA_QUALITY__P2 1.0 + #define FXAA_QUALITY__P3 1.0 + #define FXAA_QUALITY__P4 1.0 + #define FXAA_QUALITY__P5 1.5 + #define FXAA_QUALITY__P6 2.0 + #define FXAA_QUALITY__P7 2.0 + #define FXAA_QUALITY__P8 2.0 + #define FXAA_QUALITY__P9 2.0 + #define FXAA_QUALITY__P10 4.0 + #define FXAA_QUALITY__P11 8.0 +#endif + + + +/*============================================================================ + + API PORTING + +============================================================================*/ +#if (FXAA_GLSL_120 == 1) || (FXAA_GLSL_130 == 1) + #define FxaaBool bool + #define FxaaDiscard discard + #define FxaaFloat float + #define FxaaFloat2 vec2 + #define FxaaFloat3 vec3 + #define FxaaFloat4 vec4 + #define FxaaHalf float + #define FxaaHalf2 vec2 + #define FxaaHalf3 vec3 + #define FxaaHalf4 vec4 + #define FxaaInt2 ivec2 + #define FxaaSat(x) clamp(x, 0.0, 1.0) + #define FxaaTex sampler2D +#else + #define FxaaBool bool + #define FxaaDiscard clip(-1) + #define FxaaFloat float + #define FxaaFloat2 float2 + #define FxaaFloat3 float3 + #define FxaaFloat4 float4 + #define FxaaHalf half + #define FxaaHalf2 half2 + #define FxaaHalf3 half3 + #define FxaaHalf4 half4 + #define FxaaSat(x) saturate(x) +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_GLSL_120 == 1) + // Requires, + // #version 120 + // And at least, + // #extension GL_EXT_gpu_shader4 : enable + // (or set FXAA_FAST_PIXEL_OFFSET 1 to work like DX9) + #define FxaaTexTop(t, p) texture2DLod(t, p, 0.0) + #if (FXAA_FAST_PIXEL_OFFSET == 1) + #define FxaaTexOff(t, p, o, r) texture2DLodOffset(t, p, 0.0, o) + #else + #define FxaaTexOff(t, p, o, r) texture2DLod(t, p + (o * r), 0.0) + #endif + #if (FXAA_GATHER4_ALPHA == 1) + // use #extension GL_ARB_gpu_shader5 : enable + #define FxaaTexAlpha4(t, p) textureGather(t, p, 3) + #define FxaaTexOffAlpha4(t, p, o) textureGatherOffset(t, p, o, 3) + #define FxaaTexGreen4(t, p) textureGather(t, p, 1) + #define FxaaTexOffGreen4(t, p, o) textureGatherOffset(t, p, o, 1) + #endif +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_GLSL_130 == 1) + // Requires "#version 130" or better + #define FxaaTexTop(t, p) textureLod(t, p, 0.0) + #define FxaaTexOff(t, p, o, r) textureLodOffset(t, p, 0.0, o) + #if (FXAA_GATHER4_ALPHA == 1) + // use #extension GL_ARB_gpu_shader5 : enable + #define FxaaTexAlpha4(t, p) textureGather(t, p, 3) + #define FxaaTexOffAlpha4(t, p, o) textureGatherOffset(t, p, o, 3) + #define FxaaTexGreen4(t, p) textureGather(t, p, 1) + #define FxaaTexOffGreen4(t, p, o) textureGatherOffset(t, p, o, 1) + #endif +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_HLSL_3 == 1) || (FXAA_360 == 1) || (FXAA_PS3 == 1) + #define FxaaInt2 float2 + #define FxaaTex sampler2D + #define FxaaTexTop(t, p) tex2Dlod(t, float4(p, 0.0, 0.0)) + #define FxaaTexOff(t, p, o, r) tex2Dlod(t, float4(p + (o * r), 0, 0)) +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_HLSL_4 == 1) + #define FxaaInt2 int2 + struct FxaaTex { SamplerState smpl; Texture2D tex; }; + #define FxaaTexTop(t, p) t.tex.SampleLevel(t.smpl, p, 0.0) + #define FxaaTexOff(t, p, o, r) t.tex.SampleLevel(t.smpl, p, 0.0, o) +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_HLSL_5 == 1) + #define FxaaInt2 int2 + struct FxaaTex { SamplerState smpl; Texture2D tex; }; + #define FxaaTexTop(t, p) t.tex.SampleLevel(t.smpl, p, 0.0) + #define FxaaTexOff(t, p, o, r) t.tex.SampleLevel(t.smpl, p, 0.0, o) + #define FxaaTexAlpha4(t, p) t.tex.GatherAlpha(t.smpl, p) + #define FxaaTexOffAlpha4(t, p, o) t.tex.GatherAlpha(t.smpl, p, o) + #define FxaaTexGreen4(t, p) t.tex.GatherGreen(t.smpl, p) + #define FxaaTexOffGreen4(t, p, o) t.tex.GatherGreen(t.smpl, p, o) +#endif + + +/*============================================================================ + GREEN AS LUMA OPTION SUPPORT FUNCTION +============================================================================*/ +#if (FXAA_GREEN_AS_LUMA == 0) + FxaaFloat FxaaLuma(FxaaFloat4 rgba) { return rgba.w; } +#else + FxaaFloat FxaaLuma(FxaaFloat4 rgba) { return rgba.y; } +#endif + + + + +/*============================================================================ + + FXAA3 QUALITY - PC + +============================================================================*/ +#if (FXAA_PC == 1) +/*--------------------------------------------------------------------------*/ +FxaaFloat4 FxaaPixelShader( + // + // Use noperspective interpolation here (turn off perspective interpolation). + // {xy} = center of pixel + FxaaFloat2 pos, + // + // Used only for FXAA Console, and not used on the 360 version. + // Use noperspective interpolation here (turn off perspective interpolation). + // {xy__} = upper left of pixel + // {__zw} = lower right of pixel + FxaaFloat4 fxaaConsolePosPos, + // + // Input color texture. + // {rgb_} = color in linear or perceptual color space + // if (FXAA_GREEN_AS_LUMA == 0) + // {___a} = luma in perceptual color space (not linear) + FxaaTex tex, + // + // Only used on the optimized 360 version of FXAA Console. + // For everything but 360, just use the same input here as for "tex". + // For 360, same texture, just alias with a 2nd sampler. + // This sampler needs to have an exponent bias of -1. + FxaaTex fxaaConsole360TexExpBiasNegOne, + // + // Only used on the optimized 360 version of FXAA Console. + // For everything but 360, just use the same input here as for "tex". + // For 360, same texture, just alias with a 3nd sampler. + // This sampler needs to have an exponent bias of -2. + FxaaTex fxaaConsole360TexExpBiasNegTwo, + // + // Only used on FXAA Quality. + // This must be from a constant/uniform. + // {x_} = 1.0/screenWidthInPixels + // {_y} = 1.0/screenHeightInPixels + FxaaFloat2 fxaaQualityRcpFrame, + // + // Only used on FXAA Console. + // This must be from a constant/uniform. + // This effects sub-pixel AA quality and inversely sharpness. + // Where N ranges between, + // N = 0.50 (default) + // N = 0.33 (sharper) + // {x___} = -N/screenWidthInPixels + // {_y__} = -N/screenHeightInPixels + // {__z_} = N/screenWidthInPixels + // {___w} = N/screenHeightInPixels + FxaaFloat4 fxaaConsoleRcpFrameOpt, + // + // Only used on FXAA Console. + // Not used on 360, but used on PS3 and PC. + // This must be from a constant/uniform. + // {x___} = -2.0/screenWidthInPixels + // {_y__} = -2.0/screenHeightInPixels + // {__z_} = 2.0/screenWidthInPixels + // {___w} = 2.0/screenHeightInPixels + FxaaFloat4 fxaaConsoleRcpFrameOpt2, + // + // Only used on FXAA Console. + // Only used on 360 in place of fxaaConsoleRcpFrameOpt2. + // This must be from a constant/uniform. + // {x___} = 8.0/screenWidthInPixels + // {_y__} = 8.0/screenHeightInPixels + // {__z_} = -4.0/screenWidthInPixels + // {___w} = -4.0/screenHeightInPixels + FxaaFloat4 fxaaConsole360RcpFrameOpt2, + // + // Only used on FXAA Quality. + // This used to be the FXAA_QUALITY__SUBPIX define. + // It is here now to allow easier tuning. + // Choose the amount of sub-pixel aliasing removal. + // This can effect sharpness. + // 1.00 - upper limit (softer) + // 0.75 - default amount of filtering + // 0.50 - lower limit (sharper, less sub-pixel aliasing removal) + // 0.25 - almost off + // 0.00 - completely off + FxaaFloat fxaaQualitySubpix, + // + // Only used on FXAA Quality. + // This used to be the FXAA_QUALITY__EDGE_THRESHOLD define. + // It is here now to allow easier tuning. + // The minimum amount of local contrast required to apply algorithm. + // 0.333 - too little (faster) + // 0.250 - low quality + // 0.166 - default + // 0.125 - high quality + // 0.063 - overkill (slower) + FxaaFloat fxaaQualityEdgeThreshold, + // + // Only used on FXAA Quality. + // This used to be the FXAA_QUALITY__EDGE_THRESHOLD_MIN define. + // It is here now to allow easier tuning. + // Trims the algorithm from processing darks. + // 0.0833 - upper limit (default, the start of visible unfiltered edges) + // 0.0625 - high quality (faster) + // 0.0312 - visible limit (slower) + // Special notes when using FXAA_GREEN_AS_LUMA, + // Likely want to set this to zero. + // As colors that are mostly not-green + // will appear very dark in the green channel! + // Tune by looking at mostly non-green content, + // then start at zero and increase until aliasing is a problem. + FxaaFloat fxaaQualityEdgeThresholdMin, + // + // Only used on FXAA Console. + // This used to be the FXAA_CONSOLE__EDGE_SHARPNESS define. + // It is here now to allow easier tuning. + // This does not effect PS3, as this needs to be compiled in. + // Use FXAA_CONSOLE__PS3_EDGE_SHARPNESS for PS3. + // Due to the PS3 being ALU bound, + // there are only three safe values here: 2 and 4 and 8. + // These options use the shaders ability to a free *|/ by 2|4|8. + // For all other platforms can be a non-power of two. + // 8.0 is sharper (default!!!) + // 4.0 is softer + // 2.0 is really soft (good only for vector graphics inputs) + FxaaFloat fxaaConsoleEdgeSharpness, + // + // Only used on FXAA Console. + // This used to be the FXAA_CONSOLE__EDGE_THRESHOLD define. + // It is here now to allow easier tuning. + // This does not effect PS3, as this needs to be compiled in. + // Use FXAA_CONSOLE__PS3_EDGE_THRESHOLD for PS3. + // Due to the PS3 being ALU bound, + // there are only two safe values here: 1/4 and 1/8. + // These options use the shaders ability to a free *|/ by 2|4|8. + // The console setting has a different mapping than the quality setting. + // Other platforms can use other values. + // 0.125 leaves less aliasing, but is softer (default!!!) + // 0.25 leaves more aliasing, and is sharper + FxaaFloat fxaaConsoleEdgeThreshold, + // + // Only used on FXAA Console. + // This used to be the FXAA_CONSOLE__EDGE_THRESHOLD_MIN define. + // It is here now to allow easier tuning. + // Trims the algorithm from processing darks. + // The console setting has a different mapping than the quality setting. + // This only applies when FXAA_EARLY_EXIT is 1. + // This does not apply to PS3, + // PS3 was simplified to avoid more shader instructions. + // 0.06 - faster but more aliasing in darks + // 0.05 - default + // 0.04 - slower and less aliasing in darks + // Special notes when using FXAA_GREEN_AS_LUMA, + // Likely want to set this to zero. + // As colors that are mostly not-green + // will appear very dark in the green channel! + // Tune by looking at mostly non-green content, + // then start at zero and increase until aliasing is a problem. + FxaaFloat fxaaConsoleEdgeThresholdMin, + // + // Extra constants for 360 FXAA Console only. + // Use zeros or anything else for other platforms. + // These must be in physical constant registers and NOT immedates. + // Immedates will result in compiler un-optimizing. + // {xyzw} = float4(1.0, -1.0, 0.25, -0.25) + FxaaFloat4 fxaaConsole360ConstDir +) { +/*--------------------------------------------------------------------------*/ + FxaaFloat2 posM; + posM.x = pos.x; + posM.y = pos.y; + #if (FXAA_GATHER4_ALPHA == 1) + #if (FXAA_DISCARD == 0) + FxaaFloat4 rgbyM = FxaaTexTop(tex, posM); + #if (FXAA_GREEN_AS_LUMA == 0) + #define lumaM rgbyM.w + #else + #define lumaM rgbyM.y + #endif + #endif + #if (FXAA_GREEN_AS_LUMA == 0) + FxaaFloat4 luma4A = FxaaTexAlpha4(tex, posM); + FxaaFloat4 luma4B = FxaaTexOffAlpha4(tex, posM, FxaaInt2(-1, -1)); + #else + FxaaFloat4 luma4A = FxaaTexGreen4(tex, posM); + FxaaFloat4 luma4B = FxaaTexOffGreen4(tex, posM, FxaaInt2(-1, -1)); + #endif + #if (FXAA_DISCARD == 1) + #define lumaM luma4A.w + #endif + #define lumaE luma4A.z + #define lumaS luma4A.x + #define lumaSE luma4A.y + #define lumaNW luma4B.w + #define lumaN luma4B.z + #define lumaW luma4B.x + #else + FxaaFloat4 rgbyM = FxaaTexTop(tex, posM); + #if (FXAA_GREEN_AS_LUMA == 0) + #define lumaM rgbyM.w + #else + #define lumaM rgbyM.y + #endif + FxaaFloat lumaS = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2( 0, 1), fxaaQualityRcpFrame.xy)); + FxaaFloat lumaE = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2( 1, 0), fxaaQualityRcpFrame.xy)); + FxaaFloat lumaN = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2( 0,-1), fxaaQualityRcpFrame.xy)); + FxaaFloat lumaW = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2(-1, 0), fxaaQualityRcpFrame.xy)); + #endif +/*--------------------------------------------------------------------------*/ + FxaaFloat maxSM = max(lumaS, lumaM); + FxaaFloat minSM = min(lumaS, lumaM); + FxaaFloat maxESM = max(lumaE, maxSM); + FxaaFloat minESM = min(lumaE, minSM); + FxaaFloat maxWN = max(lumaN, lumaW); + FxaaFloat minWN = min(lumaN, lumaW); + FxaaFloat rangeMax = max(maxWN, maxESM); + FxaaFloat rangeMin = min(minWN, minESM); + FxaaFloat rangeMaxScaled = rangeMax * fxaaQualityEdgeThreshold; + FxaaFloat range = rangeMax - rangeMin; + FxaaFloat rangeMaxClamped = max(fxaaQualityEdgeThresholdMin, rangeMaxScaled); + FxaaBool earlyExit = range < rangeMaxClamped; +/*--------------------------------------------------------------------------*/ + if(earlyExit) + #if (FXAA_DISCARD == 1) + FxaaDiscard; + #else + return rgbyM; + #endif +/*--------------------------------------------------------------------------*/ + #if (FXAA_GATHER4_ALPHA == 0) + FxaaFloat lumaNW = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2(-1,-1), fxaaQualityRcpFrame.xy)); + FxaaFloat lumaSE = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2( 1, 1), fxaaQualityRcpFrame.xy)); + FxaaFloat lumaNE = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2( 1,-1), fxaaQualityRcpFrame.xy)); + FxaaFloat lumaSW = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2(-1, 1), fxaaQualityRcpFrame.xy)); + #else + FxaaFloat lumaNE = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2(1, -1), fxaaQualityRcpFrame.xy)); + FxaaFloat lumaSW = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2(-1, 1), fxaaQualityRcpFrame.xy)); + #endif +/*--------------------------------------------------------------------------*/ + FxaaFloat lumaNS = lumaN + lumaS; + FxaaFloat lumaWE = lumaW + lumaE; + FxaaFloat subpixRcpRange = 1.0/range; + FxaaFloat subpixNSWE = lumaNS + lumaWE; + FxaaFloat edgeHorz1 = (-2.0 * lumaM) + lumaNS; + FxaaFloat edgeVert1 = (-2.0 * lumaM) + lumaWE; +/*--------------------------------------------------------------------------*/ + FxaaFloat lumaNESE = lumaNE + lumaSE; + FxaaFloat lumaNWNE = lumaNW + lumaNE; + FxaaFloat edgeHorz2 = (-2.0 * lumaE) + lumaNESE; + FxaaFloat edgeVert2 = (-2.0 * lumaN) + lumaNWNE; +/*--------------------------------------------------------------------------*/ + FxaaFloat lumaNWSW = lumaNW + lumaSW; + FxaaFloat lumaSWSE = lumaSW + lumaSE; + FxaaFloat edgeHorz4 = (abs(edgeHorz1) * 2.0) + abs(edgeHorz2); + FxaaFloat edgeVert4 = (abs(edgeVert1) * 2.0) + abs(edgeVert2); + FxaaFloat edgeHorz3 = (-2.0 * lumaW) + lumaNWSW; + FxaaFloat edgeVert3 = (-2.0 * lumaS) + lumaSWSE; + FxaaFloat edgeHorz = abs(edgeHorz3) + edgeHorz4; + FxaaFloat edgeVert = abs(edgeVert3) + edgeVert4; +/*--------------------------------------------------------------------------*/ + FxaaFloat subpixNWSWNESE = lumaNWSW + lumaNESE; + FxaaFloat lengthSign = fxaaQualityRcpFrame.x; + FxaaBool horzSpan = edgeHorz >= edgeVert; + FxaaFloat subpixA = subpixNSWE * 2.0 + subpixNWSWNESE; +/*--------------------------------------------------------------------------*/ + if(!horzSpan) lumaN = lumaW; + if(!horzSpan) lumaS = lumaE; + if(horzSpan) lengthSign = fxaaQualityRcpFrame.y; + FxaaFloat subpixB = (subpixA * (1.0/12.0)) - lumaM; +/*--------------------------------------------------------------------------*/ + FxaaFloat gradientN = lumaN - lumaM; + FxaaFloat gradientS = lumaS - lumaM; + FxaaFloat lumaNN = lumaN + lumaM; + FxaaFloat lumaSS = lumaS + lumaM; + FxaaBool pairN = abs(gradientN) >= abs(gradientS); + FxaaFloat gradient = max(abs(gradientN), abs(gradientS)); + if(pairN) lengthSign = -lengthSign; + FxaaFloat subpixC = FxaaSat(abs(subpixB) * subpixRcpRange); +/*--------------------------------------------------------------------------*/ + FxaaFloat2 posB; + posB.x = posM.x; + posB.y = posM.y; + FxaaFloat2 offNP; + offNP.x = (!horzSpan) ? 0.0 : fxaaQualityRcpFrame.x; + offNP.y = ( horzSpan) ? 0.0 : fxaaQualityRcpFrame.y; + if(!horzSpan) posB.x += lengthSign * 0.5; + if( horzSpan) posB.y += lengthSign * 0.5; +/*--------------------------------------------------------------------------*/ + FxaaFloat2 posN; + posN.x = posB.x - offNP.x * FXAA_QUALITY__P0; + posN.y = posB.y - offNP.y * FXAA_QUALITY__P0; + FxaaFloat2 posP; + posP.x = posB.x + offNP.x * FXAA_QUALITY__P0; + posP.y = posB.y + offNP.y * FXAA_QUALITY__P0; + FxaaFloat subpixD = ((-2.0)*subpixC) + 3.0; + FxaaFloat lumaEndN = FxaaLuma(FxaaTexTop(tex, posN)); + FxaaFloat subpixE = subpixC * subpixC; + FxaaFloat lumaEndP = FxaaLuma(FxaaTexTop(tex, posP)); +/*--------------------------------------------------------------------------*/ + if(!pairN) lumaNN = lumaSS; + FxaaFloat gradientScaled = gradient * 1.0/4.0; + FxaaFloat lumaMM = lumaM - lumaNN * 0.5; + FxaaFloat subpixF = subpixD * subpixE; + FxaaBool lumaMLTZero = lumaMM < 0.0; +/*--------------------------------------------------------------------------*/ + lumaEndN -= lumaNN * 0.5; + lumaEndP -= lumaNN * 0.5; + FxaaBool doneN = abs(lumaEndN) >= gradientScaled; + FxaaBool doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P1; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P1; + FxaaBool doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P1; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P1; +/*--------------------------------------------------------------------------*/ + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P2; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P2; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P2; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P2; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 3) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P3; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P3; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P3; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P3; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 4) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P4; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P4; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P4; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P4; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 5) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P5; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P5; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P5; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P5; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 6) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P6; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P6; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P6; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P6; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 7) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P7; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P7; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P7; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P7; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 8) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P8; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P8; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P8; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P8; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 9) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P9; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P9; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P9; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P9; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 10) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P10; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P10; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P10; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P10; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 11) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P11; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P11; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P11; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P11; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 12) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P12; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P12; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P12; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P12; +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } +/*--------------------------------------------------------------------------*/ + FxaaFloat dstN = posM.x - posN.x; + FxaaFloat dstP = posP.x - posM.x; + if(!horzSpan) dstN = posM.y - posN.y; + if(!horzSpan) dstP = posP.y - posM.y; +/*--------------------------------------------------------------------------*/ + FxaaBool goodSpanN = (lumaEndN < 0.0) != lumaMLTZero; + FxaaFloat spanLength = (dstP + dstN); + FxaaBool goodSpanP = (lumaEndP < 0.0) != lumaMLTZero; + FxaaFloat spanLengthRcp = 1.0/spanLength; +/*--------------------------------------------------------------------------*/ + FxaaBool directionN = dstN < dstP; + FxaaFloat dst = min(dstN, dstP); + FxaaBool goodSpan = directionN ? goodSpanN : goodSpanP; + FxaaFloat subpixG = subpixF * subpixF; + FxaaFloat pixelOffset = (dst * (-spanLengthRcp)) + 0.5; + FxaaFloat subpixH = subpixG * fxaaQualitySubpix; +/*--------------------------------------------------------------------------*/ + FxaaFloat pixelOffsetGood = goodSpan ? pixelOffset : 0.0; + FxaaFloat pixelOffsetSubpix = max(pixelOffsetGood, subpixH); + if(!horzSpan) posM.x += pixelOffsetSubpix * lengthSign; + if( horzSpan) posM.y += pixelOffsetSubpix * lengthSign; + #if (FXAA_DISCARD == 1) + return FxaaTexTop(tex, posM); + #else + return FxaaFloat4(FxaaTexTop(tex, posM).xyz, lumaM); + #endif +} +/*==========================================================================*/ +#endif + + + + +/*============================================================================ + + FXAA3 CONSOLE - PC VERSION + +------------------------------------------------------------------------------ +Instead of using this on PC, I'd suggest just using FXAA Quality with + #define FXAA_QUALITY__PRESET 10 +Or + #define FXAA_QUALITY__PRESET 20 +Either are higher qualilty and almost as fast as this on modern PC GPUs. +============================================================================*/ +#if (FXAA_PC_CONSOLE == 1) +/*--------------------------------------------------------------------------*/ +FxaaFloat4 FxaaPixelShader( + // See FXAA Quality FxaaPixelShader() source for docs on Inputs! + FxaaFloat2 pos, + FxaaFloat4 fxaaConsolePosPos, + FxaaTex tex, + FxaaTex fxaaConsole360TexExpBiasNegOne, + FxaaTex fxaaConsole360TexExpBiasNegTwo, + FxaaFloat2 fxaaQualityRcpFrame, + FxaaFloat4 fxaaConsoleRcpFrameOpt, + FxaaFloat4 fxaaConsoleRcpFrameOpt2, + FxaaFloat4 fxaaConsole360RcpFrameOpt2, + FxaaFloat fxaaQualitySubpix, + FxaaFloat fxaaQualityEdgeThreshold, + FxaaFloat fxaaQualityEdgeThresholdMin, + FxaaFloat fxaaConsoleEdgeSharpness, + FxaaFloat fxaaConsoleEdgeThreshold, + FxaaFloat fxaaConsoleEdgeThresholdMin, + FxaaFloat4 fxaaConsole360ConstDir +) { +/*--------------------------------------------------------------------------*/ + FxaaFloat lumaNw = FxaaLuma(FxaaTexTop(tex, fxaaConsolePosPos.xy)); + FxaaFloat lumaSw = FxaaLuma(FxaaTexTop(tex, fxaaConsolePosPos.xw)); + FxaaFloat lumaNe = FxaaLuma(FxaaTexTop(tex, fxaaConsolePosPos.zy)); + FxaaFloat lumaSe = FxaaLuma(FxaaTexTop(tex, fxaaConsolePosPos.zw)); +/*--------------------------------------------------------------------------*/ + FxaaFloat4 rgbyM = FxaaTexTop(tex, pos.xy); + #if (FXAA_GREEN_AS_LUMA == 0) + FxaaFloat lumaM = rgbyM.w; + #else + FxaaFloat lumaM = rgbyM.y; + #endif +/*--------------------------------------------------------------------------*/ + FxaaFloat lumaMaxNwSw = max(lumaNw, lumaSw); + lumaNe += 1.0/384.0; + FxaaFloat lumaMinNwSw = min(lumaNw, lumaSw); +/*--------------------------------------------------------------------------*/ + FxaaFloat lumaMaxNeSe = max(lumaNe, lumaSe); + FxaaFloat lumaMinNeSe = min(lumaNe, lumaSe); +/*--------------------------------------------------------------------------*/ + FxaaFloat lumaMax = max(lumaMaxNeSe, lumaMaxNwSw); + FxaaFloat lumaMin = min(lumaMinNeSe, lumaMinNwSw); +/*--------------------------------------------------------------------------*/ + FxaaFloat lumaMaxScaled = lumaMax * fxaaConsoleEdgeThreshold; +/*--------------------------------------------------------------------------*/ + FxaaFloat lumaMinM = min(lumaMin, lumaM); + FxaaFloat lumaMaxScaledClamped = max(fxaaConsoleEdgeThresholdMin, lumaMaxScaled); + FxaaFloat lumaMaxM = max(lumaMax, lumaM); + FxaaFloat dirSwMinusNe = lumaSw - lumaNe; + FxaaFloat lumaMaxSubMinM = lumaMaxM - lumaMinM; + FxaaFloat dirSeMinusNw = lumaSe - lumaNw; + if(lumaMaxSubMinM < lumaMaxScaledClamped) return rgbyM; +/*--------------------------------------------------------------------------*/ + FxaaFloat2 dir; + dir.x = dirSwMinusNe + dirSeMinusNw; + dir.y = dirSwMinusNe - dirSeMinusNw; +/*--------------------------------------------------------------------------*/ + FxaaFloat2 dir1 = normalize(dir.xy); + FxaaFloat4 rgbyN1 = FxaaTexTop(tex, pos.xy - dir1 * fxaaConsoleRcpFrameOpt.zw); + FxaaFloat4 rgbyP1 = FxaaTexTop(tex, pos.xy + dir1 * fxaaConsoleRcpFrameOpt.zw); +/*--------------------------------------------------------------------------*/ + FxaaFloat dirAbsMinTimesC = min(abs(dir1.x), abs(dir1.y)) * fxaaConsoleEdgeSharpness; + FxaaFloat2 dir2 = clamp(dir1.xy / dirAbsMinTimesC, -2.0, 2.0); +/*--------------------------------------------------------------------------*/ + FxaaFloat4 rgbyN2 = FxaaTexTop(tex, pos.xy - dir2 * fxaaConsoleRcpFrameOpt2.zw); + FxaaFloat4 rgbyP2 = FxaaTexTop(tex, pos.xy + dir2 * fxaaConsoleRcpFrameOpt2.zw); +/*--------------------------------------------------------------------------*/ + FxaaFloat4 rgbyA = rgbyN1 + rgbyP1; + FxaaFloat4 rgbyB = ((rgbyN2 + rgbyP2) * 0.25) + (rgbyA * 0.25); +/*--------------------------------------------------------------------------*/ + #if (FXAA_GREEN_AS_LUMA == 0) + FxaaBool twoTap = (rgbyB.w < lumaMin) || (rgbyB.w > lumaMax); + #else + FxaaBool twoTap = (rgbyB.y < lumaMin) || (rgbyB.y > lumaMax); + #endif + if(twoTap) rgbyB.xyz = rgbyA.xyz * 0.5; + return rgbyB; } +/*==========================================================================*/ +#endif + + + +/*============================================================================ + + FXAA3 CONSOLE - 360 PIXEL SHADER + +------------------------------------------------------------------------------ +This optimized version thanks to suggestions from Andy Luedke. +Should be fully tex bound in all cases. +As of the FXAA 3.11 release, I have still not tested this code, +however I fixed a bug which was in both FXAA 3.9 and FXAA 3.10. +And note this is replacing the old unoptimized version. +If it does not work, please let me know so I can fix it. +============================================================================*/ +#if (FXAA_360 == 1) +/*--------------------------------------------------------------------------*/ +[reduceTempRegUsage(4)] +float4 FxaaPixelShader( + // See FXAA Quality FxaaPixelShader() source for docs on Inputs! + FxaaFloat2 pos, + FxaaFloat4 fxaaConsolePosPos, + FxaaTex tex, + FxaaTex fxaaConsole360TexExpBiasNegOne, + FxaaTex fxaaConsole360TexExpBiasNegTwo, + FxaaFloat2 fxaaQualityRcpFrame, + FxaaFloat4 fxaaConsoleRcpFrameOpt, + FxaaFloat4 fxaaConsoleRcpFrameOpt2, + FxaaFloat4 fxaaConsole360RcpFrameOpt2, + FxaaFloat fxaaQualitySubpix, + FxaaFloat fxaaQualityEdgeThreshold, + FxaaFloat fxaaQualityEdgeThresholdMin, + FxaaFloat fxaaConsoleEdgeSharpness, + FxaaFloat fxaaConsoleEdgeThreshold, + FxaaFloat fxaaConsoleEdgeThresholdMin, + FxaaFloat4 fxaaConsole360ConstDir +) { +/*--------------------------------------------------------------------------*/ + float4 lumaNwNeSwSe; + #if (FXAA_GREEN_AS_LUMA == 0) + asm { + tfetch2D lumaNwNeSwSe.w___, tex, pos.xy, OffsetX = -0.5, OffsetY = -0.5, UseComputedLOD=false + tfetch2D lumaNwNeSwSe._w__, tex, pos.xy, OffsetX = 0.5, OffsetY = -0.5, UseComputedLOD=false + tfetch2D lumaNwNeSwSe.__w_, tex, pos.xy, OffsetX = -0.5, OffsetY = 0.5, UseComputedLOD=false + tfetch2D lumaNwNeSwSe.___w, tex, pos.xy, OffsetX = 0.5, OffsetY = 0.5, UseComputedLOD=false + }; + #else + asm { + tfetch2D lumaNwNeSwSe.y___, tex, pos.xy, OffsetX = -0.5, OffsetY = -0.5, UseComputedLOD=false + tfetch2D lumaNwNeSwSe._y__, tex, pos.xy, OffsetX = 0.5, OffsetY = -0.5, UseComputedLOD=false + tfetch2D lumaNwNeSwSe.__y_, tex, pos.xy, OffsetX = -0.5, OffsetY = 0.5, UseComputedLOD=false + tfetch2D lumaNwNeSwSe.___y, tex, pos.xy, OffsetX = 0.5, OffsetY = 0.5, UseComputedLOD=false + }; + #endif +/*--------------------------------------------------------------------------*/ + lumaNwNeSwSe.y += 1.0/384.0; + float2 lumaMinTemp = min(lumaNwNeSwSe.xy, lumaNwNeSwSe.zw); + float2 lumaMaxTemp = max(lumaNwNeSwSe.xy, lumaNwNeSwSe.zw); + float lumaMin = min(lumaMinTemp.x, lumaMinTemp.y); + float lumaMax = max(lumaMaxTemp.x, lumaMaxTemp.y); +/*--------------------------------------------------------------------------*/ + float4 rgbyM = tex2Dlod(tex, float4(pos.xy, 0.0, 0.0)); + #if (FXAA_GREEN_AS_LUMA == 0) + float lumaMinM = min(lumaMin, rgbyM.w); + float lumaMaxM = max(lumaMax, rgbyM.w); + #else + float lumaMinM = min(lumaMin, rgbyM.y); + float lumaMaxM = max(lumaMax, rgbyM.y); + #endif + if((lumaMaxM - lumaMinM) < max(fxaaConsoleEdgeThresholdMin, lumaMax * fxaaConsoleEdgeThreshold)) return rgbyM; +/*--------------------------------------------------------------------------*/ + float2 dir; + dir.x = dot(lumaNwNeSwSe, fxaaConsole360ConstDir.yyxx); + dir.y = dot(lumaNwNeSwSe, fxaaConsole360ConstDir.xyxy); + dir = normalize(dir); +/*--------------------------------------------------------------------------*/ + float4 dir1 = dir.xyxy * fxaaConsoleRcpFrameOpt.xyzw; +/*--------------------------------------------------------------------------*/ + float4 dir2; + float dirAbsMinTimesC = min(abs(dir.x), abs(dir.y)) * fxaaConsoleEdgeSharpness; + dir2 = saturate(fxaaConsole360ConstDir.zzww * dir.xyxy / dirAbsMinTimesC + 0.5); + dir2 = dir2 * fxaaConsole360RcpFrameOpt2.xyxy + fxaaConsole360RcpFrameOpt2.zwzw; +/*--------------------------------------------------------------------------*/ + float4 rgbyN1 = tex2Dlod(fxaaConsole360TexExpBiasNegOne, float4(pos.xy + dir1.xy, 0.0, 0.0)); + float4 rgbyP1 = tex2Dlod(fxaaConsole360TexExpBiasNegOne, float4(pos.xy + dir1.zw, 0.0, 0.0)); + float4 rgbyN2 = tex2Dlod(fxaaConsole360TexExpBiasNegTwo, float4(pos.xy + dir2.xy, 0.0, 0.0)); + float4 rgbyP2 = tex2Dlod(fxaaConsole360TexExpBiasNegTwo, float4(pos.xy + dir2.zw, 0.0, 0.0)); +/*--------------------------------------------------------------------------*/ + float4 rgbyA = rgbyN1 + rgbyP1; + float4 rgbyB = rgbyN2 + rgbyP2 + rgbyA * 0.5; +/*--------------------------------------------------------------------------*/ + float4 rgbyR = ((FxaaLuma(rgbyB) - lumaMax) > 0.0) ? rgbyA : rgbyB; + rgbyR = ((FxaaLuma(rgbyB) - lumaMin) > 0.0) ? rgbyR : rgbyA; + return rgbyR; } +/*==========================================================================*/ +#endif + + + +/*============================================================================ + + FXAA3 CONSOLE - OPTIMIZED PS3 PIXEL SHADER (NO EARLY EXIT) + +============================================================================== +The code below does not exactly match the assembly. +I have a feeling that 12 cycles is possible, but was not able to get there. +Might have to increase register count to get full performance. +Note this shader does not use perspective interpolation. + +Use the following cgc options, + + --fenable-bx2 --fastmath --fastprecision --nofloatbindings + +------------------------------------------------------------------------------ + NVSHADERPERF OUTPUT +------------------------------------------------------------------------------ +For reference and to aid in debug, output of NVShaderPerf should match this, + +Shader to schedule: + 0: texpkb h0.w(TRUE), v5.zyxx, #0 + 2: addh h2.z(TRUE), h0.w, constant(0.001953, 0.000000, 0.000000, 0.000000).x + 4: texpkb h0.w(TRUE), v5.xwxx, #0 + 6: addh h0.z(TRUE), -h2, h0.w + 7: texpkb h1.w(TRUE), v5, #0 + 9: addh h0.x(TRUE), h0.z, -h1.w + 10: addh h3.w(TRUE), h0.z, h1 + 11: texpkb h2.w(TRUE), v5.zwzz, #0 + 13: addh h0.z(TRUE), h3.w, -h2.w + 14: addh h0.x(TRUE), h2.w, h0 + 15: nrmh h1.xz(TRUE), h0_n + 16: minh_m8 h0.x(TRUE), |h1|, |h1.z| + 17: maxh h4.w(TRUE), h0, h1 + 18: divx h2.xy(TRUE), h1_n.xzzw, h0_n + 19: movr r1.zw(TRUE), v4.xxxy + 20: madr r2.xz(TRUE), -h1, constant(cConst5.x, cConst5.y, cConst5.z, cConst5.w).zzww, r1.zzww + 22: minh h5.w(TRUE), h0, h1 + 23: texpkb h0(TRUE), r2.xzxx, #0 + 25: madr r0.zw(TRUE), h1.xzxz, constant(cConst5.x, cConst5.y, cConst5.z, cConst5.w), r1 + 27: maxh h4.x(TRUE), h2.z, h2.w + 28: texpkb h1(TRUE), r0.zwzz, #0 + 30: addh_d2 h1(TRUE), h0, h1 + 31: madr r0.xy(TRUE), -h2, constant(cConst5.x, cConst5.y, cConst5.z, cConst5.w).xyxx, r1.zwzz + 33: texpkb h0(TRUE), r0, #0 + 35: minh h4.z(TRUE), h2, h2.w + 36: fenct TRUE + 37: madr r1.xy(TRUE), h2, constant(cConst5.x, cConst5.y, cConst5.z, cConst5.w).xyxx, r1.zwzz + 39: texpkb h2(TRUE), r1, #0 + 41: addh_d2 h0(TRUE), h0, h2 + 42: maxh h2.w(TRUE), h4, h4.x + 43: minh h2.x(TRUE), h5.w, h4.z + 44: addh_d2 h0(TRUE), h0, h1 + 45: slth h2.x(TRUE), h0.w, h2 + 46: sgth h2.w(TRUE), h0, h2 + 47: movh h0(TRUE), h0 + 48: addx.c0 rc(TRUE), h2, h2.w + 49: movh h0(c0.NE.x), h1 + +IPU0 ------ Simplified schedule: -------- +Pass | Unit | uOp | PC: Op +-----+--------+------+------------------------- + 1 | SCT0/1 | mov | 0: TXLr h0.w, g[TEX1].zyxx, const.xxxx, TEX0; + | TEX | txl | 0: TXLr h0.w, g[TEX1].zyxx, const.xxxx, TEX0; + | SCB1 | add | 2: ADDh h2.z, h0.--w-, const.--x-; + | | | + 2 | SCT0/1 | mov | 4: TXLr h0.w, g[TEX1].xwxx, const.xxxx, TEX0; + | TEX | txl | 4: TXLr h0.w, g[TEX1].xwxx, const.xxxx, TEX0; + | SCB1 | add | 6: ADDh h0.z,-h2, h0.--w-; + | | | + 3 | SCT0/1 | mov | 7: TXLr h1.w, g[TEX1], const.xxxx, TEX0; + | TEX | txl | 7: TXLr h1.w, g[TEX1], const.xxxx, TEX0; + | SCB0 | add | 9: ADDh h0.x, h0.z---,-h1.w---; + | SCB1 | add | 10: ADDh h3.w, h0.---z, h1; + | | | + 4 | SCT0/1 | mov | 11: TXLr h2.w, g[TEX1].zwzz, const.xxxx, TEX0; + | TEX | txl | 11: TXLr h2.w, g[TEX1].zwzz, const.xxxx, TEX0; + | SCB0 | add | 14: ADDh h0.x, h2.w---, h0; + | SCB1 | add | 13: ADDh h0.z, h3.--w-,-h2.--w-; + | | | + 5 | SCT1 | mov | 15: NRMh h1.xz, h0; + | SRB | nrm | 15: NRMh h1.xz, h0; + | SCB0 | min | 16: MINh*8 h0.x, |h1|, |h1.z---|; + | SCB1 | max | 17: MAXh h4.w, h0, h1; + | | | + 6 | SCT0 | div | 18: DIVx h2.xy, h1.xz--, h0; + | SCT1 | mov | 19: MOVr r1.zw, g[TEX0].--xy; + | SCB0 | mad | 20: MADr r2.xz,-h1, const.z-w-, r1.z-w-; + | SCB1 | min | 22: MINh h5.w, h0, h1; + | | | + 7 | SCT0/1 | mov | 23: TXLr h0, r2.xzxx, const.xxxx, TEX0; + | TEX | txl | 23: TXLr h0, r2.xzxx, const.xxxx, TEX0; + | SCB0 | max | 27: MAXh h4.x, h2.z---, h2.w---; + | SCB1 | mad | 25: MADr r0.zw, h1.--xz, const, r1; + | | | + 8 | SCT0/1 | mov | 28: TXLr h1, r0.zwzz, const.xxxx, TEX0; + | TEX | txl | 28: TXLr h1, r0.zwzz, const.xxxx, TEX0; + | SCB0/1 | add | 30: ADDh/2 h1, h0, h1; + | | | + 9 | SCT0 | mad | 31: MADr r0.xy,-h2, const.xy--, r1.zw--; + | SCT1 | mov | 33: TXLr h0, r0, const.zzzz, TEX0; + | TEX | txl | 33: TXLr h0, r0, const.zzzz, TEX0; + | SCB1 | min | 35: MINh h4.z, h2, h2.--w-; + | | | + 10 | SCT0 | mad | 37: MADr r1.xy, h2, const.xy--, r1.zw--; + | SCT1 | mov | 39: TXLr h2, r1, const.zzzz, TEX0; + | TEX | txl | 39: TXLr h2, r1, const.zzzz, TEX0; + | SCB0/1 | add | 41: ADDh/2 h0, h0, h2; + | | | + 11 | SCT0 | min | 43: MINh h2.x, h5.w---, h4.z---; + | SCT1 | max | 42: MAXh h2.w, h4, h4.---x; + | SCB0/1 | add | 44: ADDh/2 h0, h0, h1; + | | | + 12 | SCT0 | set | 45: SLTh h2.x, h0.w---, h2; + | SCT1 | set | 46: SGTh h2.w, h0, h2; + | SCB0/1 | mul | 47: MOVh h0, h0; + | | | + 13 | SCT0 | mad | 48: ADDxc0_s rc, h2, h2.w---; + | SCB0/1 | mul | 49: MOVh h0(NE0.xxxx), h1; + +Pass SCT TEX SCB + 1: 0% 100% 25% + 2: 0% 100% 25% + 3: 0% 100% 50% + 4: 0% 100% 50% + 5: 0% 0% 50% + 6: 100% 0% 75% + 7: 0% 100% 75% + 8: 0% 100% 100% + 9: 0% 100% 25% + 10: 0% 100% 100% + 11: 50% 0% 100% + 12: 50% 0% 100% + 13: 25% 0% 100% + +MEAN: 17% 61% 67% + +Pass SCT0 SCT1 TEX SCB0 SCB1 + 1: 0% 0% 100% 0% 100% + 2: 0% 0% 100% 0% 100% + 3: 0% 0% 100% 100% 100% + 4: 0% 0% 100% 100% 100% + 5: 0% 0% 0% 100% 100% + 6: 100% 100% 0% 100% 100% + 7: 0% 0% 100% 100% 100% + 8: 0% 0% 100% 100% 100% + 9: 0% 0% 100% 0% 100% + 10: 0% 0% 100% 100% 100% + 11: 100% 100% 0% 100% 100% + 12: 100% 100% 0% 100% 100% + 13: 100% 0% 0% 100% 100% + +MEAN: 30% 23% 61% 76% 100% +Fragment Performance Setup: Driver RSX Compiler, GPU RSX, Flags 0x5 +Results 13 cycles, 3 r regs, 923,076,923 pixels/s +============================================================================*/ +#if (FXAA_PS3 == 1) && (FXAA_EARLY_EXIT == 0) +/*--------------------------------------------------------------------------*/ +#pragma regcount 7 +#pragma disablepc all +#pragma option O3 +#pragma option OutColorPrec=fp16 +#pragma texformat default RGBA8 +/*==========================================================================*/ +half4 FxaaPixelShader( + // See FXAA Quality FxaaPixelShader() source for docs on Inputs! + FxaaFloat2 pos, + FxaaFloat4 fxaaConsolePosPos, + FxaaTex tex, + FxaaTex fxaaConsole360TexExpBiasNegOne, + FxaaTex fxaaConsole360TexExpBiasNegTwo, + FxaaFloat2 fxaaQualityRcpFrame, + FxaaFloat4 fxaaConsoleRcpFrameOpt, + FxaaFloat4 fxaaConsoleRcpFrameOpt2, + FxaaFloat4 fxaaConsole360RcpFrameOpt2, + FxaaFloat fxaaQualitySubpix, + FxaaFloat fxaaQualityEdgeThreshold, + FxaaFloat fxaaQualityEdgeThresholdMin, + FxaaFloat fxaaConsoleEdgeSharpness, + FxaaFloat fxaaConsoleEdgeThreshold, + FxaaFloat fxaaConsoleEdgeThresholdMin, + FxaaFloat4 fxaaConsole360ConstDir +) { +/*--------------------------------------------------------------------------*/ +// (1) + half4 dir; + half4 lumaNe = h4tex2Dlod(tex, half4(fxaaConsolePosPos.zy, 0, 0)); + #if (FXAA_GREEN_AS_LUMA == 0) + lumaNe.w += half(1.0/512.0); + dir.x = -lumaNe.w; + dir.z = -lumaNe.w; + #else + lumaNe.y += half(1.0/512.0); + dir.x = -lumaNe.y; + dir.z = -lumaNe.y; + #endif +/*--------------------------------------------------------------------------*/ +// (2) + half4 lumaSw = h4tex2Dlod(tex, half4(fxaaConsolePosPos.xw, 0, 0)); + #if (FXAA_GREEN_AS_LUMA == 0) + dir.x += lumaSw.w; + dir.z += lumaSw.w; + #else + dir.x += lumaSw.y; + dir.z += lumaSw.y; + #endif +/*--------------------------------------------------------------------------*/ +// (3) + half4 lumaNw = h4tex2Dlod(tex, half4(fxaaConsolePosPos.xy, 0, 0)); + #if (FXAA_GREEN_AS_LUMA == 0) + dir.x -= lumaNw.w; + dir.z += lumaNw.w; + #else + dir.x -= lumaNw.y; + dir.z += lumaNw.y; + #endif +/*--------------------------------------------------------------------------*/ +// (4) + half4 lumaSe = h4tex2Dlod(tex, half4(fxaaConsolePosPos.zw, 0, 0)); + #if (FXAA_GREEN_AS_LUMA == 0) + dir.x += lumaSe.w; + dir.z -= lumaSe.w; + #else + dir.x += lumaSe.y; + dir.z -= lumaSe.y; + #endif +/*--------------------------------------------------------------------------*/ +// (5) + half4 dir1_pos; + dir1_pos.xy = normalize(dir.xyz).xz; + half dirAbsMinTimesC = min(abs(dir1_pos.x), abs(dir1_pos.y)) * half(FXAA_CONSOLE__PS3_EDGE_SHARPNESS); +/*--------------------------------------------------------------------------*/ +// (6) + half4 dir2_pos; + dir2_pos.xy = clamp(dir1_pos.xy / dirAbsMinTimesC, half(-2.0), half(2.0)); + dir1_pos.zw = pos.xy; + dir2_pos.zw = pos.xy; + half4 temp1N; + temp1N.xy = dir1_pos.zw - dir1_pos.xy * fxaaConsoleRcpFrameOpt.zw; +/*--------------------------------------------------------------------------*/ +// (7) + temp1N = h4tex2Dlod(tex, half4(temp1N.xy, 0.0, 0.0)); + half4 rgby1; + rgby1.xy = dir1_pos.zw + dir1_pos.xy * fxaaConsoleRcpFrameOpt.zw; +/*--------------------------------------------------------------------------*/ +// (8) + rgby1 = h4tex2Dlod(tex, half4(rgby1.xy, 0.0, 0.0)); + rgby1 = (temp1N + rgby1) * 0.5; +/*--------------------------------------------------------------------------*/ +// (9) + half4 temp2N; + temp2N.xy = dir2_pos.zw - dir2_pos.xy * fxaaConsoleRcpFrameOpt2.zw; + temp2N = h4tex2Dlod(tex, half4(temp2N.xy, 0.0, 0.0)); +/*--------------------------------------------------------------------------*/ +// (10) + half4 rgby2; + rgby2.xy = dir2_pos.zw + dir2_pos.xy * fxaaConsoleRcpFrameOpt2.zw; + rgby2 = h4tex2Dlod(tex, half4(rgby2.xy, 0.0, 0.0)); + rgby2 = (temp2N + rgby2) * 0.5; +/*--------------------------------------------------------------------------*/ +// (11) + // compilier moves these scalar ops up to other cycles + #if (FXAA_GREEN_AS_LUMA == 0) + half lumaMin = min(min(lumaNw.w, lumaSw.w), min(lumaNe.w, lumaSe.w)); + half lumaMax = max(max(lumaNw.w, lumaSw.w), max(lumaNe.w, lumaSe.w)); + #else + half lumaMin = min(min(lumaNw.y, lumaSw.y), min(lumaNe.y, lumaSe.y)); + half lumaMax = max(max(lumaNw.y, lumaSw.y), max(lumaNe.y, lumaSe.y)); + #endif + rgby2 = (rgby2 + rgby1) * 0.5; +/*--------------------------------------------------------------------------*/ +// (12) + #if (FXAA_GREEN_AS_LUMA == 0) + bool twoTapLt = rgby2.w < lumaMin; + bool twoTapGt = rgby2.w > lumaMax; + #else + bool twoTapLt = rgby2.y < lumaMin; + bool twoTapGt = rgby2.y > lumaMax; + #endif +/*--------------------------------------------------------------------------*/ +// (13) + if(twoTapLt || twoTapGt) rgby2 = rgby1; +/*--------------------------------------------------------------------------*/ + return rgby2; } +/*==========================================================================*/ +#endif + + + +/*============================================================================ + + FXAA3 CONSOLE - OPTIMIZED PS3 PIXEL SHADER (WITH EARLY EXIT) + +============================================================================== +The code mostly matches the assembly. +I have a feeling that 14 cycles is possible, but was not able to get there. +Might have to increase register count to get full performance. +Note this shader does not use perspective interpolation. + +Use the following cgc options, + + --fenable-bx2 --fastmath --fastprecision --nofloatbindings + +Use of FXAA_GREEN_AS_LUMA currently adds a cycle (16 clks). +Will look at fixing this for FXAA 3.12. +------------------------------------------------------------------------------ + NVSHADERPERF OUTPUT +------------------------------------------------------------------------------ +For reference and to aid in debug, output of NVShaderPerf should match this, + +Shader to schedule: + 0: texpkb h0.w(TRUE), v5.zyxx, #0 + 2: addh h2.y(TRUE), h0.w, constant(0.001953, 0.000000, 0.000000, 0.000000).x + 4: texpkb h1.w(TRUE), v5.xwxx, #0 + 6: addh h0.x(TRUE), h1.w, -h2.y + 7: texpkb h2.w(TRUE), v5.zwzz, #0 + 9: minh h4.w(TRUE), h2.y, h2 + 10: maxh h5.x(TRUE), h2.y, h2.w + 11: texpkb h0.w(TRUE), v5, #0 + 13: addh h3.w(TRUE), -h0, h0.x + 14: addh h0.x(TRUE), h0.w, h0 + 15: addh h0.z(TRUE), -h2.w, h0.x + 16: addh h0.x(TRUE), h2.w, h3.w + 17: minh h5.y(TRUE), h0.w, h1.w + 18: nrmh h2.xz(TRUE), h0_n + 19: minh_m8 h2.w(TRUE), |h2.x|, |h2.z| + 20: divx h4.xy(TRUE), h2_n.xzzw, h2_n.w + 21: movr r1.zw(TRUE), v4.xxxy + 22: maxh h2.w(TRUE), h0, h1 + 23: fenct TRUE + 24: madr r0.xy(TRUE), -h2.xzzw, constant(cConst5.x, cConst5.y, cConst5.z, cConst5.w).zwzz, r1.zwzz + 26: texpkb h0(TRUE), r0, #0 + 28: maxh h5.x(TRUE), h2.w, h5 + 29: minh h5.w(TRUE), h5.y, h4 + 30: madr r1.xy(TRUE), h2.xzzw, constant(cConst5.x, cConst5.y, cConst5.z, cConst5.w).zwzz, r1.zwzz + 32: texpkb h2(TRUE), r1, #0 + 34: addh_d2 h2(TRUE), h0, h2 + 35: texpkb h1(TRUE), v4, #0 + 37: maxh h5.y(TRUE), h5.x, h1.w + 38: minh h4.w(TRUE), h1, h5 + 39: madr r0.xy(TRUE), -h4, constant(cConst5.x, cConst5.y, cConst5.z, cConst5.w).xyxx, r1.zwzz + 41: texpkb h0(TRUE), r0, #0 + 43: addh_m8 h5.z(TRUE), h5.y, -h4.w + 44: madr r2.xy(TRUE), h4, constant(cConst5.x, cConst5.y, cConst5.z, cConst5.w).xyxx, r1.zwzz + 46: texpkb h3(TRUE), r2, #0 + 48: addh_d2 h0(TRUE), h0, h3 + 49: addh_d2 h3(TRUE), h0, h2 + 50: movh h0(TRUE), h3 + 51: slth h3.x(TRUE), h3.w, h5.w + 52: sgth h3.w(TRUE), h3, h5.x + 53: addx.c0 rc(TRUE), h3.x, h3 + 54: slth.c0 rc(TRUE), h5.z, h5 + 55: movh h0(c0.NE.w), h2 + 56: movh h0(c0.NE.x), h1 + +IPU0 ------ Simplified schedule: -------- +Pass | Unit | uOp | PC: Op +-----+--------+------+------------------------- + 1 | SCT0/1 | mov | 0: TXLr h0.w, g[TEX1].zyxx, const.xxxx, TEX0; + | TEX | txl | 0: TXLr h0.w, g[TEX1].zyxx, const.xxxx, TEX0; + | SCB0 | add | 2: ADDh h2.y, h0.-w--, const.-x--; + | | | + 2 | SCT0/1 | mov | 4: TXLr h1.w, g[TEX1].xwxx, const.xxxx, TEX0; + | TEX | txl | 4: TXLr h1.w, g[TEX1].xwxx, const.xxxx, TEX0; + | SCB0 | add | 6: ADDh h0.x, h1.w---,-h2.y---; + | | | + 3 | SCT0/1 | mov | 7: TXLr h2.w, g[TEX1].zwzz, const.xxxx, TEX0; + | TEX | txl | 7: TXLr h2.w, g[TEX1].zwzz, const.xxxx, TEX0; + | SCB0 | max | 10: MAXh h5.x, h2.y---, h2.w---; + | SCB1 | min | 9: MINh h4.w, h2.---y, h2; + | | | + 4 | SCT0/1 | mov | 11: TXLr h0.w, g[TEX1], const.xxxx, TEX0; + | TEX | txl | 11: TXLr h0.w, g[TEX1], const.xxxx, TEX0; + | SCB0 | add | 14: ADDh h0.x, h0.w---, h0; + | SCB1 | add | 13: ADDh h3.w,-h0, h0.---x; + | | | + 5 | SCT0 | mad | 16: ADDh h0.x, h2.w---, h3.w---; + | SCT1 | mad | 15: ADDh h0.z,-h2.--w-, h0.--x-; + | SCB0 | min | 17: MINh h5.y, h0.-w--, h1.-w--; + | | | + 6 | SCT1 | mov | 18: NRMh h2.xz, h0; + | SRB | nrm | 18: NRMh h2.xz, h0; + | SCB1 | min | 19: MINh*8 h2.w, |h2.---x|, |h2.---z|; + | | | + 7 | SCT0 | div | 20: DIVx h4.xy, h2.xz--, h2.ww--; + | SCT1 | mov | 21: MOVr r1.zw, g[TEX0].--xy; + | SCB1 | max | 22: MAXh h2.w, h0, h1; + | | | + 8 | SCT0 | mad | 24: MADr r0.xy,-h2.xz--, const.zw--, r1.zw--; + | SCT1 | mov | 26: TXLr h0, r0, const.xxxx, TEX0; + | TEX | txl | 26: TXLr h0, r0, const.xxxx, TEX0; + | SCB0 | max | 28: MAXh h5.x, h2.w---, h5; + | SCB1 | min | 29: MINh h5.w, h5.---y, h4; + | | | + 9 | SCT0 | mad | 30: MADr r1.xy, h2.xz--, const.zw--, r1.zw--; + | SCT1 | mov | 32: TXLr h2, r1, const.xxxx, TEX0; + | TEX | txl | 32: TXLr h2, r1, const.xxxx, TEX0; + | SCB0/1 | add | 34: ADDh/2 h2, h0, h2; + | | | + 10 | SCT0/1 | mov | 35: TXLr h1, g[TEX0], const.xxxx, TEX0; + | TEX | txl | 35: TXLr h1, g[TEX0], const.xxxx, TEX0; + | SCB0 | max | 37: MAXh h5.y, h5.-x--, h1.-w--; + | SCB1 | min | 38: MINh h4.w, h1, h5; + | | | + 11 | SCT0 | mad | 39: MADr r0.xy,-h4, const.xy--, r1.zw--; + | SCT1 | mov | 41: TXLr h0, r0, const.zzzz, TEX0; + | TEX | txl | 41: TXLr h0, r0, const.zzzz, TEX0; + | SCB0 | mad | 44: MADr r2.xy, h4, const.xy--, r1.zw--; + | SCB1 | add | 43: ADDh*8 h5.z, h5.--y-,-h4.--w-; + | | | + 12 | SCT0/1 | mov | 46: TXLr h3, r2, const.xxxx, TEX0; + | TEX | txl | 46: TXLr h3, r2, const.xxxx, TEX0; + | SCB0/1 | add | 48: ADDh/2 h0, h0, h3; + | | | + 13 | SCT0/1 | mad | 49: ADDh/2 h3, h0, h2; + | SCB0/1 | mul | 50: MOVh h0, h3; + | | | + 14 | SCT0 | set | 51: SLTh h3.x, h3.w---, h5.w---; + | SCT1 | set | 52: SGTh h3.w, h3, h5.---x; + | SCB0 | set | 54: SLThc0 rc, h5.z---, h5; + | SCB1 | add | 53: ADDxc0_s rc, h3.---x, h3; + | | | + 15 | SCT0/1 | mul | 55: MOVh h0(NE0.wwww), h2; + | SCB0/1 | mul | 56: MOVh h0(NE0.xxxx), h1; + +Pass SCT TEX SCB + 1: 0% 100% 25% + 2: 0% 100% 25% + 3: 0% 100% 50% + 4: 0% 100% 50% + 5: 50% 0% 25% + 6: 0% 0% 25% + 7: 100% 0% 25% + 8: 0% 100% 50% + 9: 0% 100% 100% + 10: 0% 100% 50% + 11: 0% 100% 75% + 12: 0% 100% 100% + 13: 100% 0% 100% + 14: 50% 0% 50% + 15: 100% 0% 100% + +MEAN: 26% 60% 56% + +Pass SCT0 SCT1 TEX SCB0 SCB1 + 1: 0% 0% 100% 100% 0% + 2: 0% 0% 100% 100% 0% + 3: 0% 0% 100% 100% 100% + 4: 0% 0% 100% 100% 100% + 5: 100% 100% 0% 100% 0% + 6: 0% 0% 0% 0% 100% + 7: 100% 100% 0% 0% 100% + 8: 0% 0% 100% 100% 100% + 9: 0% 0% 100% 100% 100% + 10: 0% 0% 100% 100% 100% + 11: 0% 0% 100% 100% 100% + 12: 0% 0% 100% 100% 100% + 13: 100% 100% 0% 100% 100% + 14: 100% 100% 0% 100% 100% + 15: 100% 100% 0% 100% 100% + +MEAN: 33% 33% 60% 86% 80% +Fragment Performance Setup: Driver RSX Compiler, GPU RSX, Flags 0x5 +Results 15 cycles, 3 r regs, 800,000,000 pixels/s +============================================================================*/ +#if (FXAA_PS3 == 1) && (FXAA_EARLY_EXIT == 1) +/*--------------------------------------------------------------------------*/ +#pragma regcount 7 +#pragma disablepc all +#pragma option O2 +#pragma option OutColorPrec=fp16 +#pragma texformat default RGBA8 +/*==========================================================================*/ +half4 FxaaPixelShader( + // See FXAA Quality FxaaPixelShader() source for docs on Inputs! + FxaaFloat2 pos, + FxaaFloat4 fxaaConsolePosPos, + FxaaTex tex, + FxaaTex fxaaConsole360TexExpBiasNegOne, + FxaaTex fxaaConsole360TexExpBiasNegTwo, + FxaaFloat2 fxaaQualityRcpFrame, + FxaaFloat4 fxaaConsoleRcpFrameOpt, + FxaaFloat4 fxaaConsoleRcpFrameOpt2, + FxaaFloat4 fxaaConsole360RcpFrameOpt2, + FxaaFloat fxaaQualitySubpix, + FxaaFloat fxaaQualityEdgeThreshold, + FxaaFloat fxaaQualityEdgeThresholdMin, + FxaaFloat fxaaConsoleEdgeSharpness, + FxaaFloat fxaaConsoleEdgeThreshold, + FxaaFloat fxaaConsoleEdgeThresholdMin, + FxaaFloat4 fxaaConsole360ConstDir +) { +/*--------------------------------------------------------------------------*/ +// (1) + half4 rgbyNe = h4tex2Dlod(tex, half4(fxaaConsolePosPos.zy, 0, 0)); + #if (FXAA_GREEN_AS_LUMA == 0) + half lumaNe = rgbyNe.w + half(1.0/512.0); + #else + half lumaNe = rgbyNe.y + half(1.0/512.0); + #endif +/*--------------------------------------------------------------------------*/ +// (2) + half4 lumaSw = h4tex2Dlod(tex, half4(fxaaConsolePosPos.xw, 0, 0)); + #if (FXAA_GREEN_AS_LUMA == 0) + half lumaSwNegNe = lumaSw.w - lumaNe; + #else + half lumaSwNegNe = lumaSw.y - lumaNe; + #endif +/*--------------------------------------------------------------------------*/ +// (3) + half4 lumaNw = h4tex2Dlod(tex, half4(fxaaConsolePosPos.xy, 0, 0)); + #if (FXAA_GREEN_AS_LUMA == 0) + half lumaMaxNwSw = max(lumaNw.w, lumaSw.w); + half lumaMinNwSw = min(lumaNw.w, lumaSw.w); + #else + half lumaMaxNwSw = max(lumaNw.y, lumaSw.y); + half lumaMinNwSw = min(lumaNw.y, lumaSw.y); + #endif +/*--------------------------------------------------------------------------*/ +// (4) + half4 lumaSe = h4tex2Dlod(tex, half4(fxaaConsolePosPos.zw, 0, 0)); + #if (FXAA_GREEN_AS_LUMA == 0) + half dirZ = lumaNw.w + lumaSwNegNe; + half dirX = -lumaNw.w + lumaSwNegNe; + #else + half dirZ = lumaNw.y + lumaSwNegNe; + half dirX = -lumaNw.y + lumaSwNegNe; + #endif +/*--------------------------------------------------------------------------*/ +// (5) + half3 dir; + dir.y = 0.0; + #if (FXAA_GREEN_AS_LUMA == 0) + dir.x = lumaSe.w + dirX; + dir.z = -lumaSe.w + dirZ; + half lumaMinNeSe = min(lumaNe, lumaSe.w); + #else + dir.x = lumaSe.y + dirX; + dir.z = -lumaSe.y + dirZ; + half lumaMinNeSe = min(lumaNe, lumaSe.y); + #endif +/*--------------------------------------------------------------------------*/ +// (6) + half4 dir1_pos; + dir1_pos.xy = normalize(dir).xz; + half dirAbsMinTimes8 = min(abs(dir1_pos.x), abs(dir1_pos.y)) * half(FXAA_CONSOLE__PS3_EDGE_SHARPNESS); +/*--------------------------------------------------------------------------*/ +// (7) + half4 dir2_pos; + dir2_pos.xy = clamp(dir1_pos.xy / dirAbsMinTimes8, half(-2.0), half(2.0)); + dir1_pos.zw = pos.xy; + dir2_pos.zw = pos.xy; + #if (FXAA_GREEN_AS_LUMA == 0) + half lumaMaxNeSe = max(lumaNe, lumaSe.w); + #else + half lumaMaxNeSe = max(lumaNe, lumaSe.y); + #endif +/*--------------------------------------------------------------------------*/ +// (8) + half4 temp1N; + temp1N.xy = dir1_pos.zw - dir1_pos.xy * fxaaConsoleRcpFrameOpt.zw; + temp1N = h4tex2Dlod(tex, half4(temp1N.xy, 0.0, 0.0)); + half lumaMax = max(lumaMaxNwSw, lumaMaxNeSe); + half lumaMin = min(lumaMinNwSw, lumaMinNeSe); +/*--------------------------------------------------------------------------*/ +// (9) + half4 rgby1; + rgby1.xy = dir1_pos.zw + dir1_pos.xy * fxaaConsoleRcpFrameOpt.zw; + rgby1 = h4tex2Dlod(tex, half4(rgby1.xy, 0.0, 0.0)); + rgby1 = (temp1N + rgby1) * 0.5; +/*--------------------------------------------------------------------------*/ +// (10) + half4 rgbyM = h4tex2Dlod(tex, half4(pos.xy, 0.0, 0.0)); + #if (FXAA_GREEN_AS_LUMA == 0) + half lumaMaxM = max(lumaMax, rgbyM.w); + half lumaMinM = min(lumaMin, rgbyM.w); + #else + half lumaMaxM = max(lumaMax, rgbyM.y); + half lumaMinM = min(lumaMin, rgbyM.y); + #endif +/*--------------------------------------------------------------------------*/ +// (11) + half4 temp2N; + temp2N.xy = dir2_pos.zw - dir2_pos.xy * fxaaConsoleRcpFrameOpt2.zw; + temp2N = h4tex2Dlod(tex, half4(temp2N.xy, 0.0, 0.0)); + half4 rgby2; + rgby2.xy = dir2_pos.zw + dir2_pos.xy * fxaaConsoleRcpFrameOpt2.zw; + half lumaRangeM = (lumaMaxM - lumaMinM) / FXAA_CONSOLE__PS3_EDGE_THRESHOLD; +/*--------------------------------------------------------------------------*/ +// (12) + rgby2 = h4tex2Dlod(tex, half4(rgby2.xy, 0.0, 0.0)); + rgby2 = (temp2N + rgby2) * 0.5; +/*--------------------------------------------------------------------------*/ +// (13) + rgby2 = (rgby2 + rgby1) * 0.5; +/*--------------------------------------------------------------------------*/ +// (14) + #if (FXAA_GREEN_AS_LUMA == 0) + bool twoTapLt = rgby2.w < lumaMin; + bool twoTapGt = rgby2.w > lumaMax; + #else + bool twoTapLt = rgby2.y < lumaMin; + bool twoTapGt = rgby2.y > lumaMax; + #endif + bool earlyExit = lumaRangeM < lumaMax; + bool twoTap = twoTapLt || twoTapGt; +/*--------------------------------------------------------------------------*/ +// (15) + if(twoTap) rgby2 = rgby1; + if(earlyExit) rgby2 = rgbyM; +/*--------------------------------------------------------------------------*/ + return rgby2; } +/*==========================================================================*/ +#endif diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Resources/FXAA3.cginc.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Resources/FXAA3.cginc.meta new file mode 100644 index 0000000..2c82c38 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/FXAA/Resources/FXAA3.cginc.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: b44d2ca11a7157e4db9f1e02f5249f95 +timeCreated: 1453990603 +licenseType: Store +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/IAntiAliasing.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/IAntiAliasing.cs new file mode 100644 index 0000000..3b77d2a --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/IAntiAliasing.cs @@ -0,0 +1,13 @@ +using UnityEngine; + +namespace UnityStandardAssets.CinematicEffects +{ + public interface IAntiAliasing + { + void OnEnable(AntiAliasing owner); + void OnDisable(); + void OnPreCull(Camera camera); + void OnPostRender(Camera camera); + void OnRenderImage(Camera camera, RenderTexture source, RenderTexture destination); + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/IAntiAliasing.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/IAntiAliasing.cs.meta new file mode 100644 index 0000000..b2b8673 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/IAntiAliasing.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 90329fa7c7a616243a47de84e6e5c041 +timeCreated: 1454590083 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA.meta new file mode 100644 index 0000000..a9141f0 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: d958f8498dd28db459dc41b661331fc8 +folderAsset: yes +timeCreated: 1446717353 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Editor.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Editor.meta new file mode 100644 index 0000000..3b2a057 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Editor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 3ab9eab0d04085b4abd47b6b0657143c +folderAsset: yes +timeCreated: 1430588699 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Editor/SMAAEditor.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Editor/SMAAEditor.cs new file mode 100644 index 0000000..24a4ce7 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Editor/SMAAEditor.cs @@ -0,0 +1,106 @@ +using UnityEditor; +using System.Collections.Generic; +using System; +using System.Linq; +using UnityEngine; +using System.Reflection; +using UnityEngine.Serialization; + +namespace UnityStandardAssets.CinematicEffects +{ + public class SMAAEditor : IAntiAliasingEditor + { + private List m_TopLevelFields = new List(); + + [Serializable] + class InfoMap + { + public string name; + public bool experimental; + public bool quality; + public List properties; + } + private List m_GroupFields = new List(); + + public void OnEnable(SerializedObject serializedObject, string path) + { + var topLevelSettings = typeof(SMAA).GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).Where(x => x.GetCustomAttributes(typeof(SMAA.TopLevelSettings), false).Any()); + var settingsGroups = typeof(SMAA).GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).Where(x => x.GetCustomAttributes(typeof(SMAA.SettingsGroup), false).Any()); + + foreach (var group in topLevelSettings) + { + var searchPath = path + "." + group.Name + "."; + + foreach (var setting in group.FieldType.GetFields(BindingFlags.Instance | BindingFlags.Public)) + { + var property = serializedObject.FindProperty(searchPath + setting.Name); + if (property != null) + m_TopLevelFields.Add(property); + } + } + + foreach (var group in settingsGroups) + { + var searchPath = path + "." + group.Name + "."; + + foreach (var setting in group.FieldType.GetFields(BindingFlags.Instance | BindingFlags.Public)) + { + var infoGroup = m_GroupFields.FirstOrDefault(x => x.name == group.Name); + if (infoGroup == null) + { + infoGroup = new InfoMap(); + infoGroup.properties = new List(); + infoGroup.name = group.Name; + infoGroup.quality = group.FieldType == typeof(SMAA.QualitySettings); + infoGroup.experimental = group.GetCustomAttributes(typeof(SMAA.ExperimentalGroup), false).Length > 0; + m_GroupFields.Add(infoGroup); + } + + var property = serializedObject.FindProperty(searchPath + setting.Name); + if (property != null) + { + infoGroup.properties.Add(property); + } + } + } + } + + public bool OnInspectorGUI(IAntiAliasing target) + { + EditorGUI.BeginChangeCheck(); + + foreach (var setting in m_TopLevelFields) + EditorGUILayout.PropertyField(setting); + + foreach (var group in m_GroupFields) + { + if (group.quality && (target as SMAA).settings.quality != SMAA.QualityPreset.Custom) + { + continue; + } + + string title = ObjectNames.NicifyVariableName(group.name); + if (group.experimental) + title += " (Experimental)"; + + EditorGUILayout.Space(); + EditorGUILayout.LabelField(title, EditorStyles.boldLabel); + EditorGUI.indentLevel++; + + var enabledField = group.properties.FirstOrDefault(x => x.propertyPath == "m_SMAA." + group.name + ".enabled"); + if (enabledField != null && !enabledField.boolValue) + { + EditorGUILayout.PropertyField(enabledField); + EditorGUI.indentLevel--; + continue; + } + + foreach (var field in group.properties) + EditorGUILayout.PropertyField(field); + + EditorGUI.indentLevel--; + } + return EditorGUI.EndChangeCheck(); + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Editor/SMAAEditor.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Editor/SMAAEditor.cs.meta new file mode 100644 index 0000000..c1ca0f6 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Editor/SMAAEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 5c2ffc06b5a6ee64d8e1d9bdf074732c +timeCreated: 1430643832 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources.meta new file mode 100644 index 0000000..9f4930c --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 9362798305520c448b294dd314a7daff +folderAsset: yes +timeCreated: 1430505545 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/AreaTex.tga b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/AreaTex.tga new file mode 100644 index 0000000..57f595e Binary files /dev/null and b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/AreaTex.tga differ diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/AreaTex.tga.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/AreaTex.tga.meta new file mode 100644 index 0000000..4938aed --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/AreaTex.tga.meta @@ -0,0 +1,57 @@ +fileFormatVersion: 2 +guid: e62aa7035ea66c94b90b2d8774d02cca +timeCreated: 1432601000 +licenseType: Store +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 8 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 2048 + textureSettings: + filterMode: 1 + aniso: 0 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + rGBM: 2 + compressionQuality: 50 + allowsAlphaSplitting: 0 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: 5 + buildTargetSettings: [] + spriteSheet: + sprites: [] + outline: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/SMAA.cginc b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/SMAA.cginc new file mode 100644 index 0000000..1d271b0 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/SMAA.cginc @@ -0,0 +1,1433 @@ +// Ported to Unity by Thomas Hourdel (thomas.hourdel@gmail.com) + +/** + * Copyright (C) 2013 Jorge Jimenez (jorge@iryoku.com) + * Copyright (C) 2013 Jose I. Echevarria (joseignacioechevarria@gmail.com) + * Copyright (C) 2013 Belen Masia (bmasia@unizar.es) + * Copyright (C) 2013 Fernando Navarro (fernandn@microsoft.com) + * Copyright (C) 2013 Diego Gutierrez (diegog@unizar.es) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to + * do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. As clarification, there + * is no requirement that the copyright notice and permission be included in + * binary distributions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + +/** + * _______ ___ ___ ___ ___ + * / || \/ | / \ / \ + * | (---- | \ / | / ^ \ / ^ \ + * \ \ | |\/| | / /_\ \ / /_\ \ + * ----) | | | | | / _____ \ / _____ \ + * |_______/ |__| |__| /__/ \__\ /__/ \__\ + * + * E N H A N C E D + * S U B P I X E L M O R P H O L O G I C A L A N T I A L I A S I N G + * + * http://www.iryoku.com/smaa/ + * + * Hi, welcome aboard! + * + * Here you'll find instructions to get the shader up and running as fast as + * possible. + * + * IMPORTANTE NOTICE: when updating, remember to update both this file and the + * precomputed textures! They may change from version to version. + * + * The shader has three passes, chained together as follows: + * + * |input|------------------· + * v | + * [ SMAA*EdgeDetection ] | + * v | + * |edgesTex| | + * v | + * [ SMAABlendingWeightCalculation ] | + * v | + * |blendTex| | + * v | + * [ SMAANeighborhoodBlending ] <------· + * v + * |output| + * + * Note that each [pass] has its own vertex and pixel shader. Remember to use + * oversized triangles instead of quads to avoid overshading along the + * diagonal. + * + * You've three edge detection methods to choose from: luma, color or depth. + * They represent different quality/performance and anti-aliasing/sharpness + * tradeoffs, so our recommendation is for you to choose the one that best + * suits your particular scenario: + * + * - Depth edge detection is usually the fastest but it may miss some edges. + * + * - Luma edge detection is usually more expensive than depth edge detection, + * but catches visible edges that depth edge detection can miss. + * + * - Color edge detection is usually the most expensive one but catches + * chroma-only edges. + * + * For quickstarters: just use luma edge detection. + * + * The general advice is to not rush the integration process and ensure each + * step is done correctly (don't try to integrate SMAA T2x with predicated edge + * detection from the start!). Ok then, let's go! + * + * 1. The first step is to create two RGBA temporal render targets for holding + * |edgesTex| and |blendTex|. + * + * In DX10 or DX11, you can use a RG render target for the edges texture. + * In the case of NVIDIA GPUs, using RG render targets seems to actually be + * slower. + * + * On the Xbox 360, you can use the same render target for resolving both + * |edgesTex| and |blendTex|, as they aren't needed simultaneously. + * + * 2. Both temporal render targets |edgesTex| and |blendTex| must be cleared + * each frame. Do not forget to clear the alpha channel! + * + * 3. The next step is loading the two supporting precalculated textures, + * 'areaTex' and 'searchTex'. You'll find them in the 'Textures' folder as + * C++ headers, and also as regular DDS files. They'll be needed for the + * 'SMAABlendingWeightCalculation' pass. + * + * If you use the C++ headers, be sure to load them in the format specified + * inside of them. + * + * You can also compress 'areaTex' and 'searchTex' using BC5 and BC4 + * respectively, if you have that option in your content processor pipeline. + * When compressing then, you get a non-perceptible quality decrease, and a + * marginal performance increase. + * + * 4. All samplers must be set to linear filtering and clamp. + * + * After you get the technique working, remember that 64-bit inputs have + * half-rate linear filtering on GCN. + * + * If SMAA is applied to 64-bit color buffers, switching to point filtering + * when accesing them will increase the performance. Search for + * 'SMAASamplePoint' to see which textures may benefit from point + * filtering, and where (which is basically the color input in the edge + * detection and resolve passes). + * + * 5. All texture reads and buffer writes must be non-sRGB, with the exception + * of the input read and the output write in + * 'SMAANeighborhoodBlending' (and only in this pass!). If sRGB reads in + * this last pass are not possible, the technique will work anyway, but + * will perform antialiasing in gamma space. + * + * IMPORTANT: for best results the input read for the color/luma edge + * detection should *NOT* be sRGB. + * + * 6. Before including SMAA.h you'll have to setup the render target metrics, + * the target and any optional configuration defines. Optionally you can + * use a preset. + * + * You have the following targets available: + * SMAA_HLSL_3 + * SMAA_HLSL_4 + * SMAA_HLSL_4_1 + * SMAA_GLSL_3 * + * SMAA_GLSL_4 * + * + * * (See SMAA_INCLUDE_VS and SMAA_INCLUDE_PS below). + * + * And four presets: + * SMAA_PRESET_LOW (%60 of the quality) + * SMAA_PRESET_MEDIUM (%80 of the quality) + * SMAA_PRESET_HIGH (%95 of the quality) + * SMAA_PRESET_ULTRA (%99 of the quality) + * + * For example: + * #define SMAA_RT_METRICS float4(1.0 / 1280.0, 1.0 / 720.0, 1280.0, 720.0) + * #define SMAA_HLSL_4 + * #define SMAA_PRESET_HIGH + * #include "SMAA.h" + * + * Note that SMAA_RT_METRICS doesn't need to be a macro, it can be a + * uniform variable. The code is designed to minimize the impact of not + * using a constant value, but it is still better to hardcode it. + * + * Depending on how you encoded 'areaTex' and 'searchTex', you may have to + * add (and customize) the following defines before including SMAA.h: + * #define SMAA_AREATEX_SELECT(sample) sample.rg + * #define SMAA_SEARCHTEX_SELECT(sample) sample.r + * + * If your engine is already using porting macros, you can define + * SMAA_CUSTOM_SL, and define the porting functions by yourself. + * + * 7. Then, you'll have to setup the passes as indicated in the scheme above. + * You can take a look into SMAA.fx, to see how we did it for our demo. + * Checkout the function wrappers, you may want to copy-paste them! + * + * 8. It's recommended to validate the produced |edgesTex| and |blendTex|. + * You can use a screenshot from your engine to compare the |edgesTex| + * and |blendTex| produced inside of the engine with the results obtained + * with the reference demo. + * + * 9. After you get the last pass to work, it's time to optimize. You'll have + * to initialize a stencil buffer in the first pass (discard is already in + * the code), then mask execution by using it the second pass. The last + * pass should be executed in all pixels. + * + * + * After this point you can choose to enable predicated thresholding, + * temporal supersampling and motion blur integration: + * + * a) If you want to use predicated thresholding, take a look into + * SMAA_PREDICATION; you'll need to pass an extra texture in the edge + * detection pass. + * + * b) If you want to enable temporal supersampling (SMAA T2x): + * + * 1. The first step is to render using subpixel jitters. I won't go into + * detail, but it's as simple as moving each vertex position in the + * vertex shader, you can check how we do it in our DX10 demo. + * + * 2. Then, you must setup the temporal resolve. You may want to take a look + * into SMAAResolve for resolving 2x modes. After you get it working, you'll + * probably see ghosting everywhere. But fear not, you can enable the + * CryENGINE temporal reprojection by setting the SMAA_REPROJECTION macro. + * Check out SMAA_DECODE_VELOCITY if your velocity buffer is encoded. + * + * 3. The next step is to apply SMAA to each subpixel jittered frame, just as + * done for 1x. + * + * 4. At this point you should already have something usable, but for best + * results the proper area textures must be set depending on current jitter. + * For this, the parameter 'subsampleIndices' of + * 'SMAABlendingWeightCalculationPS' must be set as follows, for our T2x + * mode: + * + * @SUBSAMPLE_INDICES + * + * | S# | Camera Jitter | subsampleIndices | + * +----+------------------+---------------------+ + * | 0 | ( 0.25, -0.25) | float4(1, 1, 1, 0) | + * | 1 | (-0.25, 0.25) | float4(2, 2, 2, 0) | + * + * These jitter positions assume a bottom-to-top y axis. S# stands for the + * sample number. + * + * More information about temporal supersampling here: + * http://iryoku.com/aacourse/downloads/13-Anti-Aliasing-Methods-in-CryENGINE-3.pdf + * + * c) If you want to enable spatial multisampling (SMAA S2x): + * + * 1. The scene must be rendered using MSAA 2x. The MSAA 2x buffer must be + * created with: + * - DX10: see below (*) + * - DX10.1: D3D10_STANDARD_MULTISAMPLE_PATTERN or + * - DX11: D3D11_STANDARD_MULTISAMPLE_PATTERN + * + * This allows to ensure that the subsample order matches the table in + * @SUBSAMPLE_INDICES. + * + * (*) In the case of DX10, we refer the reader to: + * - SMAA::detectMSAAOrder and + * - SMAA::msaaReorder + * + * These functions allow to match the standard multisample patterns by + * detecting the subsample order for a specific GPU, and reordering + * them appropriately. + * + * 2. A shader must be run to output each subsample into a separate buffer + * (DX10 is required). You can use SMAASeparate for this purpose, or just do + * it in an existing pass (for example, in the tone mapping pass, which has + * the advantage of feeding tone mapped subsamples to SMAA, which will yield + * better results). + * + * 3. The full SMAA 1x pipeline must be run for each separated buffer, storing + * the results in the final buffer. The second run should alpha blend with + * the existing final buffer using a blending factor of 0.5. + * 'subsampleIndices' must be adjusted as in the SMAA T2x case (see point + * b). + * + * d) If you want to enable temporal supersampling on top of SMAA S2x + * (which actually is SMAA 4x): + * + * 1. SMAA 4x consists on temporally jittering SMAA S2x, so the first step is + * to calculate SMAA S2x for current frame. In this case, 'subsampleIndices' + * must be set as follows: + * + * | F# | S# | Camera Jitter | Net Jitter | subsampleIndices | + * +----+----+--------------------+-------------------+----------------------+ + * | 0 | 0 | ( 0.125, 0.125) | ( 0.375, -0.125) | float4(5, 3, 1, 3) | + * | 0 | 1 | ( 0.125, 0.125) | (-0.125, 0.375) | float4(4, 6, 2, 3) | + * +----+----+--------------------+-------------------+----------------------+ + * | 1 | 2 | (-0.125, -0.125) | ( 0.125, -0.375) | float4(3, 5, 1, 4) | + * | 1 | 3 | (-0.125, -0.125) | (-0.375, 0.125) | float4(6, 4, 2, 4) | + * + * These jitter positions assume a bottom-to-top y axis. F# stands for the + * frame number. S# stands for the sample number. + * + * 2. After calculating SMAA S2x for current frame (with the new subsample + * indices), previous frame must be reprojected as in SMAA T2x mode (see + * point b). + * + * e) If motion blur is used, you may want to do the edge detection pass + * together with motion blur. This has two advantages: + * + * 1. Pixels under heavy motion can be omitted from the edge detection process. + * For these pixels we can just store "no edge", as motion blur will take + * care of them. + * 2. The center pixel tap is reused. + * + * Note that in this case depth testing should be used instead of stenciling, + * as we have to write all the pixels in the motion blur pass. + * + * That's it! + */ + +//----------------------------------------------------------------------------- +// SMAA Presets + +/** + * Note that if you use one of these presets, the following configuration + * macros will be ignored if set in the "Configurable Defines" section. + */ + +#if defined(SMAA_PRESET_LOW) +#define SMAA_THRESHOLD 0.15 +#define SMAA_MAX_SEARCH_STEPS 4 +#define SMAA_DISABLE_DIAG_DETECTION +#define SMAA_DISABLE_CORNER_DETECTION +#elif defined(SMAA_PRESET_MEDIUM) +#define SMAA_THRESHOLD 0.1 +#define SMAA_MAX_SEARCH_STEPS 8 +#define SMAA_DISABLE_DIAG_DETECTION +#define SMAA_DISABLE_CORNER_DETECTION +#elif defined(SMAA_PRESET_HIGH) +#define SMAA_THRESHOLD 0.1 +#define SMAA_MAX_SEARCH_STEPS 16 +#define SMAA_MAX_SEARCH_STEPS_DIAG 8 +#define SMAA_CORNER_ROUNDING 25 +#elif defined(SMAA_PRESET_ULTRA) +#define SMAA_THRESHOLD 0.05 +#define SMAA_MAX_SEARCH_STEPS 32 +#define SMAA_MAX_SEARCH_STEPS_DIAG 16 +#define SMAA_CORNER_ROUNDING 25 +#endif + +//----------------------------------------------------------------------------- +// Configurable Defines + +/** + * SMAA_THRESHOLD specifies the threshold or sensitivity to edges. + * Lowering this value you will be able to detect more edges at the expense of + * performance. + * + * Range: [0, 0.5] + * 0.1 is a reasonable value, and allows to catch most visible edges. + * 0.05 is a rather overkill value, that allows to catch 'em all. + * + * If temporal supersampling is used, 0.2 could be a reasonable value, as low + * contrast edges are properly filtered by just 2x. + */ +#ifndef SMAA_THRESHOLD +#define SMAA_THRESHOLD 0.1 +#endif + +/** + * SMAA_DEPTH_THRESHOLD specifies the threshold for depth edge detection. + * + * Range: depends on the depth range of the scene. + */ +#ifndef SMAA_DEPTH_THRESHOLD +#define SMAA_DEPTH_THRESHOLD (0.1 * SMAA_THRESHOLD) +#endif + +/** + * SMAA_MAX_SEARCH_STEPS specifies the maximum steps performed in the + * horizontal/vertical pattern searches, at each side of the pixel. + * + * In number of pixels, it's actually the double. So the maximum line length + * perfectly handled by, for example 16, is 64 (by perfectly, we meant that + * longer lines won't look as good, but still antialiased). + * + * Range: [0, 112] + */ +#ifndef SMAA_MAX_SEARCH_STEPS +#define SMAA_MAX_SEARCH_STEPS 16 +#endif + +/** + * SMAA_MAX_SEARCH_STEPS_DIAG specifies the maximum steps performed in the + * diagonal pattern searches, at each side of the pixel. In this case we jump + * one pixel at time, instead of two. + * + * Range: [0, 20] + * + * On high-end machines it is cheap (between a 0.8x and 0.9x slower for 16 + * steps), but it can have a significant impact on older machines. + * + * Define SMAA_DISABLE_DIAG_DETECTION to disable diagonal processing. + */ +#ifndef SMAA_MAX_SEARCH_STEPS_DIAG +#define SMAA_MAX_SEARCH_STEPS_DIAG 8 +#endif + +/** + * SMAA_CORNER_ROUNDING specifies how much sharp corners will be rounded. + * + * Range: [0, 100] + * + * Define SMAA_DISABLE_CORNER_DETECTION to disable corner processing. + */ +#ifndef SMAA_CORNER_ROUNDING +#define SMAA_CORNER_ROUNDING 25 +#endif + +/** + * If there is an neighbor edge that has SMAA_LOCAL_CONTRAST_FACTOR times + * bigger contrast than current edge, current edge will be discarded. + * + * This allows to eliminate spurious crossing edges, and is based on the fact + * that, if there is too much contrast in a direction, that will hide + * perceptually contrast in the other neighbors. + */ +#ifndef SMAA_LOCAL_CONTRAST_ADAPTATION_FACTOR +#define SMAA_LOCAL_CONTRAST_ADAPTATION_FACTOR 2.0 +#endif + +/** + * Predicated thresholding allows to better preserve texture details and to + * improve performance, by decreasing the number of detected edges using an + * additional buffer like the light accumulation buffer, object ids or even the + * depth buffer (the depth buffer usage may be limited to indoor or short range + * scenes). + * + * It locally decreases the luma or color threshold if an edge is found in an + * additional buffer (so the global threshold can be higher). + * + * This method was developed by Playstation EDGE MLAA team, and used in + * Killzone 3, by using the light accumulation buffer. More information here: + * http://iryoku.com/aacourse/downloads/06-MLAA-on-PS3.pptx + */ +#ifndef SMAA_PREDICATION +#define SMAA_PREDICATION 0 +#endif + +/** + * Threshold to be used in the additional predication buffer. + * + * Range: depends on the input, so you'll have to find the magic number that + * works for you. + */ +#ifndef SMAA_PREDICATION_THRESHOLD +#define SMAA_PREDICATION_THRESHOLD 0.01 +#endif + +/** + * How much to scale the global threshold used for luma or color edge + * detection when using predication. + * + * Range: [1, 5] + */ +#ifndef SMAA_PREDICATION_SCALE +#define SMAA_PREDICATION_SCALE 2.0 +#endif + +/** + * How much to locally decrease the threshold. + * + * Range: [0, 1] + */ +#ifndef SMAA_PREDICATION_STRENGTH +#define SMAA_PREDICATION_STRENGTH 0.4 +#endif + +/** + * Temporal reprojection allows to remove ghosting artifacts when using + * temporal supersampling. We use the CryEngine 3 method which also introduces + * velocity weighting. This feature is of extreme importance for totally + * removing ghosting. More information here: + * http://iryoku.com/aacourse/downloads/13-Anti-Aliasing-Methods-in-CryENGINE-3.pdf + * + * Note that you'll need to setup a velocity buffer for enabling reprojection. + * For static geometry, saving the previous depth buffer is a viable + * alternative. + */ +#ifndef SMAA_REPROJECTION +#define SMAA_REPROJECTION 0 +#endif + +/** + * Temporal reprojection allows to remove ghosting artifacts when using + * temporal supersampling. However, the default reprojection requires a velocity buffer + * in order to function properly. + * + * A velocity buffer might not always be available (hi Unity 5!). To handle such cases + * we provide a UV-based approximation for calculating motion vectors on the fly. + */ +#ifndef SMAA_UV_BASED_REPROJECTION +#define SMAA_UV_BASED_REPROJECTION 0 +#endif + +/** + * SMAA_REPROJECTION_WEIGHT_SCALE controls the velocity weighting. It allows to + * remove ghosting trails behind the moving object, which are not removed by + * just using reprojection. Using low values will exhibit ghosting, while using + * high values will disable temporal supersampling under motion. + * + * Behind the scenes, velocity weighting removes temporal supersampling when + * the velocity of the subsamples differs (meaning they are different objects). + * + * Range: [0, 80] + */ +#ifndef SMAA_REPROJECTION_WEIGHT_SCALE +#define SMAA_REPROJECTION_WEIGHT_SCALE 30.0 +#endif + +/** + * On some compilers, discard cannot be used in vertex shaders. Thus, they need + * to be compiled separately. + */ +#ifndef SMAA_INCLUDE_VS +#define SMAA_INCLUDE_VS 1 +#endif +#ifndef SMAA_INCLUDE_PS +#define SMAA_INCLUDE_PS 1 +#endif + +//----------------------------------------------------------------------------- +// Texture Access Defines + +#ifndef SMAA_AREATEX_SELECT +#if defined(SMAA_HLSL_3) +#define SMAA_AREATEX_SELECT(sample) sample.ra +#else +#define SMAA_AREATEX_SELECT(sample) sample.rg +#endif +#endif + +#ifndef SMAA_SEARCHTEX_SELECT +#define SMAA_SEARCHTEX_SELECT(sample) sample.r +#endif + +#ifndef SMAA_DECODE_VELOCITY +#define SMAA_DECODE_VELOCITY(sample) sample.rg +#endif + +//----------------------------------------------------------------------------- +// Non-Configurable Defines + +#define SMAA_AREATEX_MAX_DISTANCE 16 +#define SMAA_AREATEX_MAX_DISTANCE_DIAG 20 +#define SMAA_AREATEX_PIXEL_SIZE (1.0 / float2(160.0, 560.0)) +#define SMAA_AREATEX_SUBTEX_SIZE (1.0 / 7.0) +#define SMAA_SEARCHTEX_SIZE float2(66.0, 33.0) +#define SMAA_SEARCHTEX_PACKED_SIZE float2(64.0, 16.0) +#define SMAA_CORNER_ROUNDING_NORM (float(SMAA_CORNER_ROUNDING) / 100.0) + +//----------------------------------------------------------------------------- +// Porting Functions + +#if defined(SMAA_HLSL_3) +#define SMAATexture2D(tex) sampler2D tex +#define SMAATexturePass2D(tex) tex +#define SMAASampleLevelZero(tex, coord) tex2Dlod(tex, float4(coord, 0.0, 0.0)) +#define SMAASampleLevelZeroPoint(tex, coord) tex2Dlod(tex, float4(coord, 0.0, 0.0)) +#define SMAASampleLevelZeroOffset(tex, coord, offset) tex2Dlod(tex, float4(coord + offset * SMAA_RT_METRICS.xy, 0.0, 0.0)) +#define SMAASample(tex, coord) tex2D(tex, coord) +#define SMAASamplePoint(tex, coord) tex2D(tex, coord) +#define SMAASampleOffset(tex, coord, offset) tex2D(tex, coord + offset * SMAA_RT_METRICS.xy) +#define SMAA_FLATTEN [flatten] +#define SMAA_BRANCH [branch] +#endif +#if defined(SMAA_HLSL_4) || defined(SMAA_HLSL_4_1) +SamplerState LinearSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Clamp; AddressV = Clamp; }; +SamplerState PointSampler { Filter = MIN_MAG_MIP_POINT; AddressU = Clamp; AddressV = Clamp; }; +#define SMAATexture2D(tex) Texture2D tex +#define SMAATexturePass2D(tex) tex +#define SMAASampleLevelZero(tex, coord) tex.SampleLevel(LinearSampler, coord, 0) +#define SMAASampleLevelZeroPoint(tex, coord) tex.SampleLevel(PointSampler, coord, 0) +#define SMAASampleLevelZeroOffset(tex, coord, offset) tex.SampleLevel(LinearSampler, coord, 0, offset) +#define SMAASample(tex, coord) tex.Sample(LinearSampler, coord) +#define SMAASamplePoint(tex, coord) tex.Sample(PointSampler, coord) +#define SMAASampleOffset(tex, coord, offset) tex.Sample(LinearSampler, coord, offset) +#define SMAA_FLATTEN [flatten] +#define SMAA_BRANCH [branch] +#define SMAATexture2DMS2(tex) Texture2DMS tex +#define SMAALoad(tex, pos, sample) tex.Load(pos, sample) +#if defined(SMAA_HLSL_4_1) +#define SMAAGather(tex, coord) tex.Gather(LinearSampler, coord, 0) +#endif +#endif +#if defined(SMAA_GLSL_3) || defined(SMAA_GLSL_4) +#define SMAATexture2D(tex) sampler2D tex +#define SMAATexturePass2D(tex) tex +#define SMAASampleLevelZero(tex, coord) textureLod(tex, coord, 0.0) +#define SMAASampleLevelZeroPoint(tex, coord) textureLod(tex, coord, 0.0) +#define SMAASampleLevelZeroOffset(tex, coord, offset) textureLodOffset(tex, coord, 0.0, offset) +#define SMAASample(tex, coord) texture(tex, coord) +#define SMAASamplePoint(tex, coord) texture(tex, coord) +#define SMAASampleOffset(tex, coord, offset) texture(tex, coord, offset) +#define SMAA_FLATTEN +#define SMAA_BRANCH +#define lerp(a, b, t) mix(a, b, t) +#define saturate(a) clamp(a, 0.0, 1.0) +#if defined(SMAA_GLSL_4) +#define mad(a, b, c) fma(a, b, c) +#define SMAAGather(tex, coord) textureGather(tex, coord) +#else +#define mad(a, b, c) (a * b + c) +#endif +#define float2 vec2 +#define float3 vec3 +#define float4 vec4 +#define int2 ivec2 +#define int3 ivec3 +#define int4 ivec4 +#define bool2 bvec2 +#define bool3 bvec3 +#define bool4 bvec4 +#endif + +#if !defined(SMAA_HLSL_3) && !defined(SMAA_HLSL_4) && !defined(SMAA_HLSL_4_1) && !defined(SMAA_GLSL_3) && !defined(SMAA_GLSL_4) && !defined(SMAA_CUSTOM_SL) +#error you must define the shading language: SMAA_HLSL_*, SMAA_GLSL_* or SMAA_CUSTOM_SL +#endif + +//----------------------------------------------------------------------------- +// Misc functions + +/** + * Gathers current pixel, and the top-left neighbors. + */ +float3 SMAAGatherNeighbours(float2 texcoord, + float4 offset[3], + SMAATexture2D(tex)) { + #ifdef SMAAGather + return SMAAGather(tex, texcoord + SMAA_RT_METRICS.xy * float2(-0.5, -0.5)).grb; + #else + float P = SMAASamplePoint(tex, texcoord).r; + float Pleft = SMAASamplePoint(tex, offset[0].xy).r; + float Ptop = SMAASamplePoint(tex, offset[0].zw).r; + return float3(P, Pleft, Ptop); + #endif +} + +/** + * Adjusts the threshold by means of predication. + */ +float2 SMAACalculatePredicatedThreshold(float2 texcoord, + float4 offset[3], + SMAATexture2D(predicationTex)) { + float3 neighbours = SMAAGatherNeighbours(texcoord, offset, SMAATexturePass2D(predicationTex)); + float2 delta = abs(neighbours.xx - neighbours.yz); + float2 edges = step(SMAA_PREDICATION_THRESHOLD, delta); + return SMAA_PREDICATION_SCALE * SMAA_THRESHOLD * (1.0 - SMAA_PREDICATION_STRENGTH * edges); +} + +/** + * Conditional move: + */ +void SMAAMovc(bool2 cond, inout float2 variable, float2 value) { + SMAA_FLATTEN if (cond.x) variable.x = value.x; + SMAA_FLATTEN if (cond.y) variable.y = value.y; +} + +void SMAAMovc(bool4 cond, inout float4 variable, float4 value) { + SMAAMovc(cond.xy, variable.xy, value.xy); + SMAAMovc(cond.zw, variable.zw, value.zw); +} + + +#if SMAA_INCLUDE_VS +//----------------------------------------------------------------------------- +// Vertex Shaders + +/** + * Edge Detection Vertex Shader + */ +void SMAAEdgeDetectionVS(float2 texcoord, + out float4 offset[3]) { + offset[0] = mad(SMAA_RT_METRICS.xyxy, float4(-1.0, 0.0, 0.0, -1.0), texcoord.xyxy); + offset[1] = mad(SMAA_RT_METRICS.xyxy, float4( 1.0, 0.0, 0.0, 1.0), texcoord.xyxy); + offset[2] = mad(SMAA_RT_METRICS.xyxy, float4(-2.0, 0.0, 0.0, -2.0), texcoord.xyxy); +} + +/** + * Blend Weight Calculation Vertex Shader + */ +void SMAABlendingWeightCalculationVS(float2 texcoord, + out float2 pixcoord, + out float4 offset[3]) { + pixcoord = texcoord * SMAA_RT_METRICS.zw; + + // We will use these offsets for the searches later on (see @PSEUDO_GATHER4): + offset[0] = mad(SMAA_RT_METRICS.xyxy, float4(-0.25, -0.125, 1.25, -0.125), texcoord.xyxy); + offset[1] = mad(SMAA_RT_METRICS.xyxy, float4(-0.125, -0.25, -0.125, 1.25), texcoord.xyxy); + + // And these for the searches, they indicate the ends of the loops: + offset[2] = mad(SMAA_RT_METRICS.xxyy, + float4(-2.0, 2.0, -2.0, 2.0) * float(SMAA_MAX_SEARCH_STEPS), + float4(offset[0].xz, offset[1].yw)); +} + +/** + * Neighborhood Blending Vertex Shader + */ +void SMAANeighborhoodBlendingVS(float2 texcoord, + out float4 offset) { + offset = mad(SMAA_RT_METRICS.xyxy, float4( 1.0, 0.0, 0.0, 1.0), texcoord.xyxy); +} +#endif // SMAA_INCLUDE_VS + +#if SMAA_INCLUDE_PS +//----------------------------------------------------------------------------- +// Edge Detection Pixel Shaders (First Pass) + +/** + * Luma Edge Detection + * + * IMPORTANT NOTICE: luma edge detection requires gamma-corrected colors, and + * thus 'colorTex' should be a non-sRGB texture. + */ +float2 SMAALumaEdgeDetectionPS(float2 texcoord, + float4 offset[3], + SMAATexture2D(colorTex) + #if SMAA_PREDICATION + , SMAATexture2D(predicationTex) + #endif + ) { + // Calculate the threshold: + #if SMAA_PREDICATION + float2 threshold = SMAACalculatePredicatedThreshold(texcoord, offset, SMAATexturePass2D(predicationTex)); + #else + float2 threshold = float2(SMAA_THRESHOLD, SMAA_THRESHOLD); + #endif + + // Calculate lumas: + float3 weights = float3(0.2126, 0.7152, 0.0722); + float L = dot(SMAASamplePoint(colorTex, texcoord).rgb, weights); + + float Lleft = dot(SMAASamplePoint(colorTex, offset[0].xy).rgb, weights); + float Ltop = dot(SMAASamplePoint(colorTex, offset[0].zw).rgb, weights); + + // We do the usual threshold: + float4 delta; + delta.xy = abs(L - float2(Lleft, Ltop)); + float2 edges = step(threshold, delta.xy); + + // Then discard if there is no edge: + if (dot(edges, float2(1.0, 1.0)) == 0.0) + discard; + + // Calculate right and bottom deltas: + float Lright = dot(SMAASamplePoint(colorTex, offset[1].xy).rgb, weights); + float Lbottom = dot(SMAASamplePoint(colorTex, offset[1].zw).rgb, weights); + delta.zw = abs(L - float2(Lright, Lbottom)); + + // Calculate the maximum delta in the direct neighborhood: + float2 maxDelta = max(delta.xy, delta.zw); + + // Calculate left-left and top-top deltas: + float Lleftleft = dot(SMAASamplePoint(colorTex, offset[2].xy).rgb, weights); + float Ltoptop = dot(SMAASamplePoint(colorTex, offset[2].zw).rgb, weights); + delta.zw = abs(float2(Lleft, Ltop) - float2(Lleftleft, Ltoptop)); + + // Calculate the final maximum delta: + maxDelta = max(maxDelta.xy, delta.zw); + float finalDelta = max(maxDelta.x, maxDelta.y); + + // Local contrast adaptation: +#if !defined(SHADER_API_OPENGL) + edges.xy *= step(finalDelta, SMAA_LOCAL_CONTRAST_ADAPTATION_FACTOR * delta.xy); +#endif + + return edges; +} + +/** + * Color Edge Detection + * + * IMPORTANT NOTICE: color edge detection requires gamma-corrected colors, and + * thus 'colorTex' should be a non-sRGB texture. + */ +float2 SMAAColorEdgeDetectionPS(float2 texcoord, + float4 offset[3], + SMAATexture2D(colorTex) + #if SMAA_PREDICATION + , SMAATexture2D(predicationTex) + #endif + ) { + // Calculate the threshold: + #if SMAA_PREDICATION + float2 threshold = SMAACalculatePredicatedThreshold(texcoord, offset, predicationTex); + #else + float2 threshold = float2(SMAA_THRESHOLD, SMAA_THRESHOLD); + #endif + + // Calculate color deltas: + float4 delta; + float3 C = SMAASamplePoint(colorTex, texcoord).rgb; + + float3 Cleft = SMAASamplePoint(colorTex, offset[0].xy).rgb; + float3 t = abs(C - Cleft); + delta.x = max(max(t.r, t.g), t.b); + + float3 Ctop = SMAASamplePoint(colorTex, offset[0].zw).rgb; + t = abs(C - Ctop); + delta.y = max(max(t.r, t.g), t.b); + + // We do the usual threshold: + float2 edges = step(threshold, delta.xy); + + // Then discard if there is no edge: + if (dot(edges, float2(1.0, 1.0)) == 0.0) + discard; + + // Calculate right and bottom deltas: + float3 Cright = SMAASamplePoint(colorTex, offset[1].xy).rgb; + t = abs(C - Cright); + delta.z = max(max(t.r, t.g), t.b); + + float3 Cbottom = SMAASamplePoint(colorTex, offset[1].zw).rgb; + t = abs(C - Cbottom); + delta.w = max(max(t.r, t.g), t.b); + + // Calculate the maximum delta in the direct neighborhood: + float2 maxDelta = max(delta.xy, delta.zw); + + // Calculate left-left and top-top deltas: + float3 Cleftleft = SMAASamplePoint(colorTex, offset[2].xy).rgb; + t = abs(C - Cleftleft); + delta.z = max(max(t.r, t.g), t.b); + + float3 Ctoptop = SMAASamplePoint(colorTex, offset[2].zw).rgb; + t = abs(C - Ctoptop); + delta.w = max(max(t.r, t.g), t.b); + + // Calculate the final maximum delta: + maxDelta = max(maxDelta.xy, delta.zw); + float finalDelta = max(maxDelta.x, maxDelta.y); + + // Local contrast adaptation: +#if !defined(SHADER_API_OPENGL) + edges.xy *= step(finalDelta, SMAA_LOCAL_CONTRAST_ADAPTATION_FACTOR * delta.xy); +#endif + + return edges; +} + +/** + * Depth Edge Detection + */ +float2 SMAADepthEdgeDetectionPS(float2 texcoord, + float4 offset[3], + SMAATexture2D(depthTex)) { + float3 neighbours = SMAAGatherNeighbours(texcoord, offset, SMAATexturePass2D(depthTex)); + float2 delta = abs(neighbours.xx - float2(neighbours.y, neighbours.z)); + float2 edges = step(SMAA_DEPTH_THRESHOLD, delta); + + if (dot(edges, float2(1.0, 1.0)) == 0.0) + discard; + + return edges; +} + +//----------------------------------------------------------------------------- +// Diagonal Search Functions + +#if !defined(SMAA_DISABLE_DIAG_DETECTION) + +/** + * Allows to decode two binary values from a bilinear-filtered access. + */ +float2 SMAADecodeDiagBilinearAccess(float2 e) { + // Bilinear access for fetching 'e' have a 0.25 offset, and we are + // interested in the R and G edges: + // + // +---G---+-------+ + // | x o R x | + // +-------+-------+ + // + // Then, if one of these edge is enabled: + // Red: (0.75 * X + 0.25 * 1) => 0.25 or 1.0 + // Green: (0.75 * 1 + 0.25 * X) => 0.75 or 1.0 + // + // This function will unpack the values (mad + mul + round): + // wolframalpha.com: round(x * abs(5 * x - 5 * 0.75)) plot 0 to 1 + e.r = e.r * abs(5.0 * e.r - 5.0 * 0.75); + return round(e); +} + +float4 SMAADecodeDiagBilinearAccess(float4 e) { + e.rb = e.rb * abs(5.0 * e.rb - 5.0 * 0.75); + return round(e); +} + +/** + * These functions allows to perform diagonal pattern searches. + */ +float2 SMAASearchDiag1(SMAATexture2D(edgesTex), float2 texcoord, float2 dir, out float2 e) { + float4 coord = float4(texcoord, -1.0, 1.0); + float3 t = float3(SMAA_RT_METRICS.xy, 1.0); + while (coord.z < float(SMAA_MAX_SEARCH_STEPS_DIAG - 1) && + coord.w > 0.9) { + coord.xyz = mad(t, float3(dir, 1.0), coord.xyz); + e = SMAASampleLevelZero(edgesTex, coord.xy).rg; + coord.w = dot(e, float2(0.5, 0.5)); + } + return coord.zw; +} + +float2 SMAASearchDiag2(SMAATexture2D(edgesTex), float2 texcoord, float2 dir, out float2 e) { + float4 coord = float4(texcoord, -1.0, 1.0); + coord.x += 0.25 * SMAA_RT_METRICS.x; // See @SearchDiag2Optimization + float3 t = float3(SMAA_RT_METRICS.xy, 1.0); + while (coord.z < float(SMAA_MAX_SEARCH_STEPS_DIAG - 1) && + coord.w > 0.9) { + coord.xyz = mad(t, float3(dir, 1.0), coord.xyz); + + // @SearchDiag2Optimization + // Fetch both edges at once using bilinear filtering: + e = SMAASampleLevelZero(edgesTex, coord.xy).rg; + e = SMAADecodeDiagBilinearAccess(e); + + // Non-optimized version: + // e.g = SMAASampleLevelZero(edgesTex, coord.xy).g; + // e.r = SMAASampleLevelZeroOffset(edgesTex, coord.xy, int2(1, 0)).r; + + coord.w = dot(e, float2(0.5, 0.5)); + } + return coord.zw; +} + +/** + * Similar to SMAAArea, this calculates the area corresponding to a certain + * diagonal distance and crossing edges 'e'. + */ +float2 SMAAAreaDiag(SMAATexture2D(areaTex), float2 dist, float2 e, float offset) { + float2 texcoord = mad(float2(SMAA_AREATEX_MAX_DISTANCE_DIAG, SMAA_AREATEX_MAX_DISTANCE_DIAG), e, dist); + + // We do a scale and bias for mapping to texel space: + texcoord = mad(SMAA_AREATEX_PIXEL_SIZE, texcoord, 0.5 * SMAA_AREATEX_PIXEL_SIZE); + + // Diagonal areas are on the second half of the texture: + texcoord.x += 0.5; + + // Move to proper place, according to the subpixel offset: + texcoord.y += SMAA_AREATEX_SUBTEX_SIZE * offset; + + // Do it! + return SMAA_AREATEX_SELECT(SMAASampleLevelZero(areaTex, texcoord)); +} + +/** + * This searches for diagonal patterns and returns the corresponding weights. + */ +float2 SMAACalculateDiagWeights(SMAATexture2D(edgesTex), SMAATexture2D(areaTex), float2 texcoord, float2 e, float4 subsampleIndices) { + float2 weights = float2(0.0, 0.0); + + // Search for the line ends: + float4 d; + float2 end; + if (e.r > 0.0) { + d.xz = SMAASearchDiag1(SMAATexturePass2D(edgesTex), texcoord, float2(-1.0, 1.0), end); + d.x += float(end.y > 0.9); + } else + d.xz = float2(0.0, 0.0); + d.yw = SMAASearchDiag1(SMAATexturePass2D(edgesTex), texcoord, float2(1.0, -1.0), end); + + SMAA_BRANCH + if (d.x + d.y > 2.0) { // d.x + d.y + 1 > 3 + // Fetch the crossing edges: + float4 coords = mad(float4(-d.x + 0.25, d.x, d.y, -d.y - 0.25), SMAA_RT_METRICS.xyxy, texcoord.xyxy); + float4 c; + c.xy = SMAASampleLevelZeroOffset(edgesTex, coords.xy, int2(-1, 0)).rg; + c.zw = SMAASampleLevelZeroOffset(edgesTex, coords.zw, int2( 1, 0)).rg; + c.yxwz = SMAADecodeDiagBilinearAccess(c.xyzw); + + // Non-optimized version: + // float4 coords = mad(float4(-d.x, d.x, d.y, -d.y), SMAA_RT_METRICS.xyxy, texcoord.xyxy); + // float4 c; + // c.x = SMAASampleLevelZeroOffset(edgesTex, coords.xy, int2(-1, 0)).g; + // c.y = SMAASampleLevelZeroOffset(edgesTex, coords.xy, int2( 0, 0)).r; + // c.z = SMAASampleLevelZeroOffset(edgesTex, coords.zw, int2( 1, 0)).g; + // c.w = SMAASampleLevelZeroOffset(edgesTex, coords.zw, int2( 1, -1)).r; + + // Merge crossing edges at each side into a single value: + float2 cc = mad(float2(2.0, 2.0), c.xz, c.yw); + + // Remove the crossing edge if we didn't found the end of the line: + SMAAMovc(bool2(step(float2(0.9, 0.9), d.zw)), cc, float2(0.0, 0.0)); + + // Fetch the areas for this line: + weights += SMAAAreaDiag(SMAATexturePass2D(areaTex), d.xy, cc, subsampleIndices.z); + } + + // Search for the line ends: + d.xz = SMAASearchDiag2(SMAATexturePass2D(edgesTex), texcoord, float2(-1.0, -1.0), end); + if (SMAASampleLevelZeroOffset(edgesTex, texcoord, int2(1, 0)).r > 0.0) { + d.yw = SMAASearchDiag2(SMAATexturePass2D(edgesTex), texcoord, float2(1.0, 1.0), end); + d.y += float(end.y > 0.9); + } else + d.yw = float2(0.0, 0.0); + + SMAA_BRANCH + if (d.x + d.y > 2.0) { // d.x + d.y + 1 > 3 + // Fetch the crossing edges: + float4 coords = mad(float4(-d.x, -d.x, d.y, d.y), SMAA_RT_METRICS.xyxy, texcoord.xyxy); + float4 c; + c.x = SMAASampleLevelZeroOffset(edgesTex, coords.xy, int2(-1, 0)).g; + c.y = SMAASampleLevelZeroOffset(edgesTex, coords.xy, int2( 0, -1)).r; + c.zw = SMAASampleLevelZeroOffset(edgesTex, coords.zw, int2( 1, 0)).gr; + float2 cc = mad(float2(2.0, 2.0), c.xz, c.yw); + + // Remove the crossing edge if we didn't found the end of the line: + SMAAMovc(bool2(step(float2(0.9, 0.9), d.zw)), cc, float2(0.0, 0.0)); + + // Fetch the areas for this line: + weights += SMAAAreaDiag(SMAATexturePass2D(areaTex), d.xy, cc, subsampleIndices.w).gr; + } + + return weights; +} +#endif + +//----------------------------------------------------------------------------- +// Horizontal/Vertical Search Functions + +/** + * This allows to determine how much length should we add in the last step + * of the searches. It takes the bilinearly interpolated edge (see + * @PSEUDO_GATHER4), and adds 0, 1 or 2, depending on which edges and + * crossing edges are active. + */ +float SMAASearchLength(SMAATexture2D(searchTex), float2 e, float offset) { + // The texture is flipped vertically, with left and right cases taking half + // of the space horizontally: + float2 scale = SMAA_SEARCHTEX_SIZE * float2(0.5, -1.0); + float2 bias = SMAA_SEARCHTEX_SIZE * float2(offset, 1.0); + + // Scale and bias to access texel centers: + scale += float2(-1.0, 1.0); + bias += float2( 0.5, -0.5); + + // Convert from pixel coordinates to texcoords: + // (We use SMAA_SEARCHTEX_PACKED_SIZE because the texture is cropped) + scale *= 1.0 / SMAA_SEARCHTEX_PACKED_SIZE; + bias *= 1.0 / SMAA_SEARCHTEX_PACKED_SIZE; + + // Lookup the search texture: + return SMAA_SEARCHTEX_SELECT(SMAASampleLevelZero(searchTex, mad(scale, e, bias))); +} + +/** + * Horizontal/vertical search functions for the 2nd pass. + */ +float SMAASearchXLeft(SMAATexture2D(edgesTex), SMAATexture2D(searchTex), float2 texcoord, float end) { + /** + * @PSEUDO_GATHER4 + * This texcoord has been offset by (-0.25, -0.125) in the vertex shader to + * sample between edge, thus fetching four edges in a row. + * Sampling with different offsets in each direction allows to disambiguate + * which edges are active from the four fetched ones. + */ + float2 e = float2(0.0, 1.0); + while (texcoord.x > end && + e.g > 0.8281 && // Is there some edge not activated? + e.r == 0.0) { // Or is there a crossing edge that breaks the line? + e = SMAASampleLevelZero(edgesTex, texcoord).rg; + texcoord = mad(-float2(2.0, 0.0), SMAA_RT_METRICS.xy, texcoord); + } + + float offset = mad(-(255.0 / 127.0), SMAASearchLength(SMAATexturePass2D(searchTex), e, 0.0), 3.25); + return mad(SMAA_RT_METRICS.x, offset, texcoord.x); + + // Non-optimized version: + // We correct the previous (-0.25, -0.125) offset we applied: + // texcoord.x += 0.25 * SMAA_RT_METRICS.x; + + // The searches are bias by 1, so adjust the coords accordingly: + // texcoord.x += SMAA_RT_METRICS.x; + + // Disambiguate the length added by the last step: + // texcoord.x += 2.0 * SMAA_RT_METRICS.x; // Undo last step + // texcoord.x -= SMAA_RT_METRICS.x * (255.0 / 127.0) * SMAASearchLength(SMAATexturePass2D(searchTex), e, 0.0); + // return mad(SMAA_RT_METRICS.x, offset, texcoord.x); +} + +float SMAASearchXRight(SMAATexture2D(edgesTex), SMAATexture2D(searchTex), float2 texcoord, float end) { + float2 e = float2(0.0, 1.0); + while (texcoord.x < end && + e.g > 0.8281 && // Is there some edge not activated? + e.r == 0.0) { // Or is there a crossing edge that breaks the line? + e = SMAASampleLevelZero(edgesTex, texcoord).rg; + texcoord = mad(float2(2.0, 0.0), SMAA_RT_METRICS.xy, texcoord); + } + float offset = mad(-(255.0 / 127.0), SMAASearchLength(SMAATexturePass2D(searchTex), e, 0.5), 3.25); + return mad(-SMAA_RT_METRICS.x, offset, texcoord.x); +} + +float SMAASearchYUp(SMAATexture2D(edgesTex), SMAATexture2D(searchTex), float2 texcoord, float end) { + float2 e = float2(1.0, 0.0); + while (texcoord.y > end && + e.r > 0.8281 && // Is there some edge not activated? + e.g == 0.0) { // Or is there a crossing edge that breaks the line? + e = SMAASampleLevelZero(edgesTex, texcoord).rg; + texcoord = mad(-float2(0.0, 2.0), SMAA_RT_METRICS.xy, texcoord); + } + float offset = mad(-(255.0 / 127.0), SMAASearchLength(SMAATexturePass2D(searchTex), e.gr, 0.0), 3.25); + return mad(SMAA_RT_METRICS.y, offset, texcoord.y); +} + +float SMAASearchYDown(SMAATexture2D(edgesTex), SMAATexture2D(searchTex), float2 texcoord, float end) { + float2 e = float2(1.0, 0.0); + while (texcoord.y < end && + e.r > 0.8281 && // Is there some edge not activated? + e.g == 0.0) { // Or is there a crossing edge that breaks the line? + e = SMAASampleLevelZero(edgesTex, texcoord).rg; + texcoord = mad(float2(0.0, 2.0), SMAA_RT_METRICS.xy, texcoord); + } + float offset = mad(-(255.0 / 127.0), SMAASearchLength(SMAATexturePass2D(searchTex), e.gr, 0.5), 3.25); + return mad(-SMAA_RT_METRICS.y, offset, texcoord.y); +} + +/** + * Ok, we have the distance and both crossing edges. So, what are the areas + * at each side of current edge? + */ +float2 SMAAArea(SMAATexture2D(areaTex), float2 dist, float e1, float e2, float offset) { + // Rounding prevents precision errors of bilinear filtering: + float2 texcoord = mad(float2(SMAA_AREATEX_MAX_DISTANCE, SMAA_AREATEX_MAX_DISTANCE), round(4.0 * float2(e1, e2)), dist); + + // We do a scale and bias for mapping to texel space: + texcoord = mad(SMAA_AREATEX_PIXEL_SIZE, texcoord, 0.5 * SMAA_AREATEX_PIXEL_SIZE); + + // Move to proper place, according to the subpixel offset: + texcoord.y = mad(SMAA_AREATEX_SUBTEX_SIZE, offset, texcoord.y); + + // Do it! + return SMAA_AREATEX_SELECT(SMAASampleLevelZero(areaTex, texcoord)); +} + +//----------------------------------------------------------------------------- +// Corner Detection Functions + +void SMAADetectHorizontalCornerPattern(SMAATexture2D(edgesTex), inout float2 weights, float4 texcoord, float2 d) { + #if !defined(SMAA_DISABLE_CORNER_DETECTION) + float2 leftRight = step(d.xy, d.yx); + float2 rounding = (1.0 - SMAA_CORNER_ROUNDING_NORM) * leftRight; + + rounding /= leftRight.x + leftRight.y; // Reduce blending for pixels in the center of a line. + + float2 factor = float2(1.0, 1.0); + factor.x -= rounding.x * SMAASampleLevelZeroOffset(edgesTex, texcoord.xy, int2(0, 1)).r; + factor.x -= rounding.y * SMAASampleLevelZeroOffset(edgesTex, texcoord.zw, int2(1, 1)).r; + factor.y -= rounding.x * SMAASampleLevelZeroOffset(edgesTex, texcoord.xy, int2(0, -2)).r; + factor.y -= rounding.y * SMAASampleLevelZeroOffset(edgesTex, texcoord.zw, int2(1, -2)).r; + + weights *= saturate(factor); + #endif +} + +void SMAADetectVerticalCornerPattern(SMAATexture2D(edgesTex), inout float2 weights, float4 texcoord, float2 d) { + #if !defined(SMAA_DISABLE_CORNER_DETECTION) + float2 leftRight = step(d.xy, d.yx); + float2 rounding = (1.0 - SMAA_CORNER_ROUNDING_NORM) * leftRight; + + rounding /= leftRight.x + leftRight.y; + + float2 factor = float2(1.0, 1.0); + factor.x -= rounding.x * SMAASampleLevelZeroOffset(edgesTex, texcoord.xy, int2( 1, 0)).g; + factor.x -= rounding.y * SMAASampleLevelZeroOffset(edgesTex, texcoord.zw, int2( 1, 1)).g; + factor.y -= rounding.x * SMAASampleLevelZeroOffset(edgesTex, texcoord.xy, int2(-2, 0)).g; + factor.y -= rounding.y * SMAASampleLevelZeroOffset(edgesTex, texcoord.zw, int2(-2, 1)).g; + + weights *= saturate(factor); + #endif +} + + +//----------------------------------------------------------------------------- +// Blending Weight Calculation Pixel Shader (Second Pass) + +float4 SMAABlendingWeightCalculationPS(float2 texcoord, + float2 pixcoord, + float4 offset[3], + SMAATexture2D(edgesTex), + SMAATexture2D(areaTex), + SMAATexture2D(searchTex), + float4 subsampleIndices) { // Just pass zero for SMAA 1x, see @SUBSAMPLE_INDICES. + float4 weights = float4(0.0, 0.0, 0.0, 0.0); + + float2 e = SMAASample(edgesTex, texcoord).rg; + + SMAA_BRANCH + if (e.g > 0.0) { // Edge at north + #if !defined(SMAA_DISABLE_DIAG_DETECTION) + // Diagonals have both north and west edges, so searching for them in + // one of the boundaries is enough. + weights.rg = SMAACalculateDiagWeights(SMAATexturePass2D(edgesTex), SMAATexturePass2D(areaTex), texcoord, e, subsampleIndices); + + // We give priority to diagonals, so if we find a diagonal we skip + // horizontal/vertical processing. + SMAA_BRANCH + if (weights.r == -weights.g) { // weights.r + weights.g == 0.0 + #endif + + float2 d; + + // Find the distance to the left: + float3 coords; + coords.x = SMAASearchXLeft(SMAATexturePass2D(edgesTex), SMAATexturePass2D(searchTex), offset[0].xy, offset[2].x); + coords.y = offset[1].y; // offset[1].y = texcoord.y - 0.25 * SMAA_RT_METRICS.y (@CROSSING_OFFSET) + d.x = coords.x; + + // Now fetch the left crossing edges, two at a time using bilinear + // filtering. Sampling at -0.25 (see @CROSSING_OFFSET) enables to + // discern what value each edge has: + float e1 = SMAASampleLevelZero(edgesTex, coords.xy).r; + + // Find the distance to the right: + coords.z = SMAASearchXRight(SMAATexturePass2D(edgesTex), SMAATexturePass2D(searchTex), offset[0].zw, offset[2].y); + d.y = coords.z; + + // We want the distances to be in pixel units (doing this here allow to + // better interleave arithmetic and memory accesses): + d = abs(round(mad(SMAA_RT_METRICS.zz, d, -pixcoord.xx))); + + // SMAAArea below needs a sqrt, as the areas texture is compressed + // quadratically: + float2 sqrt_d = sqrt(d); + + // Fetch the right crossing edges: + float e2 = SMAASampleLevelZeroOffset(edgesTex, coords.zy, int2(1, 0)).r; + + // Ok, we know how this pattern looks like, now it is time for getting + // the actual area: + weights.rg = SMAAArea(SMAATexturePass2D(areaTex), sqrt_d, e1, e2, subsampleIndices.y); + + // Fix corners: + coords.y = texcoord.y; + SMAADetectHorizontalCornerPattern(SMAATexturePass2D(edgesTex), weights.rg, coords.xyzy, d); + + #if !defined(SMAA_DISABLE_DIAG_DETECTION) + } else + e.r = 0.0; // Skip vertical processing. + #endif + } + + SMAA_BRANCH + if (e.r > 0.0) { // Edge at west + float2 d; + + // Find the distance to the top: + float3 coords; + coords.y = SMAASearchYUp(SMAATexturePass2D(edgesTex), SMAATexturePass2D(searchTex), offset[1].xy, offset[2].z); + coords.x = offset[0].x; // offset[1].x = texcoord.x - 0.25 * SMAA_RT_METRICS.x; + d.x = coords.y; + + // Fetch the top crossing edges: + float e1 = SMAASampleLevelZero(edgesTex, coords.xy).g; + + // Find the distance to the bottom: + coords.z = SMAASearchYDown(SMAATexturePass2D(edgesTex), SMAATexturePass2D(searchTex), offset[1].zw, offset[2].w); + d.y = coords.z; + + // We want the distances to be in pixel units: + d = abs(round(mad(SMAA_RT_METRICS.ww, d, -pixcoord.yy))); + + // SMAAArea below needs a sqrt, as the areas texture is compressed + // quadratically: + float2 sqrt_d = sqrt(d); + + // Fetch the bottom crossing edges: + float e2 = SMAASampleLevelZeroOffset(edgesTex, coords.xz, int2(0, 1)).g; + + // Get the area for this direction: + weights.ba = SMAAArea(SMAATexturePass2D(areaTex), sqrt_d, e1, e2, subsampleIndices.x); + + // Fix corners: + coords.x = texcoord.x; + SMAADetectVerticalCornerPattern(SMAATexturePass2D(edgesTex), weights.ba, coords.xyxz, d); + } + + return weights; +} + +//----------------------------------------------------------------------------- +// UV-based reprojection functions + +#if SMAA_UV_BASED_REPROJECTION +float2 SMAAReproject(float2 texcoord) +{ + // UV to clip-position: + // -- This must be sampled at exactly mip 0 due to possible gradient divergence + // -- as this function is called within a control flow block down below. + float depth = SMAASampleLevelZero(_CameraDepthTexture, texcoord).r; + float3 clipPosition = float3(2. * texcoord - 1., depth); + + // Reproject + float4 previousClipPosition = mul(_ReprojectionMatrix, float4(clipPosition, 1.)); + previousClipPosition.xyz /= previousClipPosition.w; + + // Clip-position to UV + return (.5 * previousClipPosition.xy + .5); +} +#endif + +//----------------------------------------------------------------------------- +// Neighborhood Blending Pixel Shader (Third Pass) + +float4 SMAANeighborhoodBlendingPS(float2 texcoord, + float4 offset, + SMAATexture2D(colorTex), + SMAATexture2D(blendTex) + #if SMAA_REPROJECTION + , SMAATexture2D(velocityTex) + #endif + ) { + // Fetch the blending weights for current pixel: + float4 a; + a.x = SMAASample(blendTex, offset.xy).a; // Right + a.y = SMAASample(blendTex, offset.zw).g; // Top + a.wz = SMAASample(blendTex, texcoord).xz; // Bottom / Left + + // Is there any blending weight with a value greater than 0.0? + SMAA_BRANCH + if (dot(a, float4(1.0, 1.0, 1.0, 1.0)) < 1e-5) { + float4 color = SMAASampleLevelZero(colorTex, texcoord); + + #if SMAA_REPROJECTION + float2 velocity = SMAA_DECODE_VELOCITY(SMAASampleLevelZero(velocityTex, texcoord)); + #elif SMAA_UV_BASED_REPROJECTION + float2 velocity = texcoord - SMAAReproject(texcoord); + #endif + + #if (SMAA_REPROJECTION || SMAA_UV_BASED_REPROJECTION) + // Pack velocity into the alpha channel: + color.a = sqrt(5.0 * length(velocity)); + #endif + + return color; + } else { + bool h = max(a.x, a.z) > max(a.y, a.w); // max(horizontal) > max(vertical) + + // Calculate the blending offsets: + float4 blendingOffset = float4(0.0, a.y, 0.0, a.w); + float2 blendingWeight = a.yw; + SMAAMovc(bool4(h, h, h, h), blendingOffset, float4(a.x, 0.0, a.z, 0.0)); + SMAAMovc(bool2(h, h), blendingWeight, a.xz); + blendingWeight /= dot(blendingWeight, float2(1.0, 1.0)); + + // Calculate the texture coordinates: + float4 blendingCoord = mad(blendingOffset, float4(SMAA_RT_METRICS.xy, -SMAA_RT_METRICS.xy), texcoord.xyxy); + + // We exploit bilinear filtering to mix current pixel with the chosen + // neighbor: + float4 color = blendingWeight.x * SMAASampleLevelZero(colorTex, blendingCoord.xy); + color += blendingWeight.y * SMAASampleLevelZero(colorTex, blendingCoord.zw); + + #if SMAA_REPROJECTION + // Antialias velocity for proper reprojection in a later stage: + float2 velocity = blendingWeight.x * SMAA_DECODE_VELOCITY(SMAASampleLevelZero(velocityTex, blendingCoord.xy)); + velocity += blendingWeight.y * SMAA_DECODE_VELOCITY(SMAASampleLevelZero(velocityTex, blendingCoord.zw)); + #elif SMAA_UV_BASED_REPROJECTION + // Antialias velocity for proper reprojection in a later stage: + float2 velocity = blendingWeight.x * (blendingCoord.xy - SMAAReproject(blendingCoord.xy)); + velocity += blendingWeight.y * (blendingCoord.zw - SMAAReproject(blendingCoord.zw)); + #endif + + #if (SMAA_REPROJECTION || SMAA_UV_BASED_REPROJECTION) + // Pack velocity into the alpha channel: + color.a = sqrt(5.0 * length(velocity)); + #endif + + return color; + } +} + +//----------------------------------------------------------------------------- +// Temporal Resolve Pixel Shader (Optional Pass) + +float4 SMAAResolvePS(float2 texcoord, + SMAATexture2D(currentColorTex), + SMAATexture2D(previousColorTex) + #if SMAA_REPROJECTION + , SMAATexture2D(velocityTex) + #endif + ) { + #if SMAA_REPROJECTION + // Velocity is assumed to be calculated for motion blur, so we need to + // inverse it for reprojection: + float2 velocity = -SMAA_DECODE_VELOCITY(SMAASamplePoint(velocityTex, texcoord).rg); + #elif SMAA_UV_BASED_REPROJECTION + float2 velocity = SMAAReproject(texcoord) - texcoord; + #endif + + #if (SMAA_REPROJECTION || SMAA_UV_BASED_REPROJECTION) + // Fetch current pixel: + float4 current = SMAASamplePoint(currentColorTex, texcoord); + + // Reproject current coordinates and fetch previous pixel: + float4 previous = SMAASamplePoint(previousColorTex, texcoord + velocity); + + // Attenuate the previous pixel if the velocity is different: + float delta = abs(current.a * current.a - previous.a * previous.a) / 5.0; + float weight = 0.5 * saturate(1.0 - sqrt(delta) * SMAA_REPROJECTION_WEIGHT_SCALE); + + // Blend the pixels according to the calculated weight: + // return lerp(current, previous, weight); + + // Neighbour clamp + // Contributed by pommak + float4 n0 = SMAASampleOffset(currentColorTex, texcoord, float2(-1, -1)); + float4 n1 = SMAASampleOffset(currentColorTex, texcoord, float2(+1, -1)); + float4 n2 = SMAASampleOffset(currentColorTex, texcoord, float2(-1, +1)); + float4 n3 = SMAASampleOffset(currentColorTex, texcoord, float2(+1, +1)); + float4 cmax = max(n0, max(n1, max(n2, n3))); + float4 cmin = min(n0, min(n1, min(n2, n3))); + float4 avg = 0.25 * (n0+n1+n2+n3); + float4 wk = abs(avg - current); + float blend = saturate(lerp(0.35, 0.85, wk)); + + // Clamp previous to neighbours colors + float4 previousClamped = clamp(previous, cmin, cmax); + + float4 color = lerp(lerp(current, previousClamped, 0.5*weight), previousClamped, weight); + return color; + #else + // Just blend the pixels: + float4 current = SMAASamplePoint(currentColorTex, texcoord); + float4 previous = SMAASamplePoint(previousColorTex, texcoord); + return lerp(current, previous, 0.5); + #endif +} + +//----------------------------------------------------------------------------- +// Separate Multisamples Pixel Shader (Optional Pass) + +#ifdef SMAALoad +void SMAASeparatePS(float4 position, + float2 texcoord, + out float4 target0, + out float4 target1, + SMAATexture2DMS2(colorTexMS)) { + int2 pos = int2(position.xy); + target0 = SMAALoad(colorTexMS, pos, 0); + target1 = SMAALoad(colorTexMS, pos, 1); +} +#endif + +//----------------------------------------------------------------------------- +#endif // SMAA_INCLUDE_PS diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/SMAA.cginc.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/SMAA.cginc.meta new file mode 100644 index 0000000..184d013 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/SMAA.cginc.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 74597699f47d8ae458dca68f79f1b21f +timeCreated: 1430504573 +licenseType: Store +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/SMAA.shader b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/SMAA.shader new file mode 100644 index 0000000..fe37cec --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/SMAA.shader @@ -0,0 +1,382 @@ +Shader "Hidden/Subpixel Morphological Anti-aliasing" +{ + Properties + { + _MainTex ("Base (RGB)", 2D) = "white" {} + } + + CGINCLUDE + + #pragma fragmentoption ARB_precision_hint_fastest + #pragma target 3.0 + #pragma glsl + #pragma exclude_renderers flash + + sampler2D _MainTex; + sampler2D _BlendTex; + sampler2D _AreaTex; + sampler2D _SearchTex; + sampler2D _AccumulationTex; + + sampler2D _CameraDepthTexture; + + float4 _MainTex_TexelSize; + + float4 _Metrics; // 1f / width, 1f / height, width, height + float4 _Params1; // SMAA_THRESHOLD, SMAA_DEPTH_THRESHOLD, SMAA_MAX_SEARCH_STEPS, SMAA_MAX_SEARCH_STEPS_DIAG + float2 _Params2; // SMAA_CORNER_ROUNDING, SMAA_LOCAL_CONTRAST_ADAPTATION_FACTOR + float3 _Params3; // SMAA_PREDICATION_THRESHOLD, SMAA_PREDICATION_SCALE, SMAA_PREDICATION_STRENGTH + + float4x4 _ReprojectionMatrix; + float4 _SubsampleIndices; + + #define SMAA_RT_METRICS _Metrics + #define SMAA_THRESHOLD _Params1.x + #define SMAA_DEPTH_THRESHOLD _Params1.y + #define SMAA_MAX_SEARCH_STEPS _Params1.z + #define SMAA_MAX_SEARCH_STEPS_DIAG _Params1.w + #define SMAA_CORNER_ROUNDING _Params2.x + #define SMAA_LOCAL_CONTRAST_ADAPTATION_FACTOR _Params2.y + #define SMAA_PREDICATION_THRESHOLD _Params3.x + #define SMAA_PREDICATION_SCALE _Params3.y + #define SMAA_PREDICATION_STRENGTH _Params3.z + + // Can't use SMAA_HLSL_3 as it won't compile with OpenGL, so lets make our own set of defines for Unity + #define SMAA_CUSTOM_SL + + #define mad(a, b, c) (a * b + c) + #define SMAATexture2D(tex) sampler2D tex + #define SMAATexturePass2D(tex) tex + #define SMAASampleLevelZero(tex, coord) tex2Dlod(tex, float4(coord, 0.0, 0.0)) + #define SMAASampleLevelZeroPoint(tex, coord) tex2Dlod(tex, float4(coord, 0.0, 0.0)) + #define SMAASampleLevelZeroOffset(tex, coord, offset) tex2Dlod(tex, float4(coord + offset * SMAA_RT_METRICS.xy, 0.0, 0.0)) + #define SMAASample(tex, coord) tex2D(tex, coord) + #define SMAASamplePoint(tex, coord) tex2D(tex, coord) + #define SMAASampleOffset(tex, coord, offset) tex2D(tex, coord + offset * SMAA_RT_METRICS.xy) + + #define SMAA_FLATTEN UNITY_FLATTEN + #define SMAA_BRANCH UNITY_BRANCH + // SMAA_CUSTOM_SL + + #define SMAA_AREATEX_SELECT(sample) sample.rg + #define SMAA_SEARCHTEX_SELECT(sample) sample.a + #define SMAA_INCLUDE_VS 0 + + struct vInput + { + float4 pos : POSITION; + float2 uv : TEXCOORD0; + }; + + struct fInput_edge + { + float4 pos : SV_POSITION; + float2 uv : TEXCOORD0; + float4 offset[3] : TEXCOORD1; + }; + + fInput_edge vert_edge(vInput i) + { + fInput_edge o; + o.pos = mul(UNITY_MATRIX_MVP, i.pos); + o.uv = i.uv; + + #if UNITY_UV_STARTS_AT_TOP + if (_MainTex_TexelSize.y < 0) + o.uv.y = 1.0 - i.uv.y; + #endif + + o.offset[0] = mad(SMAA_RT_METRICS.xyxy, float4(-1.0, 0.0, 0.0, -1.0), o.uv.xyxy); + o.offset[1] = mad(SMAA_RT_METRICS.xyxy, float4( 1.0, 0.0, 0.0, 1.0), o.uv.xyxy); + o.offset[2] = mad(SMAA_RT_METRICS.xyxy, float4(-2.0, 0.0, 0.0, -2.0), o.uv.xyxy); + return o; + } + + ENDCG + + SubShader + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + // (0) Clear + Pass + { + CGPROGRAM + + #pragma vertex vert_img + #pragma fragment frag + #include "UnityCG.cginc" + + float4 frag(v2f_img i) : SV_Target + { + return float4(0.0, 0.0, 0.0, 0.0); + } + + ENDCG + } + + + // ----------------------------------------------------------------------------- + // Edge Detection + + // (1) Luma + Pass + { + // TODO: Stencil not working + // Stencil + // { + // Pass replace + // Ref 1 + // } + + CGPROGRAM + + #pragma vertex vert_edge + #pragma fragment frag + #pragma multi_compile __ USE_PREDICATION + + #if USE_PREDICATION + #define SMAA_PREDICATION 1 + #else + #define SMAA_PREDICATION 0 + #endif + + #include "UnityCG.cginc" + #include "SMAA.cginc" + + float4 frag(fInput_edge i) : SV_Target + { + #if SMAA_PREDICATION + return float4(SMAALumaEdgeDetectionPS(i.uv, i.offset, _MainTex, _CameraDepthTexture), 0.0, 0.0); + #else + return float4(SMAALumaEdgeDetectionPS(i.uv, i.offset, _MainTex), 0.0, 0.0); + #endif + } + + ENDCG + } + + // (2) Color + Pass + { + // TODO: Stencil not working + // Stencil + // { + // Pass replace + // Ref 1 + // } + + CGPROGRAM + + #pragma vertex vert_edge + #pragma fragment frag + #pragma multi_compile __ USE_PREDICATION + + #if USE_PREDICATION + #define SMAA_PREDICATION 1 + #else + #define SMAA_PREDICATION 0 + #endif + + #include "UnityCG.cginc" + #include "SMAA.cginc" + + float4 frag(fInput_edge i) : SV_Target + { + #if SMAA_PREDICATION + return float4(SMAAColorEdgeDetectionPS(i.uv, i.offset, _MainTex, _CameraDepthTexture), 0.0, 0.0); + #else + return float4(SMAAColorEdgeDetectionPS(i.uv, i.offset, _MainTex), 0.0, 0.0); + #endif + } + + ENDCG + } + + // (3) Depth + Pass + { + // TODO: Stencil not working + // Stencil + // { + // Pass replace + // Ref 1 + // } + + CGPROGRAM + + #pragma vertex vert_edge + #pragma fragment frag + + #define SMAA_PREDICATION 0 + + #include "UnityCG.cginc" + #include "SMAA.cginc" + + float4 frag(fInput_edge i) : SV_Target + { + return float4(SMAADepthEdgeDetectionPS(i.uv, i.offset, _CameraDepthTexture), 0.0, 0.0); + } + + ENDCG + } + + + // ----------------------------------------------------------------------------- + // Blend Weights Calculation + + // (4) + Pass + { + // TODO: Stencil not working + // Stencil + // { + // Pass keep + // Comp equal + // Ref 1 + // } + + CGPROGRAM + + #pragma vertex vert + #pragma fragment frag + #pragma multi_compile __ USE_DIAG_SEARCH + #pragma multi_compile __ USE_CORNER_DETECTION + + #if !defined(USE_DIAG_SEARCH) + #define SMAA_DISABLE_DIAG_DETECTION + #endif + + #if !defined(USE_CORNER_DETECTION) + #define SMAA_DISABLE_CORNER_DETECTION + #endif + + #include "UnityCG.cginc" + #include "SMAA.cginc" + + struct fInput + { + float4 pos : SV_POSITION; + float2 uv : TEXCOORD0; + float2 pixcoord : TEXCOORD1; + float4 offset[3] : TEXCOORD2; + }; + + fInput vert(vInput i) + { + fInput o; + o.pos = mul(UNITY_MATRIX_MVP, i.pos); + o.uv = i.uv; + o.pixcoord = o.uv * SMAA_RT_METRICS.zw; + + // We will use these offsets for the searches later on (see @PSEUDO_GATHER4): + o.offset[0] = mad(SMAA_RT_METRICS.xyxy, float4(-0.25, -0.125, 1.25, -0.125), o.uv.xyxy); + o.offset[1] = mad(SMAA_RT_METRICS.xyxy, float4(-0.125, -0.25, -0.125, 1.25), o.uv.xyxy); + + // And these for the searches, they indicate the ends of the loops: + o.offset[2] = mad(SMAA_RT_METRICS.xxyy, float4(-2.0, 2.0, -2.0, 2.0) * float(SMAA_MAX_SEARCH_STEPS), + float4(o.offset[0].xz, o.offset[1].yw)); + + return o; + } + + float4 frag(fInput i) : SV_Target + { + return SMAABlendingWeightCalculationPS(i.uv, i.pixcoord, i.offset, _MainTex, _AreaTex, _SearchTex, + _SubsampleIndices); + } + + ENDCG + } + + + // ----------------------------------------------------------------------------- + // Neighborhood Blending + + // (5) + Pass + { + CGPROGRAM + + #pragma vertex vert + #pragma fragment frag + + #pragma multi_compile __ USE_UV_BASED_REPROJECTION + + #if defined (USE_UV_BASED_REPROJECTION) + #define SMAA_UV_BASED_REPROJECTION 1 + #endif + + #include "UnityCG.cginc" + #include "SMAA.cginc" + + struct fInput + { + float4 pos : SV_POSITION; + float2 uv : TEXCOORD0; + float4 offset : TEXCOORD1; + }; + + fInput vert(vInput i) + { + fInput o; + o.pos = mul(UNITY_MATRIX_MVP, i.pos); + o.uv = i.uv; + o.offset = mad(SMAA_RT_METRICS.xyxy, float4(1.0, 0.0, 0.0, 1.0), o.uv.xyxy); + return o; + } + + float4 frag(fInput i) : SV_Target + { + return SMAANeighborhoodBlendingPS(i.uv, i.offset, _MainTex, _BlendTex); + } + + ENDCG + } + + // ----------------------------------------------------------------------------- + // Accumulation Resolve + + // (6) + Pass + { + CGPROGRAM + + #pragma vertex vert + #pragma fragment frag + + #pragma multi_compile __ USE_UV_BASED_REPROJECTION + + #if defined (USE_UV_BASED_REPROJECTION) + #define SMAA_UV_BASED_REPROJECTION 1 + #endif + + #include "UnityCG.cginc" + #include "SMAA.cginc" + + struct fInput + { + float4 pos : SV_POSITION; + float2 uv : TEXCOORD0; + }; + + fInput vert(vInput i) + { + fInput o; + o.pos = mul(UNITY_MATRIX_MVP, i.pos); + o.uv = i.uv; + return o; + } + + float4 frag(fInput i) : SV_Target + { + return SMAAResolvePS(i.uv, _MainTex, _AccumulationTex); + } + + ENDCG + } + } + + FallBack off +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/SMAA.shader.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/SMAA.shader.meta new file mode 100644 index 0000000..931b06f --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/SMAA.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 4505fec7a81214243b8e59edf89e3a53 +timeCreated: 1432603500 +licenseType: Store +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/SearchTex.tga b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/SearchTex.tga new file mode 100644 index 0000000..bda78d0 Binary files /dev/null and b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/SearchTex.tga differ diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/SearchTex.tga.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/SearchTex.tga.meta new file mode 100644 index 0000000..637bc38 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/Resources/SearchTex.tga.meta @@ -0,0 +1,57 @@ +fileFormatVersion: 2 +guid: 387ed7c38eb63554db846987adb98e68 +timeCreated: 1432601000 +licenseType: Store +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 1 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 8 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + filterMode: 0 + aniso: -1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + rGBM: 2 + compressionQuality: 50 + allowsAlphaSplitting: 0 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: 5 + buildTargetSettings: [] + spriteSheet: + sprites: [] + outline: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/SMAA.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/SMAA.cs new file mode 100644 index 0000000..63328fc --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/SMAA.cs @@ -0,0 +1,484 @@ +using UnityEngine; +using System; +#if UNITY_EDITOR +using UnityEditor; +#endif +using Object = UnityEngine.Object; + +namespace UnityStandardAssets.CinematicEffects +{ + [Serializable] + public class SMAA : IAntiAliasing + { + [AttributeUsage(AttributeTargets.Field)] + public class SettingsGroup : Attribute + {} + + [AttributeUsage(AttributeTargets.Field)] + public class TopLevelSettings : Attribute + {} + + [AttributeUsage(AttributeTargets.Field)] + public class ExperimentalGroup : Attribute + {} + + public enum DebugPass + { + Off, + Edges, + Weights, + Accumulation + } + + public enum QualityPreset + { + Low = 0, + Medium = 1, + High = 2, + Ultra = 3, + Custom + } + + public enum EdgeDetectionMethod + { + Luma = 1, + Color = 2, + Depth = 3 + } + + [Serializable] + public struct GlobalSettings + { + [Tooltip("Use this to fine tune your settings when working in Custom quality mode. \"Accumulation\" only works when \"Temporal Filtering\" is enabled.")] + public DebugPass debugPass; + + [Tooltip("Low: 60% of the quality.\nMedium: 80% of the quality.\nHigh: 95% of the quality.\nUltra: 99% of the quality (overkill).")] + public QualityPreset quality; + + [Tooltip("You've three edge detection methods to choose from: luma, color or depth.\nThey represent different quality/performance and anti-aliasing/sharpness tradeoffs, so our recommendation is for you to choose the one that best suits your particular scenario:\n\n- Depth edge detection is usually the fastest but it may miss some edges.\n- Luma edge detection is usually more expensive than depth edge detection, but catches visible edges that depth edge detection can miss.\n- Color edge detection is usually the most expensive one but catches chroma-only edges.")] + public EdgeDetectionMethod edgeDetectionMethod; + + public static GlobalSettings defaultSettings + { + get + { + return new GlobalSettings + { + debugPass = DebugPass.Off, + quality = QualityPreset.High, + edgeDetectionMethod = EdgeDetectionMethod.Color + }; + } + } + } + + [Serializable] + public struct QualitySettings + { + [Tooltip("Enables/Disables diagonal processing.")] + public bool diagonalDetection; + + [Tooltip("Enables/Disables corner detection. Leave this on to avoid blurry corners.")] + public bool cornerDetection; + + [Range(0f, 0.5f)] + [Tooltip("Specifies the threshold or sensitivity to edges. Lowering this value you will be able to detect more edges at the expense of performance.\n0.1 is a reasonable value, and allows to catch most visible edges. 0.05 is a rather overkill value, that allows to catch 'em all.")] + public float threshold; + + [Min(0.0001f)] + [Tooltip("Specifies the threshold for depth edge detection. Lowering this value you will be able to detect more edges at the expense of performance.")] + public float depthThreshold; + + [Range(0, 112)] + [Tooltip("Specifies the maximum steps performed in the horizontal/vertical pattern searches, at each side of the pixel.\nIn number of pixels, it's actually the double. So the maximum line length perfectly handled by, for example 16, is 64 (by perfectly, we meant that longer lines won't look as good, but still antialiased).")] + public int maxSearchSteps; + + [Range(0, 20)] + [Tooltip("Specifies the maximum steps performed in the diagonal pattern searches, at each side of the pixel. In this case we jump one pixel at time, instead of two.\nOn high-end machines it is cheap (between a 0.8x and 0.9x slower for 16 steps), but it can have a significant impact on older machines.")] + public int maxDiagonalSearchSteps; + + [Range(0, 100)] + [Tooltip("Specifies how much sharp corners will be rounded.")] + public int cornerRounding; + + [Min(0f)] + [Tooltip("If there is an neighbor edge that has a local contrast factor times bigger contrast than current edge, current edge will be discarded.\nThis allows to eliminate spurious crossing edges, and is based on the fact that, if there is too much contrast in a direction, that will hide perceptually contrast in the other neighbors.")] + public float localContrastAdaptationFactor; + + public static QualitySettings[] presetQualitySettings = + { + // Low + new QualitySettings + { + diagonalDetection = false, + cornerDetection = false, + threshold = 0.15f, + depthThreshold = 0.01f, + maxSearchSteps = 4, + maxDiagonalSearchSteps = 8, + cornerRounding = 25, + localContrastAdaptationFactor = 2f + }, + + // Medium + new QualitySettings + { + diagonalDetection = false, + cornerDetection = false, + threshold = 0.1f, + depthThreshold = 0.01f, + maxSearchSteps = 8, + maxDiagonalSearchSteps = 8, + cornerRounding = 25, + localContrastAdaptationFactor = 2f + }, + + // High + new QualitySettings + { + diagonalDetection = true, + cornerDetection = true, + threshold = 0.1f, + depthThreshold = 0.01f, + maxSearchSteps = 16, + maxDiagonalSearchSteps = 8, + cornerRounding = 25, + localContrastAdaptationFactor = 2f + }, + + // Ultra + new QualitySettings + { + diagonalDetection = true, + cornerDetection = true, + threshold = 0.05f, + depthThreshold = 0.01f, + maxSearchSteps = 32, + maxDiagonalSearchSteps = 16, + cornerRounding = 25, + localContrastAdaptationFactor = 2f + }, + }; + } + + [Serializable] + public struct TemporalSettings + { + [Tooltip("Temporal filtering makes it possible for the SMAA algorithm to benefit from minute subpixel information available that has been accumulated over many frames.")] + public bool enabled; + + public bool UseTemporal() + { +#if UNITY_EDITOR + return enabled && EditorApplication.isPlayingOrWillChangePlaymode; +#else + return enabled; +#endif + } + + [Range(0.5f, 10.0f)] + [Tooltip("The size of the fuzz-displacement (jitter) in pixels applied to the camera's perspective projection matrix.\nUsed for 2x temporal anti-aliasing.")] + public float fuzzSize; + + public static TemporalSettings defaultSettings + { + get + { + return new TemporalSettings + { + enabled = false, + fuzzSize = 2f + }; + } + } + } + + [Serializable] + public struct PredicationSettings + { + [Tooltip("Predicated thresholding allows to better preserve texture details and to improve performance, by decreasing the number of detected edges using an additional buffer (the detph buffer).\nIt locally decreases the luma or color threshold if an edge is found in an additional buffer (so the global threshold can be higher).")] + public bool enabled; + + [Min(0.0001f)] + [Tooltip("Threshold to be used in the additional predication buffer.")] + public float threshold; + + [Range(1f, 5f)] + [Tooltip("How much to scale the global threshold used for luma or color edge detection when using predication.")] + public float scale; + + [Range(0f, 1f)] + [Tooltip("How much to locally decrease the threshold.")] + public float strength; + + public static PredicationSettings defaultSettings + { + get + { + return new PredicationSettings + { + enabled = false, + threshold = 0.01f, + scale = 2f, + strength = 0.4f + }; + } + } + } + + [TopLevelSettings] + public GlobalSettings settings = GlobalSettings.defaultSettings; + + [SettingsGroup] + public QualitySettings quality = QualitySettings.presetQualitySettings[2]; + + [SettingsGroup] + public PredicationSettings predication = PredicationSettings.defaultSettings; + + [SettingsGroup, ExperimentalGroup] + public TemporalSettings temporal = TemporalSettings.defaultSettings; + + private Matrix4x4 m_ProjectionMatrix; + private Matrix4x4 m_PreviousViewProjectionMatrix; + private float m_FlipFlop = 1.0f; + private RenderTexture m_Accumulation; + + private Shader m_Shader; + public Shader shader + { + get + { + if (m_Shader == null) + m_Shader = Shader.Find("Hidden/Subpixel Morphological Anti-aliasing"); + + return m_Shader; + } + } + + private Texture2D m_AreaTexture; + private Texture2D areaTexture + { + get + { + if (m_AreaTexture == null) + m_AreaTexture = Resources.Load("AreaTex"); + return m_AreaTexture; + } + } + + private Texture2D m_SearchTexture; + private Texture2D searchTexture + { + get + { + if (m_SearchTexture == null) + m_SearchTexture = Resources.Load("SearchTex"); + return m_SearchTexture; + } + } + + private Material m_Material; + private Material material + { + get + { + if (m_Material == null) + m_Material = ImageEffectHelper.CheckShaderAndCreateMaterial(shader); + + return m_Material; + } + } + + public void OnEnable(AntiAliasing owner) + { + if (!ImageEffectHelper.IsSupported(shader, true, false, owner)) + owner.enabled = false; + } + + public void OnDisable() + { + // Cleanup + if (m_Material != null) + Object.DestroyImmediate(m_Material); + + if (m_Accumulation != null) + Object.DestroyImmediate(m_Accumulation); + + m_Material = null; + m_Accumulation = null; + } + + public void OnPreCull(Camera camera) + { + if (temporal.UseTemporal()) + { + m_ProjectionMatrix = camera.projectionMatrix; + m_FlipFlop -= (2.0f * m_FlipFlop); + + Matrix4x4 fuzz = Matrix4x4.identity; + + fuzz.m03 = (0.25f * m_FlipFlop) * temporal.fuzzSize / camera.pixelWidth; + fuzz.m13 = (-0.25f * m_FlipFlop) * temporal.fuzzSize / camera.pixelHeight; + + camera.projectionMatrix = fuzz * camera.projectionMatrix; + } + } + + public void OnPostRender(Camera camera) + { + if (temporal.UseTemporal()) + camera.ResetProjectionMatrix(); + } + + public void OnRenderImage(Camera camera, RenderTexture source, RenderTexture destination) + { + int width = camera.pixelWidth; + int height = camera.pixelHeight; + + bool isFirstFrame = false; + + QualitySettings preset = quality; + + if (settings.quality != QualityPreset.Custom) + preset = QualitySettings.presetQualitySettings[(int)settings.quality]; + + // Pass IDs + int passEdgeDetection = (int)settings.edgeDetectionMethod; + int passBlendWeights = 4; + int passNeighborhoodBlending = 5; + int passResolve = 6; + + // Reprojection setup + var viewProjectionMatrix = GL.GetGPUProjectionMatrix(m_ProjectionMatrix, true) * camera.worldToCameraMatrix; + + // Uniforms + material.SetTexture("_AreaTex", areaTexture); + material.SetTexture("_SearchTex", searchTexture); + + material.SetVector("_Metrics", new Vector4(1f / width, 1f / height, width, height)); + material.SetVector("_Params1", new Vector4(preset.threshold, preset.depthThreshold, preset.maxSearchSteps, preset.maxDiagonalSearchSteps)); + material.SetVector("_Params2", new Vector2(preset.cornerRounding, preset.localContrastAdaptationFactor)); + + material.SetMatrix("_ReprojectionMatrix", m_PreviousViewProjectionMatrix * Matrix4x4.Inverse(viewProjectionMatrix)); + + float subsampleIndex = (m_FlipFlop < 0.0f) ? 2.0f : 1.0f; + material.SetVector("_SubsampleIndices", new Vector4(subsampleIndex, subsampleIndex, subsampleIndex, 0.0f)); + + // Handle predication & depth-based edge detection + Shader.DisableKeyword("USE_PREDICATION"); + + if (settings.edgeDetectionMethod == EdgeDetectionMethod.Depth) + { + camera.depthTextureMode |= DepthTextureMode.Depth; + } + else if (predication.enabled) + { + camera.depthTextureMode |= DepthTextureMode.Depth; + Shader.EnableKeyword("USE_PREDICATION"); + material.SetVector("_Params3", new Vector3(predication.threshold, predication.scale, predication.strength)); + } + + // Diag search & corner detection + Shader.DisableKeyword("USE_DIAG_SEARCH"); + Shader.DisableKeyword("USE_CORNER_DETECTION"); + + if (preset.diagonalDetection) + Shader.EnableKeyword("USE_DIAG_SEARCH"); + + if (preset.cornerDetection) + Shader.EnableKeyword("USE_CORNER_DETECTION"); + + // UV-based reprojection (up to Unity 5.x) + // TODO: use motion vectors when available! + Shader.DisableKeyword("USE_UV_BASED_REPROJECTION"); + + if (temporal.UseTemporal()) + Shader.EnableKeyword("USE_UV_BASED_REPROJECTION"); + + // Persistent textures and lazy-initializations + if (m_Accumulation == null || (m_Accumulation.width != width || m_Accumulation.height != height)) + { + if (m_Accumulation) + RenderTexture.ReleaseTemporary(m_Accumulation); + + m_Accumulation = RenderTexture.GetTemporary(width, height, 0, source.format, RenderTextureReadWrite.Linear); + m_Accumulation.hideFlags = HideFlags.HideAndDontSave; + + isFirstFrame = true; + } + + RenderTexture rt1 = TempRT(width, height, source.format); + Graphics.Blit(null, rt1, material, 0); // Clear + + // Edge Detection + Graphics.Blit(source, rt1, material, passEdgeDetection); + + if (settings.debugPass == DebugPass.Edges) + { + Graphics.Blit(rt1, destination); + } + else + { + RenderTexture rt2 = TempRT(width, height, source.format); + Graphics.Blit(null, rt2, material, 0); // Clear + + // Blend Weights + Graphics.Blit(rt1, rt2, material, passBlendWeights); + + if (settings.debugPass == DebugPass.Weights) + { + Graphics.Blit(rt2, destination); + } + else + { + // Neighborhood Blending + material.SetTexture("_BlendTex", rt2); + + if (temporal.UseTemporal()) + { + // Temporal filtering + Graphics.Blit(source, rt1, material, passNeighborhoodBlending); + + if (settings.debugPass == DebugPass.Accumulation) + { + Graphics.Blit(m_Accumulation, destination); + } + else if (!isFirstFrame) + { + material.SetTexture("_AccumulationTex", m_Accumulation); + Graphics.Blit(rt1, destination, material, passResolve); + } + else + { + Graphics.Blit(rt1, destination); + } + + //Graphics.Blit(rt1, m_Accumulation); + Graphics.Blit(destination, m_Accumulation); + RenderTexture.active = null; + } + else + { + Graphics.Blit(source, destination, material, passNeighborhoodBlending); + } + } + + RenderTexture.ReleaseTemporary(rt2); + } + + RenderTexture.ReleaseTemporary(rt1); + + // Store the future-previous frame's view-projection matrix + m_PreviousViewProjectionMatrix = viewProjectionMatrix; + } + + private RenderTexture TempRT(int width, int height, RenderTextureFormat format) + { + // Skip the depth & stencil buffer creation when DebugPass is set to avoid flickering + // TODO: Stencil buffer not working for some reason + // int depthStencilBits = DebugPass == DebugPass.Off ? 24 : 0; + int depthStencilBits = 0; + return RenderTexture.GetTemporary(width, height, depthStencilBits, format, RenderTextureReadWrite.Linear); + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/SMAA.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/SMAA.cs.meta new file mode 100644 index 0000000..48dccc5 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/AntiAliasing/SMAA/SMAA.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: 9c2502951f8f3e743917c441eba57d1c +timeCreated: 1454511067 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: + - m_Shader: {fileID: 4800000, guid: 4505fec7a81214243b8e59edf89e3a53, type: 3} + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom.meta new file mode 100644 index 0000000..599b855 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 193f90bb87f484c62ad73788d9cb2d44 +folderAsset: yes +timeCreated: 1454052266 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Bloom.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Bloom.cs new file mode 100644 index 0000000..596843c --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Bloom.cs @@ -0,0 +1,205 @@ +using System; +using UnityEngine; + +namespace UnityStandardAssets.CinematicEffects +{ + [ExecuteInEditMode] + [RequireComponent(typeof(Camera))] + [AddComponentMenu("Image Effects/Cinematic/Bloom")] +#if UNITY_5_4_OR_NEWER + [ImageEffectAllowedInSceneView] +#endif + public class Bloom : MonoBehaviour + { + [Serializable] + public struct Settings + { + [SerializeField] + [Tooltip("Filters out pixels under this level of brightness.")] + public float threshold; + + public float thresholdGamma + { + set { threshold = value; } + get { return Mathf.Max(0.0f, threshold); } + } + + public float thresholdLinear + { + set { threshold = Mathf.LinearToGammaSpace(value); } + get { return Mathf.GammaToLinearSpace(thresholdGamma); } + } + + [SerializeField, Range(0, 1)] + [Tooltip("Makes transition between under/over-threshold gradual.")] + public float softKnee; + + [SerializeField, Range(1, 7)] + [Tooltip("Changes extent of veiling effects in a screen resolution-independent fashion.")] + public float radius; + + [SerializeField] + [Tooltip("Blend factor of the result image.")] + public float intensity; + + [SerializeField] + [Tooltip("Controls filter quality and buffer resolution.")] + public bool highQuality; + + [SerializeField] + [Tooltip("Reduces flashing noise with an additional filter.")] + public bool antiFlicker; + + public static Settings defaultSettings + { + get + { + var settings = new Settings + { + threshold = 0.9f, + softKnee = 0.5f, + radius = 2.0f, + intensity = 0.7f, + highQuality = true, + antiFlicker = false + }; + return settings; + } + } + } + + #region Public Properties + + [SerializeField] + public Settings settings = Settings.defaultSettings; + + #endregion + + [SerializeField, HideInInspector] + private Shader m_Shader; + + public Shader shader + { + get + { + if (m_Shader == null) + { + const string shaderName = "Hidden/Image Effects/Cinematic/Bloom"; + m_Shader = Shader.Find(shaderName); + } + + return m_Shader; + } + } + + private Material m_Material; + public Material material + { + get + { + if (m_Material == null) + m_Material = ImageEffectHelper.CheckShaderAndCreateMaterial(shader); + + return m_Material; + } + } + + #region Private Members + + const int kMaxIterations = 16; + RenderTexture[] m_blurBuffer1 = new RenderTexture[kMaxIterations]; + RenderTexture[] m_blurBuffer2 = new RenderTexture[kMaxIterations]; + + private void OnEnable() + { + if (!ImageEffectHelper.IsSupported(shader, true, false, this)) + enabled = false; + } + + private void OnDisable() + { + if (m_Material != null) + DestroyImmediate(m_Material); + + m_Material = null; + } + + private void OnRenderImage(RenderTexture source, RenderTexture destination) + { + var useRGBM = Application.isMobilePlatform; + + // source texture size + var tw = source.width; + var th = source.height; + + // halve the texture size for the low quality mode + if (!settings.highQuality) + { + tw /= 2; + th /= 2; + } + + // blur buffer format + var rtFormat = useRGBM ? RenderTextureFormat.Default : RenderTextureFormat.DefaultHDR; + + // determine the iteration count + var logh = Mathf.Log(th, 2) + settings.radius - 8; + var logh_i = (int)logh; + var iterations = Mathf.Clamp(logh_i, 1, kMaxIterations); + + // update the shader properties + var threshold = settings.thresholdLinear; + material.SetFloat("_Threshold", threshold); + + var knee = threshold * settings.softKnee + 1e-5f; + var curve = new Vector3(threshold - knee, knee * 2, 0.25f / knee); + material.SetVector("_Curve", curve); + + var pfo = !settings.highQuality && settings.antiFlicker; + material.SetFloat("_PrefilterOffs", pfo ? -0.5f : 0.0f); + + material.SetFloat("_SampleScale", 0.5f + logh - logh_i); + material.SetFloat("_Intensity", Mathf.Max(0.0f, settings.intensity)); + + // prefilter pass + var prefiltered = RenderTexture.GetTemporary(tw, th, 0, rtFormat); + Graphics.Blit(source, prefiltered, material, settings.antiFlicker ? 1 : 0); + + // construct a mip pyramid + var last = prefiltered; + for (var level = 0; level < iterations; level++) + { + m_blurBuffer1[level] = RenderTexture.GetTemporary(last.width / 2, last.height / 2, 0, rtFormat); + Graphics.Blit(last, m_blurBuffer1[level], material, level == 0 ? (settings.antiFlicker ? 3 : 2) : 4); + last = m_blurBuffer1[level]; + } + + // upsample and combine loop + for (var level = iterations - 2; level >= 0; level--) + { + var basetex = m_blurBuffer1[level]; + material.SetTexture("_BaseTex", basetex); + m_blurBuffer2[level] = RenderTexture.GetTemporary(basetex.width, basetex.height, 0, rtFormat); + Graphics.Blit(last, m_blurBuffer2[level], material, settings.highQuality ? 6 : 5); + last = m_blurBuffer2[level]; + } + + // finish process + material.SetTexture("_BaseTex", source); + Graphics.Blit(last, destination, material, settings.highQuality ? 8 : 7); + + // release the temporary buffers + for (var i = 0; i < kMaxIterations; i++) + { + if (m_blurBuffer1[i] != null) RenderTexture.ReleaseTemporary(m_blurBuffer1[i]); + if (m_blurBuffer2[i] != null) RenderTexture.ReleaseTemporary(m_blurBuffer2[i]); + m_blurBuffer1[i] = null; + m_blurBuffer2[i] = null; + } + + RenderTexture.ReleaseTemporary(prefiltered); + } + + #endregion + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Bloom.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Bloom.cs.meta new file mode 100644 index 0000000..fa96e0a --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Bloom.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: 32187365ced0c42219cde2b57c99b323 +timeCreated: 1454052338 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: + - _shader: {fileID: 4800000, guid: e45d4f28262b04d10a075856ab5fdb5e, type: 3} + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Editor.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Editor.meta new file mode 100644 index 0000000..73fe404 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Editor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 92a024b1f1430409eb656f65969aa3d5 +folderAsset: yes +timeCreated: 1454052266 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Editor/BloomEditor.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Editor/BloomEditor.cs new file mode 100644 index 0000000..183ca3e --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Editor/BloomEditor.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; + +namespace UnityStandardAssets.CinematicEffects +{ + [CanEditMultipleObjects] + [CustomEditor(typeof(Bloom))] + public class BloomEditor : Editor + { + [NonSerialized] + private List m_Properties = new List(); + + BloomGraphDrawer _graph; + + bool CheckHdr(Bloom target) + { + var camera = target.GetComponent(); + return camera != null && camera.hdr; + } + + void OnEnable() + { + var settings = FieldFinder.GetField(x => x.settings); + foreach (var setting in settings.FieldType.GetFields()) + { + var prop = settings.Name + "." + setting.Name; + m_Properties.Add(serializedObject.FindProperty(prop)); + } + + _graph = new BloomGraphDrawer(); + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + if (!serializedObject.isEditingMultipleObjects) + { + EditorGUILayout.Space(); + var bloom = (Bloom)target; + _graph.Prepare(bloom.settings, CheckHdr(bloom)); + _graph.DrawGraph(); + EditorGUILayout.Space(); + } + + foreach (var property in m_Properties) + EditorGUILayout.PropertyField(property); + + serializedObject.ApplyModifiedProperties(); + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Editor/BloomEditor.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Editor/BloomEditor.cs.meta new file mode 100644 index 0000000..8f01ef2 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Editor/BloomEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 38020a6029a85434a95a6f725a5aae5f +timeCreated: 1454052266 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Editor/BloomGraphDrawer.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Editor/BloomGraphDrawer.cs new file mode 100644 index 0000000..c8f1522 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Editor/BloomGraphDrawer.cs @@ -0,0 +1,156 @@ +using UnityEngine; +using UnityEditor; + +namespace UnityStandardAssets.CinematicEffects +{ + // Class used for drawing the brightness response curve + public class BloomGraphDrawer + { + #region Public Methods + + // Update internal state from given settings. + public void Prepare(Bloom.Settings settings, bool isHdr) + { + if (isHdr) + { + _rangeX = 6; + _rangeY = 1.5f; + } + else + { + _rangeX = 1; + _rangeY = 1; + } + + _threshold = settings.thresholdLinear; + _knee = settings.softKnee * _threshold + 1e-5f; + + // Intensity is capped to prevent sampling errors. + _intensity = Mathf.Min(settings.intensity, 10); + } + + // Draw the graph at the current position. + public void DrawGraph() + { + _rectGraph = GUILayoutUtility.GetRect(128, 80); + + // Background + DrawRect(0, 0, _rangeX, _rangeY, 0.1f, 0.4f); + + // Soft-knee range + DrawRect(_threshold - _knee, 0, _threshold + _knee, _rangeY, 0.25f, -1); + + // Horizontal lines + for (var i = 1; i < _rangeY; i++) + DrawLine(0, i, _rangeX, i, 0.4f); + + // Vertical lines + for (var i = 1; i < _rangeX; i++) + DrawLine(i, 0, i, _rangeY, 0.4f); + + // Label + Handles.Label( + PointInRect(0, _rangeY) + Vector3.right, + "Brightness Response (linear)", EditorStyles.miniLabel + ); + + // Threshold line + DrawLine(_threshold, 0, _threshold, _rangeY, 0.6f); + + // Response curve + var vcount = 0; + while (vcount < _curveResolution) + { + var x = _rangeX * vcount / (_curveResolution - 1); + var y = ResponseFunction(x); + if (y < _rangeY) + { + _curveVertices[vcount++] = PointInRect(x, y); + } + else + { + if (vcount > 1) + { + // Extend the last segment to the top edge of the rect. + var v1 = _curveVertices[vcount - 2]; + var v2 = _curveVertices[vcount - 1]; + var clip = (_rectGraph.y - v1.y) / (v2.y - v1.y); + _curveVertices[vcount - 1] = v1 + (v2 - v1) * clip; + } + break; + } + } + + if (vcount > 1) + { + Handles.color = Color.white * 0.9f; + Handles.DrawAAPolyLine(2.0f, vcount, _curveVertices); + } + } + + #endregion + + #region Response Function + + float _threshold; + float _knee; + float _intensity; + + float ResponseFunction(float x) + { + var rq = Mathf.Clamp(x - _threshold + _knee, 0, _knee * 2); + rq = rq * rq * 0.25f / _knee; + return Mathf.Max(rq, x - _threshold) * _intensity; + } + + #endregion + + #region Graph Functions + + // Number of vertices in curve + const int _curveResolution = 96; + + // Vertex buffers + Vector3[] _rectVertices = new Vector3[4]; + Vector3[] _lineVertices = new Vector3[2]; + Vector3[] _curveVertices = new Vector3[_curveResolution]; + + Rect _rectGraph; + float _rangeX; + float _rangeY; + + // Transform a point into the graph rect. + Vector3 PointInRect(float x, float y) + { + x = Mathf.Lerp(_rectGraph.x, _rectGraph.xMax, x / _rangeX); + y = Mathf.Lerp(_rectGraph.yMax, _rectGraph.y, y / _rangeY); + return new Vector3(x, y, 0); + } + + // Draw a line in the graph rect. + void DrawLine(float x1, float y1, float x2, float y2, float grayscale) + { + _lineVertices[0] = PointInRect(x1, y1); + _lineVertices[1] = PointInRect(x2, y2); + Handles.color = Color.white * grayscale; + Handles.DrawAAPolyLine(2.0f, _lineVertices); + } + + // Draw a rect in the graph rect. + void DrawRect(float x1, float y1, float x2, float y2, float fill, float line) + { + _rectVertices[0] = PointInRect(x1, y1); + _rectVertices[1] = PointInRect(x2, y1); + _rectVertices[2] = PointInRect(x2, y2); + _rectVertices[3] = PointInRect(x1, y2); + + Handles.DrawSolidRectangleWithOutline( + _rectVertices, + fill < 0 ? Color.clear : Color.white * fill, + line < 0 ? Color.clear : Color.white * line + ); + } + + #endregion + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Editor/BloomGraphDrawer.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Editor/BloomGraphDrawer.cs.meta new file mode 100644 index 0000000..3bd76e8 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Editor/BloomGraphDrawer.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: e2d62b6f4e4eb4c6783477b5d99abdff +timeCreated: 1465439082 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Resources.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Resources.meta new file mode 100644 index 0000000..c17ec7c --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Resources.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 4af3202dbe79e460e9be42bcb6509fe0 +folderAsset: yes +timeCreated: 1454052266 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Resources/Bloom.cginc b/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Resources/Bloom.cginc new file mode 100644 index 0000000..59502f5 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Resources/Bloom.cginc @@ -0,0 +1,238 @@ +#include "UnityCG.cginc" + +// Mobile: use RGBM instead of float/half RGB +#define USE_RGBM defined(SHADER_API_MOBILE) + +sampler2D _MainTex; +sampler2D _BaseTex; +float2 _MainTex_TexelSize; +float2 _BaseTex_TexelSize; +half4 _MainTex_ST; +half4 _BaseTex_ST; + +float _PrefilterOffs; +half _Threshold; +half3 _Curve; +float _SampleScale; +half _Intensity; + +// Brightness function +half Brightness(half3 c) +{ + return max(max(c.r, c.g), c.b); +} + +// 3-tap median filter +half3 Median(half3 a, half3 b, half3 c) +{ + return a + b + c - min(min(a, b), c) - max(max(a, b), c); +} + +// Clamp HDR value within a safe range +half3 SafeHDR(half3 c) { return min(c, 65000); } +half4 SafeHDR(half4 c) { return min(c, 65000); } + +// RGBM encoding/decoding +half4 EncodeHDR(float3 rgb) +{ +#if USE_RGBM + rgb *= 1.0 / 8; + float m = max(max(rgb.r, rgb.g), max(rgb.b, 1e-6)); + m = ceil(m * 255) / 255; + return half4(rgb / m, m); +#else + return half4(rgb, 0); +#endif +} + +float3 DecodeHDR(half4 rgba) +{ +#if USE_RGBM + return rgba.rgb * rgba.a * 8; +#else + return rgba.rgb; +#endif +} + +// Downsample with a 4x4 box filter +half3 DownsampleFilter(float2 uv) +{ + float4 d = _MainTex_TexelSize.xyxy * float4(-1, -1, +1, +1); + + half3 s; + s = DecodeHDR(tex2D(_MainTex, uv + d.xy)); + s += DecodeHDR(tex2D(_MainTex, uv + d.zy)); + s += DecodeHDR(tex2D(_MainTex, uv + d.xw)); + s += DecodeHDR(tex2D(_MainTex, uv + d.zw)); + + return s * (1.0 / 4); +} + +// Downsample with a 4x4 box filter + anti-flicker filter +half3 DownsampleAntiFlickerFilter(float2 uv) +{ + float4 d = _MainTex_TexelSize.xyxy * float4(-1, -1, +1, +1); + + half3 s1 = DecodeHDR(tex2D(_MainTex, uv + d.xy)); + half3 s2 = DecodeHDR(tex2D(_MainTex, uv + d.zy)); + half3 s3 = DecodeHDR(tex2D(_MainTex, uv + d.xw)); + half3 s4 = DecodeHDR(tex2D(_MainTex, uv + d.zw)); + + // Karis's luma weighted average (using brightness instead of luma) + half s1w = 1 / (Brightness(s1) + 1); + half s2w = 1 / (Brightness(s2) + 1); + half s3w = 1 / (Brightness(s3) + 1); + half s4w = 1 / (Brightness(s4) + 1); + half one_div_wsum = 1 / (s1w + s2w + s3w + s4w); + + return (s1 * s1w + s2 * s2w + s3 * s3w + s4 * s4w) * one_div_wsum; +} + +half3 UpsampleFilter(float2 uv) +{ +#if HIGH_QUALITY + // 9-tap bilinear upsampler (tent filter) + float4 d = _MainTex_TexelSize.xyxy * float4(1, 1, -1, 0) * _SampleScale; + + half3 s; + s = DecodeHDR(tex2D(_MainTex, uv - d.xy)); + s += DecodeHDR(tex2D(_MainTex, uv - d.wy)) * 2; + s += DecodeHDR(tex2D(_MainTex, uv - d.zy)); + + s += DecodeHDR(tex2D(_MainTex, uv + d.zw)) * 2; + s += DecodeHDR(tex2D(_MainTex, uv )) * 4; + s += DecodeHDR(tex2D(_MainTex, uv + d.xw)) * 2; + + s += DecodeHDR(tex2D(_MainTex, uv + d.zy)); + s += DecodeHDR(tex2D(_MainTex, uv + d.wy)) * 2; + s += DecodeHDR(tex2D(_MainTex, uv + d.xy)); + + return s * (1.0 / 16); +#else + // 4-tap bilinear upsampler + float4 d = _MainTex_TexelSize.xyxy * float4(-1, -1, +1, +1) * (_SampleScale * 0.5); + + half3 s; + s = DecodeHDR(tex2D(_MainTex, uv + d.xy)); + s += DecodeHDR(tex2D(_MainTex, uv + d.zy)); + s += DecodeHDR(tex2D(_MainTex, uv + d.xw)); + s += DecodeHDR(tex2D(_MainTex, uv + d.zw)); + + return s * (1.0 / 4); +#endif +} + +// +// Vertex shader +// + +v2f_img vert(appdata_img v) +{ + v2f_img o; +#if UNITY_VERSION >= 540 + o.pos = UnityObjectToClipPos(v.vertex); + o.uv = UnityStereoScreenSpaceUVAdjust(v.texcoord, _MainTex_ST); +#else + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv = v.texcoord; +#endif + return o; +} + +struct v2f_multitex +{ + float4 pos : SV_POSITION; + float2 uvMain : TEXCOORD0; + float2 uvBase : TEXCOORD1; +}; + +v2f_multitex vert_multitex(appdata_img v) +{ + v2f_multitex o; +#if UNITY_VERSION >= 540 + o.pos = UnityObjectToClipPos(v.vertex); + o.uvMain = UnityStereoScreenSpaceUVAdjust(v.texcoord, _MainTex_ST); + o.uvBase = UnityStereoScreenSpaceUVAdjust(v.texcoord, _BaseTex_ST); +#else + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uvMain = v.texcoord; + o.uvBase = v.texcoord; +#endif +#if UNITY_UV_STARTS_AT_TOP + if (_BaseTex_TexelSize.y < 0.0) + o.uvBase.y = 1.0 - v.texcoord.y; +#endif + return o; +} + +// +// fragment shader +// + +half4 frag_prefilter(v2f_img i) : SV_Target +{ + float2 uv = i.uv + _MainTex_TexelSize.xy * _PrefilterOffs; + +#if ANTI_FLICKER + float3 d = _MainTex_TexelSize.xyx * float3(1, 1, 0); + half4 s0 = SafeHDR(tex2D(_MainTex, uv)); + half3 s1 = SafeHDR(tex2D(_MainTex, uv - d.xz).rgb); + half3 s2 = SafeHDR(tex2D(_MainTex, uv + d.xz).rgb); + half3 s3 = SafeHDR(tex2D(_MainTex, uv - d.zy).rgb); + half3 s4 = SafeHDR(tex2D(_MainTex, uv + d.zy).rgb); + half3 m = Median(Median(s0.rgb, s1, s2), s3, s4); +#else + half4 s0 = SafeHDR(tex2D(_MainTex, uv)); + half3 m = s0.rgb; +#endif + +#if UNITY_COLORSPACE_GAMMA + m = GammaToLinearSpace(m); +#endif + // Pixel brightness + half br = Brightness(m); + + // Under-threshold part: quadratic curve + half rq = clamp(br - _Curve.x, 0, _Curve.y); + rq = _Curve.z * rq * rq; + + // Combine and apply the brightness response curve. + m *= max(rq, br - _Threshold) / max(br, 1e-5); + + return EncodeHDR(m); +} + +half4 frag_downsample1(v2f_img i) : SV_Target +{ +#if ANTI_FLICKER + return EncodeHDR(DownsampleAntiFlickerFilter(i.uv)); +#else + return EncodeHDR(DownsampleFilter(i.uv)); +#endif +} + +half4 frag_downsample2(v2f_img i) : SV_Target +{ + return EncodeHDR(DownsampleFilter(i.uv)); +} + +half4 frag_upsample(v2f_multitex i) : SV_Target +{ + half3 base = DecodeHDR(tex2D(_BaseTex, i.uvBase)); + half3 blur = UpsampleFilter(i.uvMain); + return EncodeHDR(base + blur); +} + +half4 frag_upsample_final(v2f_multitex i) : SV_Target +{ + half4 base = tex2D(_BaseTex, i.uvBase); + half3 blur = UpsampleFilter(i.uvMain); +#if UNITY_COLORSPACE_GAMMA + base.rgb = GammaToLinearSpace(base.rgb); +#endif + half3 cout = base.rgb + blur * _Intensity; +#if UNITY_COLORSPACE_GAMMA + cout = LinearToGammaSpace(cout); +#endif + return half4(cout, base.a); +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Resources/Bloom.cginc.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Resources/Bloom.cginc.meta new file mode 100644 index 0000000..2d7c7de --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Resources/Bloom.cginc.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 386a80fc77a074d2ca8e6f097dd68ea3 +timeCreated: 1463538726 +licenseType: Store +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Resources/Bloom.shader b/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Resources/Bloom.shader new file mode 100644 index 0000000..44ad6a5 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Resources/Bloom.shader @@ -0,0 +1,118 @@ +Shader "Hidden/Image Effects/Cinematic/Bloom" +{ + Properties + { + _MainTex("", 2D) = "" {} + _BaseTex("", 2D) = "" {} + } + SubShader + { + // 0: Prefilter + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #pragma multi_compile _ UNITY_COLORSPACE_GAMMA + #include "Bloom.cginc" + #pragma vertex vert + #pragma fragment frag_prefilter + #pragma target 3.0 + ENDCG + } + // 1: Prefilter with anti-flicker + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #define ANTI_FLICKER 1 + #pragma multi_compile _ UNITY_COLORSPACE_GAMMA + #include "Bloom.cginc" + #pragma vertex vert + #pragma fragment frag_prefilter + #pragma target 3.0 + ENDCG + } + // 2: First level downsampler + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #include "Bloom.cginc" + #pragma vertex vert + #pragma fragment frag_downsample1 + #pragma target 3.0 + ENDCG + } + // 3: First level downsampler with anti-flicker + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #define ANTI_FLICKER 1 + #include "Bloom.cginc" + #pragma vertex vert + #pragma fragment frag_downsample1 + #pragma target 3.0 + ENDCG + } + // 4: Second level downsampler + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #include "Bloom.cginc" + #pragma vertex vert + #pragma fragment frag_downsample2 + #pragma target 3.0 + ENDCG + } + // 5: Upsampler + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #include "Bloom.cginc" + #pragma vertex vert_multitex + #pragma fragment frag_upsample + #pragma target 3.0 + ENDCG + } + // 6: High quality upsampler + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #define HIGH_QUALITY 1 + #include "Bloom.cginc" + #pragma vertex vert_multitex + #pragma fragment frag_upsample + #pragma target 3.0 + ENDCG + } + // 7: Combiner + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #pragma multi_compile _ UNITY_COLORSPACE_GAMMA + #include "Bloom.cginc" + #pragma vertex vert_multitex + #pragma fragment frag_upsample_final + #pragma target 3.0 + ENDCG + } + // 8: High quality combiner + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #define HIGH_QUALITY 1 + #pragma multi_compile _ UNITY_COLORSPACE_GAMMA + #include "Bloom.cginc" + #pragma vertex vert_multitex + #pragma fragment frag_upsample_final + #pragma target 3.0 + ENDCG + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Resources/Bloom.shader.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Resources/Bloom.shader.meta new file mode 100644 index 0000000..3097437 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Bloom/Resources/Bloom.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: e45d4f28262b04d10a075856ab5fdb5e +timeCreated: 1454052270 +licenseType: Store +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Common.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common.meta new file mode 100644 index 0000000..7511643 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 88d2f1c604c7f6d4bb80a72b2f0219a7 +folderAsset: yes +timeCreated: 1449044555 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/Editor.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/Editor.meta new file mode 100644 index 0000000..1ecc01b --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/Editor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: e862ecde714eb154ca2d86a9a0809732 +folderAsset: yes +timeCreated: 1453372226 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/Editor/EditorGUIHelper.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/Editor/EditorGUIHelper.cs new file mode 100644 index 0000000..05fb09a --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/Editor/EditorGUIHelper.cs @@ -0,0 +1,62 @@ +using UnityEngine; +using UnityEditor; +using System; +using System.Linq.Expressions; +using System.Reflection; + +namespace UnityStandardAssets.CinematicEffects +{ + public static class EditorGUIHelper + { + private static Styles s_Styles; + private class Styles + { + public GUIStyle header = "ShurikenModuleTitle"; + public GUIStyle headerCheckbox = "ShurikenCheckMark"; + + internal Styles() + { + header.font = (new GUIStyle("Label")).font; + header.border = new RectOffset(15, 7, 4, 4); + header.fixedHeight = 22; + header.contentOffset = new Vector2(20f, -2f); + } + } + + static EditorGUIHelper() + { + s_Styles = new Styles(); + } + + public static bool Header(SerializedProperty group, SerializedProperty enabledField) + { + var display = group == null || group.isExpanded; + var enabled = enabledField != null && enabledField.boolValue; + var title = group == null ? "Unknown Group" : ObjectNames.NicifyVariableName(group.displayName); + + Rect rect = GUILayoutUtility.GetRect(16f, 22f, s_Styles.header); + GUI.Box(rect, title, s_Styles.header); + + Rect toggleRect = new Rect(rect.x + 4f, rect.y + 4f, 13f, 13f); + if (Event.current.type == EventType.Repaint) + s_Styles.headerCheckbox.Draw(toggleRect, false, false, enabled, false); + + Event e = Event.current; + if (e.type == EventType.MouseDown) + { + if (toggleRect.Contains(e.mousePosition) && enabledField != null) + { + enabledField.boolValue = !enabledField.boolValue; + e.Use(); + } + else if (rect.Contains(e.mousePosition) && group != null) + { + display = !display; + group.isExpanded = !group.isExpanded; + e.Use(); + } + } + return display; + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/Editor/EditorGUIHelper.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/Editor/EditorGUIHelper.cs.meta new file mode 100644 index 0000000..94ced04 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/Editor/EditorGUIHelper.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 5b995f06a3ed14d449823cf7ab1c5a58 +timeCreated: 1454681943 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/Editor/FieldFinder.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/Editor/FieldFinder.cs new file mode 100644 index 0000000..fe77bdd --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/Editor/FieldFinder.cs @@ -0,0 +1,25 @@ +using System; +using System.Linq.Expressions; +using System.Reflection; + +namespace UnityStandardAssets.CinematicEffects +{ + public static class FieldFinder + { + public static FieldInfo GetField(Expression> selector) + { + Expression body = selector; + if (body is LambdaExpression) + { + body = ((LambdaExpression)body).Body; + } + switch (body.NodeType) + { + case ExpressionType.MemberAccess: + return (FieldInfo)((MemberExpression)body).Member; + default: + throw new InvalidOperationException(); + } + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/Editor/FieldFinder.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/Editor/FieldFinder.cs.meta new file mode 100644 index 0000000..c4f8182 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/Editor/FieldFinder.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 39e54cb37a3a81a40b248f1cc25c4619 +timeCreated: 1454073160 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/Editor/MinDrawer.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/Editor/MinDrawer.cs new file mode 100644 index 0000000..73ca7b2 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/Editor/MinDrawer.cs @@ -0,0 +1,29 @@ +using UnityEditor; +using UnityEngine; + +namespace UnityStandardAssets.CinematicEffects +{ + [CustomPropertyDrawer(typeof(MinAttribute))] + internal sealed class MinDrawer : PropertyDrawer + { + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + MinAttribute attribute = (MinAttribute) base.attribute; + + if (property.propertyType == SerializedPropertyType.Integer) + { + int v = EditorGUI.IntField(position, label, property.intValue); + property.intValue = (int)Mathf.Max(v, attribute.min); + } + else if (property.propertyType == SerializedPropertyType.Float) + { + float v = EditorGUI.FloatField(position, label, property.floatValue); + property.floatValue = Mathf.Max(v, attribute.min); + } + else + { + EditorGUI.LabelField(position, label.text, "Use Min with float or int."); + } + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/Editor/MinDrawer.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/Editor/MinDrawer.cs.meta new file mode 100644 index 0000000..c053e4d --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/Editor/MinDrawer.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 9c615a85f13c6764fa4496d1d7f75f52 +timeCreated: 1453220014 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/ImageEffectHelper.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/ImageEffectHelper.cs new file mode 100644 index 0000000..d3761b6 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/ImageEffectHelper.cs @@ -0,0 +1,63 @@ +using UnityEngine; +#if UNITY_EDITOR +using UnityEditor; +#endif + +namespace UnityStandardAssets.CinematicEffects +{ + public static class ImageEffectHelper + { + public static bool IsSupported(Shader s, bool needDepth, bool needHdr, MonoBehaviour effect) + { +#if UNITY_EDITOR + // Don't check for shader compatibility while it's building as it would disable most effects + // on build farms without good-enough gaming hardware. + if (!BuildPipeline.isBuildingPlayer) + { +#endif + if (s == null || !s.isSupported) + { + Debug.LogWarningFormat("Missing shader for image effect {0}", effect); + return false; + } + + if (!SystemInfo.supportsImageEffects || !SystemInfo.supportsRenderTextures) + { + Debug.LogWarningFormat("Image effects aren't supported on this device ({0})", effect); + return false; + } + + if (needDepth && !SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.Depth)) + { + Debug.LogWarningFormat("Depth textures aren't supported on this device ({0})", effect); + return false; + } + + if (needHdr && !SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.ARGBHalf)) + { + Debug.LogWarningFormat("Floating point textures aren't supported on this device ({0})", effect); + return false; + } +#if UNITY_EDITOR + } +#endif + + return true; + } + + public static Material CheckShaderAndCreateMaterial(Shader s) + { + if (s == null || !s.isSupported) + return null; + + var material = new Material(s); + material.hideFlags = HideFlags.DontSave; + return material; + } + + public static bool supportsDX11 + { + get { return SystemInfo.graphicsShaderLevel >= 50 && SystemInfo.supportsComputeShaders; } + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/ImageEffectHelper.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/ImageEffectHelper.cs.meta new file mode 100644 index 0000000..2e5b46d --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/ImageEffectHelper.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: ab6a3f50deeee984c88794eeeb901226 +timeCreated: 1448544124 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/MinAttribute.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/MinAttribute.cs new file mode 100644 index 0000000..84e7c1a --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/MinAttribute.cs @@ -0,0 +1,14 @@ +namespace UnityStandardAssets.CinematicEffects +{ + using UnityEngine; + + public sealed class MinAttribute : PropertyAttribute + { + public readonly float min; + + public MinAttribute(float min) + { + this.min = min; + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/MinAttribute.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/MinAttribute.cs.meta new file mode 100644 index 0000000..0b42bb8 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/MinAttribute.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: b07292ae638766047a6751da7552e566 +timeCreated: 1453220005 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/RenderTextureUtility.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/RenderTextureUtility.cs new file mode 100644 index 0000000..ae71657 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/RenderTextureUtility.cs @@ -0,0 +1,44 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace UnityStandardAssets.CinematicEffects +{ + public class RenderTextureUtility + { + //Temporary render texture handling + private List m_TemporaryRTs = new List(); + + public RenderTexture GetTemporaryRenderTexture(int width, int height, int depthBuffer = 0, RenderTextureFormat format = RenderTextureFormat.ARGBHalf, FilterMode filterMode = FilterMode.Bilinear) + { + var rt = RenderTexture.GetTemporary(width, height, depthBuffer, format); + rt.filterMode = filterMode; + rt.wrapMode = TextureWrapMode.Clamp; + rt.name = "RenderTextureUtilityTempTexture"; + m_TemporaryRTs.Add(rt); + return rt; + } + + public void ReleaseTemporaryRenderTexture(RenderTexture rt) + { + if (rt == null) + return; + + if (!m_TemporaryRTs.Contains(rt)) + { + Debug.LogErrorFormat("Attempting to remove texture that was not allocated: {0}", rt); + return; + } + + m_TemporaryRTs.Remove(rt); + RenderTexture.ReleaseTemporary(rt); + } + + public void ReleaseAllTemporaryRenderTextures() + { + for (int i = 0; i < m_TemporaryRTs.Count; ++i) + RenderTexture.ReleaseTemporary(m_TemporaryRTs[i]); + + m_TemporaryRTs.Clear(); + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/RenderTextureUtility.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/RenderTextureUtility.cs.meta new file mode 100644 index 0000000..6de4df1 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/Common/RenderTextureUtility.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 054e694bae00c374a97c2bc495fca66b +timeCreated: 1449148391 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField.meta new file mode 100644 index 0000000..85f341c --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 34369cdf66de04c65a8cef766bb1797b +folderAsset: yes +timeCreated: 1429220270 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/DepthOfField.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/DepthOfField.cs new file mode 100644 index 0000000..0f9da65 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/DepthOfField.cs @@ -0,0 +1,846 @@ +using UnityEngine; +using System; + +namespace UnityStandardAssets.CinematicEffects +{ + //Improvement ideas: + // Use rgba8 buffer in ldr / in some pass in hdr (in correlation to previous point and remapping coc from -1/0/1 to 0/0.5/1) + // Use temporal stabilisation + // Add a mode to do bokeh texture in quarter res as well + // Support different near and far blur for the bokeh texture + // Try distance field for the bokeh texture + // Try to separate the output of the blur pass to two rendertarget near+far, see the gain in quality vs loss in performance + // Try swirl effect on the samples of the circle blur + + //References : + // This DOF implementation use ideas from public sources, a big thank to them : + // http://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare + // http://www.crytek.com/download/Sousa_Graphics_Gems_CryENGINE3.pdf + // http://graphics.cs.williams.edu/papers/MedianShaderX6/ + // http://http.developer.nvidia.com/GPUGems/gpugems_ch24.html + // http://vec3.ca/bicubic-filtering-in-fewer-taps/ + + [ExecuteInEditMode] + [AddComponentMenu("Image Effects/Cinematic/Depth Of Field")] + [RequireComponent(typeof(Camera))] + public class DepthOfField : MonoBehaviour + { + private const float kMaxBlur = 40.0f; + + #region Render passes + private enum Passes + { + BlurAlphaWeighted, + BoxBlur, + DilateFgCocFromColor, + DilateFgCoc, + CaptureCocExplicit, + VisualizeCocExplicit, + CocPrefilter, + CircleBlur, + CircleBlurWithDilatedFg, + CircleBlurLowQuality, + CircleBlowLowQualityWithDilatedFg, + MergeExplicit, + ShapeLowQuality, + ShapeLowQualityDilateFg, + ShapeLowQualityMerge, + ShapeLowQualityMergeDilateFg, + ShapeMediumQuality, + ShapeMediumQualityDilateFg, + ShapeMediumQualityMerge, + ShapeMediumQualityMergeDilateFg, + ShapeHighQuality, + ShapeHighQualityDilateFg, + ShapeHighQualityMerge, + ShapeHighQualityMergeDilateFg + } + + private enum MedianPasses + { + Median3, + Median3X3 + } + + private enum BokehTexturesPasses + { + Apply, + Collect + } + #endregion + + public enum TweakMode + { + Range, + Explicit + } + + public enum ApertureShape + { + Circular, + Hexagonal, + Octogonal + } + + public enum QualityPreset + { + Low, + Medium, + High + } + + public enum FilterQuality + { + None, + Normal, + High + } + + #region Settings + [Serializable] + public struct GlobalSettings + { + [Tooltip("Allows to view where the blur will be applied. Yellow for near blur, blue for far blur.")] + public bool visualizeFocus; + + [Tooltip("Setup mode. Use \"Advanced\" if you need more control on blur settings and/or want to use a bokeh texture. \"Explicit\" is the same as \"Advanced\" but makes use of \"Near Plane\" and \"Far Plane\" values instead of \"F-Stop\".")] + public TweakMode tweakMode; + + [Tooltip("Quality presets. Use \"Custom\" for more advanced settings.")] + public QualityPreset filteringQuality; + + [Tooltip("\"Circular\" is the fastest, followed by \"Hexagonal\" and \"Octogonal\".")] + public ApertureShape apertureShape; + + [Range(0f, 179f), Tooltip("Rotates the aperture when working with \"Hexagonal\" and \"Ortogonal\".")] + public float apertureOrientation; + + public static GlobalSettings defaultSettings + { + get + { + return new GlobalSettings + { + visualizeFocus = false, + tweakMode = TweakMode.Range, + filteringQuality = QualityPreset.High, + apertureShape = ApertureShape.Circular, + apertureOrientation = 0f + }; + } + } + } + + [Serializable] + public struct QualitySettings + { + [Tooltip("Enable this to get smooth bokeh.")] + public bool prefilterBlur; + + [Tooltip("Applies a median filter for even smoother bokeh.")] + public FilterQuality medianFilter; + + [Tooltip("Dilates near blur over in focus area.")] + public bool dilateNearBlur; + + public static QualitySettings[] presetQualitySettings = + { + // Low + new QualitySettings + { + prefilterBlur = false, + medianFilter = FilterQuality.None, + dilateNearBlur = false + }, + + // Medium + new QualitySettings + { + prefilterBlur = true, + medianFilter = FilterQuality.Normal, + dilateNearBlur = false + }, + + // High + new QualitySettings + { + prefilterBlur = true, + medianFilter = FilterQuality.High, + dilateNearBlur = true + } + }; + } + + [Serializable] + public struct FocusSettings + { + [Tooltip("Auto-focus on a selected transform.")] + public Transform transform; + + [Min(0f), Tooltip("Focus distance (in world units).")] + public float focusPlane; + + [Min(0.1f), Tooltip("Focus range (in world units). The focus plane is located in the center of the range.")] + public float range; + + [Min(0f), Tooltip("Near focus distance (in world units).")] + public float nearPlane; + + [Min(0f), Tooltip("Near blur falloff (in world units).")] + public float nearFalloff; + + [Min(0f), Tooltip("Far focus distance (in world units).")] + public float farPlane; + + [Min(0f), Tooltip("Far blur falloff (in world units).")] + public float farFalloff; + + [Range(0f, kMaxBlur), Tooltip("Maximum blur radius for the near plane.")] + public float nearBlurRadius; + + [Range(0f, kMaxBlur), Tooltip("Maximum blur radius for the far plane.")] + public float farBlurRadius; + + public static FocusSettings defaultSettings + { + get + { + return new FocusSettings + { + transform = null, + focusPlane = 20f, + range = 35f, + nearPlane = 2.5f, + nearFalloff = 15f, + farPlane = 37.5f, + farFalloff = 50f, + nearBlurRadius = 15f, + farBlurRadius = 20f + }; + } + } + } + + [Serializable] + public struct BokehTextureSettings + { + [Tooltip("Adding a texture to this field will enable the use of \"Bokeh Textures\". Use with care. This feature is only available on Shader Model 5 compatible-hardware and performance scale with the amount of bokeh.")] + public Texture2D texture; + + [Range(0.01f, 10f), Tooltip("Maximum size of bokeh textures on screen.")] + public float scale; + + [Range(0.01f, 100f), Tooltip("Bokeh brightness.")] + public float intensity; + + [Range(0.01f, 5f), Tooltip("Controls the amount of bokeh textures. Lower values mean more bokeh splats.")] + public float threshold; + + [Range(0.01f, 1f), Tooltip("Controls the spawn conditions. Lower values mean more visible bokeh.")] + public float spawnHeuristic; + + public static BokehTextureSettings defaultSettings + { + get + { + return new BokehTextureSettings + { + texture = null, + scale = 1f, + intensity = 50f, + threshold = 2f, + spawnHeuristic = 0.15f + }; + } + } + } + #endregion + + public GlobalSettings settings = GlobalSettings.defaultSettings; + public FocusSettings focus = FocusSettings.defaultSettings; + public BokehTextureSettings bokehTexture = BokehTextureSettings.defaultSettings; + + [SerializeField] + private Shader m_FilmicDepthOfFieldShader; + + public Shader filmicDepthOfFieldShader + { + get + { + if (m_FilmicDepthOfFieldShader == null) + m_FilmicDepthOfFieldShader = Shader.Find("Hidden/DepthOfField/DepthOfField"); + + return m_FilmicDepthOfFieldShader; + } + } + + [SerializeField] + private Shader m_MedianFilterShader; + + public Shader medianFilterShader + { + get + { + if (m_MedianFilterShader == null) + m_MedianFilterShader = Shader.Find("Hidden/DepthOfField/MedianFilter"); + + return m_MedianFilterShader; + } + } + + [SerializeField] + private Shader m_TextureBokehShader; + + public Shader textureBokehShader + { + get + { + if (m_TextureBokehShader == null) + m_TextureBokehShader = Shader.Find("Hidden/DepthOfField/BokehSplatting"); + + return m_TextureBokehShader; + } + } + + private RenderTextureUtility m_RTU = new RenderTextureUtility(); + + private Material m_FilmicDepthOfFieldMaterial; + + public Material filmicDepthOfFieldMaterial + { + get + { + if (m_FilmicDepthOfFieldMaterial == null) + m_FilmicDepthOfFieldMaterial = ImageEffectHelper.CheckShaderAndCreateMaterial(filmicDepthOfFieldShader); + + return m_FilmicDepthOfFieldMaterial; + } + } + + private Material m_MedianFilterMaterial; + + public Material medianFilterMaterial + { + get + { + if (m_MedianFilterMaterial == null) + m_MedianFilterMaterial = ImageEffectHelper.CheckShaderAndCreateMaterial(medianFilterShader); + + return m_MedianFilterMaterial; + } + } + + private Material m_TextureBokehMaterial; + + public Material textureBokehMaterial + { + get + { + if (m_TextureBokehMaterial == null) + m_TextureBokehMaterial = ImageEffectHelper.CheckShaderAndCreateMaterial(textureBokehShader); + + return m_TextureBokehMaterial; + } + } + + private ComputeBuffer m_ComputeBufferDrawArgs; + + public ComputeBuffer computeBufferDrawArgs + { + get + { + if (m_ComputeBufferDrawArgs == null) + { +#if UNITY_5_4_OR_NEWER + m_ComputeBufferDrawArgs = new ComputeBuffer(1, 16, ComputeBufferType.IndirectArguments); +#else + m_ComputeBufferDrawArgs = new ComputeBuffer(1, 16, ComputeBufferType.DrawIndirect); +#endif + m_ComputeBufferDrawArgs.SetData(new[] {0, 1, 0, 0}); + } + + return m_ComputeBufferDrawArgs; + } + } + + private ComputeBuffer m_ComputeBufferPoints; + + public ComputeBuffer computeBufferPoints + { + get + { + if (m_ComputeBufferPoints == null) + m_ComputeBufferPoints = new ComputeBuffer(90000, 12 + 16, ComputeBufferType.Append); + + return m_ComputeBufferPoints; + } + } + + private QualitySettings m_CurrentQualitySettings; + private float m_LastApertureOrientation; + private Vector4 m_OctogonalBokehDirection1; + private Vector4 m_OctogonalBokehDirection2; + private Vector4 m_OctogonalBokehDirection3; + private Vector4 m_OctogonalBokehDirection4; + private Vector4 m_HexagonalBokehDirection1; + private Vector4 m_HexagonalBokehDirection2; + private Vector4 m_HexagonalBokehDirection3; + + private void OnEnable() + { + if (!ImageEffectHelper.IsSupported(filmicDepthOfFieldShader, true, true, this) || !ImageEffectHelper.IsSupported(medianFilterShader, true, true, this)) + { + enabled = false; + return; + } + + if (ImageEffectHelper.supportsDX11 && !ImageEffectHelper.IsSupported(textureBokehShader, true, true, this)) + { + enabled = false; + return; + } + + ComputeBlurDirections(true); + GetComponent().depthTextureMode |= DepthTextureMode.Depth; + } + + private void OnDisable() + { + ReleaseComputeResources(); + + if (m_FilmicDepthOfFieldMaterial != null) + DestroyImmediate(m_FilmicDepthOfFieldMaterial); + + if (m_TextureBokehMaterial != null) + DestroyImmediate(m_TextureBokehMaterial); + + if (m_MedianFilterMaterial != null) + DestroyImmediate(m_MedianFilterMaterial); + + m_FilmicDepthOfFieldMaterial = null; + m_TextureBokehMaterial = null; + m_MedianFilterMaterial = null; + + m_RTU.ReleaseAllTemporaryRenderTextures(); + } + + //-------------------------------------------------------------------// + // Main entry point // + //-------------------------------------------------------------------// + private void OnRenderImage(RenderTexture source, RenderTexture destination) + { + if (medianFilterMaterial == null || filmicDepthOfFieldMaterial == null) + { + Graphics.Blit(source, destination); + return; + } + + if (settings.visualizeFocus) + { + Vector4 blurrinessParam; + Vector4 blurrinessCoe; + ComputeCocParameters(out blurrinessParam, out blurrinessCoe); + filmicDepthOfFieldMaterial.SetVector("_BlurParams", blurrinessParam); + filmicDepthOfFieldMaterial.SetVector("_BlurCoe", blurrinessCoe); + Graphics.Blit(null, destination, filmicDepthOfFieldMaterial, (int)Passes.VisualizeCocExplicit); + } + else + { + DoDepthOfField(source, destination); + } + + m_RTU.ReleaseAllTemporaryRenderTextures(); + } + + private void DoDepthOfField(RenderTexture source, RenderTexture destination) + { + m_CurrentQualitySettings = QualitySettings.presetQualitySettings[(int)settings.filteringQuality]; + + float radiusAdjustement = source.height / 720f; + + float textureBokehScale = radiusAdjustement; + float textureBokehMaxRadius = Mathf.Max(focus.nearBlurRadius, focus.farBlurRadius) * textureBokehScale * 0.75f; + + float nearBlurRadius = focus.nearBlurRadius * radiusAdjustement; + float farBlurRadius = focus.farBlurRadius * radiusAdjustement; + float maxBlurRadius = Mathf.Max(nearBlurRadius, farBlurRadius); + switch (settings.apertureShape) + { + case ApertureShape.Hexagonal: + maxBlurRadius *= 1.2f; + break; + case ApertureShape.Octogonal: + maxBlurRadius *= 1.15f; + break; + } + + if (maxBlurRadius < 0.5f) + { + Graphics.Blit(source, destination); + return; + } + + // Quarter resolution + int rtW = source.width / 2; + int rtH = source.height / 2; + var blurrinessCoe = new Vector4(nearBlurRadius * 0.5f, farBlurRadius * 0.5f, 0f, 0f); + var colorAndCoc = m_RTU.GetTemporaryRenderTexture(rtW, rtH); + var colorAndCoc2 = m_RTU.GetTemporaryRenderTexture(rtW, rtH); + + // Downsample to Color + COC buffer + Vector4 cocParam; + Vector4 cocCoe; + ComputeCocParameters(out cocParam, out cocCoe); + filmicDepthOfFieldMaterial.SetVector("_BlurParams", cocParam); + filmicDepthOfFieldMaterial.SetVector("_BlurCoe", cocCoe); + Graphics.Blit(source, colorAndCoc2, filmicDepthOfFieldMaterial, (int)Passes.CaptureCocExplicit); + var src = colorAndCoc2; + var dst = colorAndCoc; + + // Collect texture bokeh candidates and replace with a darker pixel + if (shouldPerformBokeh) + { + // Blur a bit so we can do a frequency check + var blurred = m_RTU.GetTemporaryRenderTexture(rtW, rtH); + Graphics.Blit(src, blurred, filmicDepthOfFieldMaterial, (int)Passes.BoxBlur); + filmicDepthOfFieldMaterial.SetVector("_Offsets", new Vector4(0f, 1.5f, 0f, 1.5f)); + Graphics.Blit(blurred, dst, filmicDepthOfFieldMaterial, (int)Passes.BlurAlphaWeighted); + filmicDepthOfFieldMaterial.SetVector("_Offsets", new Vector4(1.5f, 0f, 0f, 1.5f)); + Graphics.Blit(dst, blurred, filmicDepthOfFieldMaterial, (int)Passes.BlurAlphaWeighted); + + // Collect texture bokeh candidates and replace with a darker pixel + textureBokehMaterial.SetTexture("_BlurredColor", blurred); + textureBokehMaterial.SetFloat("_SpawnHeuristic", bokehTexture.spawnHeuristic); + textureBokehMaterial.SetVector("_BokehParams", new Vector4(bokehTexture.scale * textureBokehScale, bokehTexture.intensity, bokehTexture.threshold, textureBokehMaxRadius)); + Graphics.SetRandomWriteTarget(1, computeBufferPoints); + Graphics.Blit(src, dst, textureBokehMaterial, (int)BokehTexturesPasses.Collect); + Graphics.ClearRandomWriteTargets(); + SwapRenderTexture(ref src, ref dst); + m_RTU.ReleaseTemporaryRenderTexture(blurred); + } + + filmicDepthOfFieldMaterial.SetVector("_BlurParams", cocParam); + filmicDepthOfFieldMaterial.SetVector("_BlurCoe", blurrinessCoe); + + // Dilate near blur factor + RenderTexture blurredFgCoc = null; + if (m_CurrentQualitySettings.dilateNearBlur) + { + var blurredFgCoc2 = m_RTU.GetTemporaryRenderTexture(rtW, rtH, 0, RenderTextureFormat.RGHalf); + blurredFgCoc = m_RTU.GetTemporaryRenderTexture(rtW, rtH, 0, RenderTextureFormat.RGHalf); + filmicDepthOfFieldMaterial.SetVector("_Offsets", new Vector4(0f, nearBlurRadius * 0.75f, 0f, 0f)); + Graphics.Blit(src, blurredFgCoc2, filmicDepthOfFieldMaterial, (int)Passes.DilateFgCocFromColor); + filmicDepthOfFieldMaterial.SetVector("_Offsets", new Vector4(nearBlurRadius * 0.75f, 0f, 0f, 0f)); + Graphics.Blit(blurredFgCoc2, blurredFgCoc, filmicDepthOfFieldMaterial, (int)Passes.DilateFgCoc); + m_RTU.ReleaseTemporaryRenderTexture(blurredFgCoc2); + blurredFgCoc.filterMode = FilterMode.Point; + } + + // Blur downsampled color to fill the gap between samples + if (m_CurrentQualitySettings.prefilterBlur) + { + Graphics.Blit(src, dst, filmicDepthOfFieldMaterial, (int)Passes.CocPrefilter); + SwapRenderTexture(ref src, ref dst); + } + + // Apply blur : Circle / Hexagonal or Octagonal (blur will create bokeh if bright pixel where not removed by "m_UseBokehTexture") + switch (settings.apertureShape) + { + case ApertureShape.Circular: + DoCircularBlur(blurredFgCoc, ref src, ref dst, maxBlurRadius); + break; + case ApertureShape.Hexagonal: + DoHexagonalBlur(blurredFgCoc, ref src, ref dst, maxBlurRadius); + break; + case ApertureShape.Octogonal: + DoOctogonalBlur(blurredFgCoc, ref src, ref dst, maxBlurRadius); + break; + } + + // Smooth result + switch (m_CurrentQualitySettings.medianFilter) + { + case FilterQuality.Normal: + { + medianFilterMaterial.SetVector("_Offsets", new Vector4(1f, 0f, 0f, 0f)); + Graphics.Blit(src, dst, medianFilterMaterial, (int)MedianPasses.Median3); + SwapRenderTexture(ref src, ref dst); + medianFilterMaterial.SetVector("_Offsets", new Vector4(0f, 1f, 0f, 0f)); + Graphics.Blit(src, dst, medianFilterMaterial, (int)MedianPasses.Median3); + SwapRenderTexture(ref src, ref dst); + break; + } + case FilterQuality.High: + { + Graphics.Blit(src, dst, medianFilterMaterial, (int)MedianPasses.Median3X3); + SwapRenderTexture(ref src, ref dst); + break; + } + } + + // Merge to full resolution (with boost) + upsampling (linear or bicubic) + filmicDepthOfFieldMaterial.SetVector("_BlurCoe", blurrinessCoe); + filmicDepthOfFieldMaterial.SetVector("_Convolved_TexelSize", new Vector4(src.width, src.height, 1f / src.width, 1f / src.height)); + filmicDepthOfFieldMaterial.SetTexture("_SecondTex", src); + int mergePass = (int)Passes.MergeExplicit; + + // Apply texture bokeh + if (shouldPerformBokeh) + { + var tmp = m_RTU.GetTemporaryRenderTexture(source.height, source.width, 0, source.format); + Graphics.Blit(source, tmp, filmicDepthOfFieldMaterial, mergePass); + + Graphics.SetRenderTarget(tmp); + ComputeBuffer.CopyCount(computeBufferPoints, computeBufferDrawArgs, 0); + textureBokehMaterial.SetBuffer("pointBuffer", computeBufferPoints); + textureBokehMaterial.SetTexture("_MainTex", bokehTexture.texture); + textureBokehMaterial.SetVector("_Screen", new Vector3(1f / (1f * source.width), 1f / (1f * source.height), textureBokehMaxRadius)); + textureBokehMaterial.SetPass((int)BokehTexturesPasses.Apply); + Graphics.DrawProceduralIndirect(MeshTopology.Points, computeBufferDrawArgs, 0); + Graphics.Blit(tmp, destination); // Hackaround for DX11 flipfun (OPTIMIZEME) + } + else + { + Graphics.Blit(source, destination, filmicDepthOfFieldMaterial, mergePass); + } + } + + //-------------------------------------------------------------------// + // Blurs // + //-------------------------------------------------------------------// + private void DoHexagonalBlur(RenderTexture blurredFgCoc, ref RenderTexture src, ref RenderTexture dst, float maxRadius) + { + ComputeBlurDirections(false); + + int blurPass; + int blurPassMerge; + GetDirectionalBlurPassesFromRadius(blurredFgCoc, maxRadius, out blurPass, out blurPassMerge); + filmicDepthOfFieldMaterial.SetTexture("_SecondTex", blurredFgCoc); + var tmp = m_RTU.GetTemporaryRenderTexture(src.width, src.height, 0, src.format); + + filmicDepthOfFieldMaterial.SetVector("_Offsets", m_HexagonalBokehDirection1); + Graphics.Blit(src, tmp, filmicDepthOfFieldMaterial, blurPass); + + filmicDepthOfFieldMaterial.SetVector("_Offsets", m_HexagonalBokehDirection2); + Graphics.Blit(tmp, src, filmicDepthOfFieldMaterial, blurPass); + + filmicDepthOfFieldMaterial.SetVector("_Offsets", m_HexagonalBokehDirection3); + filmicDepthOfFieldMaterial.SetTexture("_ThirdTex", src); + Graphics.Blit(tmp, dst, filmicDepthOfFieldMaterial, blurPassMerge); + m_RTU.ReleaseTemporaryRenderTexture(tmp); + SwapRenderTexture(ref src, ref dst); + } + + private void DoOctogonalBlur(RenderTexture blurredFgCoc, ref RenderTexture src, ref RenderTexture dst, float maxRadius) + { + ComputeBlurDirections(false); + + int blurPass; + int blurPassMerge; + GetDirectionalBlurPassesFromRadius(blurredFgCoc, maxRadius, out blurPass, out blurPassMerge); + filmicDepthOfFieldMaterial.SetTexture("_SecondTex", blurredFgCoc); + var tmp = m_RTU.GetTemporaryRenderTexture(src.width, src.height, 0, src.format); + + filmicDepthOfFieldMaterial.SetVector("_Offsets", m_OctogonalBokehDirection1); + Graphics.Blit(src, tmp, filmicDepthOfFieldMaterial, blurPass); + + filmicDepthOfFieldMaterial.SetVector("_Offsets", m_OctogonalBokehDirection2); + Graphics.Blit(tmp, dst, filmicDepthOfFieldMaterial, blurPass); + + filmicDepthOfFieldMaterial.SetVector("_Offsets", m_OctogonalBokehDirection3); + Graphics.Blit(src, tmp, filmicDepthOfFieldMaterial, blurPass); + + filmicDepthOfFieldMaterial.SetVector("_Offsets", m_OctogonalBokehDirection4); + filmicDepthOfFieldMaterial.SetTexture("_ThirdTex", dst); + Graphics.Blit(tmp, src, filmicDepthOfFieldMaterial, blurPassMerge); + m_RTU.ReleaseTemporaryRenderTexture(tmp); + } + + private void DoCircularBlur(RenderTexture blurredFgCoc, ref RenderTexture src, ref RenderTexture dst, float maxRadius) + { + int bokehPass; + + if (blurredFgCoc != null) + { + filmicDepthOfFieldMaterial.SetTexture("_SecondTex", blurredFgCoc); + bokehPass = (maxRadius > 10f) ? (int)Passes.CircleBlurWithDilatedFg : (int)Passes.CircleBlowLowQualityWithDilatedFg; + } + else + { + bokehPass = (maxRadius > 10f) ? (int)Passes.CircleBlur : (int)Passes.CircleBlurLowQuality; + } + + Graphics.Blit(src, dst, filmicDepthOfFieldMaterial, bokehPass); + SwapRenderTexture(ref src, ref dst); + } + + //-------------------------------------------------------------------// + // Helpers // + //-------------------------------------------------------------------// + private void ComputeCocParameters(out Vector4 blurParams, out Vector4 blurCoe) + { + var sceneCamera = GetComponent(); + + float focusDistance; + float nearFalloff = focus.nearFalloff * 2f; + float farFalloff = focus.farFalloff * 2f; + float nearPlane = focus.nearPlane; + float farPlane = focus.farPlane; + + if (settings.tweakMode == TweakMode.Range) + { + if (focus.transform != null) + focusDistance = sceneCamera.WorldToViewportPoint(focus.transform.position).z; + else + focusDistance = focus.focusPlane; + + float s = focus.range * 0.5f; + nearPlane = focusDistance - s; + farPlane = focusDistance + s; + } + + nearPlane -= (nearFalloff * 0.5f); + farPlane += (farFalloff * 0.5f); + focusDistance = (nearPlane + farPlane) * 0.5f; + + float focusDistance01 = focusDistance / sceneCamera.farClipPlane; + float nearDistance01 = nearPlane / sceneCamera.farClipPlane; + float farDistance01 = farPlane / sceneCamera.farClipPlane; + + var dof = farPlane - nearPlane; + var dof01 = farDistance01 - nearDistance01; + var nearFalloff01 = nearFalloff / dof; + var farFalloff01 = farFalloff / dof; + float nearFocusRange01 = (1f - nearFalloff01) * (dof01 * 0.5f); + float farFocusRange01 = (1f - farFalloff01) * (dof01 * 0.5f); + + if (focusDistance01 <= nearDistance01) + focusDistance01 = nearDistance01 + 1e-6f; + if (focusDistance01 >= farDistance01) + focusDistance01 = farDistance01 - 1e-6f; + + if ((focusDistance01 - nearFocusRange01) <= nearDistance01) + nearFocusRange01 = focusDistance01 - nearDistance01 - 1e-6f; + if ((focusDistance01 + farFocusRange01) >= farDistance01) + farFocusRange01 = farDistance01 - focusDistance01 - 1e-6f; + + float a1 = 1f / (nearDistance01 - focusDistance01 + nearFocusRange01); + float a2 = 1f / (farDistance01 - focusDistance01 - farFocusRange01); + float b1 = 1f - a1 * nearDistance01; + float b2 = 1f - a2 * farDistance01; + const float c1 = -1f; + const float c2 = 1f; + blurParams = new Vector4(c1 * a1, c1 * b1, c2 * a2, c2 * b2); + blurCoe = new Vector4(0f, 0f, (b2 - b1) / (a1 - a2), 0f); + + // Save values so we can switch from one tweak mode to the other on the fly + focus.nearPlane = nearPlane + (nearFalloff * 0.5f); + focus.farPlane = farPlane - (farFalloff * 0.5f); + focus.focusPlane = (focus.nearPlane + focus.farPlane) * 0.5f; + focus.range = focus.farPlane - focus.nearPlane; + } + + private void ReleaseComputeResources() + { + if (m_ComputeBufferDrawArgs != null) + m_ComputeBufferDrawArgs.Release(); + + if (m_ComputeBufferPoints != null) + m_ComputeBufferPoints.Release(); + + m_ComputeBufferDrawArgs = null; + m_ComputeBufferPoints = null; + } + + private void ComputeBlurDirections(bool force) + { + if (!force && Math.Abs(m_LastApertureOrientation - settings.apertureOrientation) < float.Epsilon) + return; + + m_LastApertureOrientation = settings.apertureOrientation; + + float rotationRadian = settings.apertureOrientation * Mathf.Deg2Rad; + float cosinus = Mathf.Cos(rotationRadian); + float sinus = Mathf.Sin(rotationRadian); + + m_OctogonalBokehDirection1 = new Vector4(0.5f, 0f, 0f, 0f); + m_OctogonalBokehDirection2 = new Vector4(0f, 0.5f, 1f, 0f); + m_OctogonalBokehDirection3 = new Vector4(-0.353553f, 0.353553f, 1f, 0f); + m_OctogonalBokehDirection4 = new Vector4(0.353553f, 0.353553f, 1f, 0f); + + m_HexagonalBokehDirection1 = new Vector4(0.5f, 0f, 0f, 0f); + m_HexagonalBokehDirection2 = new Vector4(0.25f, 0.433013f, 1f, 0f); + m_HexagonalBokehDirection3 = new Vector4(0.25f, -0.433013f, 1f, 0f); + + if (rotationRadian > float.Epsilon) + { + Rotate2D(ref m_OctogonalBokehDirection1, cosinus, sinus); + Rotate2D(ref m_OctogonalBokehDirection2, cosinus, sinus); + Rotate2D(ref m_OctogonalBokehDirection3, cosinus, sinus); + Rotate2D(ref m_OctogonalBokehDirection4, cosinus, sinus); + Rotate2D(ref m_HexagonalBokehDirection1, cosinus, sinus); + Rotate2D(ref m_HexagonalBokehDirection2, cosinus, sinus); + Rotate2D(ref m_HexagonalBokehDirection3, cosinus, sinus); + } + } + + private bool shouldPerformBokeh + { + get { return ImageEffectHelper.supportsDX11 && bokehTexture.texture != null && textureBokehMaterial; } + } + + private static void Rotate2D(ref Vector4 direction, float cosinus, float sinus) + { + var source = direction; + direction.x = source.x * cosinus - source.y * sinus; + direction.y = source.x * sinus + source.y * cosinus; + } + + private static void SwapRenderTexture(ref RenderTexture src, ref RenderTexture dst) + { + RenderTexture tmp = dst; + dst = src; + src = tmp; + } + + private static void GetDirectionalBlurPassesFromRadius(RenderTexture blurredFgCoc, float maxRadius, out int blurPass, out int blurAndMergePass) + { + if (blurredFgCoc == null) + { + if (maxRadius > 10f) + { + blurPass = (int)Passes.ShapeHighQuality; + blurAndMergePass = (int)Passes.ShapeHighQualityMerge; + } + else if (maxRadius > 5f) + { + blurPass = (int)Passes.ShapeMediumQuality; + blurAndMergePass = (int)Passes.ShapeMediumQualityMerge; + } + else + { + blurPass = (int)Passes.ShapeLowQuality; + blurAndMergePass = (int)Passes.ShapeLowQualityMerge; + } + } + else + { + if (maxRadius > 10f) + { + blurPass = (int)Passes.ShapeHighQualityDilateFg; + blurAndMergePass = (int)Passes.ShapeHighQualityMergeDilateFg; + } + else if (maxRadius > 5f) + { + blurPass = (int)Passes.ShapeMediumQualityDilateFg; + blurAndMergePass = (int)Passes.ShapeMediumQualityMergeDilateFg; + } + else + { + blurPass = (int)Passes.ShapeLowQualityDilateFg; + blurAndMergePass = (int)Passes.ShapeLowQualityMergeDilateFg; + } + } + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/DepthOfField.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/DepthOfField.cs.meta new file mode 100644 index 0000000..c12eba8 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/DepthOfField.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 8a338d679868f45439ea43c7ae035e36 +timeCreated: 1453985420 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: + - m_FilmicDepthOfFieldShader: {fileID: 4800000, guid: bff0e5458fb914f5c9985ba4f09171d2, + type: 3} + - m_MedianFilterShader: {fileID: 4800000, guid: a058b22d4123add4b807e832604e5e7b, + type: 3} + - m_TextureBokehShader: {fileID: 4800000, guid: c961b8ed1f00f924d804ada5143bd0e8, + type: 3} + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Editor.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Editor.meta new file mode 100644 index 0000000..79c6494 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Editor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 1a8273952ce5743428d8c42b25cb0458 +folderAsset: yes +timeCreated: 1449046242 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Editor/DepthOfFieldEditor.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Editor/DepthOfFieldEditor.cs new file mode 100644 index 0000000..9d9e327 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Editor/DepthOfFieldEditor.cs @@ -0,0 +1,139 @@ +using UnityEditor; +using UnityEngine; + +namespace UnityStandardAssets.CinematicEffects +{ + [CustomEditor(typeof(DepthOfField))] + class DepthOfFieldEditor : Editor + { + private SerializedProperty m_VisualizeFocus; + private SerializedProperty m_TweakMode; + private SerializedProperty m_FilteringQuality; + private SerializedProperty m_ApertureShape; + private SerializedProperty m_ApertureOrientation; + + private SerializedProperty m_Transform; + private SerializedProperty m_FocusPlane; + private SerializedProperty m_Range; + private SerializedProperty m_NearPlane; + private SerializedProperty m_NearFalloff; + private SerializedProperty m_FarPlane; + private SerializedProperty m_FarFalloff; + private SerializedProperty m_NearBlurRadius; + private SerializedProperty m_FarBlurRadius; + + private SerializedProperty m_Texture; + private SerializedProperty m_Scale; + private SerializedProperty m_Intensity; + private SerializedProperty m_Threshold; + private SerializedProperty m_SpawnHeuristic; + + private void OnEnable() + { + var o = serializedObject; + + m_VisualizeFocus = o.FindProperty("settings.visualizeFocus"); + m_TweakMode = o.FindProperty("settings.tweakMode"); + m_FilteringQuality = o.FindProperty("settings.filteringQuality"); + m_ApertureShape = o.FindProperty("settings.apertureShape"); + m_ApertureOrientation = o.FindProperty("settings.apertureOrientation"); + + m_Transform = o.FindProperty("focus.transform"); + m_FocusPlane = o.FindProperty("focus.focusPlane"); + m_Range = o.FindProperty("focus.range"); + m_NearPlane = o.FindProperty("focus.nearPlane"); + m_NearFalloff = o.FindProperty("focus.nearFalloff"); + m_FarPlane = o.FindProperty("focus.farPlane"); + m_FarFalloff = o.FindProperty("focus.farFalloff"); + m_NearBlurRadius = o.FindProperty("focus.nearBlurRadius"); + m_FarBlurRadius = o.FindProperty("focus.farBlurRadius"); + + m_Texture = o.FindProperty("bokehTexture.texture"); + m_Scale = o.FindProperty("bokehTexture.scale"); + m_Intensity = o.FindProperty("bokehTexture.intensity"); + m_Threshold = o.FindProperty("bokehTexture.threshold"); + m_SpawnHeuristic = o.FindProperty("bokehTexture.spawnHeuristic"); + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + EditorGUILayout.PropertyField(m_VisualizeFocus); + EditorGUILayout.PropertyField(m_TweakMode); + EditorGUILayout.PropertyField(m_FilteringQuality); + EditorGUILayout.PropertyField(m_ApertureShape); + + if (m_ApertureShape.intValue != (int)DepthOfField.ApertureShape.Circular) + { + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(m_ApertureOrientation, new GUIContent("Orientation")); + EditorGUI.indentLevel--; + } + + EditorGUILayout.Space(); + EditorGUILayout.LabelField("Focus", EditorStyles.boldLabel); + + var falloff = new GUIContent("Falloff"); + var blurRadius = new GUIContent("Blur Radius"); + + EditorGUI.indentLevel++; + + if (m_TweakMode.intValue == (int)DepthOfField.TweakMode.Range) + { + EditorGUILayout.PropertyField(m_Transform); + + using (new EditorGUI.DisabledGroupScope(m_Transform.objectReferenceValue != null)) + { + EditorGUILayout.PropertyField(m_FocusPlane); + } + + EditorGUILayout.PropertyField(m_Range); + + EditorGUILayout.LabelField(m_NearPlane.displayName); + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(m_NearFalloff, falloff); + EditorGUILayout.PropertyField(m_NearBlurRadius, blurRadius); + EditorGUI.indentLevel--; + + EditorGUILayout.LabelField(m_FarPlane.displayName); + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(m_FarFalloff, falloff); + EditorGUILayout.PropertyField(m_FarBlurRadius, blurRadius); + EditorGUI.indentLevel--; + } + else + { + EditorGUILayout.PropertyField(m_NearPlane); + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(m_NearFalloff, falloff); + EditorGUILayout.PropertyField(m_NearBlurRadius, blurRadius); + EditorGUI.indentLevel--; + + EditorGUILayout.PropertyField(m_FarPlane); + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(m_FarFalloff, falloff); + EditorGUILayout.PropertyField(m_FarBlurRadius, blurRadius); + EditorGUI.indentLevel--; + } + + EditorGUI.indentLevel--; + + EditorGUILayout.Space(); + EditorGUILayout.LabelField("Bokeh", EditorStyles.boldLabel); + + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(m_Texture); + if (m_Texture.objectReferenceValue != null) + { + EditorGUILayout.PropertyField(m_Scale); + EditorGUILayout.PropertyField(m_Intensity); + EditorGUILayout.PropertyField(m_Threshold); + EditorGUILayout.PropertyField(m_SpawnHeuristic); + } + EditorGUI.indentLevel--; + + serializedObject.ApplyModifiedProperties(); + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Editor/DepthOfFieldEditor.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Editor/DepthOfFieldEditor.cs.meta new file mode 100644 index 0000000..92f56d3 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Editor/DepthOfFieldEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 3eb07ef5681934662814cc768bcdb60c +timeCreated: 1429220270 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Helpers.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Helpers.meta new file mode 100644 index 0000000..5e30d18 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Helpers.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 5427d9a5126366c42b9509de8233bff7 +folderAsset: yes +timeCreated: 1453985653 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Helpers/HexShape.psd b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Helpers/HexShape.psd new file mode 100644 index 0000000..eef48cb Binary files /dev/null and b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Helpers/HexShape.psd differ diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Helpers/HexShape.psd.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Helpers/HexShape.psd.meta new file mode 100644 index 0000000..c46144f --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Helpers/HexShape.psd.meta @@ -0,0 +1,55 @@ +fileFormatVersion: 2 +guid: a4cdca73d61814d33ac1587f6c163bca +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 7 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 64 + textureSettings: + filterMode: -1 + aniso: 0 + mipBias: -1 + wrapMode: 1 + nPOTScale: 1 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + allowsAlphaSplitting: 0 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + outline: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Helpers/RoundedHexShape.tif b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Helpers/RoundedHexShape.tif new file mode 100644 index 0000000..9dccaf3 Binary files /dev/null and b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Helpers/RoundedHexShape.tif differ diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Helpers/RoundedHexShape.tif.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Helpers/RoundedHexShape.tif.meta new file mode 100644 index 0000000..46b330b --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Helpers/RoundedHexShape.tif.meta @@ -0,0 +1,57 @@ +fileFormatVersion: 2 +guid: 9014ef007a9a1d545b0fba20daa0fc7c +timeCreated: 1454425451 +licenseType: Store +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 1 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 7 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 64 + textureSettings: + filterMode: -1 + aniso: 0 + mipBias: -1 + wrapMode: 1 + nPOTScale: 1 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + allowsAlphaSplitting: 0 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + outline: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Helpers/SphereShape.psd b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Helpers/SphereShape.psd new file mode 100644 index 0000000..a100649 Binary files /dev/null and b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Helpers/SphereShape.psd differ diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Helpers/SphereShape.psd.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Helpers/SphereShape.psd.meta new file mode 100644 index 0000000..fa783fc --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Helpers/SphereShape.psd.meta @@ -0,0 +1,55 @@ +fileFormatVersion: 2 +guid: fc00ec05a89da4ff695a4273715cd5ce +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 7 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 64 + textureSettings: + filterMode: -1 + aniso: 0 + mipBias: -1 + wrapMode: 1 + nPOTScale: 1 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + allowsAlphaSplitting: 0 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + outline: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Resources.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Resources.meta new file mode 100644 index 0000000..931926e --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Resources.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: aa2234edaeebe8b4fb5d67be342dbac9 +folderAsset: yes +timeCreated: 1453906992 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Resources/BokehSplatting.shader b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Resources/BokehSplatting.shader new file mode 100644 index 0000000..ad58718 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Resources/BokehSplatting.shader @@ -0,0 +1,235 @@ +/* + DX11 Bokeh splatting + + Basic algorithm: + * Find bright spots + * Verify high frequency (otherwise dont care) + * If positive, replace with black pixel and add to append buffer + * Blend bokeh texture sprites via append buffer on top of blurred buffer +*/ + +Shader "Hidden/DepthOfField/BokehSplatting" +{ + Properties + { + _MainTex ("", 2D) = "white" {} + _BlurredColor ("", 2D) = "white" {} + _FgCocMask ("", 2D) = "white" {} + } + + CGINCLUDE + + #include "UnityCG.cginc" + + #define BOKEH_ZERO_VEC (float4(0.0,0.0,0.0,0.0)) + #define BOKEH_ONE_VEC (float4(1.0,1.0,1.0,1.0)) + + float4 _BokehParams; // dx11BokehScale, dx11BokehIntensity,dx11BokehThreshhold, internalBlurWidth + float4 _MainTex_TexelSize; + float3 _Screen; + float _SpawnHeuristic; + + sampler2D_float _CameraDepthTexture; + sampler2D _BlurredColor; + sampler2D _MainTex; + sampler2D _FgCocMask; + + struct appendStruct + { + float3 pos; + float4 color; + }; + + struct gs_out + { + float4 pos : SV_POSITION; + float3 uv : TEXCOORD0; + float4 color : TEXCOORD1; + float4 misc : TEXCOORD2; + }; + + // TODO: activate border clamp tex sampler state instead? + inline float4 clampBorderColor(float2 uv) + { + #if 1 + if(uv.x <= 0.0) return BOKEH_ZERO_VEC; if(uv.x >= 1.0) return BOKEH_ZERO_VEC; + if(uv.y <= 0.0) return BOKEH_ZERO_VEC; if(uv.y >= 1.0) return BOKEH_ZERO_VEC; + #endif + return BOKEH_ONE_VEC; + } + + struct vs_out + { + float4 pos : SV_POSITION; + float2 uv : TEXCOORD0; + float4 color : TEXCOORD1; + float cocOverlap : TEXCOORD2; + }; + + struct appdata + { + float4 vertex : POSITION; + float2 texcoord : TEXCOORD0; + }; + + struct v2f + { + float4 pos : SV_POSITION; + float2 uv_flip : TEXCOORD0; + float2 uv : TEXCOORD1; + }; + + AppendStructuredBuffer pointBufferOutput : register(u1); + StructuredBuffer pointBuffer; + + vs_out vertApply (uint id : SV_VertexID) + { + vs_out o = (vs_out)0; + float2 pos = pointBuffer[id].pos.xy ; + o.pos = float4(pos * 2.0 - 1.0, 0.0, 1.0); + o.color = pointBuffer[id].color; + + #if UNITY_UV_STARTS_AT_TOP + o.pos.y *= -1.0; + #endif + + o.cocOverlap = pointBuffer[id].pos.z; + + return o; + } + + v2f vertCollect (appdata v) + { + v2f o; + o.pos = mul (UNITY_MATRIX_MVP, v.vertex); + o.uv = v.texcoord; + o.uv_flip = v.texcoord; + + #if UNITY_UV_STARTS_AT_TOP + if (_MainTex_TexelSize.y < 0.0) + { + o.uv_flip.y = 1.0 - o.uv_flip.y; + o.pos.y *= -1.0; + } + #endif + + return o; + } + + [maxvertexcount(4)] + void geom (point vs_out input[1], inout TriangleStream outStream) + { + // NEW ENERGY CONSERVATION: + float2 scale2 = _BokehParams.ww * input[0].color.aa * _BokehParams.xx; + float4 offs = 0.0; + offs.xy = float2(3.0, 3.0) + 2.0 * floor(scale2 + float2(0.5, 0.5)); + + float2 rs = ((float2(1.0, 1.0) + 2.0 * (scale2 + float2(0.5, 0.5))));; + float2 f2 = offs.xy / rs; + + float energyAdjustment = (_BokehParams.y) / (rs.x * rs.y); + offs.xy *= _Screen.xy; + + gs_out output; + + output.pos = input[0].pos + offs * float4(-1.0, 1.0, 0.0, 0.0); + output.misc = float4(f2, 0.0, 0.0); + output.uv = float3(0.0, 1.0, input[0].cocOverlap); + output.color = input[0].color * energyAdjustment; + outStream.Append (output); + + output.pos = input[0].pos + offs*float4(1.0, 1.0, 0.0, 0.0); + output.misc = float4(f2, 0.0, 0.0); + output.uv = float3(1.0, 1.0, input[0].cocOverlap); + output.color = input[0].color * energyAdjustment; + outStream.Append (output); + + output.pos = input[0].pos + offs*float4(-1.0, -1.0, 0.0, 0.0); + output.misc = float4(f2, 0.0, 0.0); + output.uv = float3(0.0, 0.0, input[0].cocOverlap); + output.color = input[0].color * energyAdjustment; + outStream.Append (output); + + output.pos = input[0].pos + offs*float4(1.0, -1.0, 0.0, 0.0); + output.misc = float4(f2, 0.0, 0.0); + output.uv = float3(1.0, 0.0, input[0].cocOverlap); + output.color = input[0].color * energyAdjustment; + outStream.Append (output); + + outStream.RestartStrip(); + } + + float4 collectBrightPixel(half2 uv) + { + half4 c = tex2D(_MainTex, uv); + half coc = abs(c.a); + half lumc = Luminance(c.rgb); + + half4 cblurred = tex2D(_BlurredColor, uv); + half cocBlurred = abs(cblurred.a); + half lumblurred = Luminance(cblurred.rgb); + half fgCoc = -min(c.a, 0.0); + + [branch] + if (coc * _BokehParams.w > 1.0 && cocBlurred > 0.1 && lumc > _BokehParams.z && abs(lumc - lumblurred) > _SpawnHeuristic) + { + appendStruct append = (appendStruct)0; + append.pos = float3(uv, fgCoc); + append.color.rgba = half4(c.rgb * saturate(coc * 4.0), coc); + pointBufferOutput.Append(append); + c = half4(c.rgb * saturate(1.0 - coc * 4.0), c.a); + } + + return c; + } + + ENDCG + + SubShader + { + // Pass 0: bokeh splatting + Pass + { + ZWrite Off ZTest Always Cull Off + BlendOp Add, Add + Blend DstAlpha One, Zero One + ColorMask RGBA + + CGPROGRAM + + #pragma target 5.0 + #pragma vertex vertApply + #pragma geometry geom + #pragma fragment frag + + fixed4 frag (gs_out i) : SV_Target + { + float2 uv = (i.uv.xy) * i.misc.xy + (float2(1,1)-i.misc.xy) * 0.5; // smooth uv scale + return float4(i.color.rgb, 1) * float4(tex2D(_MainTex, uv.xy).rgb, i.uv.z) * clampBorderColor (uv); + } + + ENDCG + } + + // Pass 1: append buffer "collect" + Pass + { + ZWrite Off ZTest Always Cull Off + + CGPROGRAM + + #pragma vertex vertCollect + #pragma fragment frag + #pragma target 5.0 + + float4 frag (v2f i) : SV_Target + { + return collectBrightPixel(i.uv); + } + + ENDCG + } + } + + Fallback Off +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Resources/BokehSplatting.shader.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Resources/BokehSplatting.shader.meta new file mode 100644 index 0000000..36cccae --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Resources/BokehSplatting.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: c961b8ed1f00f924d804ada5143bd0e8 +timeCreated: 1449750679 +licenseType: Store +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Resources/DepthOfField.shader b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Resources/DepthOfField.shader new file mode 100644 index 0000000..5914588 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/DepthOfField/Resources/DepthOfField.shader @@ -0,0 +1,1221 @@ +Shader "Hidden/DepthOfField/DepthOfField" +{ + Properties + { + _MainTex ("-", 2D) = "black" + _SecondTex ("-", 2D) = "black" + _ThirdTex ("-", 2D) = "black" + } + + CGINCLUDE + + #pragma target 3.0 + #pragma fragmentoption ARB_precision_hint_fastest + #include "UnityCG.cginc" + + // Undef USE_LOCAL_TONEMAPPING if you dont want to use local tonemapping. + // Tweaking these values down will trade stability for less bokeh (see Tonemap/TonemapInvert methods below). + #ifndef SHADER_API_MOBILE + #define USE_LOCAL_TONEMAPPING + #endif + #define LOCAL_TONEMAP_START_LUMA 1.0 + #define LOCAL_TONEMAP_RANGE_LUMA 5.0 + + sampler2D _SecondTex; + sampler2D _ThirdTex; + + uniform half4 _MainTex_TexelSize; + uniform half4 _BlurCoe; + uniform half4 _BlurParams; + uniform half4 _Convolved_TexelSize; + uniform float4 _Offsets; + + uniform half4 _MainTex_ST; + uniform half4 _SecondTex_ST; + uniform half4 _ThirdTex_ST; + + #if (SHADER_TARGET >= 50 && !defined(SHADER_API_PSSL)) + #define USE_TEX2DOBJECT_FOR_COC + #endif + + #if defined(USE_TEX2DOBJECT_FOR_COC) + Texture2D _CameraDepthTexture; + SamplerState sampler_CameraDepthTexture; + Texture2D _MainTex; + SamplerState sampler_MainTex; + #else + sampler2D _MainTex; + sampler2D _CameraDepthTexture; + #endif + + /////////////////////////////////////////////////////////////////////////////// + // Verter Shaders and declaration + /////////////////////////////////////////////////////////////////////////////// + + struct v2f + { + float4 pos : SV_POSITION; + float2 uv : TEXCOORD0; + float2 uv1 : TEXCOORD1; + }; + + struct v2fDepth + { + half4 pos : SV_POSITION; + half2 uv : TEXCOORD0; + }; + + struct v2fBlur + { + float4 pos : SV_POSITION; + float2 uv : TEXCOORD0; + float4 uv01 : TEXCOORD1; + float4 uv23 : TEXCOORD2; + float4 uv45 : TEXCOORD3; + float4 uv67 : TEXCOORD4; + float4 uv89 : TEXCOORD5; + }; + + v2fDepth vert(appdata_img v) + { + v2fDepth o; + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv = v.texcoord.xy; + + #if UNITY_UV_STARTS_AT_TOP + if (_MainTex_TexelSize.y < 0.0) + o.uv.y = 1.0 - o.uv.y; + #endif + + return o; + } + + v2fDepth vertNoFlip(appdata_img v) + { + v2fDepth o; + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv = v.texcoord.xy; + return o; + } + + v2f vert_d(appdata_img v) + { + v2f o; + o.pos = mul (UNITY_MATRIX_MVP, v.vertex); + o.uv1.xy = v.texcoord.xy; + o.uv.xy = v.texcoord.xy; + + #if UNITY_UV_STARTS_AT_TOP + if (_MainTex_TexelSize.y < 0.0) + o.uv.y = 1.0 - o.uv.y; + #endif + + return o; + } + + v2f vertFlip(appdata_img v) + { + v2f o; + o.pos = mul (UNITY_MATRIX_MVP, v.vertex); + o.uv1.xy = v.texcoord.xy; + o.uv.xy = v.texcoord.xy; + + #if UNITY_UV_STARTS_AT_TOP + if (_MainTex_TexelSize.y < 0.0) + { + o.uv.y = 1.0 - o.uv.y; + o.uv1.y = 1.0 - o.uv1.y; + } + #endif + + return o; + } + + v2fBlur vertBlurPlusMinus(appdata_img v) + { + v2fBlur o; + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv.xy = v.texcoord.xy; + o.uv01 = v.texcoord.xyxy + _Offsets.xyxy * float4(1,1, -1,-1) * _MainTex_TexelSize.xyxy / 6.0; + o.uv23 = v.texcoord.xyxy + _Offsets.xyxy * float4(2,2, -2,-2) * _MainTex_TexelSize.xyxy / 6.0; + o.uv45 = v.texcoord.xyxy + _Offsets.xyxy * float4(3,3, -3,-3) * _MainTex_TexelSize.xyxy / 6.0; + o.uv67 = v.texcoord.xyxy + _Offsets.xyxy * float4(4,4, -4,-4) * _MainTex_TexelSize.xyxy / 6.0; + o.uv89 = v.texcoord.xyxy + _Offsets.xyxy * float4(5,5, -5,-5) * _MainTex_TexelSize.xyxy / 6.0; + return o; + } + + /////////////////////////////////////////////////////////////////////////////// + // Helpers + /////////////////////////////////////////////////////////////////////////////// + + inline half4 FetchMainTex(float2 uv) + { + #if defined(USE_TEX2DOBJECT_FOR_COC) + return _MainTex.SampleLevel(sampler_MainTex, uv, 0.0); + #else + return tex2Dlod(_MainTex, float4(uv, 0.0, 0.0)); + #endif + } + + inline half2 GetBilinearFetchTexOffsetFromAbsCoc(half4 absCoc) + { + half4 cocWeights = absCoc * absCoc * absCoc; + + half2 offset = 0.0; + offset += cocWeights.r * float2(-1.0, 1.0); + offset += cocWeights.g * float2( 1.0, 1.0); + offset += cocWeights.b * float2( 1.0,-1.0); + offset += cocWeights.a * float2(-1.0,-1.0); + offset = clamp((half2)-1.0,(half2)1.0, offset); + offset *= 0.5; + return offset; + } + + inline half4 FetchColorAndCocFromMainTex(float2 uv, float2 offsetFromKernelCenter) + { + // Bilinear + half4 fetch = FetchMainTex(uv); + + // CoC can't be linearly interpolated while doing "scatter and gather" or we will have haloing where coc vary sharply. + #if defined(USE_TEX2DOBJECT_FOR_COC) + half4 allCoc = _MainTex.GatherAlpha(sampler_MainTex, uv); + half cocAB = (abs(allCoc.r) < abs(allCoc.g)) ? allCoc.r : allCoc.g; + half cocCD = (abs(allCoc.b) < abs(allCoc.a)) ? allCoc.b : allCoc.a; + half coc = (abs(cocAB) < abs(cocCD)) ? cocAB : cocCD; + #else + // No gather available -> instead point sample the coc from the fartest away texel (not as good). + half2 bilinearCenter = floor(uv * _MainTex_TexelSize.zw - 0.5) + 1.0; + half2 cocUV = bilinearCenter + 0.5 * sign(offsetFromKernelCenter); + half coc = tex2Dlod(_MainTex, float4(cocUV * _MainTex_TexelSize.xy, 0.0, 0.0)).a; + #endif + + fetch.a = coc; + return fetch; + } + + inline half GetCocFromZValue(half d) + { + d = Linear01Depth(d); + half coc = d < _BlurCoe.z + ? clamp((_BlurParams.x * d + _BlurParams.y), -1.0, 0.0) + : saturate((_BlurParams.z * d + _BlurParams.w)); + return coc; + } + + inline half GetCocFromDepth(half2 uv) + { + #if defined(USE_TEX2DOBJECT_FOR_COC) + half d = _CameraDepthTexture.SampleLevel(sampler_CameraDepthTexture, uv, 0.0); + #else + half d = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, uv); + #endif + return GetCocFromZValue(d); + } + + #if (SHADER_TARGET < 50 && !defined(SHADER_API_PSSL)) + half rcp(half x) + { + return 1.0 / x; + } + #endif + + // From http://graphicrants.blogspot.dk/2013/12/tone-mapping.html + inline half3 Tonemap(half3 color) + { + #ifdef USE_LOCAL_TONEMAPPING + half a = LOCAL_TONEMAP_START_LUMA; + half b = LOCAL_TONEMAP_RANGE_LUMA; + + half luma = max(color.r, max(color.g, color.b)); + if (luma <= a) + return color; + + return color * rcp(luma) * (a * a - b * luma) / (2.0 * a - b - luma); + #else + return color; + #endif + } + + inline half3 TonemapInvert(half3 color) + { + #ifdef USE_LOCAL_TONEMAPPING + half a = LOCAL_TONEMAP_START_LUMA; + half b = LOCAL_TONEMAP_RANGE_LUMA; + + half luma = max(color.r, max(color.g, color.b)); + if (luma <= a) + return color; + + return color * rcp(luma) * (a * a - (2.0 * a - b) * luma) / (b - luma); + #else + return color; + #endif + } + + + /////////////////////////////////////////////////////////////////////////////// + // Directional (hexagonal/octogonal) bokeh + /////////////////////////////////////////////////////////////////////////////// + + #define SAMPLE_NUM_L 6 + #define SAMPLE_NUM_M 11 + #define SAMPLE_NUM_H 16 + + inline half4 shapeDirectionalBlur(half2 uv, bool mergePass, int numSample, bool sampleDilatedFG) + { + half4 centerTap = FetchMainTex(uv); + half fgCoc = centerTap.a; + half fgBlendFromPreviousPass = centerTap.a * _Offsets.z; + + if (sampleDilatedFG) + { + half2 cocs = tex2Dlod(_SecondTex, half4(uv, 0.0, 0.0)).rg; + fgCoc = min(cocs.r, cocs.g); + centerTap.a = cocs.g; + } + + half bgRadius = smoothstep(0.0, 0.85, centerTap.a) * _BlurCoe.y; + half fgRadius = smoothstep(0.0, 0.85, -fgCoc) * _BlurCoe.x; + half radius = max(bgRadius, fgRadius); + + if (radius < 1e-2) + return half4(centerTap.rgb, (sampleDilatedFG || mergePass) ? fgBlendFromPreviousPass : centerTap.a); + + half radOtherFgRad = radius / (fgRadius + 1e-2); + half radOtherBgRad = radius / (bgRadius + 1e-2); + half2 range = radius * _MainTex_TexelSize.xy; + + half fgWeight = 1e-3; + half bgWeight = 1e-3; + half3 fgSum = half3(0.0, 0.0, 0.0); + half3 bgSum = half3(0.0, 0.0, 0.0); + + for (int k = 0; k < numSample; k++) + { + half t = (half)k / half(numSample - 1.0); + half2 kVal = lerp(_Offsets.xy, -_Offsets.xy, t); + half2 offset = kVal * range; + half2 texCoord = uv + offset; + half4 sample0 = FetchColorAndCocFromMainTex(texCoord, offset); + + if (sampleDilatedFG) + sample0.a = tex2Dlod(_SecondTex, half4(texCoord, 0.0, 0.0)).g; + + half dist = abs(2.0 * t - 1.0); + half distanceFactor = saturate(-0.5 * abs(sample0.a - centerTap.a) * dist + 1.0); + half isNear = max(0.0, -sample0.a); + half isFar = max(0.0, sample0.a) * distanceFactor; + isNear *= 1.0 - smoothstep(1.0, 2.0, dist * radOtherFgRad); + isFar *= 1.0 - smoothstep(1.0, 2.0, dist * radOtherBgRad); + + fgWeight += isNear; + fgSum += sample0.rgb * isNear; + bgWeight += isFar; + bgSum += sample0.rgb * isFar; + } + + half3 fgColor = fgSum / (fgWeight + 1e-4); + half3 bgColor = bgSum / (bgWeight + 1e-4); + half bgBlend = saturate(2.0 * bgWeight / numSample); + half fgBlend = saturate(2.0 * fgWeight / numSample); + + half3 finalBg = lerp(centerTap.rgb, bgColor, bgBlend); + half3 finalColor = lerp(finalBg, fgColor, max(max(0.0 , -centerTap.a), fgBlend)); + + if (mergePass) + finalColor = min(finalColor, tex2Dlod(_ThirdTex, half4(uv, 0.0, 0.0)).rgb); + + finalColor = lerp(centerTap.rgb, finalColor, saturate(bgBlend + fgBlend)); + fgBlend = max(fgBlendFromPreviousPass, fgBlend); + return half4(finalColor, (sampleDilatedFG || mergePass) ? fgBlend : centerTap.a); + } + + half4 fragShapeLowQuality(v2fDepth i) : SV_Target + { + return shapeDirectionalBlur(i.uv, false, SAMPLE_NUM_L, false); + } + + half4 fragShapeLowQualityDilateFg(v2fDepth i) : SV_Target + { + return shapeDirectionalBlur(i.uv, false, SAMPLE_NUM_L, true); + } + + half4 fragShapeLowQualityMerge(v2fDepth i) : SV_Target + { + return shapeDirectionalBlur(i.uv, true, SAMPLE_NUM_L, false); + } + + half4 fragShapeLowQualityMergeDilateFg(v2fDepth i) : SV_Target + { + return shapeDirectionalBlur(i.uv, true, SAMPLE_NUM_L, true); + } + + half4 fragShapeMediumQuality(v2fDepth i) : SV_Target + { + return shapeDirectionalBlur(i.uv, false, SAMPLE_NUM_M, false); + } + + half4 fragShapeMediumQualityDilateFg(v2fDepth i) : SV_Target + { + return shapeDirectionalBlur(i.uv, false, SAMPLE_NUM_M, true); + } + + half4 fragShapeMediumQualityMerge(v2fDepth i) : SV_Target + { + return shapeDirectionalBlur(i.uv, true, SAMPLE_NUM_M, false); + } + + half4 fragShapeMediumQualityMergeDilateFg(v2fDepth i) : SV_Target + { + return shapeDirectionalBlur(i.uv, true, SAMPLE_NUM_M, true); + } + + half4 fragShapeHighQuality(v2fDepth i) : SV_Target + { + return shapeDirectionalBlur(i.uv, false, SAMPLE_NUM_H, false); + } + + half4 fragShapeHighQualityDilateFg(v2fDepth i) : SV_Target + { + return shapeDirectionalBlur(i.uv, false, SAMPLE_NUM_H, true); + } + + half4 fragShapeHighQualityMerge(v2fDepth i) : SV_Target + { + return shapeDirectionalBlur(i.uv, true, SAMPLE_NUM_H, false); + } + + half4 fragShapeHighQualityMergeDilateFg(v2fDepth i) : SV_Target + { + return shapeDirectionalBlur(i.uv, true, SAMPLE_NUM_H, true); + } + + /////////////////////////////////////////////////////////////////////////////// + // Disk Bokeh + /////////////////////////////////////////////////////////////////////////////// + + static const half3 DiscBokeh48[48] = + { + // 48 tap regularly spaced circular kernel (x,y, length) + // Fill free to change the shape to try other bokehs style :) + half3( 0.99144h, 0.13053h, 1.0h), + half3( 0.92388h, 0.38268h, 1.0h), + half3( 0.79335h, 0.60876h, 1.0h), + half3( 0.60876h, 0.79335h, 1.0h), + half3( 0.38268h, 0.92388h, 1.0h), + half3( 0.13053h, 0.99144h, 1.0h), + half3(-0.13053h, 0.99144h, 1.0h), + half3(-0.38268h, 0.92388h, 1.0h), + half3(-0.60876h, 0.79335h, 1.0h), + half3(-0.79335h, 0.60876h, 1.0h), + half3(-0.92388h, 0.38268h, 1.0h), + half3(-0.99144h, 0.13053h, 1.0h), + half3(-0.99144h,-0.13053h, 1.0h), + half3(-0.92388h,-0.38268h, 1.0h), + half3(-0.79335h,-0.60876h, 1.0h), + half3(-0.60876h,-0.79335h, 1.0h), + half3(-0.38268h,-0.92388h, 1.0h), + half3(-0.13053h,-0.99144h, 1.0h), + half3( 0.13053h,-0.99144h, 1.0h), + half3( 0.38268h,-0.92388h, 1.0h), + half3( 0.60876h,-0.79335h, 1.0h), + half3( 0.79335h,-0.60876h, 1.0h), + half3( 0.92388h,-0.38268h, 1.0h), + half3( 0.99144h,-0.13053h, 1.0h), + half3( 0.64732h, 0.12876h, 0.66h), + half3( 0.54877h, 0.36668h, 0.66h), + half3( 0.36668h, 0.54877h, 0.66h), + half3( 0.12876h, 0.64732h, 0.66h), + half3(-0.12876h, 0.64732h, 0.66h), + half3(-0.36668h, 0.54877h, 0.66h), + half3(-0.54877h, 0.36668h, 0.66h), + half3(-0.64732h, 0.12876h, 0.66h), + half3(-0.64732h,-0.12876h, 0.66h), + half3(-0.54877h,-0.36668h, 0.66h), + half3(-0.36668h,-0.54877h, 0.66h), + half3(-0.12876h,-0.64732h, 0.66h), + half3( 0.12876h,-0.64732h, 0.66h), + half3( 0.36668h,-0.54877h, 0.66h), + half3( 0.54877h,-0.36668h, 0.66h), + half3( 0.64732h,-0.12876h, 0.66h), + half3( 0.30488h, 0.12629h, 0.33h), + half3( 0.12629h, 0.30488h, 0.33h), + half3(-0.12629h, 0.30488h, 0.33h), + half3(-0.30488h, 0.12629h, 0.33h), + half3(-0.30488h,-0.12629h, 0.33h), + half3(-0.12629h,-0.30488h, 0.33h), + half3( 0.12629h,-0.30488h, 0.33h), + half3( 0.30488h,-0.12629h, 0.33h) + }; + + inline half4 circleCocBokeh(half2 uv, bool sampleDilatedFG, int increment) + { + half4 centerTap = FetchMainTex(uv); + half fgCoc = centerTap.a; + + if (sampleDilatedFG) + fgCoc = min(tex2Dlod(_SecondTex, half4(uv, 0.0, 0.0)).r, fgCoc); + + half bgRadius = 0.5 * smoothstep(0.0, 0.85, centerTap.a) * _BlurCoe.y; + half fgRadius = 0.5 * smoothstep(0.0, 0.85, -fgCoc) * _BlurCoe.x; + half radius = max(bgRadius, fgRadius); + + if (radius < 1e-2) + return half4(centerTap.rgb, 0.0); + + half2 poissonScale = radius * _MainTex_TexelSize.xy; + half fgWeight = max(0.0,-centerTap.a); + half bgWeight = max(0.0, centerTap.a); + half3 fgSum = centerTap.rgb * fgWeight; + half3 bgSum = centerTap.rgb * bgWeight; + + half radOtherFgRad = radius / (fgRadius + 1e-2); + half radOtherBgRad = radius / (bgRadius + 1e-2); + + for (int l = 0; l < 48; l += increment) + { + half2 sampleUV = uv + DiscBokeh48[l].xy * poissonScale.xy; + half4 sample0 = FetchColorAndCocFromMainTex(sampleUV, DiscBokeh48[l].xy); + + half isNear = max(0.0, -sample0.a); + half distanceFactor = saturate(-0.5 * abs(sample0.a - centerTap.a) * DiscBokeh48[l].z + 1.0); + half isFar = max(0.0, sample0.a) * distanceFactor; + isNear *= 1.0 - smoothstep(1.0, 2.0, DiscBokeh48[l].z * radOtherFgRad); + isFar *= 1.0 - smoothstep(1.0, 2.0, DiscBokeh48[l].z * radOtherBgRad); + + fgWeight += isNear; + fgSum += sample0.rgb * isNear; + bgWeight += isFar; + bgSum += sample0.rgb * isFar; + } + + half3 fgColor = fgSum / (fgWeight + 1e-4); + half3 bgColor = bgSum / (bgWeight + 1e-4); + half bgBlend = saturate(2.0 * bgWeight / 49.0); + half fgBlend = saturate(2.0 * fgWeight / 49.0); + + half3 finalBg = lerp(centerTap.rgb, bgColor, bgBlend); + half3 finalColor = lerp(finalBg, fgColor, max(max(0.0 , -centerTap.a), fgBlend)); + half4 returnValue = half4(finalColor, fgBlend); + + return returnValue; + } + + half4 fragCircleBlurWithDilatedFg(v2fDepth i) : SV_Target + { + return circleCocBokeh(i.uv, true, 1); + } + + half4 fragCircleBlur(v2fDepth i) : SV_Target + { + return circleCocBokeh(i.uv, false, 1); + } + + half4 fragCircleBlurWithDilatedFgLowQuality(v2fDepth i) : SV_Target + { + return circleCocBokeh(i.uv, true, 2); + } + + half4 fragCircleBlurLowQuality(v2fDepth i) : SV_Target + { + return circleCocBokeh(i.uv, false, 2); + } + + /////////////////////////////////////////////////////////////////////////////// + // Prefilter blur + /////////////////////////////////////////////////////////////////////////////// + + #define DISC_PREFILTER_SAMPLE 9 + static const half2 DiscPrefilter[DISC_PREFILTER_SAMPLE] = + { + half2(0.01288369, 0.5416069), + half2(-0.9192798, -0.09529364), + half2( 0.7596578, 0.1922738), + half2( -0.14132, -0.2880242), + half2(-0.5249333, 0.7777638), + half2(-0.5871695, -0.7403569), + half2( 0.3202196, -0.6442268), + half2( 0.8553214, -0.3920982), + half2( 0.5827708, 0.7599297) + }; + + half4 fragCocPrefilter(v2fDepth i) : SV_Target + { + half4 centerTap = FetchMainTex(i.uv); + half radius = 0.33 * 0.5 * (centerTap.a < 0.0 + ? -(centerTap.a * _BlurCoe.x) + : (centerTap.a * _BlurCoe.y)); + half2 poissonScale = radius * _MainTex_TexelSize.xy; + + if (radius < 1e-2) + return centerTap; + + half sampleCount = 1.0; + half3 sum = centerTap.rgb; + + for (int l = 0; l < DISC_PREFILTER_SAMPLE; l++) + { + half2 sampleUV = i.uv + DiscPrefilter[l].xy * poissonScale.xy; + half4 sample0 = FetchColorAndCocFromMainTex(sampleUV, DiscPrefilter[l].xy); + half weight = max(sample0.a * centerTap.a, 0.0); + sum += sample0.rgb * weight; + sampleCount += weight; + } + + half4 returnValue = half4(sum / sampleCount, centerTap.a); + return returnValue; + } + + /////////////////////////////////////////////////////////////////////////////// + // Final merge and upsample + /////////////////////////////////////////////////////////////////////////////// + + inline half4 upSampleConvolved(half2 uv) + { + half2 convolvedTexelPos = uv * _Convolved_TexelSize.xy; + half2 convolvedTexelCenter = floor( convolvedTexelPos ) + 0.5; + half2 convolvedTexelOffsetFromCenter = convolvedTexelPos - convolvedTexelCenter; + half2 offsetFromCoc = half2(0.0, 0.0); + + #if defined(USE_TEX2DOBJECT_FOR_COC) + half2 cocUV = (convolvedTexelOffsetFromCenter * _Convolved_TexelSize.zw) + uv; + half4 coc = _CameraDepthTexture.GatherRed(sampler_CameraDepthTexture, cocUV); + coc.r = GetCocFromZValue(coc.r); + coc.g = GetCocFromZValue(coc.g); + coc.b = GetCocFromZValue(coc.b); + coc.a = GetCocFromZValue(coc.a); + + half4 absCoc = abs(coc); + offsetFromCoc = GetBilinearFetchTexOffsetFromAbsCoc(absCoc) * 0.5; + uv += offsetFromCoc * _Convolved_TexelSize.zw; + #endif + + /* + // Bicubic upsampling (B-spline) - Uncomment me for higher quality upsampling + // Adding offsetFromCoc "antialias" haloing from bright in focus region on dark out of focus region. + // However its a hack as we should consider all the COC of the bicubic region and kill the bicubic + // interpolation to avoid in any leaking but that would be too expensive, so when this is a problem + // one should rather disable bicubic interpolation. + half2 f = convolvedTexelOffsetFromCenter + offsetFromCoc; + half2 f2 = f * f; + half2 f3 = f * f2; + + half2 w0 = -0.166 * f3 + 0.5 * f2 - 0.5 * f + 0.166; + half2 w1 = 0.5 * f3 - f2 + 0.666; + half2 w3 = 0.166 * f3; + half2 w2 = 1.0 - w0 - w1 - w3; + + half2 s0 = w0 + w1; + half2 s1 = w2 + w3; + half2 f0 = w1 / s0; + half2 f1 = w3 / s1; + + half2 t0 = _Convolved_TexelSize.zw * (convolvedTexelCenter - 1.0 + f0); + half2 t1 = _Convolved_TexelSize.zw * (convolvedTexelCenter + 1.0 + f1); + + return tex2Dlod(_SecondTex, half4(t0.x, t0.y, 0.0, 0.0)) * s0.x * s0.y + + tex2Dlod(_SecondTex, half4(t1.x, t0.y, 0.0, 0.0)) * s1.x * s0.y + + tex2Dlod(_SecondTex, half4(t0.x, t1.y, 0.0, 0.0)) * s0.x * s1.y + + tex2Dlod(_SecondTex, half4(t1.x, t1.y, 0.0, 0.0)) * s1.x * s1.y; + */ + + return tex2Dlod(_SecondTex, half4(uv, 0.0, 0.0)); + } + + inline half4 dofMerge(half2 uv) + { + half4 convolvedTap = upSampleConvolved(uv); + convolvedTap.rgb = TonemapInvert(convolvedTap.rgb); + + half4 sourceTap = FetchMainTex(uv); + half coc = GetCocFromDepth(uv); + + coc = (coc * _BlurCoe.y > 1.0) ? coc : 0.0; + half blendValue = smoothstep(0.0, 0.33, max(coc, convolvedTap.a)); + half3 returnValue = lerp(sourceTap.rgb, convolvedTap.rgb, blendValue); + return (blendValue < 1e-2) ? sourceTap : half4(returnValue.rgb, sourceTap.a); + } + + half4 fragMergeExplicit(v2fDepth i) : SV_Target + { + return dofMerge(i.uv); + } + + /////////////////////////////////////////////////////////////////////////////// + // Downsampling and COC computation + /////////////////////////////////////////////////////////////////////////////// + + inline half4 captureCoc(half2 uvColor, half2 uvDepth) + { + /*****************/ + /* coc.a | coc.b */ + /* coc.r | coc.g */ + /*****************/ + #if defined(USE_TEX2DOBJECT_FOR_COC) + half4 coc = _CameraDepthTexture.GatherRed(sampler_CameraDepthTexture, uvDepth); + coc.r = GetCocFromZValue(coc.r); + coc.g = GetCocFromZValue(coc.g); + coc.b = GetCocFromZValue(coc.b); + coc.a = GetCocFromZValue(coc.a); + #else + half4 coc; + coc.r = GetCocFromDepth(uvDepth + _MainTex_TexelSize.xy * half2(-0.25, 0.25)); + coc.g = GetCocFromDepth(uvDepth + _MainTex_TexelSize.xy * half2( 0.25, 0.25)); + coc.b = GetCocFromDepth(uvDepth + _MainTex_TexelSize.xy * half2( 0.25,-0.25)); + coc.a = GetCocFromDepth(uvDepth + _MainTex_TexelSize.xy * half2(-0.25,-0.25)); + #endif + + half4 absCoc = abs(coc); + half2 offset = GetBilinearFetchTexOffsetFromAbsCoc(absCoc) * _MainTex_TexelSize.xy; + half4 color = FetchMainTex(uvColor + offset); + + half cocRG = (absCoc.r> m_GroupFields = new Dictionary>(); + + private LensAberrations concreteTarget + { + get { return target as LensAberrations; } + } + + private void PopulateMap(FieldInfo group) + { + var searchPath = group.Name + "."; + foreach (var setting in group.FieldType.GetFields(BindingFlags.Instance | BindingFlags.Public)) + { + List settingsGroup; + if (!m_GroupFields.TryGetValue(group, out settingsGroup)) + { + settingsGroup = new List(); + m_GroupFields[group] = settingsGroup; + } + + var property = serializedObject.FindProperty(searchPath + setting.Name); + if (property != null) + settingsGroup.Add(property); + } + } + + private void OnEnable() + { + var settingsGroups = typeof(LensAberrations).GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).Where(x => x.GetCustomAttributes(typeof(LensAberrations.SettingsGroup), false).Any()); + + foreach (var settingGroup in settingsGroups) + PopulateMap(settingGroup); + } + + private void DrawFields() + { + foreach (var group in m_GroupFields) + { + var enabledField = group.Value.FirstOrDefault(x => x.propertyPath == group.Key.Name + ".enabled"); + var groupProperty = serializedObject.FindProperty(group.Key.Name); + + GUILayout.Space(5); + bool display = EditorGUIHelper.Header(groupProperty, enabledField); + if (!display) + continue; + + GUILayout.BeginHorizontal(); + { + GUILayout.Space(10); + GUILayout.BeginVertical(); + { + GUILayout.Space(3); + foreach (var field in group.Value.Where(x => x.propertyPath != group.Key.Name + ".enabled")) + { + EditorGUILayout.PropertyField(field); + } + } + GUILayout.EndVertical(); + } + GUILayout.EndHorizontal(); + } + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + DrawFields(); + serializedObject.ApplyModifiedProperties(); + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/LensAberrations/Editor/LensAberrationsEditor.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/LensAberrations/Editor/LensAberrationsEditor.cs.meta new file mode 100644 index 0000000..b72f52e --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/LensAberrations/Editor/LensAberrationsEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 8becb41f431ef90468376f6c5845e0bd +timeCreated: 1454680396 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/LensAberrations/LensAberrations.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/LensAberrations/LensAberrations.cs new file mode 100644 index 0000000..2f3cca7 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/LensAberrations/LensAberrations.cs @@ -0,0 +1,311 @@ +using UnityEngine; +using System; + +namespace UnityStandardAssets.CinematicEffects +{ + [ExecuteInEditMode] + [RequireComponent(typeof(Camera))] + [AddComponentMenu("Image Effects/Cinematic/Lens Aberrations")] + public class LensAberrations : MonoBehaviour + { + #region Attributes + [AttributeUsage(AttributeTargets.Field)] + public class SettingsGroup : Attribute + {} + + [AttributeUsage(AttributeTargets.Field)] + public class AdvancedSetting : Attribute + {} + #endregion + + #region Settings + [Serializable] + public struct DistortionSettings + { + public bool enabled; + + [Range(-100f, 100f), Tooltip("Distortion amount.")] + public float amount; + + [Range(-1f, 1f), Tooltip("Distortion center point (X axis).")] + public float centerX; + + [Range(-1f, 1f), Tooltip("Distortion center point (Y axis).")] + public float centerY; + + [Range(0f, 1f), Tooltip("Amount multiplier on X axis. Set it to 0 to disable distortion on this axis.")] + public float amountX; + + [Range(0f, 1f), Tooltip("Amount multiplier on Y axis. Set it to 0 to disable distortion on this axis.")] + public float amountY; + + [Range(0.01f, 5f), Tooltip("Global screen scaling.")] + public float scale; + + public static DistortionSettings defaultSettings + { + get + { + return new DistortionSettings + { + enabled = false, + amount = 0f, + centerX = 0f, + centerY = 0f, + amountX = 1f, + amountY = 1f, + scale = 1f + }; + } + } + } + + [Serializable] + public struct VignetteSettings + { + public bool enabled; + + [ColorUsage(false)] + [Tooltip("Vignette color. Use the alpha channel for transparency.")] + public Color color; + + [Tooltip("Sets the vignette center point (screen center is [0.5,0.5]).")] + public Vector2 center; + + [Range(0f, 3f), Tooltip("Amount of vignetting on screen.")] + public float intensity; + + [Range(0.01f, 3f), Tooltip("Smoothness of the vignette borders.")] + public float smoothness; + + [AdvancedSetting, Range(0f, 1f), Tooltip("Lower values will make a square-ish vignette.")] + public float roundness; + + [Range(0f, 1f), Tooltip("Blurs the corners of the screen. Leave this at 0 to disable it.")] + public float blur; + + [Range(0f, 1f), Tooltip("Desaturate the corners of the screen. Leave this to 0 to disable it.")] + public float desaturate; + + public static VignetteSettings defaultSettings + { + get + { + return new VignetteSettings + { + enabled = false, + color = new Color(0f, 0f, 0f, 1f), + center = new Vector2(0.5f, 0.5f), + intensity = 1.4f, + smoothness = 0.8f, + roundness = 1f, + blur = 0f, + desaturate = 0f + }; + } + } + } + + [Serializable] + public struct ChromaticAberrationSettings + { + public bool enabled; + + [ColorUsage(false)] + [Tooltip("Channels to apply chromatic aberration to.")] + public Color color; + + [Range(-50f, 50f)] + [Tooltip("Amount of tangential distortion.")] + public float amount; + + public static ChromaticAberrationSettings defaultSettings + { + get + { + return new ChromaticAberrationSettings + { + enabled = false, + color = Color.green, + amount = 0f + }; + } + } + } + #endregion + + [SettingsGroup] + public DistortionSettings distortion = DistortionSettings.defaultSettings; + + [SettingsGroup] + public VignetteSettings vignette = VignetteSettings.defaultSettings; + + [SettingsGroup] + public ChromaticAberrationSettings chromaticAberration = ChromaticAberrationSettings.defaultSettings; + + private enum Pass + { + BlurPrePass, + Chroma, + Distort, + Vignette, + ChromaDistort, + ChromaVignette, + DistortVignette, + ChromaDistortVignette + } + + [SerializeField] + private Shader m_Shader; + public Shader shader + { + get + { + if (m_Shader == null) + m_Shader = Shader.Find("Hidden/LensAberrations"); + + return m_Shader; + } + } + + private Material m_Material; + public Material material + { + get + { + if (m_Material == null) + m_Material = ImageEffectHelper.CheckShaderAndCreateMaterial(shader); + + return m_Material; + } + } + + private RenderTextureUtility m_RTU; + + private void OnEnable() + { + if (!ImageEffectHelper.IsSupported(shader, false, false, this)) + enabled = false; + + m_RTU = new RenderTextureUtility(); + } + + private void OnDisable() + { + if (m_Material != null) + DestroyImmediate(m_Material); + + m_Material = null; + m_RTU.ReleaseAllTemporaryRenderTextures(); + } + + private void OnRenderImage(RenderTexture source, RenderTexture destination) + { + if (!vignette.enabled && !chromaticAberration.enabled && !distortion.enabled) + { + Graphics.Blit(source, destination); + return; + } + + material.shaderKeywords = null; + + if (distortion.enabled) + { + float amount = 1.6f * Math.Max(Mathf.Abs(distortion.amount), 1f); + float theta = 0.01745329251994f * Math.Min(160f, amount); + float sigma = 2f * Mathf.Tan(theta * 0.5f); + var p0 = new Vector4(distortion.centerX, distortion.centerY, Mathf.Max(distortion.amountX, 1e-4f), Mathf.Max(distortion.amountY, 1e-4f)); + var p1 = new Vector3(distortion.amount >= 0f ? theta : 1f / theta, sigma, 1f / distortion.scale); + material.EnableKeyword(distortion.amount >= 0f ? "DISTORT" : "UNDISTORT"); + material.SetVector("_DistCenterScale", p0); + material.SetVector("_DistAmount", p1); + } + + if (chromaticAberration.enabled) + { + material.EnableKeyword("CHROMATIC_ABERRATION"); + var chromaParams = new Vector4(chromaticAberration.color.r, chromaticAberration.color.g, chromaticAberration.color.b, chromaticAberration.amount * 0.001f); + material.SetVector("_ChromaticAberration", chromaParams); + } + + if (vignette.enabled) + { + material.SetColor("_VignetteColor", vignette.color); + + if (vignette.blur > 0f) + { + // Downscale + gaussian blur (2 passes) + int w = source.width / 2; + int h = source.height / 2; + var rt1 = m_RTU.GetTemporaryRenderTexture(w, h, 0, source.format); + var rt2 = m_RTU.GetTemporaryRenderTexture(w, h, 0, source.format); + + material.SetVector("_BlurPass", new Vector2(1f / w, 0f)); + Graphics.Blit(source, rt1, material, (int)Pass.BlurPrePass); + + if (distortion.enabled) + { + material.DisableKeyword("DISTORT"); + material.DisableKeyword("UNDISTORT"); + } + + material.SetVector("_BlurPass", new Vector2(0f, 1f / h)); + Graphics.Blit(rt1, rt2, material, (int)Pass.BlurPrePass); + + material.SetVector("_BlurPass", new Vector2(1f / w, 0f)); + Graphics.Blit(rt2, rt1, material, (int)Pass.BlurPrePass); + material.SetVector("_BlurPass", new Vector2(0f, 1f / h)); + Graphics.Blit(rt1, rt2, material, (int)Pass.BlurPrePass); + + material.SetTexture("_BlurTex", rt2); + material.SetFloat("_VignetteBlur", vignette.blur * 3f); + material.EnableKeyword("VIGNETTE_BLUR"); + + if (distortion.enabled) + material.EnableKeyword(distortion.amount >= 0f ? "DISTORT" : "UNDISTORT"); + } + + if (vignette.desaturate > 0f) + { + material.EnableKeyword("VIGNETTE_DESAT"); + material.SetFloat("_VignetteDesat", 1f - vignette.desaturate); + } + + material.SetVector("_VignetteCenter", vignette.center); + + if (Mathf.Approximately(vignette.roundness, 1f)) + { + material.EnableKeyword("VIGNETTE_CLASSIC"); + material.SetVector("_VignetteSettings", new Vector2(vignette.intensity, vignette.smoothness)); + } + else + { + material.EnableKeyword("VIGNETTE_FILMIC"); + float roundness = (1f - vignette.roundness) * 6f + vignette.roundness; + material.SetVector("_VignetteSettings", new Vector3(vignette.intensity, vignette.smoothness, roundness)); + } + } + + int pass = 0; + + if (vignette.enabled && chromaticAberration.enabled && distortion.enabled) + pass = (int)Pass.ChromaDistortVignette; + else if (vignette.enabled && chromaticAberration.enabled) + pass = (int)Pass.ChromaVignette; + else if (vignette.enabled && distortion.enabled) + pass = (int)Pass.DistortVignette; + else if (chromaticAberration.enabled && distortion.enabled) + pass = (int)Pass.ChromaDistort; + else if (vignette.enabled) + pass = (int)Pass.Vignette; + else if (chromaticAberration.enabled) + pass = (int)Pass.Chroma; + else if (distortion.enabled) + pass = (int)Pass.Distort; + + Graphics.Blit(source, destination, material, pass); + + m_RTU.ReleaseAllTemporaryRenderTextures(); + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/LensAberrations/LensAberrations.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/LensAberrations/LensAberrations.cs.meta new file mode 100644 index 0000000..49f8d7d --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/LensAberrations/LensAberrations.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: ff5335a7357baa3489a469d0ca0f40f3 +timeCreated: 1454589487 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: + - m_Shader: {fileID: 4800000, guid: 136ab50fe2b9ad64d9c22adc3668abb7, type: 3} + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/LensAberrations/Resources.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/LensAberrations/Resources.meta new file mode 100644 index 0000000..f75b438 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/LensAberrations/Resources.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 6580025651e0f284489694492cf3ce61 +folderAsset: yes +timeCreated: 1454583120 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/LensAberrations/Resources/LensAberrations.shader b/IronToad_UnityProject/Assets/Standard Assets/Effects/LensAberrations/Resources/LensAberrations.shader new file mode 100644 index 0000000..4a38b3a --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/LensAberrations/Resources/LensAberrations.shader @@ -0,0 +1,293 @@ +Shader "Hidden/LensAberrations" +{ + Properties + { + _MainTex ("Texture", 2D) = "white" {} + } + SubShader + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGINCLUDE + + #pragma fragmentoption ARB_precision_hint_fastest + #include "UnityCG.cginc" + #pragma target 3.0 + + sampler2D _MainTex; + float4 _MainTex_TexelSize; + + half4 _ChromaticAberration; + + half4 chromaticAberration(half2 uv) + { + half2 coords = 2.0 * uv - 1.0; + half2 cd = coords * dot(coords, coords); + half4 color = tex2D(_MainTex, uv); + half3 fringe = tex2D(_MainTex, uv - cd * _ChromaticAberration.a).rgb; + color.rgb = lerp(color.rgb, fringe, _ChromaticAberration.rgb); + return color; + } + + half4 _DistCenterScale; + half3 _DistAmount; + + half2 distort(half2 uv) + { + uv = (uv - 0.5) * _DistAmount.z + 0.5; + half2 ruv = _DistCenterScale.zw * (uv - 0.5 - _DistCenterScale.xy); + half ru = length(ruv); + + #if DISTORT + + half wu = ru * _DistAmount.x; + ru = tan(wu) * (1.0 / (ru * _DistAmount.y)); + uv = uv + ruv * (ru - 1.0); + + #elif UNDISTORT + + ru = (1.0 / ru) * _DistAmount.x * atan(ru * _DistAmount.y); + uv = uv + ruv * (ru - 1.0); + + #endif + + return uv; + } + + half3 _VignetteColor; + half3 _VignetteSettings; + half2 _VignetteCenter; + half _VignetteBlur; + half _VignetteDesat; + sampler2D _BlurTex; + + half4 vignette(half4 color, half2 uv) + { + #define _Intensity _VignetteSettings.x + #define _Smoothness _VignetteSettings.y + #define _Roundness _VignetteSettings.z + + half vfactor = 1.0; + + #if VIGNETTE_CLASSIC + + half2 d = (uv - _VignetteCenter) * _Intensity; + vfactor = pow(saturate(1.0 - dot(d, d)), _Smoothness); + + #else + + half2 d = abs(uv - _VignetteCenter) * _Intensity; + d = pow(d, _Roundness); + + #endif + + vfactor = pow(saturate(1.0 - dot(d, d)), _Smoothness); + + #if VIGNETTE_BLUR + + half2 coords = 2.0 * uv - 1.0; + half3 blur = tex2D(_BlurTex, uv).rgb; + color.rgb = lerp(color.rgb, blur, saturate(_VignetteBlur * dot(coords, coords))); + + #endif + + #if VIGNETTE_DESAT + + half lum = Luminance(color); + color.rgb = lerp(lerp(lum.xxx, color.rgb, _VignetteDesat), color.rgb, vfactor); + + #endif + + color.rgb *= lerp(_VignetteColor, (1.0).xxx, vfactor); + + return color; + } + + ENDCG + + // (0) Blur pre-pass + Pass + { + CGPROGRAM + #pragma vertex vert_blur_prepass + #pragma fragment frag_blur_prepass + #pragma multi_compile __ CHROMATIC_ABERRATION + #pragma multi_compile __ DISTORT UNDISTORT + #pragma + + half2 _BlurPass; + + struct v2f + { + half4 pos : SV_POSITION; + half2 uv : TEXCOORD0; + half4 uv1 : TEXCOORD1; + half4 uv2 : TEXCOORD2; + }; + + v2f vert_blur_prepass(appdata_img v) + { + v2f o; + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv = v.texcoord.xy; + + #if UNITY_UV_STARTS_AT_TOP + if (_MainTex_TexelSize.y < 0) + o.uv.y = 1.0 - o.uv.y; + #endif + + half2 d1 = 1.3846153846 * _BlurPass; + half2 d2 = 3.2307692308 * _BlurPass; + o.uv1 = half4(o.uv + d1, o.uv - d1); + o.uv2 = half4(o.uv + d2, o.uv - d2); + return o; + } + + half4 fetch(half2 uv) + { + #if (DISTORT || UNDISTORT) + uv = distort(uv); + #endif + + #if CHROMATIC_ABERRATION + return chromaticAberration(uv); + #else + return tex2D(_MainTex, uv); + #endif + } + + half4 frag_blur_prepass(v2f i) : SV_Target + { + half4 c = fetch(i.uv) * 0.2270270270; + c += fetch(i.uv1.xy) * 0.3162162162; + c += fetch(i.uv1.zw) * 0.3162162162; + c += fetch(i.uv2.xy) * 0.0702702703; + c += fetch(i.uv2.zw) * 0.0702702703; + return c; + } + ENDCG + } + + // (1) Chroma + Pass + { + CGPROGRAM + #pragma vertex vert_img + #pragma fragment frag + + half4 frag(v2f_img i) : SV_Target + { + return chromaticAberration(i.uv); + } + ENDCG + } + + // (2) Distort + Pass + { + CGPROGRAM + #pragma vertex vert_img + #pragma fragment frag + #pragma multi_compile DISTORT UNDISTORT + + half4 frag(v2f_img i) : SV_Target + { + half2 uv = distort(i.uv); + return tex2D(_MainTex, uv); + } + ENDCG + } + + // (3) Vignette + Pass + { + CGPROGRAM + #pragma vertex vert_img + #pragma fragment frag + #pragma multi_compile VIGNETTE_CLASSIC VIGNETTE_FILMIC + #pragma multi_compile __ VIGNETTE_BLUR + #pragma multi_compile __ VIGNETTE_DESAT + + half4 frag(v2f_img i) : SV_Target + { + half4 color = tex2D(_MainTex, i.uv); + return vignette(color, i.uv); + } + ENDCG + } + + // (4) Chroma / Distort + Pass + { + CGPROGRAM + #pragma vertex vert_img + #pragma fragment frag + #pragma multi_compile DISTORT UNDISTORT + + half4 frag(v2f_img i) : SV_Target + { + half2 uv = distort(i.uv); + return chromaticAberration(uv); + } + ENDCG + } + + // (5) Chroma / Vignette + Pass + { + CGPROGRAM + #pragma vertex vert_img + #pragma fragment frag + #pragma multi_compile VIGNETTE_CLASSIC VIGNETTE_FILMIC + #pragma multi_compile __ VIGNETTE_BLUR + #pragma multi_compile __ VIGNETTE_DESAT + + half4 frag(v2f_img i) : SV_Target + { + return vignette(chromaticAberration(i.uv), i.uv); + } + ENDCG + } + + // (6) Distort / Vignette + Pass + { + CGPROGRAM + #pragma vertex vert_img + #pragma fragment frag + #pragma multi_compile DISTORT UNDISTORT + #pragma multi_compile VIGNETTE_CLASSIC VIGNETTE_FILMIC + #pragma multi_compile __ VIGNETTE_BLUR + #pragma multi_compile __ VIGNETTE_DESAT + + half4 frag(v2f_img i) : SV_Target + { + half2 uv = distort(i.uv); + return vignette(tex2D(_MainTex, uv), i.uv); + } + ENDCG + } + + // (6) Chroma / Distort / Vignette + Pass + { + CGPROGRAM + #pragma vertex vert_img + #pragma fragment frag + #pragma multi_compile DISTORT UNDISTORT + #pragma multi_compile VIGNETTE_CLASSIC VIGNETTE_FILMIC + #pragma multi_compile __ VIGNETTE_BLUR + #pragma multi_compile __ VIGNETTE_DESAT + + half4 frag(v2f_img i) : SV_Target + { + half2 uv = distort(i.uv); + half4 chroma = chromaticAberration(uv); + return vignette(chroma, i.uv); + } + ENDCG + } + } + FallBack off +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/LensAberrations/Resources/LensAberrations.shader.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/LensAberrations/Resources/LensAberrations.shader.meta new file mode 100644 index 0000000..915929c --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/LensAberrations/Resources/LensAberrations.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 136ab50fe2b9ad64d9c22adc3668abb7 +timeCreated: 1454583143 +licenseType: Store +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection.meta new file mode 100644 index 0000000..1c8f804 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 0190f05cacbdca84c932a2f2e0035c51 +folderAsset: yes +timeCreated: 1448358989 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Editor.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Editor.meta new file mode 100644 index 0000000..48b2c1b --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Editor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 4834a3e1213004b48b14703e6723c17c +folderAsset: yes +timeCreated: 1448359076 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Editor/ScreenSpaceReflectionEditor.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Editor/ScreenSpaceReflectionEditor.cs new file mode 100644 index 0000000..000bafa --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Editor/ScreenSpaceReflectionEditor.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using UnityEditor; +using UnityEngine; + +namespace UnityStandardAssets.CinematicEffects +{ + [CustomPropertyDrawer(typeof(ScreenSpaceReflection.SSRSettings.LayoutAttribute))] + public class LayoutDrawer : PropertyDrawer + { + private const float kHeadingSpace = 22.0f; + + static Styles m_Styles; + + private class Styles + { + public readonly GUIStyle header = "ShurikenModuleTitle"; + + internal Styles() + { + header.font = (new GUIStyle("Label")).font; + header.border = new RectOffset(15, 7, 4, 4); + header.fixedHeight = kHeadingSpace; + header.contentOffset = new Vector2(20f, -2f); + } + } + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + if (!property.isExpanded) + return kHeadingSpace; + + var count = property.CountInProperty(); + return EditorGUIUtility.singleLineHeight * count + 15; + } + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + if (m_Styles == null) + m_Styles = new Styles(); + + position.height = EditorGUIUtility.singleLineHeight; + property.isExpanded = Header(position, property.displayName, property.isExpanded); + position.y += kHeadingSpace; + + if (!property.isExpanded) + return; + + foreach (SerializedProperty child in property) + { + EditorGUI.PropertyField(position, child); + position.y += EditorGUIUtility.singleLineHeight; + } + } + + private bool Header(Rect position, String title, bool display) + { + Rect rect = position; + position.height = EditorGUIUtility.singleLineHeight; + GUI.Box(rect, title, m_Styles.header); + + Rect toggleRect = new Rect(rect.x + 4f, rect.y + 2f, 13f, 13f); + if (Event.current.type == EventType.Repaint) + EditorStyles.foldout.Draw(toggleRect, false, false, display, false); + + Event e = Event.current; + if (e.type == EventType.MouseDown && rect.Contains(e.mousePosition)) + { + display = !display; + e.Use(); + } + return display; + } + } + + [CustomEditor(typeof(ScreenSpaceReflection))] + internal class ScreenSpaceReflectionEditor : Editor + { + [NonSerialized] + private List m_Properties = new List(); + + void OnEnable() + { + var settings = FieldFinder.GetField(x => x.settings); + foreach (var setting in settings.FieldType.GetFields()) + { + var prop = settings.Name + "." + setting.Name; + m_Properties.Add(serializedObject.FindProperty(prop)); + } + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + EditorGUILayout.Space(); + + // move into the m_Settings fields... + foreach (var property in m_Properties) + EditorGUILayout.PropertyField(property); + + serializedObject.ApplyModifiedProperties(); + } + + private void Apply(ScreenSpaceReflection.SSRSettings settings) + { + var validTargets = targets.Where(x => x is ScreenSpaceReflection).Cast().ToArray(); + + Undo.RecordObjects(validTargets, "Apply SSR Settings"); + foreach (var validTarget in validTargets) + validTarget.settings = settings; + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Editor/ScreenSpaceReflectionEditor.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Editor/ScreenSpaceReflectionEditor.cs.meta new file mode 100644 index 0000000..8ed616c --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Editor/ScreenSpaceReflectionEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: eb0236f80884a1f4793c96b4d2da5c68 +timeCreated: 1446039760 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Resources.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Resources.meta new file mode 100644 index 0000000..3481967 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Resources.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: a19e50b158b32e6458d43c13406863ff +folderAsset: yes +timeCreated: 1453972687 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Resources/ScreenSpaceRaytrace.cginc b/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Resources/ScreenSpaceRaytrace.cginc new file mode 100644 index 0000000..24f95d4 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Resources/ScreenSpaceRaytrace.cginc @@ -0,0 +1,243 @@ +/** +\author Michael Mara and Morgan McGuire, Casual Effects. 2015. +*/ + +#ifndef SCREEN_SPACE_RAYTRACE_INCLUDED +#define SCREEN_SPACE_RAYTRACE_INCLUDED + + +sampler2D_float _CameraDepthTexture; + + +float distanceSquared(float2 A, float2 B) +{ + A -= B; + return dot(A, A); +} + +float distanceSquared(float3 A, float3 B) +{ + A -= B; + return dot(A, A); +} + +void swap(inout float v0, inout float v1) +{ + float temp = v0; + v0 = v1; + v1 = temp; +} + + +bool isIntersecting(float rayZMin, float rayZMax, float sceneZ, float layerThickness) +{ + return (rayZMax >= sceneZ - layerThickness) && (rayZMin <= sceneZ); +} + +void rayIterations(in bool traceBehindObjects, inout float2 P, inout float stepDirection, inout float end, inout int stepCount, inout int maxSteps, inout bool intersecting, + inout float sceneZ, inout float2 dP, inout float3 Q, inout float3 dQ, inout float k, inout float dk, + inout float rayZMin, inout float rayZMax, inout float prevZMaxEstimate, inout bool permute, inout float2 hitPixel, + inout float2 invSize, inout float layerThickness) +{ + bool stop = intersecting; + + UNITY_LOOP + + for (; (P.x * stepDirection) <= end && stepCount < maxSteps && !stop; P += dP, Q.z += dQ.z, k += dk, stepCount += 1) + { + // The depth range that the ray covers within this loop iteration. + // Assume that the ray is moving in increasing z and swap if backwards. + rayZMin = prevZMaxEstimate; + //rayZMin = (dQ.z * -0.5 + Q.z) / (dk * -0.5 + k); + // Compute the value at 1/2 pixel into the future + rayZMax = (dQ.z * 0.5 + Q.z) / (dk * 0.5 + k); + prevZMaxEstimate = rayZMax; + + if (rayZMin > rayZMax) + { + swap(rayZMin, rayZMax); + } + + // Undo the homogeneous operation to obtain the camera-space + // Q at each point + hitPixel = permute ? P.yx : P; + + sceneZ = tex2Dlod(_CameraDepthTexture, float4(hitPixel * invSize,0,0)).r; + sceneZ = -LinearEyeDepth(sceneZ); + + bool isBehind = (rayZMin <= sceneZ); + intersecting = isBehind && (rayZMax >= sceneZ - layerThickness); + stop = traceBehindObjects ? intersecting : isBehind; + + } // pixel on ray + + P -= dP, Q.z -= dQ.z, k -= dk; +} + +/** + \param csOrigin must have z < -0.01, and project within the valid screen rectangle + \param stepRate Set to 1.0 by default, higher to step faster + */ +bool castDenseScreenSpaceRay + (float3 csOrigin, + float3 csDirection, + float4x4 projectToPixelMatrix, + float2 csZBufferSize, + float3 clipInfo, + float jitterFraction, + int maxSteps, + float layerThickness, + float maxRayTraceDistance, + out float2 hitPixel, + int stepRate, + bool traceBehindObjects, + out float3 csHitPoint, + out float stepCount) { + + float2 invSize = float2(1.0 / csZBufferSize.x, 1.0 / csZBufferSize.y); + + // Initialize to off screen + hitPixel = float2(-1, -1); + + float nearPlaneZ = -0.01; + // Clip ray to a near plane in 3D (doesn't have to be *the* near plane, although that would be a good idea) + float rayLength = ((csOrigin.z + csDirection.z * maxRayTraceDistance) > nearPlaneZ) ? + ((nearPlaneZ - csOrigin.z) / csDirection.z) : + maxRayTraceDistance; + + float3 csEndPoint = csDirection * rayLength + csOrigin; + + // Project into screen space + // This matrix has a lot of zeroes in it. We could expand + // out these multiplies to avoid multiplying by zero + // ...but 16 MADDs are not a big deal compared to what's ahead + float4 H0 = mul(projectToPixelMatrix, float4(csOrigin, 1.0)); + float4 H1 = mul(projectToPixelMatrix, float4(csEndPoint, 1.0)); + + // There are a lot of divisions by w that can be turned into multiplications + // at some minor precision loss...and we need to interpolate these 1/w values + // anyway. + // + // Because the caller was required to clip to the near plane, + // this homogeneous division (projecting from 4D to 2D) is guaranteed + // to succeed. + float k0 = 1.0 / H0.w; + float k1 = 1.0 / H1.w; + + // Screen-space endpoints + float2 P0 = H0.xy * k0; + float2 P1 = H1.xy * k1; + + // Switch the original points to values that interpolate linearly in 2D: + float3 Q0 = csOrigin * k0; + float3 Q1 = csEndPoint * k1; + +#if 1 // Clipping to the screen coordinates. We could simply modify maxSteps instead + float yMax = csZBufferSize.y - 0.5; + float yMin = 0.5; + float xMax = csZBufferSize.x - 0.5; + float xMin = 0.5; + + // 2D interpolation parameter + float alpha = 0.0; + // P0 must be in bounds + if (P1.y > yMax || P1.y < yMin) { + float yClip = (P1.y > yMax) ? yMax : yMin; + float yAlpha = (P1.y - yClip) / (P1.y - P0.y); // Denominator is not zero, since P0 != P1 (or P0 would have been clipped!) + alpha = yAlpha; + } + + // P0 must be in bounds + if (P1.x > xMax || P1.x < xMin) { + float xClip = (P1.x > xMax) ? xMax : xMin; + float xAlpha = (P1.x - xClip) / (P1.x - P0.x); // Denominator is not zero, since P0 != P1 (or P0 would have been clipped!) + alpha = max(alpha, xAlpha); + } + + // These are all in homogeneous space, so they interpolate linearly + P1 = lerp(P1, P0, alpha); + k1 = lerp(k1, k0, alpha); + Q1 = lerp(Q1, Q0, alpha); +#endif + + // We're doing this to avoid divide by zero (rays exactly parallel to an eye ray) + P1 = (distanceSquared(P0, P1) < 0.0001) ? P0 + float2(0.01, 0.01) : P1; + + float2 delta = P1 - P0; + + // Assume horizontal + bool permute = false; + if (abs(delta.x) < abs(delta.y)) { + // More-vertical line. Create a permutation that swaps x and y in the output + permute = true; + + // Directly swizzle the inputs + delta = delta.yx; + P1 = P1.yx; + P0 = P0.yx; + } + + // From now on, "x" is the primary iteration direction and "y" is the secondary one + + float stepDirection = sign(delta.x); + float invdx = stepDirection / delta.x; + float2 dP = float2(stepDirection, invdx * delta.y); + + // Track the derivatives of Q and k + float3 dQ = (Q1 - Q0) * invdx; + float dk = (k1 - k0) * invdx; + + dP *= stepRate; + dQ *= stepRate; + dk *= stepRate; + + P0 += dP * jitterFraction; + Q0 += dQ * jitterFraction; + k0 += dk * jitterFraction; + + // Slide P from P0 to P1, (now-homogeneous) Q from Q0 to Q1, and k from k0 to k1 + float3 Q = Q0; + float k = k0; + + // We track the ray depth at +/- 1/2 pixel to treat pixels as clip-space solid + // voxels. Because the depth at -1/2 for a given pixel will be the same as at + // +1/2 for the previous iteration, we actually only have to compute one value + // per iteration. + float prevZMaxEstimate = csOrigin.z; + stepCount = 0.0; + float rayZMax = prevZMaxEstimate, rayZMin = prevZMaxEstimate; + float sceneZ = 100000; + + // P1.x is never modified after this point, so pre-scale it by + // the step direction for a signed comparison + float end = P1.x * stepDirection; + + bool intersecting = isIntersecting(rayZMin, rayZMax, sceneZ, layerThickness); + // We only advance the z field of Q in the inner loop, since + // Q.xy is never used until after the loop terminates + + //int rayIterations = min(maxSteps, stepsToGetOffscreen); + + + float2 P = P0; + + int originalStepCount = 0; + rayIterations(traceBehindObjects, P, stepDirection, end, originalStepCount, maxSteps, intersecting, + sceneZ, dP, Q, dQ, k, dk, + rayZMin, rayZMax, prevZMaxEstimate, permute, hitPixel, + invSize, layerThickness); + + + stepCount = originalStepCount; + + // Loop only advanced the Z component. Now that we know where we are going + // update xy + Q.xy += dQ.xy * stepCount; + // Q is a vector, so we are trying to get by with 1 division instead of 3. + csHitPoint = Q * (1.0 / k); + + return intersecting; +} + + +#endif // SCREEN_SPACE_RAYTRACE_INCLUDED diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Resources/ScreenSpaceRaytrace.cginc.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Resources/ScreenSpaceRaytrace.cginc.meta new file mode 100644 index 0000000..3c90b99 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Resources/ScreenSpaceRaytrace.cginc.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 6f70a4658ebf5f947abc302c6b49a6ba +timeCreated: 1449750676 +licenseType: Store +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Resources/ScreenSpaceReflection.shader b/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Resources/ScreenSpaceReflection.shader new file mode 100644 index 0000000..13869ed --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Resources/ScreenSpaceReflection.shader @@ -0,0 +1,949 @@ +/** +\author Michael Mara and Morgan McGuire, Casual Effects. 2015. +*/ +Shader "Hidden/ScreenSpaceReflection" +{ + Properties + { + _MainTex ("Base (RGB)", 2D) = "white" {} + } + + + CGINCLUDE + + #include "UnityCG.cginc" + #include "UnityPBSLighting.cginc" + #include "UnityStandardBRDF.cginc" + #include "UnityStandardUtils.cginc" + #include "ScreenSpaceRaytrace.cginc" + + float4 _ProjInfo; + float4x4 _WorldToCameraMatrix; + float4x4 _CameraToWorldMatrix; + float4x4 _ProjectToPixelMatrix; + float2 _ScreenSize; + float2 _ReflectionBufferSize; + float2 _InvScreenSize; + float3 _CameraClipInfo; + + sampler2D _CameraGBufferTexture0; + sampler2D _CameraGBufferTexture1; + sampler2D _CameraGBufferTexture2; + sampler2D _CameraGBufferTexture3; + sampler2D _CameraReflectionsTexture; + + float _CurrentMipLevel; + float _RayStepSize; + float _MaxRayTraceDistance; + float _LayerThickness; + float _FresnelFade; + float _FresnelFadePower; + float _ReflectionBlur; + + + sampler2D _MainTex; + + int _HalfResolution; + int _TreatBackfaceHitAsMiss; + int _AllowBackwardsRays; + + + // RG: SS Hitpoint of ray + // B: distance ray travelled, used for mip-selection in the final resolve + // A: confidence value + sampler2D _HitPointTexture; + sampler2D _FinalReflectionTexture; + + // RGB: camera-space normal (encoded in [0-1]) + // A: Roughness + sampler2D _NormalAndRoughnessTexture; + + float4 _MainTex_TexelSize; + + int _EnableRefine; + int _AdditiveReflection; + + float _ScreenEdgeFading; + + int _MaxSteps; + + int _BilateralUpsampling; + + float _MaxRoughness; + float _RoughnessFalloffRange; + float _SSRMultiplier; + + float _FadeDistance; + + int _TraceBehindObjects; + int _UseEdgeDetector; + int _HighlightSuppression; + + /** The height in pixels of a 1m object if viewed from 1m away. */ + float _PixelsPerMeterAtOneMeter; + + // For temporal filtering: + float4x4 _CurrentCameraToPreviousCamera; + sampler2D _PreviousReflectionTexture; + sampler2D _PreviousCSZBuffer; + float _TemporalAlpha; + int _UseTemporalConfidence; + + struct v2f + { + float4 pos : SV_POSITION; + float2 uv : TEXCOORD0; + float2 uv2 : TEXCOORD1; + }; + + v2f vert( appdata_img v ) + { + v2f o; + + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv = v.texcoord.xy; + o.uv2 = v.texcoord.xy; + + #if UNITY_UV_STARTS_AT_TOP + if (_MainTex_TexelSize.y < 0) + o.uv2.y = 1-o.uv2.y; + #endif + + return o; + } + + float2 mipToSize(int mip) + { + return floor(_ReflectionBufferSize * exp2(-mip)); + } + + float3 ReconstructCSPosition(float2 S, float z) + { + float linEyeZ = -LinearEyeDepth(z); + return float3(( (( S.xy * _MainTex_TexelSize.zw) ) * _ProjInfo.xy + _ProjInfo.zw) * linEyeZ, linEyeZ); + } + + /** Read the camera-space position of the point at screen-space pixel ssP */ + float3 GetPosition(float2 ssP) + { + float3 P; + + P.z = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, ssP.xy); + + // Offset to pixel center + P = ReconstructCSPosition(float2(ssP) /*+ float2(0.5, 0.5)*/, P.z); + return P; + } + + float square(float x) + { + return x*x; + } + + float applyEdgeFade(float2 tsP, float fadeStrength) + { + float maxFade = 0.1; + + float2 itsP = float2(1.0, 1.0) - tsP; + float dist = min(min(itsP.x, itsP.y), min(tsP.x, tsP.x)); + float fade = dist / (maxFade*fadeStrength + 0.001); + fade = max(min(fade, 1.0), 0.0); + fade = pow(fade, 0.2); + + return fade; + } + + float3 csMirrorVector(float3 csPosition, float3 csN) + { + float3 csE = -normalize(csPosition.xyz); + float cos_o = dot(csN, csE); + float3 c_mi = normalize((csN * (2.0 * cos_o)) - csE); + + return c_mi; + } + + + float4 fragRaytrace(v2f i, int stepRate) + { + float2 ssP = i.uv2.xy; + float3 csPosition = GetPosition(ssP); + + float smoothness = tex2D(_CameraGBufferTexture1, ssP).a; + if (csPosition.z < -100.0 || smoothness == 0.0) + { + return float4(0.0,0.0,0.0,0.0); + } + + float3 wsNormal = tex2D(_CameraGBufferTexture2, ssP).rgb * 2.0 - 1.0; + + int2 ssC = int2(ssP * _ScreenSize); + + float3 csN = mul((float3x3)(_WorldToCameraMatrix), wsNormal); + float3 csRayDirection = csMirrorVector(csPosition, csN); + + if (_AllowBackwardsRays == 0 && csRayDirection.z > 0.0) + { + return float4(0.0, 0.0, 0.0, 0.0); + } + + float maxRayTraceDistance = _MaxRayTraceDistance; + float jitterFraction = 0.0f; + float layerThickness = _LayerThickness; + + int maxSteps = _MaxSteps; + + // Bump the ray more in world space as it gets farther away (and so each pixel covers more WS distance) + float rayBump = max(-0.01*csPosition.z, 0.001); + float2 hitPixel; + float3 csHitPoint; + float stepCount; + + bool wasHit = castDenseScreenSpaceRay + (csPosition + (csN) * rayBump, + csRayDirection, + _ProjectToPixelMatrix, + _ScreenSize, + _CameraClipInfo, + jitterFraction, + maxSteps, + layerThickness, + maxRayTraceDistance, + hitPixel, + stepRate, + _TraceBehindObjects == 1, + csHitPoint, + stepCount); + + float2 tsPResult = hitPixel / _ScreenSize; + + float rayDist = dot(csHitPoint - csPosition, csRayDirection); + float confidence = 0.0; + + if (wasHit) + { + confidence = square(1.0 - max(2.0*float(stepCount) / float(maxSteps) - 1.0, 0.0)); + confidence *= clamp(((_MaxRayTraceDistance - rayDist) / _FadeDistance), 0.0, 1.0); + + // Fake fresnel fade + float3 csE = -normalize(csPosition.xyz); + confidence *= max(0.0, lerp(pow(abs(dot(csRayDirection, -csE)), _FresnelFadePower), 1, 1.0 - _FresnelFade)); + + if (_TreatBackfaceHitAsMiss > 0) + { + float3 wsHitNormal = tex2Dlod(_CameraGBufferTexture2, float4(tsPResult, 0, 0)).rgb * 2.0 - 1.0; + float3 wsRayDirection = mul(_CameraToWorldMatrix, float4(csRayDirection, 0)).xyz; + + if (dot(wsHitNormal, wsRayDirection) > 0) + { + confidence = 0.0; + } + } + + } + + // Fade out reflections that hit near edge of screen, to prevent abrupt appearance/disappearance when object go off screen + // Fade out reflections that hit near edge of screen, + // to prevent abrupt appearance/disappearance when object go off screen + float vignette = applyEdgeFade(tsPResult, _ScreenEdgeFading); + confidence *= vignette; + confidence *= vignette; + + + return float4(tsPResult, rayDist, confidence); + } + + float4 fragComposite(v2f i) : SV_Target + { + // Pixel being shaded + float2 tsP = i.uv2.xy; + + // View space point being shaded + float3 C = GetPosition(tsP); + + // Final image before this pass + float4 gbuffer3 = tex2D(_MainTex, i.uv); + + float4 specEmission = float4(0.0,0.0,0.0,0.0); + float3 specColor = tex2D(_CameraGBufferTexture1, tsP).rgb; + + float roughness = 1.0-tex2D(_CameraGBufferTexture1, tsP).a; + + float4 reflectionTexel = tex2D(_FinalReflectionTexture, tsP); + + float4 gbuffer0 = tex2D(_CameraGBufferTexture0, tsP); + // Let core Unity functions do the dirty work of applying the BRDF + float3 baseColor = gbuffer0.rgb; + float occlusion = gbuffer0.a; + float oneMinusReflectivity; + baseColor = EnergyConservationBetweenDiffuseAndSpecular(baseColor, specColor, oneMinusReflectivity); + + float3 wsNormal = tex2D(_CameraGBufferTexture2, tsP).rgb * 2.0 - 1.0; + + float3 csEyeVec = normalize(C); + float3 eyeVec = mul(_CameraToWorldMatrix, float4(csEyeVec, 0)).xyz; + + float3 worldPos = mul(_CameraToWorldMatrix, float4(C, 1)).xyz; + + float cos_o = dot(wsNormal, eyeVec); + float3 w_mi = -normalize((wsNormal * (2.0 * cos_o)) - eyeVec); + + + float3 incomingRadiance = reflectionTexel.rgb; + + UnityLight light; + light.color = 0; + light.dir = 0; + light.ndotl = 0; + + UnityIndirect ind; + ind.diffuse = 0; + ind.specular = incomingRadiance; + + float3 ssrResult = UNITY_BRDF_PBS (0, specColor, oneMinusReflectivity, 1-roughness, wsNormal, -eyeVec, light, ind).rgb * _SSRMultiplier; + float confidence = reflectionTexel.a; + + specEmission.rgb = tex2D(_CameraReflectionsTexture, tsP).rgb; + float3 finalGlossyTerm; + + // Subtract out Unity's glossy result: (we're just applying the delta) + if (_AdditiveReflection == 0) + { + gbuffer3 -= specEmission; + // We may have blown out our dynamic range by adding then subtracting the reflection probes. + // As a half-measure to fix this, simply clamp to zero + gbuffer3 = max(gbuffer3, 0); + finalGlossyTerm = lerp(specEmission.rgb, ssrResult, saturate(confidence)); + } + else + { + finalGlossyTerm = ssrResult*saturate(confidence); + } + + finalGlossyTerm *= occlusion; + + // Additively blend the glossy GI result with the output buffer + return gbuffer3 + float4(finalGlossyTerm, 0); + } + + float roughnessWeight(float midpointRoughness, float tapRoughness) + { + return (1.0 - sqrt(sqrt(abs(midpointRoughness-tapRoughness)))); + } + + float normalWeight(float3 midpointNormal, float3 tapNormal) + { + return clamp(dot(midpointNormal, tapNormal), 0, 1); + } + + float highlightDecompression(float x) + { + return x / (1.0 - x); + } + + float3 highlightDecompression(float3 x) + { + return float3( + highlightDecompression(x.x), + highlightDecompression(x.y), + highlightDecompression(x.z)); + } + + float highlightCompression(float x) + { + return x / (1.0 + x); + } + + float3 highlightCompression(float3 x) + { + return float3( + highlightCompression(x.x), + highlightCompression(x.y), + highlightCompression(x.z)); + } + + float4 _Axis; + float4 fragGBlur(v2f i) : SV_Target + { + int radius = 4; + + // Pixel being shaded + float2 tsP = i.uv2.xy; + + float weightSum = 0.0; + float gaussWeights[5] = { 0.225, 0.150, 0.110, 0.075, 0.0525 };//{0.225, 0.150, 0.110, 0.075, 0.0525}; + float4 resultSum = float4(0.0, 0.0, 0.0, 0.0); + float4 unweightedResultSum = float4(0.0, 0.0, 0.0, 0.0); + float4 nAndRough = tex2D(_NormalAndRoughnessTexture, tsP); + float midpointRoughness = nAndRough.a; + float3 midpointNormal = nAndRough.rgb * 2 - 1; + + for (int i = -radius; i <= radius; ++i) + { + float4 temp; + float tapRoughness; + float3 tapNormal; + float2 tsTap = tsP + (_Axis.xy * _MainTex_TexelSize.xy * float2(i,i)*2.0); + + temp = tex2D(_MainTex, tsTap); + + float weight = temp.a * gaussWeights[abs(i)]; + // Bilateral filtering + // if (_ImproveCorners) + // { + nAndRough = tex2D(_NormalAndRoughnessTexture, tsTap); + tapRoughness = nAndRough.a; + tapNormal = nAndRough.rgb * 2 - 1; + weight *= normalWeight(midpointNormal, tapNormal); + // } + + weightSum += weight; + + if (_HighlightSuppression) + { + temp.rgb = highlightCompression(temp.rgb); + } + + unweightedResultSum += temp; + resultSum += temp*weight; + } + + if (weightSum > 0.01) + { + float invWeightSum = (1.0/weightSum); + // Adding the sqrt seems to decrease temporal flickering at the expense + // of having larger "halos" of fallback on rough surfaces + // Subject to change with testing. Sqrt around only half the expression is *intentional*. + float confidence = min(resultSum.a * sqrt(max(invWeightSum, 2.0)), 1.0); + float3 finalColor = resultSum.rgb * invWeightSum; + + if (_HighlightSuppression) + { + finalColor = highlightDecompression(finalColor); + } + + return float4(finalColor, confidence); + } + else + { + float3 finalColor = unweightedResultSum.rgb / (2 * radius + 1); + + if (_HighlightSuppression) + { + finalColor = highlightDecompression(finalColor); + } + + return float4(finalColor, 0.0); + } + } + + sampler2D _ReflectionTexture0; + sampler2D _ReflectionTexture1; + sampler2D _ReflectionTexture2; + sampler2D _ReflectionTexture3; + sampler2D _ReflectionTexture4; + + // Simulate mip maps, since we don't have NPOT mip-chains + float4 getReflectionValue(float2 tsP, int mip) + { + float4 coord = float4(tsP,0,0); + if (mip == 0) + { + return tex2Dlod(_ReflectionTexture0, coord); + } + else if (mip == 1) + { + return tex2Dlod(_ReflectionTexture1, coord); + } + else if (mip == 2) + { + return tex2Dlod(_ReflectionTexture2, coord); + } + else if (mip == 3) + { + return tex2Dlod(_ReflectionTexture3, coord); + } + else + { + return tex2Dlod(_ReflectionTexture4, coord); + } + } + + sampler2D _EdgeTexture0; + sampler2D _EdgeTexture1; + sampler2D _EdgeTexture2; + sampler2D _EdgeTexture3; + sampler2D _EdgeTexture4; + + // Simulate mip maps, since we don't have NPOT mip-chains + float4 getEdgeValue(float2 tsP, int mip) + { + float4 coord = float4(tsP + float2(1.0/(2 * mipToSize(mip))),0,0); + + if (mip == 0) + { + return tex2Dlod(_EdgeTexture0, coord); + } + else if (mip == 1) + { + return tex2Dlod(_EdgeTexture1, coord); + } + else if (mip == 2) + { + return tex2Dlod(_EdgeTexture2, coord); + } + else if (mip == 3) + { + return tex2Dlod(_EdgeTexture3, coord); + } + else + { + return tex2Dlod(_EdgeTexture4, coord); + } + } + + float2 centerPixel(float2 inputP) + { + return floor(inputP - float2(0.5,0.5)) + float2(0.5,0.5); + } + + float2 snapToTexelCenter(float2 inputP, float2 texSize, float2 texSizeInv) + { + return centerPixel(inputP * texSize) * texSizeInv; + } + + float4 bilateralUpsampleReflection(float2 tsP, int mip) + { + float2 smallTexSize = mipToSize(mip); + float2 smallPixelPos = tsP * smallTexSize; + float2 smallPixelPosi = centerPixel(smallPixelPos); + float2 smallTexSizeInv = 1.0 / smallTexSize; + + + float2 p0 = smallPixelPosi * smallTexSizeInv; + float2 p3 = (smallPixelPosi + float2(1.0, 1.0)) * smallTexSizeInv; + float2 p1 = float2(p3.x, p0.y); + float2 p2 = float2(p0.x, p3.y); + + float4 V0 = getReflectionValue(p0.xy, mip); + float4 V1 = getReflectionValue(p1.xy, mip); + float4 V2 = getReflectionValue(p2.xy, mip); + float4 V3 = getReflectionValue(p3.xy, mip); + + // Bilateral weights: + // Bilinear interpolation (filter distance) + float2 smallPixelPosf = smallPixelPos - smallPixelPosi; + float a0 = (1.0 - smallPixelPosf.x) * (1.0 - smallPixelPosf.y); + float a1 = smallPixelPosf.x * (1.0 - smallPixelPosf.y); + float a2 = (1.0 - smallPixelPosf.x) * smallPixelPosf.y; + float a3 = smallPixelPosf.x * smallPixelPosf.y; + + float2 fullTexSize = _ReflectionBufferSize; + float2 fullTexSizeInv = 1.0 / fullTexSize; + + float4 hiP0 = float4(snapToTexelCenter(p0, fullTexSize, fullTexSizeInv), 0,0); + float4 hiP3 = float4(snapToTexelCenter(p3, fullTexSize, fullTexSizeInv), 0,0); + float4 hiP1 = float4(snapToTexelCenter(p1, fullTexSize, fullTexSizeInv), 0,0); + float4 hiP2 = float4(snapToTexelCenter(p2, fullTexSize, fullTexSizeInv), 0,0); + + float4 tempCenter = tex2Dlod(_NormalAndRoughnessTexture, float4(tsP, 0, 0)); + float3 n = tempCenter.xyz * 2 - 1; + + float4 temp0 = tex2Dlod(_NormalAndRoughnessTexture, hiP0); + float4 temp1 = tex2Dlod(_NormalAndRoughnessTexture, hiP1); + float4 temp2 = tex2Dlod(_NormalAndRoughnessTexture, hiP2); + float4 temp3 = tex2Dlod(_NormalAndRoughnessTexture, hiP3); + + float3 n0 = temp0.xyz * 2 - 1; + float3 n1 = temp1.xyz * 2 - 1; + float3 n2 = temp2.xyz * 2 - 1; + float3 n3 = temp3.xyz * 2 - 1; + + a0 *= normalWeight(n, n0); + a1 *= normalWeight(n, n1); + a2 *= normalWeight(n, n2); + a3 *= normalWeight(n, n3); + + float r = tempCenter.a; + float r0 = temp0.a; + float r1 = temp1.a; + float r2 = temp2.a; + float r3 = temp3.a; + + a0 *= roughnessWeight(r, r0); + a1 *= roughnessWeight(r, r1); + a2 *= roughnessWeight(r, r2); + a3 *= roughnessWeight(r, r3); + + // Slightly offset from zero + a0 = max(a0, 0.001); + a1 = max(a1, 0.001); + a2 = max(a2, 0.001); + a3 = max(a3, 0.001); + + // Nearest neighbor + // a0 = a1 = a2 = a3 = 1.0; + + // Normalize the blending weights (weights were chosen so that + // the denominator can never be zero) + float norm = 1.0 / (a0 + a1 + a2 + a3); + + // Blend + float4 value = (V0 * a0 + V1 * a1 + V2 * a2 + V3 * a3) * norm; + //return V0; + return value; + } + + /** Explicit bilinear fetches; must be used if the reflection buffer is bound using point sampling */ + float4 bilinearUpsampleReflection(float2 tsP, int mip) + { + float2 smallTexSize = mipToSize(mip); + float2 smallPixelPos = tsP * smallTexSize; + float2 smallPixelPosi = centerPixel(smallPixelPos); + float2 smallTexSizeInv = 1.0 / smallTexSize; + + + float2 p0 = smallPixelPosi * smallTexSizeInv; + float2 p3 = (smallPixelPosi + float2(1.0, 1.0)) * smallTexSizeInv; + float2 p1 = float2(p3.x, p0.y); + float2 p2 = float2(p0.x, p3.y); + + float4 V0 = getReflectionValue(p0.xy, mip); + float4 V1 = getReflectionValue(p1.xy, mip); + float4 V2 = getReflectionValue(p2.xy, mip); + float4 V3 = getReflectionValue(p3.xy, mip); + + float a0 = 1.0; + float a1 = 1.0; + float a2 = 1.0; + float a3 = 1.0; + + // Bilateral weights: + // Bilinear interpolation (filter distance) + float2 smallPixelPosf = smallPixelPos - smallPixelPosi; + a0 = (1.0 - smallPixelPosf.x) * (1.0 - smallPixelPosf.y); + a1 = smallPixelPosf.x * (1.0 - smallPixelPosf.y); + a2 = (1.0 - smallPixelPosf.x) * smallPixelPosf.y; + a3 = smallPixelPosf.x * smallPixelPosf.y; + + // Blend + float4 value = (V0 * a0 + V1 * a1 + V2 * a2 + V3 * a3); + return value; + } + + // Unity's roughness is GGX roughness squared + float roughnessToBlinnPhongExponent(float roughness) + { + float r2 = roughness*roughness; + return 2.0f / r2*r2 - 2.0f; + } + + float glossyLobeSlope(float roughness) + { + return pow(roughness, 4.0/3.0); + } + + + // Empirically based on our filter: + // Mip | Pixels + // -------------- + // 0 | 1 no filter, so single pixel + // 1 | 17 2r + 1 filter applied once, grabbing from pixels r away in either direction (r=8, four samples times stride of 2) + // 2 | 50 2r + 1 filter applied on double size pixels, and each of those pixels had reached another r out to the side 2(2r + 1) + m_1 + // 3 | 118 4(2r + 1) + m_2 + // 4 | 254 8(2r + 1) + m_3 + // + // Approximated by pixels = 16*2^mip-15 + // rearranging we get mip = log_2((pixels + 15) / 16) + // + float filterFootprintInPixelsToMip(float footprint) + { + return log2((footprint + 15) / 16); + } + + float3 ansiGradient(float t) + { + //return float3(t, t, t); + return fmod(floor(t * float3(8.0, 4.0, 2.0)), 2.0); + } + + float4 fragCompositeSSR(v2f i) : SV_Target + { + // Pixel being shaded + float2 tsP = i.uv2.xy; + + float roughness = 1.0-tex2D(_CameraGBufferTexture1, tsP).a; + + float rayDistance = tex2D(_HitPointTexture, tsP).z; + + // Get the camera space position of the reflection hit + float3 csPosition = GetPosition(tsP); + float3 wsNormal = tex2D(_CameraGBufferTexture2, tsP).rgb * 2.0 - 1.0; + float3 csN = mul((float3x3)(_WorldToCameraMatrix), wsNormal); + float3 c_mi = csMirrorVector(csPosition, csN); + float3 csHitpoint = c_mi * rayDistance + csPosition; + + + float gatherFootprintInMeters = glossyLobeSlope(roughness) * rayDistance; + // We could add a term that incorporates the normal + // This approximation assumes reflections happen at a glancing angle + float filterFootprintInPixels = gatherFootprintInMeters * _PixelsPerMeterAtOneMeter / csHitpoint.z; + if (_HalfResolution == 1) + { + filterFootprintInPixels *= 0.5; + } + + float mip = filterFootprintInPixelsToMip(filterFootprintInPixels); + + float nonPhysicalMip = pow(roughness, 3.0 / 4.0) * UNITY_SPECCUBE_LOD_STEPS; + + if (_HalfResolution == 1) + { + nonPhysicalMip = nonPhysicalMip * 0.7; + } + + mip = max(0, min(4, mip)); + + float4 result = 0.; + + { + int mipMin = int(mip); + int mipMax = min(mipMin + 1, 4); + float mipLerp = mip-mipMin; + + if (_BilateralUpsampling == 1) + { + result = lerp(bilateralUpsampleReflection(tsP, mipMin), bilateralUpsampleReflection(tsP, mipMax), mipLerp); + } + else + { + float4 minResult = getReflectionValue(tsP, mipMin); + float4 maxResult = getReflectionValue(tsP, mipMax); + result = lerp(minResult, maxResult, mipLerp); + result.a = min(minResult.a, maxResult.a); + } + } + + result.a = min(result.a, 1.0); + float vignette = applyEdgeFade(tsP, _ScreenEdgeFading); + result.a *= vignette; + + + // THIS MIGHT BE SLIGHTLY WRONG, TRY STEP() + float alphaModifier = 1.0 - clamp(roughness * .3, 0., 1.); + result.a *= alphaModifier; + return result; + } + + int _LastMip; + + float4 fragMin(v2f i) : SV_Target + { + float2 tsP = i.uv2.xy; + float2 lastTexSize = mipToSize(_LastMip); + float2 lastTexSizeInv = 1.0 / lastTexSize; + float2 p00 = snapToTexelCenter(tsP, lastTexSize, lastTexSizeInv); + float2 p11 = p00 + lastTexSizeInv; + + return min( + min(tex2D(_MainTex, p00), tex2D(_MainTex, p11)), + min(tex2D(_MainTex, float2(p00.x, p11.y)), tex2D(_MainTex, float2(p11.x, p00.y))) + ); + } + + float4 fragResolveHitPoints(v2f i) : SV_Target + { + float2 tsP = i.uv2.xy; + float4 temp = tex2D(_HitPointTexture, tsP); + float2 hitPoint = temp.xy; + float confidence = temp.w; + float3 colorResult = confidence > 0.0 ? tex2D(_MainTex, hitPoint).rgb : tex2D(_CameraReflectionsTexture, tsP).rgb; + + #ifdef UNITY_COMPILER_HLSL + /*if (any(isnan(colorResult))) + colorResult = float3(0.0, 0.0, 0.0); + + // As of 11/29/2015, on Unity 5.3 on a Windows 8.1 computer with a NVIDIA GeForce 980, + // with driver 347.62, the above check does not actually work to get rid of NaNs! + // So we add this "redundant" check. + if (!all(isfinite(colorResult))) + colorResult = float3(0.0, 0.0, 0.0);*/ + #endif + return float4(colorResult, confidence); + } + + float4 fragBilatKeyPack(v2f i) : SV_Target + { + float2 tsP = i.uv2.xy; + float3 csN = tex2D(_CameraGBufferTexture2, tsP).xyz; + float roughness = tex2D(_CameraGBufferTexture1, tsP).a; + return float4(csN, roughness); + } + + float4 fragDepthToCSZ(v2f i) : SV_Target + { + float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv2.xy); + return float4(-LinearEyeDepth(depth), 0.0, 0.0, 0.0); + } + + static const int NUM_POISSON_TAPS = 12; + // Same as used in CameraMotionBlur.shader + static const float2 poissonSamples[NUM_POISSON_TAPS] = + { + float2(-0.326212,-0.40581), + float2(-0.840144,-0.07358), + float2(-0.695914,0.457137), + float2(-0.203345,0.620716), + float2(0.96234,-0.194983), + float2(0.473434,-0.480026), + float2(0.519456,0.767022), + float2(0.185461,-0.893124), + float2(0.507431,0.064425), + float2(0.89642,0.412458), + float2(-0.32194,-0.932615), + float2(-0.791559,-0.59771) + }; + + float4 fragFilterSharpReflections(v2f i) : SV_Target + { + // Could improve perf by not computing blur when we won't be sampling the highest level anyways + float2 tsP = i.uv2.xy; + float4 sum = 0.0; + float sampleRadius = _MainTex_TexelSize.xy * _ReflectionBlur; + + for (int i = 0; i < NUM_POISSON_TAPS; i++) + { + float2 p = tsP + poissonSamples[i] * sampleRadius; + + float4 tap = tex2D(_MainTex, p); + if (_HighlightSuppression) + { + tap.rgb = highlightCompression(tap.rgb); + } + + sum += tap; + } + + float4 result = sum / float(NUM_POISSON_TAPS); + + if (_HighlightSuppression) + { + result.rgb = highlightDecompression(result.rgb); + } + + return result; + } + + ENDCG + + SubShader + { + ZTest Always Cull Off ZWrite Off + + // 0: Raytrace + Pass + { + CGPROGRAM + #pragma exclude_renderers gles xbox360 ps3 + #pragma vertex vert + #pragma fragment fragRaytrace1 + #pragma target 3.0 + + float4 fragRaytrace1(v2f i) : SV_Target + { + return fragRaytrace(i, _RayStepSize); + } + ENDCG + } + + // 1: Composite + Pass + { + CGPROGRAM + #pragma exclude_renderers gles xbox360 ps3 + #pragma vertex vert + #pragma fragment fragComposite + #pragma target 3.0 + ENDCG + } + + // 2: GBlur + Pass + { + CGPROGRAM + #pragma exclude_renderers gles xbox360 ps3 + #pragma vertex vert + #pragma fragment fragGBlur + #pragma target 3.0 + ENDCG + } + + // 3: CompositeSSR + Pass + { + CGPROGRAM + #pragma exclude_renderers gles xbox360 ps3 + #pragma vertex vert + #pragma fragment fragCompositeSSR + #pragma target 3.0 + ENDCG + } + + // 4: Min mip generation + Pass + { + CGPROGRAM + #pragma exclude_renderers gles xbox360 ps3 + #pragma vertex vert + #pragma fragment fragMin + #pragma target 3.0 + ENDCG + } + + // 5: Hit point texture to reflection buffer + Pass + { + CGPROGRAM + #pragma exclude_renderers gles xbox360 ps3 + #pragma vertex vert + #pragma fragment fragResolveHitPoints + #pragma target 3.0 + ENDCG + } + + // 6: Pack Bilateral Filter Keys in single buffer + Pass + { + CGPROGRAM + #pragma exclude_renderers gles xbox360 ps3 + #pragma vertex vert + #pragma fragment fragBilatKeyPack + #pragma target 3.0 + ENDCG + } + + // 7: Blit depth information as camera space Z + Pass + { + CGPROGRAM + #pragma exclude_renderers gles xbox360 ps3 + #pragma vertex vert + #pragma fragment fragDepthToCSZ + #pragma target 3.0 + ENDCG + } + + // 8: Filter the highest quality reflection buffer + Pass + { + CGPROGRAM + #pragma exclude_renderers gles xbox360 ps3 + #pragma vertex vert + #pragma fragment fragFilterSharpReflections + #pragma target 3.0 + ENDCG + } + + } + + Fallback "Diffuse" +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Resources/ScreenSpaceReflection.shader.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Resources/ScreenSpaceReflection.shader.meta new file mode 100644 index 0000000..170b098 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/Resources/ScreenSpaceReflection.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 7e2fcc83af19e744787647ec0ac5d42c +timeCreated: 1449750821 +licenseType: Store +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/ScreenSpaceReflection.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/ScreenSpaceReflection.cs new file mode 100644 index 0000000..f1ea41c --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/ScreenSpaceReflection.cs @@ -0,0 +1,424 @@ +using System; +using UnityEngine; + +using UnityEngine.Rendering; + +namespace UnityStandardAssets.CinematicEffects +{ + [ExecuteInEditMode] +#if UNITY_5_4_OR_NEWER + [ImageEffectAllowedInSceneView] +#endif + [RequireComponent(typeof(Camera))] + [AddComponentMenu("Cinematic Image Effects/Screen Space Reflections")] + public class ScreenSpaceReflection : MonoBehaviour + { + public enum SSRResolution + { + High = 0, + Low = 2 + } + + public enum SSRReflectionBlendType + { + PhysicallyBased, + Additive + } + + [Serializable] + public struct SSRSettings + { + [AttributeUsage(AttributeTargets.Field)] + public class LayoutAttribute : PropertyAttribute + { + } + + [Layout] + public ReflectionSettings reflectionSettings; + + [Layout] + public IntensitySettings intensitySettings; + + [Layout] + public ScreenEdgeMask screenEdgeMask; + + private static readonly SSRSettings s_Default = new SSRSettings + { + reflectionSettings = new ReflectionSettings + { + blendType = SSRReflectionBlendType.PhysicallyBased, + reflectionQuality = SSRResolution.High, + maxDistance = 100.0f, + iterationCount = 256, + stepSize = 3, + widthModifier = 0.5f, + reflectionBlur = 1.0f, + reflectBackfaces = true + }, + + intensitySettings = new IntensitySettings + { + reflectionMultiplier = 1.0f, + fadeDistance = 100.0f, + + fresnelFade = 1.0f, + fresnelFadePower = 1.0f, + }, + + screenEdgeMask = new ScreenEdgeMask + { + intensity = 0.03f + } + }; + + public static SSRSettings defaultSettings + { + get + { + return s_Default; + } + } + } + + [Serializable] + public struct IntensitySettings + { + [Tooltip("Nonphysical multiplier for the SSR reflections. 1.0 is physically based.")] + [Range(0.0f, 2.0f)] + public float reflectionMultiplier; + + [Tooltip("How far away from the maxDistance to begin fading SSR.")] + [Range(0.0f, 1000.0f)] + public float fadeDistance; + + [Tooltip("Amplify Fresnel fade out. Increase if floor reflections look good close to the surface and bad farther 'under' the floor.")] + [Range(0.0f, 1.0f)] + public float fresnelFade; + + [Tooltip("Higher values correspond to a faster Fresnel fade as the reflection changes from the grazing angle.")] + [Range(0.1f, 10.0f)] + public float fresnelFadePower; + } + + [Serializable] + public struct ReflectionSettings + { + // When enabled, we just add our reflections on top of the existing ones. This is physically incorrect, but several + // popular demos and games have taken this approach, and it does hide some artifacts. + [Tooltip("How the reflections are blended into the render.")] + public SSRReflectionBlendType blendType; + + [Tooltip("Half resolution SSRR is much faster, but less accurate.")] + public SSRResolution reflectionQuality; + + [Tooltip("Maximum reflection distance in world units.")] + [Range(0.1f, 300.0f)] + public float maxDistance; + + /// REFLECTIONS + [Tooltip("Max raytracing length.")] + [Range(16, 1024)] + public int iterationCount; + + [Tooltip("Log base 2 of ray tracing coarse step size. Higher traces farther, lower gives better quality silhouettes.")] + [Range(1, 16)] + public int stepSize; + + [Tooltip("Typical thickness of columns, walls, furniture, and other objects that reflection rays might pass behind.")] + [Range(0.01f, 10.0f)] + public float widthModifier; + + [Tooltip("Blurriness of reflections.")] + [Range(0.1f, 8.0f)] + public float reflectionBlur; + + [Tooltip("Enable for a performance gain in scenes where most glossy objects are horizontal, like floors, water, and tables. Leave on for scenes with glossy vertical objects.")] + public bool reflectBackfaces; + } + + [Serializable] + public struct ScreenEdgeMask + { + [Tooltip("Higher = fade out SSRR near the edge of the screen so that reflections don't pop under camera motion.")] + [Range(0.0f, 1.0f)] + public float intensity; + } + + + [SerializeField] + public SSRSettings settings = SSRSettings.defaultSettings; + + ///////////// Unexposed Variables ////////////////// + + [Tooltip("Enable to limit the effect a few bright pixels can have on rougher surfaces")] + private bool highlightSuppression = false; + + [Tooltip("Enable to allow rays to pass behind objects. This can lead to more screen-space reflections, but the reflections are more likely to be wrong.")] + private bool traceBehindObjects = true; + + [Tooltip("Enable to force more surfaces to use reflection probes if you see streaks on the sides of objects or bad reflections of their backs.")] + private bool treatBackfaceHitAsMiss = false; + + [Tooltip("Drastically improves reflection reconstruction quality at the expense of some performance.")] + private bool bilateralUpsample = true; + + ///////////// Unexposed Variables ////////////////// + + [SerializeField] + private Shader m_Shader; + public Shader shader + { + get + { + if (m_Shader == null) + m_Shader = Shader.Find("Hidden/ScreenSpaceReflection"); + + return m_Shader; + } + } + + private Material m_Material; + public Material material + { + get + { + if (m_Material == null) + m_Material = ImageEffectHelper.CheckShaderAndCreateMaterial(shader); + + return m_Material; + } + } + + private Camera m_Camera; + public Camera camera_ + { + get + { + if (m_Camera == null) + m_Camera = GetComponent(); + + return m_Camera; + } + } + + private CommandBuffer m_CommandBuffer; + + private static int kNormalAndRoughnessTexture; + private static int kHitPointTexture; + private static int[] kReflectionTextures; + private static int kFilteredReflections; + private static int kBlurTexture; + private static int kFinalReflectionTexture; + private static int kTempTexture; + + // Shader pass indices used by the effect + private enum PassIndex + { + RayTraceStep = 0, + CompositeFinal = 1, + Blur = 2, + CompositeSSR = 3, + MinMipGeneration = 4, + HitPointToReflections = 5, + BilateralKeyPack = 6, + BlitDepthAsCSZ = 7, + PoissonBlur = 8, + } + + private void OnEnable() + { + if (!ImageEffectHelper.IsSupported(shader, false, true, this)) + { + enabled = false; + return; + } + + camera_.depthTextureMode |= DepthTextureMode.Depth; + + kReflectionTextures = new int[5]; + + kNormalAndRoughnessTexture = Shader.PropertyToID("_NormalAndRoughnessTexture"); + kHitPointTexture = Shader.PropertyToID("_HitPointTexture"); + kReflectionTextures[0] = Shader.PropertyToID("_ReflectionTexture0"); + kReflectionTextures[1] = Shader.PropertyToID("_ReflectionTexture1"); + kReflectionTextures[2] = Shader.PropertyToID("_ReflectionTexture2"); + kReflectionTextures[3] = Shader.PropertyToID("_ReflectionTexture3"); + kReflectionTextures[4] = Shader.PropertyToID("_ReflectionTexture4"); + kBlurTexture = Shader.PropertyToID("_BlurTexture"); + kFilteredReflections = Shader.PropertyToID("_FilteredReflections"); + kFinalReflectionTexture = Shader.PropertyToID("_FinalReflectionTexture"); + kTempTexture = Shader.PropertyToID("_TempTexture"); + } + + void OnDisable() + { + if (m_Material) + DestroyImmediate(m_Material); + + m_Material = null; + + if (camera_ != null) + { + if (m_CommandBuffer != null) + { + camera_.RemoveCommandBuffer(CameraEvent.AfterFinalPass, m_CommandBuffer); + } + + m_CommandBuffer = null; + } + } + +#if UNITY_EDITOR + void OnValidate() + { + if (camera_ != null) + { + if (m_CommandBuffer != null) + { + camera_.RemoveCommandBuffer(CameraEvent.AfterFinalPass, m_CommandBuffer); + } + + m_CommandBuffer = null; + } + } +#endif + + // [ImageEffectOpaque] + public void OnPreRender() + { + if (material == null) + { + return; + } + else if (Camera.current.actualRenderingPath != RenderingPath.DeferredShading) + { + return; + } + + int downsampleAmount = (settings.reflectionSettings.reflectionQuality == SSRResolution.High) ? 1 : 2; + + var rtW = camera_.pixelWidth / downsampleAmount; + var rtH = camera_.pixelHeight / downsampleAmount; + + float sWidth = camera_.pixelWidth; + float sHeight = camera_.pixelHeight; + + float sx = sWidth / 2.0f; + float sy = sHeight / 2.0f; + + const int maxMip = 5; + + RenderTextureFormat intermediateFormat = camera_.hdr ? RenderTextureFormat.ARGBHalf : RenderTextureFormat.ARGB32; + + material.SetInt("_RayStepSize", settings.reflectionSettings.stepSize); + material.SetInt("_AdditiveReflection", settings.reflectionSettings.blendType == SSRReflectionBlendType.Additive ? 1 : 0); + material.SetInt("_BilateralUpsampling", bilateralUpsample ? 1 : 0); + material.SetInt("_TreatBackfaceHitAsMiss", treatBackfaceHitAsMiss ? 1 : 0); + material.SetInt("_AllowBackwardsRays", settings.reflectionSettings.reflectBackfaces ? 1 : 0); + material.SetInt("_TraceBehindObjects", traceBehindObjects ? 1 : 0); + material.SetInt("_MaxSteps", settings.reflectionSettings.iterationCount); + material.SetInt("_FullResolutionFiltering", 0); + material.SetInt("_HalfResolution", (settings.reflectionSettings.reflectionQuality != SSRResolution.High) ? 1 : 0); + material.SetInt("_HighlightSuppression", highlightSuppression ? 1 : 0); + + /** The height in pixels of a 1m object if viewed from 1m away. */ + float pixelsPerMeterAtOneMeter = sWidth / (-2.0f * (float)(Math.Tan(camera_.fieldOfView / 180.0 * Math.PI * 0.5))); + + material.SetFloat("_PixelsPerMeterAtOneMeter", pixelsPerMeterAtOneMeter); + material.SetFloat("_ScreenEdgeFading", settings.screenEdgeMask.intensity); + material.SetFloat("_ReflectionBlur", settings.reflectionSettings.reflectionBlur); + material.SetFloat("_MaxRayTraceDistance", settings.reflectionSettings.maxDistance); + material.SetFloat("_FadeDistance", settings.intensitySettings.fadeDistance); + material.SetFloat("_LayerThickness", settings.reflectionSettings.widthModifier); + material.SetFloat("_SSRMultiplier", settings.intensitySettings.reflectionMultiplier); + material.SetFloat("_FresnelFade", settings.intensitySettings.fresnelFade); + material.SetFloat("_FresnelFadePower", settings.intensitySettings.fresnelFadePower); + + Matrix4x4 P = camera_.projectionMatrix; + Vector4 projInfo = new Vector4 + ((-2.0f / (sWidth * P[0])), + (-2.0f / (sHeight * P[5])), + ((1.0f - P[2]) / P[0]), + ((1.0f + P[6]) / P[5])); + + Vector3 cameraClipInfo = (float.IsPositiveInfinity(camera_.farClipPlane)) ? + new Vector3(camera_.nearClipPlane, -1.0f, 1.0f) : + new Vector3(camera_.nearClipPlane * camera_.farClipPlane, camera_.nearClipPlane - camera_.farClipPlane, camera_.farClipPlane); + + material.SetVector("_ReflectionBufferSize", new Vector2(rtW, rtH)); + material.SetVector("_ScreenSize", new Vector2(sWidth, sHeight)); + material.SetVector("_InvScreenSize", new Vector2((float)(1.0f / sWidth), (float)(1.0f / sHeight))); + material.SetVector("_ProjInfo", projInfo); // used for unprojection + + material.SetVector("_CameraClipInfo", cameraClipInfo); + + Matrix4x4 warpToScreenSpaceMatrix = new Matrix4x4(); + warpToScreenSpaceMatrix.SetRow(0, new Vector4(sx, 0.0f, 0.0f, sx)); + warpToScreenSpaceMatrix.SetRow(1, new Vector4(0.0f, sy, 0.0f, sy)); + warpToScreenSpaceMatrix.SetRow(2, new Vector4(0.0f, 0.0f, 1.0f, 0.0f)); + warpToScreenSpaceMatrix.SetRow(3, new Vector4(0.0f, 0.0f, 0.0f, 1.0f)); + + Matrix4x4 projectToPixelMatrix = warpToScreenSpaceMatrix * P; + + material.SetMatrix("_ProjectToPixelMatrix", projectToPixelMatrix); + material.SetMatrix("_WorldToCameraMatrix", camera_.worldToCameraMatrix); + material.SetMatrix("_CameraToWorldMatrix", camera_.worldToCameraMatrix.inverse); + + if (m_CommandBuffer == null) + { + m_CommandBuffer = new CommandBuffer(); + m_CommandBuffer.name = "Screen Space Reflections"; + + // RGB: Normals, A: Roughness. + // Has the nice benefit of allowing us to control the filtering mode as well. + m_CommandBuffer.GetTemporaryRT(kNormalAndRoughnessTexture, -1, -1, 0, FilterMode.Point, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear); + + m_CommandBuffer.GetTemporaryRT(kHitPointTexture, rtW, rtH, 0, FilterMode.Bilinear, RenderTextureFormat.ARGBHalf, RenderTextureReadWrite.Linear); + + for (int i = 0; i < maxMip; ++i) + { + // We explicitly interpolate during bilateral upsampling. + m_CommandBuffer.GetTemporaryRT(kReflectionTextures[i], rtW >> i, rtH >> i, 0, FilterMode.Bilinear, intermediateFormat); + } + + m_CommandBuffer.GetTemporaryRT(kFilteredReflections, rtW, rtH, 0, bilateralUpsample ? FilterMode.Point : FilterMode.Bilinear, intermediateFormat); + m_CommandBuffer.GetTemporaryRT(kFinalReflectionTexture, rtW, rtH, 0, FilterMode.Point, intermediateFormat); + + m_CommandBuffer.Blit(BuiltinRenderTextureType.CameraTarget, kNormalAndRoughnessTexture, material, (int)PassIndex.BilateralKeyPack); + m_CommandBuffer.Blit(BuiltinRenderTextureType.CameraTarget, kHitPointTexture, material, (int)PassIndex.RayTraceStep); + m_CommandBuffer.Blit(BuiltinRenderTextureType.CameraTarget, kFilteredReflections, material, (int)PassIndex.HitPointToReflections); + m_CommandBuffer.Blit(kFilteredReflections, kReflectionTextures[0], material, (int)PassIndex.PoissonBlur); + + for (int i = 1; i < maxMip; ++i) + { + int inputTex = kReflectionTextures[i - 1]; + + int lowMip = i; + + m_CommandBuffer.GetTemporaryRT(kBlurTexture, rtW >> lowMip, rtH >> lowMip, 0, FilterMode.Bilinear, intermediateFormat); + m_CommandBuffer.SetGlobalVector("_Axis", new Vector4(1.0f, 0.0f, 0.0f, 0.0f)); + m_CommandBuffer.SetGlobalFloat("_CurrentMipLevel", i - 1.0f); + + m_CommandBuffer.Blit(inputTex, kBlurTexture, material, (int)PassIndex.Blur); + + m_CommandBuffer.SetGlobalVector("_Axis", new Vector4(0.0f, 1.0f, 0.0f, 0.0f)); + + inputTex = kReflectionTextures[i]; + m_CommandBuffer.Blit(kBlurTexture, inputTex, material, (int)PassIndex.Blur); + m_CommandBuffer.ReleaseTemporaryRT(kBlurTexture); + } + + m_CommandBuffer.Blit(kReflectionTextures[0], kFinalReflectionTexture, material, (int)PassIndex.CompositeSSR); + + m_CommandBuffer.GetTemporaryRT(kTempTexture, camera_.pixelWidth, camera_.pixelHeight, 0, FilterMode.Bilinear, intermediateFormat); + + m_CommandBuffer.Blit(BuiltinRenderTextureType.CameraTarget, kTempTexture, material, (int)PassIndex.CompositeFinal); + m_CommandBuffer.Blit(kTempTexture, BuiltinRenderTextureType.CameraTarget); + + + m_CommandBuffer.ReleaseTemporaryRT(kTempTexture); + camera_.AddCommandBuffer(CameraEvent.AfterFinalPass, m_CommandBuffer); + } + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/ScreenSpaceReflection.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/ScreenSpaceReflection.cs.meta new file mode 100644 index 0000000..fc99e3a --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/ScreenSpaceReflection/ScreenSpaceReflection.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: da3ff4a1bef2e8d47a1dfb734aa54de1 +timeCreated: 1433488439 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: + - ssrShader: {fileID: 4800000, guid: 7e2fcc83af19e744787647ec0ac5d42c, type: 3} + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading.meta new file mode 100644 index 0000000..ccbb7eb --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 33083b2f3c4953846890c256af8cc606 +folderAsset: yes +timeCreated: 1435676891 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Editor.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Editor.meta new file mode 100644 index 0000000..f54837b --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Editor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: a232fdc401b30b549b2ac3a54d76f6cc +folderAsset: yes +timeCreated: 1448359112 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Editor/TonemappingColorGradingEditor.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Editor/TonemappingColorGradingEditor.cs new file mode 100644 index 0000000..8d30a3a --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Editor/TonemappingColorGradingEditor.cs @@ -0,0 +1,736 @@ +namespace UnityStandardAssets.CinematicEffects +{ + using UnityEngine; + using UnityEditor; + using UnityEditorInternal; + using System.Reflection; + using System.Collections.Generic; + using System.Linq; + + [CanEditMultipleObjects, CustomEditor(typeof(TonemappingColorGrading))] + public class TonemappingColorGradingEditor : Editor + { + #region Property drawers + [CustomPropertyDrawer(typeof(TonemappingColorGrading.ColorWheelGroup))] + private class ColorWheelGroupDrawer : PropertyDrawer + { + int m_RenderSizePerWheel; + int m_NumberOfWheels; + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + var wheelAttribute = (TonemappingColorGrading.ColorWheelGroup)attribute; + property.isExpanded = true; + + m_NumberOfWheels = property.CountInProperty() - 1; + if (m_NumberOfWheels == 0) + return 0f; + + m_RenderSizePerWheel = Mathf.FloorToInt((EditorGUIUtility.currentViewWidth) / m_NumberOfWheels) - 30; + m_RenderSizePerWheel = Mathf.Clamp(m_RenderSizePerWheel, wheelAttribute.minSizePerWheel, wheelAttribute.maxSizePerWheel); + m_RenderSizePerWheel = Mathf.FloorToInt(pixelRatio * m_RenderSizePerWheel); + return ColorWheel.GetColorWheelHeight(m_RenderSizePerWheel); + } + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + if (m_NumberOfWheels == 0) + return; + + var width = position.width; + Rect newPosition = new Rect(position.x, position.y, width / m_NumberOfWheels, position.height); + + foreach (SerializedProperty prop in property) + { + if (prop.propertyType == SerializedPropertyType.Color) + prop.colorValue = ColorWheel.DoGUI(newPosition, prop.displayName, prop.colorValue, m_RenderSizePerWheel); + + newPosition.x += width / m_NumberOfWheels; + } + } + } + + [CustomPropertyDrawer(typeof(TonemappingColorGrading.IndentedGroup))] + private class IndentedGroupDrawer : PropertyDrawer + { + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + return 0f; + } + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + EditorGUILayout.LabelField(label, EditorStyles.boldLabel); + + EditorGUI.indentLevel++; + + foreach (SerializedProperty prop in property) + EditorGUILayout.PropertyField(prop); + + EditorGUI.indentLevel--; + } + } + + [CustomPropertyDrawer(typeof(TonemappingColorGrading.ChannelMixer))] + private class ChannelMixerDrawer : PropertyDrawer + { + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + return 0f; + } + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + // TODO: Hardcoded variable names, rewrite this function + if (property.type != "ChannelMixerSettings") + return; + + SerializedProperty currentChannel = property.FindPropertyRelative("currentChannel"); + int intCurrentChannel = currentChannel.intValue; + + EditorGUILayout.LabelField(label, EditorStyles.boldLabel); + + EditorGUI.indentLevel++; + + EditorGUILayout.BeginHorizontal(); + { + EditorGUILayout.PrefixLabel("Channel"); + if (GUILayout.Toggle(intCurrentChannel == 0, "Red", EditorStyles.miniButtonLeft)) intCurrentChannel = 0; + if (GUILayout.Toggle(intCurrentChannel == 1, "Green", EditorStyles.miniButtonMid)) intCurrentChannel = 1; + if (GUILayout.Toggle(intCurrentChannel == 2, "Blue", EditorStyles.miniButtonRight)) intCurrentChannel = 2; + } + EditorGUILayout.EndHorizontal(); + + SerializedProperty serializedChannel = property.FindPropertyRelative("channels").GetArrayElementAtIndex(intCurrentChannel); + currentChannel.intValue = intCurrentChannel; + + Vector3 v = serializedChannel.vector3Value; + v.x = EditorGUILayout.Slider("Red", v.x, -2f, 2f); + v.y = EditorGUILayout.Slider("Green", v.y, -2f, 2f); + v.z = EditorGUILayout.Slider("Blue", v.z, -2f, 2f); + serializedChannel.vector3Value = v; + + EditorGUI.indentLevel--; + } + } + + [CustomPropertyDrawer(typeof(TonemappingColorGrading.Curve))] + private class CurveDrawer : PropertyDrawer + { + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + TonemappingColorGrading.Curve attribute = (TonemappingColorGrading.Curve)base.attribute; + + if (property.propertyType != SerializedPropertyType.AnimationCurve) + { + EditorGUI.LabelField(position, label.text, "Use ClampCurve with an AnimationCurve."); + return; + } + + property.animationCurveValue = EditorGUI.CurveField(position, label, property.animationCurveValue, attribute.color, new Rect(0f, 0f, 1f, 1f)); + } + } + #endregion + + #region Styling + private static Styles s_Styles; + private class Styles + { + public GUIStyle thumb2D = "ColorPicker2DThumb"; + public Vector2 thumb2DSize; + + internal Styles() + { + thumb2DSize = new Vector2( + !Mathf.Approximately(thumb2D.fixedWidth, 0f) ? thumb2D.fixedWidth : thumb2D.padding.horizontal, + !Mathf.Approximately(thumb2D.fixedHeight, 0f) ? thumb2D.fixedHeight : thumb2D.padding.vertical + ); + } + } + + public static readonly Color masterCurveColor = new Color(1f, 1f, 1f, 2f); + public static readonly Color redCurveColor = new Color(1f, 0f, 0f, 2f); + public static readonly Color greenCurveColor = new Color(0f, 1f, 0f, 2f); + public static readonly Color blueCurveColor = new Color(0f, 1f, 1f, 2f); + #endregion + + private TonemappingColorGrading concreteTarget + { + get { return target as TonemappingColorGrading; } + } + + private static float pixelRatio + { + get + { + #if !(UNITY_3 || UNITY_4 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2 || UNITY_5_3) + return EditorGUIUtility.pixelsPerPoint; + #else + return 1f; + #endif + } + } + + private bool isHistogramSupported + { + get + { + return concreteTarget.histogramComputeShader != null + && ImageEffectHelper.supportsDX11 + && concreteTarget.histogramShader != null + && concreteTarget.histogramShader.isSupported; + } + } + + private enum HistogramMode + { + Red = 0, + Green = 1, + Blue = 2, + Luminance = 3, + RGB, + } + + private HistogramMode m_HistogramMode = HistogramMode.RGB; + private Rect m_HistogramRect; + private Material m_HistogramMaterial; + private ComputeBuffer m_HistogramBuffer; + private RenderTexture m_HistogramTexture; + + // settings group + private Dictionary> m_GroupFields = new Dictionary>(); + + private void PopulateMap(FieldInfo group) + { + var searchPath = group.Name + "."; + foreach (var setting in group.FieldType.GetFields(BindingFlags.Instance | BindingFlags.Public)) + { + List settingsGroup; + if (!m_GroupFields.TryGetValue(group, out settingsGroup)) + { + settingsGroup = new List(); + m_GroupFields[group] = settingsGroup; + } + + var property = serializedObject.FindProperty(searchPath + setting.Name); + if (property != null) + settingsGroup.Add(property); + } + } + + private void OnEnable() + { + var settingsGroups = typeof(TonemappingColorGrading).GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).Where(x => x.GetCustomAttributes(typeof(TonemappingColorGrading.SettingsGroup), false).Any()); + + foreach (var settingGroup in settingsGroups) + PopulateMap(settingGroup); + + concreteTarget.onFrameEndEditorOnly = OnFrameEnd; + } + + private void OnDisable() + { + concreteTarget.onFrameEndEditorOnly = null; + + if (m_HistogramMaterial != null) + DestroyImmediate(m_HistogramMaterial); + + if (m_HistogramTexture != null) + DestroyImmediate(m_HistogramTexture); + + if (m_HistogramBuffer != null) + m_HistogramBuffer.Release(); + } + + private void SetLUTImportSettings(TextureImporter importer) + { + importer.textureType = TextureImporterType.Default; + importer.anisoLevel = 0; + importer.mipmapEnabled = false; + importer.linearTexture = true; + importer.textureFormat = TextureImporterFormat.RGB24; + importer.SaveAndReimport(); + } + + private void DrawFields() + { + foreach (var group in m_GroupFields) + { + var enabledField = group.Value.FirstOrDefault(x => x.propertyPath == group.Key.Name + ".enabled"); + var groupProperty = serializedObject.FindProperty(group.Key.Name); + + GUILayout.Space(5); + bool display = EditorGUIHelper.Header(groupProperty, enabledField); + if (!display) + continue; + + GUILayout.BeginHorizontal(); + { + GUILayout.Space(10); + GUILayout.BeginVertical(); + { + GUILayout.Space(3); + foreach (var field in group.Value.Where(x => x.propertyPath != group.Key.Name + ".enabled")) + { + // Special case for the tonemapping curve field + if (group.Key.FieldType == typeof(TonemappingColorGrading.TonemappingSettings) && + field.propertyType == SerializedPropertyType.AnimationCurve && + concreteTarget.tonemapping.tonemapper != TonemappingColorGrading.Tonemapper.Curve) + continue; + + // Special case for the neutral tonemapper + bool neutralParam = field.name.StartsWith("neutral"); + + if (group.Key.FieldType == typeof(TonemappingColorGrading.TonemappingSettings) && + concreteTarget.tonemapping.tonemapper != TonemappingColorGrading.Tonemapper.Neutral && + neutralParam) + continue; + + if (neutralParam) + EditorGUILayout.PropertyField(field, new GUIContent(ObjectNames.NicifyVariableName(field.name.Substring(7)))); + else + EditorGUILayout.PropertyField(field); + } + + // Bake button + if (group.Key.FieldType == typeof(TonemappingColorGrading.ColorGradingSettings)) + { + EditorGUI.BeginDisabledGroup(!enabledField.boolValue); + + if (GUILayout.Button("Export LUT as PNG", EditorStyles.miniButton)) + { + string path = EditorUtility.SaveFilePanelInProject("Export LUT as PNG", "LUT.png", "png", "Please enter a file name to save the LUT texture to"); + + if (!string.IsNullOrEmpty(path)) + { + Texture2D lut = concreteTarget.BakeLUT(); + + if (!concreteTarget.isGammaColorSpace) + { + var pixels = lut.GetPixels(); + + for (int i = 0; i < pixels.Length; i++) + pixels[i] = pixels[i].linear; + + lut.SetPixels(pixels); + lut.Apply(); + } + + byte[] bytes = lut.EncodeToPNG(); + System.IO.File.WriteAllBytes(path, bytes); + DestroyImmediate(lut); + + AssetDatabase.Refresh(); + TextureImporter importer = (TextureImporter)AssetImporter.GetAtPath(path); + SetLUTImportSettings(importer); + } + } + + EditorGUI.EndDisabledGroup(); + } + } + GUILayout.EndVertical(); + } + GUILayout.EndHorizontal(); + } + } + + public override void OnInspectorGUI() + { + if (s_Styles == null) + s_Styles = new Styles(); + + serializedObject.Update(); + + GUILayout.Label("All following effects will use LDR color buffers.", EditorStyles.miniBoldLabel); + + if (concreteTarget.tonemapping.enabled) + { + Camera camera = concreteTarget.GetComponent(); + + if (camera != null && !camera.hdr) + EditorGUILayout.HelpBox("The camera is not HDR enabled. This will likely break the tonemapper.", MessageType.Warning); + else if (!concreteTarget.validRenderTextureFormat) + EditorGUILayout.HelpBox("The input to tonemapper is not in HDR. Make sure that all effects prior to this are executed in HDR.", MessageType.Warning); + } + + if (concreteTarget.lut.enabled && concreteTarget.lut.texture != null) + { + if (!concreteTarget.validUserLutSize) + { + EditorGUILayout.HelpBox("Invalid LUT size. Should be \"height = sqrt(width)\" (e.g. 256x16).", MessageType.Error); + } + else + { + // Checks import settings on the lut, offers to fix them if invalid + TextureImporter importer = (TextureImporter)AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(concreteTarget.lut.texture)); + bool valid = importer.anisoLevel == 0 + && importer.mipmapEnabled == false + && importer.linearTexture == true + && (importer.textureFormat == TextureImporterFormat.RGB24 || importer.textureFormat == TextureImporterFormat.AutomaticTruecolor); + + if (!valid) + { + EditorGUILayout.HelpBox("Invalid LUT import settings.", MessageType.Warning); + + GUILayout.Space(-32); + EditorGUILayout.BeginHorizontal(); + { + GUILayout.FlexibleSpace(); + if (GUILayout.Button("Fix", GUILayout.Width(60))) + { + SetLUTImportSettings(importer); + AssetDatabase.Refresh(); + } + GUILayout.Space(8); + } + EditorGUILayout.EndHorizontal(); + GUILayout.Space(11); + } + } + } + + DrawFields(); + + serializedObject.ApplyModifiedProperties(); + } + + private static readonly GUIContent k_HistogramTitle = new GUIContent("Histogram"); + public override GUIContent GetPreviewTitle() + { + return k_HistogramTitle; + } + + public override bool HasPreviewGUI() + { + return isHistogramSupported && targets.Length == 1 && concreteTarget != null && concreteTarget.enabled; + } + + public override void OnPreviewGUI(Rect r, GUIStyle background) + { + serializedObject.Update(); + + if (Event.current.type == EventType.Repaint) + { + // If m_HistogramRect isn't set the preview was just opened so refresh the render to get the histogram data + if (m_HistogramRect.width == 0 && m_HistogramRect.height == 0) + InternalEditorUtility.RepaintAllViews(); + + // Sizing + float width = Mathf.Min(512f, r.width); + float height = Mathf.Min(128f, r.height); + m_HistogramRect = new Rect( + Mathf.Floor(r.x + r.width / 2f - width / 2f), + Mathf.Floor(r.y + r.height / 2f - height / 2f), + width, height + ); + + if (m_HistogramTexture != null) + GUI.DrawTexture(m_HistogramRect, m_HistogramTexture); + } + + // Toolbar + GUILayout.BeginHorizontal(); + EditorGUI.BeginChangeCheck(); + { + concreteTarget.histogramRefreshOnPlay = GUILayout.Toggle(concreteTarget.histogramRefreshOnPlay, new GUIContent("Refresh on Play", "Keep refreshing the histogram in play mode; this may impact performances."), EditorStyles.miniButton); + GUILayout.FlexibleSpace(); + m_HistogramMode = (HistogramMode)EditorGUILayout.EnumPopup(m_HistogramMode); + } + GUILayout.EndHorizontal(); + + serializedObject.ApplyModifiedProperties(); + + if (EditorGUI.EndChangeCheck()) + InternalEditorUtility.RepaintAllViews(); + } + + private void OnFrameEnd(RenderTexture source) + { + if (Application.isPlaying && !concreteTarget.histogramRefreshOnPlay) + return; + + if (Mathf.Approximately(m_HistogramRect.width, 0) || Mathf.Approximately(m_HistogramRect.height, 0) || !isHistogramSupported) + return; + + // No need to process the full frame to get an histogram, resize the input to a max-size of 512 + int rw = Mathf.Min(Mathf.Max(source.width, source.height), 512); + RenderTexture rt = RenderTexture.GetTemporary(rw, rw, 0); + Graphics.Blit(source, rt); + UpdateHistogram(rt, m_HistogramRect, m_HistogramMode); + Repaint(); + RenderTexture.ReleaseTemporary(rt); + RenderTexture.active = null; + } + + private static readonly int[] k_EmptyBuffer = new int[256 << 2]; + void UpdateHistogram(RenderTexture source, Rect rect, HistogramMode mode) + { + if (m_HistogramMaterial == null) + m_HistogramMaterial = ImageEffectHelper.CheckShaderAndCreateMaterial(concreteTarget.histogramShader); + + if (m_HistogramBuffer == null) + m_HistogramBuffer = new ComputeBuffer(256, sizeof(uint) << 2); + + m_HistogramBuffer.SetData(k_EmptyBuffer); + + ComputeShader cs = concreteTarget.histogramComputeShader; + + int kernel = cs.FindKernel("KHistogramGather"); + cs.SetBuffer(kernel, "_Histogram", m_HistogramBuffer); + cs.SetTexture(kernel, "_Source", source); + + int[] channels = null; + switch (mode) + { + case HistogramMode.Luminance: + channels = new[] { 0, 0, 0, 1 }; + break; + case HistogramMode.RGB: + channels = new[] { 1, 1, 1, 0 }; + break; + case HistogramMode.Red: + channels = new[] { 1, 0, 0, 0 }; + break; + case HistogramMode.Green: + channels = new[] { 0, 1, 0, 0 }; + break; + case HistogramMode.Blue: + channels = new[] { 0, 0, 1, 0 }; + break; + } + + cs.SetInts("_Channels", channels); + cs.SetInt("_IsLinear", concreteTarget.isGammaColorSpace ? 0 : 1); + cs.Dispatch(kernel, Mathf.CeilToInt(source.width / 32f), Mathf.CeilToInt(source.height / 32f), 1); + + kernel = cs.FindKernel("KHistogramScale"); + cs.SetBuffer(kernel, "_Histogram", m_HistogramBuffer); + cs.SetFloat("_Height", rect.height); + cs.Dispatch(kernel, 1, 1, 1); + + if (m_HistogramTexture == null) + { + DestroyImmediate(m_HistogramTexture); + m_HistogramTexture = new RenderTexture((int)rect.width, (int)rect.height, 0, RenderTextureFormat.ARGB32); + m_HistogramTexture.hideFlags = HideFlags.HideAndDontSave; + } + + m_HistogramMaterial.SetBuffer("_Histogram", m_HistogramBuffer); + m_HistogramMaterial.SetVector("_Size", new Vector2(m_HistogramTexture.width, m_HistogramTexture.height)); + m_HistogramMaterial.SetColor("_ColorR", redCurveColor); + m_HistogramMaterial.SetColor("_ColorG", greenCurveColor); + m_HistogramMaterial.SetColor("_ColorB", blueCurveColor); + m_HistogramMaterial.SetColor("_ColorL", masterCurveColor); + m_HistogramMaterial.SetInt("_Channel", (int)mode); + Graphics.Blit(m_HistogramTexture, m_HistogramTexture, m_HistogramMaterial, (mode == HistogramMode.RGB) ? 1 : 0); + } + + public static class ColorWheel + { + // Constants + private const float PI_2 = Mathf.PI / 2f; + private const float PI2 = Mathf.PI * 2f; + + // hue Wheel + private static Texture2D s_WheelTexture; + private static float s_LastDiameter; + private static GUIStyle s_CenteredStyle; + + public static Color DoGUI(Rect area, string title, Color color, float diameter) + { + var labelrect = area; + labelrect.height = EditorGUIUtility.singleLineHeight; + + if (s_CenteredStyle == null) + { + s_CenteredStyle = new GUIStyle(GUI.skin.GetStyle("Label")) + { + alignment = TextAnchor.UpperCenter + }; + } + + GUI.Label(labelrect, title, s_CenteredStyle); + + // Figure out the wheel draw area + var wheelDrawArea = area; + wheelDrawArea.y += EditorGUIUtility.singleLineHeight; + wheelDrawArea.height = diameter; + + if (wheelDrawArea.width > wheelDrawArea.height) + { + wheelDrawArea.x += (wheelDrawArea.width - wheelDrawArea.height) / 2.0f; + wheelDrawArea.width = area.height; + } + + wheelDrawArea.width = wheelDrawArea.height; + + var radius = diameter / 2.0f; + Vector3 hsv; + Color.RGBToHSV(color, out hsv.x, out hsv.y, out hsv.z); + + // Retina/HDPI screens handling + wheelDrawArea.width /= pixelRatio; + wheelDrawArea.height /= pixelRatio; + float scaledRadius = radius / pixelRatio; + + if (Event.current.type == EventType.Repaint) + { + if (!Mathf.Approximately(diameter, s_LastDiameter)) + { + s_LastDiameter = diameter; + UpdateHueWheel((int)diameter); + } + + // Wheel + GUI.DrawTexture(wheelDrawArea, s_WheelTexture); + + // Thumb + Vector2 thumbPos = Vector2.zero; + float theta = hsv.x * PI2; + float len = hsv.y * scaledRadius; + thumbPos.x = Mathf.Cos(theta + PI_2); + thumbPos.y = Mathf.Sin(theta - PI_2); + thumbPos *= len; + Vector2 thumbSize = s_Styles.thumb2DSize; + Color oldColor = GUI.color; + GUI.color = Color.black; + Vector2 thumbSizeH = thumbSize / 2f; + Handles.color = Color.white; + Handles.DrawAAPolyLine(new Vector2(wheelDrawArea.x + scaledRadius + thumbSizeH.x, wheelDrawArea.y + scaledRadius + thumbSizeH.y), new Vector2(wheelDrawArea.x + scaledRadius + thumbPos.x, wheelDrawArea.y + scaledRadius + thumbPos.y)); + s_Styles.thumb2D.Draw(new Rect(wheelDrawArea.x + scaledRadius + thumbPos.x - thumbSizeH.x, wheelDrawArea.y + scaledRadius + thumbPos.y - thumbSizeH.y, thumbSize.x, thumbSize.y), false, false, false, false); + GUI.color = oldColor; + } + hsv = GetInput(wheelDrawArea, hsv, scaledRadius); + + var sliderDrawArea = wheelDrawArea; + sliderDrawArea.y = sliderDrawArea.yMax; + sliderDrawArea.height = EditorGUIUtility.singleLineHeight; + + hsv.y = GUI.HorizontalSlider(sliderDrawArea, hsv.y, 1e-04f, 1f); + color = Color.HSVToRGB(hsv.x, hsv.y, hsv.z); + return color; + } + + private static readonly int k_ThumbHash = "colorWheelThumb".GetHashCode(); + + private static Vector3 GetInput(Rect bounds, Vector3 hsv, float radius) + { + Event e = Event.current; + var id = GUIUtility.GetControlID(k_ThumbHash, FocusType.Passive, bounds); + + Vector2 mousePos = e.mousePosition; + Vector2 relativePos = mousePos - new Vector2(bounds.x, bounds.y); + + if (e.type == EventType.MouseDown && e.button == 0 && GUIUtility.hotControl == 0) + { + if (bounds.Contains(mousePos)) + { + Vector2 center = new Vector2(bounds.x + radius, bounds.y + radius); + float dist = Vector2.Distance(center, mousePos); + + if (dist <= radius) + { + e.Use(); + GetWheelHueSaturation(relativePos.x, relativePos.y, radius, out hsv.x, out hsv.y); + GUIUtility.hotControl = id; + } + } + } + else if (e.type == EventType.MouseDrag && e.button == 0 && GUIUtility.hotControl == id) + { + Vector2 center = new Vector2(bounds.x + radius, bounds.y + radius); + float dist = Vector2.Distance(center, mousePos); + + if (dist <= radius) + { + e.Use(); + GetWheelHueSaturation(relativePos.x, relativePos.y, radius, out hsv.x, out hsv.y); + } + } + else if (e.type == EventType.MouseUp && e.button == 0 && GUIUtility.hotControl == id) + { + e.Use(); + GUIUtility.hotControl = 0; + } + + return hsv; + } + + private static void GetWheelHueSaturation(float x, float y, float radius, out float hue, out float saturation) + { + float dx = (x - radius) / radius; + float dy = (y - radius) / radius; + float d = Mathf.Sqrt(dx * dx + dy * dy); + hue = Mathf.Atan2(dx, -dy); + hue = 1f - ((hue > 0) ? hue : PI2 + hue) / PI2; + saturation = Mathf.Clamp01(d); + } + + private static void UpdateHueWheel(int diameter) + { + CleanTexture(s_WheelTexture); + s_WheelTexture = MakeTexture(diameter); + + var radius = diameter / 2.0f; + + Color[] pixels = s_WheelTexture.GetPixels(); + + for (int y = 0; y < diameter; y++) + { + for (int x = 0; x < diameter; x++) + { + int index = y * diameter + x; + float dx = (x - radius) / radius; + float dy = (y - radius) / radius; + float d = Mathf.Sqrt(dx * dx + dy * dy); + + // Out of the wheel, early exit + if (d >= 1f) + { + pixels[index] = new Color(0f, 0f, 0f, 0f); + continue; + } + + // red (0) on top, counter-clockwise (industry standard) + float saturation = d; + float hue = Mathf.Atan2(dx, dy); + hue = 1f - ((hue > 0) ? hue : PI2 + hue) / PI2; + Color color = Color.HSVToRGB(hue, saturation, 1f); + + // Quick & dirty antialiasing + color.a = (saturation > 0.99) ? (1f - saturation) * 100f : 1f; + + pixels[index] = color; + } + } + + s_WheelTexture.SetPixels(pixels); + s_WheelTexture.Apply(); + } + + private static Texture2D MakeTexture(int dimension) + { + return new Texture2D(dimension, dimension, TextureFormat.ARGB32, false, true) + { + filterMode = FilterMode.Point, + wrapMode = TextureWrapMode.Clamp, + hideFlags = HideFlags.HideAndDontSave, + alphaIsTransparency = true + }; + } + + private static void CleanTexture(Texture2D texture) + { + if (texture != null) + DestroyImmediate(texture); + } + + public static float GetColorWheelHeight(int renderSizePerWheel) + { + // wheel height + title label + alpha slider + return renderSizePerWheel + 2 * EditorGUIUtility.singleLineHeight; + } + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Editor/TonemappingColorGradingEditor.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Editor/TonemappingColorGradingEditor.cs.meta new file mode 100644 index 0000000..51e5b4a --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Editor/TonemappingColorGradingEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 64bb64b30a05a0d4b8afe58a356fc8fb +timeCreated: 1441354689 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Helpers.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Helpers.meta new file mode 100644 index 0000000..e7cf980 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Helpers.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 54915b6fdd14fd042add2d153a8b892d +folderAsset: yes +timeCreated: 1454073138 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Helpers/NeutralLUT16.png b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Helpers/NeutralLUT16.png new file mode 100644 index 0000000..0e4bda4 Binary files /dev/null and b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Helpers/NeutralLUT16.png differ diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Helpers/NeutralLUT16.png.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Helpers/NeutralLUT16.png.meta new file mode 100644 index 0000000..667bfbb --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Helpers/NeutralLUT16.png.meta @@ -0,0 +1,57 @@ +fileFormatVersion: 2 +guid: 36c322ded1667bc4a867aea5e662c51b +timeCreated: 1454073156 +licenseType: Store +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 7 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: 3 + maxTextureSize: 2048 + textureSettings: + filterMode: -1 + aniso: 0 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + allowsAlphaSplitting: 0 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: 5 + buildTargetSettings: [] + spriteSheet: + sprites: [] + outline: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Helpers/NeutralLUT32.png b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Helpers/NeutralLUT32.png new file mode 100644 index 0000000..b8724d4 Binary files /dev/null and b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Helpers/NeutralLUT32.png differ diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Helpers/NeutralLUT32.png.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Helpers/NeutralLUT32.png.meta new file mode 100644 index 0000000..6e85fa8 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Helpers/NeutralLUT32.png.meta @@ -0,0 +1,57 @@ +fileFormatVersion: 2 +guid: 6ac6980bae76ac241971e97191b6c30c +timeCreated: 1454073159 +licenseType: Store +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 7 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: 3 + maxTextureSize: 2048 + textureSettings: + filterMode: -1 + aniso: 0 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + allowsAlphaSplitting: 0 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: 5 + buildTargetSettings: [] + spriteSheet: + sprites: [] + outline: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources.meta new file mode 100644 index 0000000..3e60aaf --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 710c12a933657234f859808d82c5dd8b +folderAsset: yes +timeCreated: 1453901184 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/HistogramCompute.compute b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/HistogramCompute.compute new file mode 100644 index 0000000..0e45d61 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/HistogramCompute.compute @@ -0,0 +1,85 @@ +#include "UnityCG.cginc" + +RWStructuredBuffer _Histogram; +Texture2D _Source; + +CBUFFER_START (Params) + uint4 _Channels; + uint _IsLinear; + float _Height; +CBUFFER_END + +// Gathering pass +groupshared uint4 gs_histogram[256]; + +#pragma kernel KHistogramGather +[numthreads(32,32,1)] // Needs at least 256 threads per group +void KHistogramGather(uint3 id : SV_DispatchThreadID, uint3 _group_thread_id : SV_GroupThreadID) +{ + const uint thread_id = _group_thread_id.y * 32 + _group_thread_id.x; + + if (thread_id < 256) + gs_histogram[thread_id] = uint4(0, 0, 0, 0); + + uint sw, sh; + _Source.GetDimensions(sw, sh); + + GroupMemoryBarrierWithGroupSync(); + + if (id.x < sw && id.y < sh) + { + // We want a gamma histogram (like Photoshop & all) + float3 color = saturate(_Source[id.xy].xyz); + if (_IsLinear > 0) + color = LinearToGammaSpace(color); + + // Convert color & luminance to histogram bin + uint3 idx_c = (uint3)(round(color * 255.0)); + uint idx_l = (uint)(round(dot(color.rgb, float3(0.2126, 0.7152, 0.0722)) * 255.0)); + + // Fill the group shared histogram + if (_Channels.r > 0) InterlockedAdd(gs_histogram[idx_c.x].x, 1); // Red + if (_Channels.g > 0) InterlockedAdd(gs_histogram[idx_c.y].y, 1); // Green + if (_Channels.b > 0) InterlockedAdd(gs_histogram[idx_c.z].z, 1); // Blue + if (_Channels.a > 0) InterlockedAdd(gs_histogram[idx_l].w, 1); // Luminance + } + + GroupMemoryBarrierWithGroupSync(); + + // Merge + if (thread_id < 256) + { + uint4 h = gs_histogram[thread_id]; + InterlockedAdd(_Histogram[thread_id].x, h.x); // Red + InterlockedAdd(_Histogram[thread_id].y, h.y); // Green + InterlockedAdd(_Histogram[thread_id].z, h.z); // Blue + InterlockedAdd(_Histogram[thread_id].w, h.w); // Luminance + } +} + +// Scaling pass +groupshared uint4 gs_pyramid[256]; + +#pragma kernel KHistogramScale +[numthreads(16,16,1)] +void KHistogramScale(uint3 _group_thread_id : SV_GroupThreadID) +{ + const uint thread_id = _group_thread_id.y * 16 + _group_thread_id.x; + gs_pyramid[thread_id] = _Histogram[thread_id]; + + GroupMemoryBarrierWithGroupSync(); + + // Parallel reduction to find the max value + [unroll] + for(uint i = 256 >> 1; i > 0; i >>= 1) + { + if(thread_id < i) + gs_pyramid[thread_id] = max(gs_pyramid[thread_id], gs_pyramid[thread_id + i]); + + GroupMemoryBarrierWithGroupSync(); + } + + // Actual scaling + float4 factor = _Height / (float4)gs_pyramid[0]; + _Histogram[thread_id] = (uint4)round(_Histogram[thread_id] * factor); +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/HistogramCompute.compute.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/HistogramCompute.compute.meta new file mode 100644 index 0000000..3dc83f2 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/HistogramCompute.compute.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 5ee4b74fa28a3e74e89423dd49705fc5 +timeCreated: 1436170077 +licenseType: Store +ComputeShaderImporter: + currentBuildTarget: 5 + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/HistogramRender.shader b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/HistogramRender.shader new file mode 100644 index 0000000..c78673c --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/HistogramRender.shader @@ -0,0 +1,104 @@ +Shader "Hidden/TonemappingColorGradingHistogram" +{ + SubShader + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + CGINCLUDE + + #pragma fragmentoption ARB_precision_hint_fastest + #pragma target 5.0 + #include "UnityCG.cginc" + + struct v_data + { + float4 pos : SV_POSITION; + float2 uv : TEXCOORD0; + }; + + StructuredBuffer _Histogram; + float2 _Size; + uint _Channel; + float4 _ColorR; + float4 _ColorG; + float4 _ColorB; + float4 _ColorL; + + v_data vert(appdata_img v) + { + v_data o; + o.pos = mul(UNITY_MATRIX_MVP, v.vertex); + o.uv = v.texcoord; + return o; + } + + float4 frag_channel(v_data i) : SV_Target + { + const float4 COLORS[4] = { _ColorR, _ColorG, _ColorB, _ColorL }; + + float remapI = i.uv.x * 255.0; + uint index = floor(remapI); + float delta = frac(remapI); + float v1 = _Histogram[index][_Channel]; + float v2 = _Histogram[min(index + 1, 255)][_Channel]; + float h = v1 * (1.0 - delta) + v2 * delta; + uint y = (uint)round(i.uv.y * _Size.y); + + float4 color = float4(0.0, 0.0, 0.0, 0.0); + float fill = step(y, h); + color = lerp(color, COLORS[_Channel], fill); + return color; + } + + float4 frag_rgb(v_data i) : SV_Target + { + const float4 COLORS[3] = { _ColorR, _ColorG, _ColorB }; + + float4 targetColor = float4(0.0, 0.0, 0.0, 0.0); + float4 emptyColor = float4(0.0, 0.0, 0.0, 0.0); + float fill = 0; + + for (int j = 0; j < 3; j++) + { + float remapI = i.uv.x * 255.0; + uint index = floor(remapI); + float delta = frac(remapI); + float v1 = _Histogram[index][j]; + float v2 = _Histogram[min(index + 1, 255)][j]; + float h = v1 * (1.0 - delta) + v2 * delta; + uint y = (uint)round(i.uv.y * _Size.y); + float fill = step(y, h); + float4 color = lerp(emptyColor, COLORS[j], fill); + targetColor += color; + } + + return saturate(targetColor); + } + + ENDCG + + // (0) Channel + Pass + { + CGPROGRAM + + #pragma vertex vert + #pragma fragment frag_channel + + ENDCG + } + + // (1) RGB + Pass + { + CGPROGRAM + + #pragma vertex vert + #pragma fragment frag_rgb + + ENDCG + } + } + FallBack off +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/HistogramRender.shader.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/HistogramRender.shader.meta new file mode 100644 index 0000000..75e246a --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/HistogramRender.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 9a8e838691462194482a43a02e424876 +timeCreated: 1436173774 +licenseType: Store +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.cginc b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.cginc new file mode 100644 index 0000000..bad7822 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.cginc @@ -0,0 +1,260 @@ +#include "UnityCG.cginc" + +sampler2D _MainTex; +half4 _MainTex_TexelSize; + +half _Exposure; +half _ToneCurveRange; +sampler2D _ToneCurve; +half4 _NeutralTonemapperParams1; +half4 _NeutralTonemapperParams2; + +sampler2D _InternalLutTex; +half3 _InternalLutParams; + +sampler2D _UserLutTex; +half4 _UserLutParams; + +sampler2D _LumTex; +half _AdaptationSpeed; +half _MiddleGrey; +half _AdaptationMin; +half _AdaptationMax; + +inline half LinToPerceptual(half3 color) +{ + half lum = Luminance(color); + return log(max(lum, 0.001)); +} + +inline half PerceptualToLin(half f) +{ + return exp(f); +} + +half4 frag_log(v2f_img i) : SV_Target +{ + half sum = 0.0; + sum += LinToPerceptual(tex2D(_MainTex, i.uv + _MainTex_TexelSize.xy * half2(-1,-1)).rgb); + sum += LinToPerceptual(tex2D(_MainTex, i.uv + _MainTex_TexelSize.xy * half2( 1, 1)).rgb); + sum += LinToPerceptual(tex2D(_MainTex, i.uv + _MainTex_TexelSize.xy * half2(-1, 1)).rgb); + sum += LinToPerceptual(tex2D(_MainTex, i.uv + _MainTex_TexelSize.xy * half2( 1,-1)).rgb); + half avg = sum / 4.0; + return half4(avg, avg, avg, avg); +} + +half4 frag_exp(v2f_img i) : SV_Target +{ + half sum = 0.0; + sum += tex2D(_MainTex, i.uv + _MainTex_TexelSize.xy * half2(-1,-1)).x; + sum += tex2D(_MainTex, i.uv + _MainTex_TexelSize.xy * half2( 1, 1)).x; + sum += tex2D(_MainTex, i.uv + _MainTex_TexelSize.xy * half2( 1,-1)).x; + sum += tex2D(_MainTex, i.uv + _MainTex_TexelSize.xy * half2(-1, 1)).x; + half avg = PerceptualToLin(sum / 4.0); + return half4(avg, avg, avg, saturate(0.0125 * _AdaptationSpeed)); +} + +half3 apply_lut(sampler2D tex, half3 uvw, half3 scaleOffset) +{ + // Strip format where `height = sqrt(width)` + uvw.z *= scaleOffset.z; + half shift = floor(uvw.z); + uvw.xy = uvw.xy * scaleOffset.z * scaleOffset.xy + scaleOffset.xy * 0.5; + uvw.x += shift * scaleOffset.y; + uvw.xyz = lerp(tex2D(tex, uvw.xy).rgb, tex2D(tex, uvw.xy + half2(scaleOffset.y, 0)).rgb, uvw.z - shift); + return uvw; +} + +half3 ToCIE(half3 color) +{ + // RGB -> XYZ conversion + // http://www.w3.org/Graphics/Color/sRGB + // The official sRGB to XYZ conversion matrix is (following ITU-R BT.709) + // 0.4125 0.3576 0.1805 + // 0.2126 0.7152 0.0722 + // 0.0193 0.1192 0.9505 + half3x3 RGB2XYZ = { 0.5141364, 0.3238786, 0.16036376, 0.265068, 0.67023428, 0.06409157, 0.0241188, 0.1228178, 0.84442666 }; + half3 XYZ = mul(RGB2XYZ, color.rgb); + + // XYZ -> Yxy conversion + half3 Yxy; + Yxy.r = XYZ.g; + half temp = dot(half3(1.0, 1.0, 1.0), XYZ.rgb); + Yxy.gb = XYZ.rg / temp; + return Yxy; +} + +half3 FromCIE(half3 Yxy) +{ + // Yxy -> XYZ conversion + half3 XYZ; + XYZ.r = Yxy.r * Yxy.g / Yxy.b; + XYZ.g = Yxy.r; + + // Copy luminance Y + XYZ.b = Yxy.r * (1 - Yxy.g - Yxy.b) / Yxy.b; + + // XYZ -> RGB conversion + // The official XYZ to sRGB conversion matrix is (following ITU-R BT.709) + // 3.2410 -1.5374 -0.4986 + // -0.9692 1.8760 0.0416 + // 0.0556 -0.2040 1.0570 + half3x3 XYZ2RGB = { 2.5651, -1.1665, -0.3986, -1.0217, 1.9777, 0.0439, 0.0753, -0.2543, 1.1892 }; + return mul(XYZ2RGB, XYZ); +} + +half3 tonemapACES(half3 color) +{ + color *= _Exposure; + + // See https://knarkowicz.wordpress.com/2016/01/06/aces-filmic-tone-mapping-curve/ + const half a = 2.51; + const half b = 0.03; + const half c = 2.43; + const half d = 0.59; + const half e = 0.14; + return saturate((color * (a * color + b)) / (color * (c * color + d) + e)); +} + +half3 tonemapPhotographic(half3 color) +{ + color *= _Exposure; + return 1.0 - exp2(-color); +} + +half3 tonemapHable(half3 color) +{ + const half a = 0.15; + const half b = 0.50; + const half c = 0.10; + const half d = 0.20; + const half e = 0.02; + const half f = 0.30; + const half w = 11.2; + + color *= _Exposure * 2.0; + half3 curr = ((color * (a * color + c * b) + d * e) / (color * (a * color + b) + d * f)) - e / f; + color = w; + half3 whiteScale = 1.0 / (((color * (a * color + c * b) + d * e) / (color * (a * color + b) + d * f)) - e / f); + return curr * whiteScale; +} + +half3 tonemapHejlDawson(half3 color) +{ + const half a = 6.2; + const half b = 0.5; + const half c = 1.7; + const half d = 0.06; + + color *= _Exposure; + color = max((0.0).xxx, color - (0.004).xxx); + color = (color * (a * color + b)) / (color * (a * color + c) + d); + return color * color; +} + +half3 tonemapReinhard(half3 color) +{ + half lum = Luminance(color); + half lumTm = lum * _Exposure; + half scale = lumTm / (1.0 + lumTm); + return color * scale / lum; +} + +half3 tonemapCurve(half3 color) +{ + color *= _Exposure; + half3 cie = ToCIE(color); + half newLum = tex2D(_ToneCurve, half2(cie.r * _ToneCurveRange, 0.5)).r; + cie.r = newLum; + return FromCIE(cie); +} + +half3 neutralCurve(half3 x, half a, half b, half c, half d, half e, half f) +{ + return ((x * (a * x + c * b) + d * e) / (x * (a * x + b) + d * f)) - e / f; +} + +half3 tonemapNeutral(half3 color) +{ + color *= _Exposure; + + // Tonemap + half a = _NeutralTonemapperParams1.x; + half b = _NeutralTonemapperParams1.y; + half c = _NeutralTonemapperParams1.z; + half d = _NeutralTonemapperParams1.w; + half e = _NeutralTonemapperParams2.x; + half f = _NeutralTonemapperParams2.y; + half whiteLevel = _NeutralTonemapperParams2.z; + half whiteClip = _NeutralTonemapperParams2.w; + + half3 whiteScale = (1.0).xxx / neutralCurve(whiteLevel, a, b, c, d, e, f); + color = neutralCurve(color * whiteScale, a, b, c, d, e, f); + color *= whiteScale; + + // Post-curve white point adjustment + color = color / whiteClip.xxx; + + return color; +} + +half4 frag_tcg(v2f_img i) : SV_Target +{ + half4 color = tex2D(_MainTex, i.uv); + +#if UNITY_COLORSPACE_GAMMA + color.rgb = GammaToLinearSpace(color.rgb); +#endif + +#if ENABLE_EYE_ADAPTATION + // Fast eye adaptation + half avg_luminance = tex2D(_LumTex, i.uv).x; + half linear_exposure = _MiddleGrey / avg_luminance; + color.rgb *= max(_AdaptationMin, min(_AdaptationMax, linear_exposure)); +#endif + +#if defined(TONEMAPPING_ACES) + color.rgb = tonemapACES(color.rgb); +#elif defined(TONEMAPPING_CURVE) + color.rgb = tonemapCurve(color.rgb); +#elif defined(TONEMAPPING_HABLE) + color.rgb = tonemapHable(color.rgb); +#elif defined(TONEMAPPING_HEJL_DAWSON) + color.rgb = tonemapHejlDawson(color.rgb); +#elif defined(TONEMAPPING_PHOTOGRAPHIC) + color.rgb = tonemapPhotographic(color.rgb); +#elif defined(TONEMAPPING_REINHARD) + color.rgb = tonemapReinhard(color.rgb); +#elif defined(TONEMAPPING_NEUTRAL) + color.rgb = tonemapNeutral(color.rgb); +#endif + +#if ENABLE_COLOR_GRADING + // LUT color grading + color.rgb = apply_lut(_InternalLutTex, saturate(color.rgb), _InternalLutParams); +#endif + +#if ENABLE_DITHERING + // Interleaved Gradient Noise from http://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare (slide 122) + half3 magic = float3(0.06711056, 0.00583715, 52.9829189); + half gradient = frac(magic.z * frac(dot(i.uv / _MainTex_TexelSize, magic.xy))) / 255.0; + color.rgb -= gradient.xxx; +#endif + +#if UNITY_COLORSPACE_GAMMA + color.rgb = LinearToGammaSpace(color.rgb); +#endif + +#if ENABLE_USER_LUT + #if !UNITY_COLORSPACE_GAMMA + half3 lc = apply_lut(_UserLutTex, saturate(LinearToGammaSpace(color.rgb)), _UserLutParams.xyz); + lc = GammaToLinearSpace(lc); + #else + half3 lc = apply_lut(_UserLutTex, saturate(color.rgb), _UserLutParams.xyz); + #endif + + color.rgb = lerp(color.rgb, lc, _UserLutParams.w); +#endif + + return color; +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.cginc.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.cginc.meta new file mode 100644 index 0000000..5609bcd --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.cginc.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: a7e68b07525bc7f459ff03bf6cba782a +timeCreated: 1453723607 +licenseType: Store +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.shader b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.shader new file mode 100644 index 0000000..ab303dd --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.shader @@ -0,0 +1,305 @@ +Shader "Hidden/TonemappingColorGrading" +{ + Properties + { + _MainTex ("Texture", 2D) = "white" {} + } + + CGINCLUDE + + #pragma vertex vert_img + #pragma fragmentoption ARB_precision_hint_fastest + #pragma target 3.0 + + ENDCG + + SubShader + { + ZTest Always Cull Off ZWrite Off + Fog { Mode off } + + // Lut generator + Pass + { + CGPROGRAM + + #pragma fragment frag_lut_gen + #include "TonemappingColorGrading.cginc" + + half3 _WhiteBalance; + half3 _Lift; + half3 _Gamma; + half3 _Gain; + half3 _ContrastGainGamma; + half _Vibrance; + half3 _HSV; + half3 _ChannelMixerRed; + half3 _ChannelMixerGreen; + half3 _ChannelMixerBlue; + sampler2D _CurveTex; + half _Contribution; + + static const half3x3 LIN_2_LMS_MAT = { + 3.90405e-1, 5.49941e-1, 8.92632e-3, + 7.08416e-2, 9.63172e-1, 1.35775e-3, + 2.31082e-2, 1.28021e-1, 9.36245e-1 + }; + + static const half3x3 LMS_2_LIN_MAT = { + 2.85847e+0, -1.62879e+0, -2.48910e-2, + -2.10182e-1, 1.15820e+0, 3.24281e-4, + -4.18120e-2, -1.18169e-1, 1.06867e+0 + }; + + half3 rgb_to_hsv(half3 c) + { + half4 K = half4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); + half4 p = lerp(half4(c.bg, K.wz), half4(c.gb, K.xy), step(c.b, c.g)); + half4 q = lerp(half4(p.xyw, c.r), half4(c.r, p.yzx), step(p.x, c.r)); + half d = q.x - min(q.w, q.y); + half e = 1.0e-4; + return half3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); + } + + half3 hsv_to_rgb(half3 c) + { + half4 K = half4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); + half3 p = abs(frac(c.xxx + K.xyz) * 6.0 - K.www); + return c.z * lerp(K.xxx, saturate(p - K.xxx), c.y); + } + + // CG's fmod() is not the same as GLSL's mod() with negative values, we'll use our own + inline half gmod(half x, half y) + { + return x - y * floor(x / y); + } + + half4 frag_lut_gen(v2f_img i) : SV_Target + { + half3 neutral_lut = tex2D(_MainTex, i.uv).rgb; + half3 final_lut = neutral_lut; + + // White balance + half3 lms = mul(LIN_2_LMS_MAT, final_lut); + lms *= _WhiteBalance; + final_lut = mul(LMS_2_LIN_MAT, lms); + + // Lift/gamma/gain + final_lut = _Gain * (_Lift * (1.0 - final_lut) + pow(final_lut, _Gamma)); + final_lut = max(final_lut, 0.0); + + // Hue/saturation/value + half3 hsv = rgb_to_hsv(final_lut); + hsv.x = gmod(hsv.x + _HSV.x, 1.0); + hsv.yz *= _HSV.yz; + final_lut = saturate(hsv_to_rgb(hsv)); + + // Vibrance + half sat = max(final_lut.r, max(final_lut.g, final_lut.b)) - min(final_lut.r, min(final_lut.g, final_lut.b)); + final_lut = lerp(Luminance(final_lut).xxx, final_lut, (1.0 + (_Vibrance * (1.0 - (sign(_Vibrance) * sat))))); + + // Contrast + final_lut = saturate((final_lut - 0.5) * _ContrastGainGamma.x + 0.5); + + // Gain + half f = pow(2.0, _ContrastGainGamma.y) * 0.5; + final_lut = (final_lut < 0.5) ? pow(final_lut, _ContrastGainGamma.y) * f : 1.0 - pow(1.0 - final_lut, _ContrastGainGamma.y) * f; + + // Gamma + final_lut = pow(final_lut, _ContrastGainGamma.z); + + // Color mixer + final_lut = half3( + dot(final_lut, _ChannelMixerRed), + dot(final_lut, _ChannelMixerGreen), + dot(final_lut, _ChannelMixerBlue) + ); + + // Curves + half mr = tex2D(_CurveTex, half2(final_lut.r, 0.5)).a; + half mg = tex2D(_CurveTex, half2(final_lut.g, 0.5)).a; + half mb = tex2D(_CurveTex, half2(final_lut.b, 0.5)).a; + final_lut = half3(mr, mg, mb); + half r = tex2D(_CurveTex, half2(final_lut.r, 0.5)).r; + half g = tex2D(_CurveTex, half2(final_lut.g, 0.5)).g; + half b = tex2D(_CurveTex, half2(final_lut.b, 0.5)).b; + final_lut = half3(r, g, b); + + return half4(final_lut, 1.0); + } + + ENDCG + } + + // The three following passes are used to get an average log luminance using a downsample pyramid + Pass + { + CGPROGRAM + #pragma fragment frag_log + #include "TonemappingColorGrading.cginc" + ENDCG + } + + Pass + { + Blend SrcAlpha OneMinusSrcAlpha + + CGPROGRAM + #pragma fragment frag_exp + #include "TonemappingColorGrading.cginc" + ENDCG + } + + Pass + { + Blend Off + + CGPROGRAM + #pragma fragment frag_exp + #include "TonemappingColorGrading.cginc" + ENDCG + } + + // Tonemapping off + Pass + { + CGPROGRAM + #pragma multi_compile __ UNITY_COLORSPACE_GAMMA + #pragma multi_compile __ ENABLE_COLOR_GRADING + #pragma multi_compile __ ENABLE_EYE_ADAPTATION + #pragma multi_compile __ ENABLE_DITHERING + #pragma multi_compile __ ENABLE_USER_LUT + #pragma fragment frag_tcg + #include "TonemappingColorGrading.cginc" + ENDCG + } + + // Tonemapping (ACES) + Pass + { + CGPROGRAM + #pragma multi_compile __ UNITY_COLORSPACE_GAMMA + #pragma multi_compile __ ENABLE_COLOR_GRADING + #pragma multi_compile __ ENABLE_EYE_ADAPTATION + #pragma multi_compile __ ENABLE_DITHERING + #pragma multi_compile __ ENABLE_USER_LUT + #pragma fragment frag_tcg + #define TONEMAPPING_ACES + #include "TonemappingColorGrading.cginc" + ENDCG + } + + // Tonemapping (Curve) + Pass + { + CGPROGRAM + #pragma multi_compile __ UNITY_COLORSPACE_GAMMA + #pragma multi_compile __ ENABLE_COLOR_GRADING + #pragma multi_compile __ ENABLE_EYE_ADAPTATION + #pragma multi_compile __ ENABLE_DITHERING + #pragma multi_compile __ ENABLE_USER_LUT + #pragma fragment frag_tcg + #define TONEMAPPING_CURVE + #include "TonemappingColorGrading.cginc" + ENDCG + } + + // Tonemapping (Hable) + Pass + { + CGPROGRAM + #pragma multi_compile __ UNITY_COLORSPACE_GAMMA + #pragma multi_compile __ ENABLE_COLOR_GRADING + #pragma multi_compile __ ENABLE_EYE_ADAPTATION + #pragma multi_compile __ ENABLE_DITHERING + #pragma multi_compile __ ENABLE_USER_LUT + #pragma fragment frag_tcg + #define TONEMAPPING_HABLE + #include "TonemappingColorGrading.cginc" + ENDCG + } + + // Tonemapping (Hejl-Dawson) + Pass + { + CGPROGRAM + #pragma multi_compile __ UNITY_COLORSPACE_GAMMA + #pragma multi_compile __ ENABLE_COLOR_GRADING + #pragma multi_compile __ ENABLE_EYE_ADAPTATION + #pragma multi_compile __ ENABLE_DITHERING + #pragma multi_compile __ ENABLE_USER_LUT + #pragma fragment frag_tcg + #define TONEMAPPING_HEJL_DAWSON + #include "TonemappingColorGrading.cginc" + ENDCG + } + + // Tonemapping (Photographic) + Pass + { + CGPROGRAM + #pragma multi_compile __ UNITY_COLORSPACE_GAMMA + #pragma multi_compile __ ENABLE_COLOR_GRADING + #pragma multi_compile __ ENABLE_EYE_ADAPTATION + #pragma multi_compile __ ENABLE_DITHERING + #pragma multi_compile __ ENABLE_USER_LUT + #pragma fragment frag_tcg + #define TONEMAPPING_PHOTOGRAPHIC + #include "TonemappingColorGrading.cginc" + ENDCG + } + + // Tonemapping (Reinhard) + Pass + { + CGPROGRAM + #pragma multi_compile __ UNITY_COLORSPACE_GAMMA + #pragma multi_compile __ ENABLE_COLOR_GRADING + #pragma multi_compile __ ENABLE_EYE_ADAPTATION + #pragma multi_compile __ ENABLE_DITHERING + #pragma multi_compile __ ENABLE_USER_LUT + #pragma fragment frag_tcg + #define TONEMAPPING_REINHARD + #include "TonemappingColorGrading.cginc" + ENDCG + } + + // Tonemapping (Neutral Hejl/Habble) + Pass + { + CGPROGRAM + #pragma multi_compile __ UNITY_COLORSPACE_GAMMA + #pragma multi_compile __ ENABLE_COLOR_GRADING + #pragma multi_compile __ ENABLE_EYE_ADAPTATION + #pragma multi_compile __ ENABLE_DITHERING + #pragma multi_compile __ ENABLE_USER_LUT + #pragma fragment frag_tcg + #define TONEMAPPING_NEUTRAL + #include "TonemappingColorGrading.cginc" + ENDCG + } + + // Eye adaptation debug slider + Pass + { + CGPROGRAM + #pragma fragment frag_debug + #include "TonemappingColorGrading.cginc" + + half4 frag_debug(v2f_img i) : SV_Target + { + half lum = tex2D(_MainTex, i.uv).r; + half grey = i.uv.x; + + int lum_px = floor(256.0 * lum); + int g_px = floor(256.0 * grey); + + half3 color = half3(grey, grey, grey); + color = lerp(color, half3(1.0, 0.0, 0.0), lum_px == g_px); + + return half4(color, 1.0); + } + ENDCG + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.shader.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.shader.meta new file mode 100644 index 0000000..3ca5284 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/Resources/TonemappingColorGrading.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 964b34bbab7f5e64fa40f37eaccac1ad +timeCreated: 1435513939 +licenseType: Store +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/TonemappingColorGrading.cs b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/TonemappingColorGrading.cs new file mode 100644 index 0000000..e387bd2 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/TonemappingColorGrading.cs @@ -0,0 +1,1044 @@ +namespace UnityStandardAssets.CinematicEffects +{ + using UnityEngine; + using UnityEngine.Events; + using System; + + [ExecuteInEditMode] + [RequireComponent(typeof(Camera))] + [AddComponentMenu("Image Effects/Cinematic/Tonemapping and Color Grading")] +#if UNITY_5_4_OR_NEWER + [ImageEffectAllowedInSceneView] +#endif + public class TonemappingColorGrading : MonoBehaviour + { +#if UNITY_EDITOR + // EDITOR ONLY call for allowing the editor to update the histogram + public UnityAction onFrameEndEditorOnly; + + [SerializeField] + private ComputeShader m_HistogramComputeShader; + public ComputeShader histogramComputeShader + { + get + { + if (m_HistogramComputeShader == null) + m_HistogramComputeShader = Resources.Load("HistogramCompute"); + + return m_HistogramComputeShader; + } + } + + [SerializeField] + private Shader m_HistogramShader; + public Shader histogramShader + { + get + { + if (m_HistogramShader == null) + m_HistogramShader = Shader.Find("Hidden/TonemappingColorGradingHistogram"); + + return m_HistogramShader; + } + } + + [SerializeField] + public bool histogramRefreshOnPlay = true; +#endif + + #region Attributes + [AttributeUsage(AttributeTargets.Field)] + public class SettingsGroup : Attribute + {} + + public class IndentedGroup : PropertyAttribute + {} + + public class ChannelMixer : PropertyAttribute + {} + + public class ColorWheelGroup : PropertyAttribute + { + public int minSizePerWheel = 60; + public int maxSizePerWheel = 150; + + public ColorWheelGroup() + {} + + public ColorWheelGroup(int minSizePerWheel, int maxSizePerWheel) + { + this.minSizePerWheel = minSizePerWheel; + this.maxSizePerWheel = maxSizePerWheel; + } + } + + public class Curve : PropertyAttribute + { + public Color color = Color.white; + + public Curve() + {} + + public Curve(float r, float g, float b, float a) // Can't pass a struct in an attribute + { + color = new Color(r, g, b, a); + } + } + #endregion + + #region Settings + [Serializable] + public struct EyeAdaptationSettings + { + public bool enabled; + + [Min(0f), Tooltip("Midpoint Adjustment.")] + public float middleGrey; + + [Tooltip("The lowest possible exposure value; adjust this value to modify the brightest areas of your level.")] + public float min; + + [Tooltip("The highest possible exposure value; adjust this value to modify the darkest areas of your level.")] + public float max; + + [Min(0f), Tooltip("Speed of linear adaptation. Higher is faster.")] + public float speed; + + [Tooltip("Displays a luminosity helper in the GameView.")] + public bool showDebug; + + public static EyeAdaptationSettings defaultSettings + { + get + { + return new EyeAdaptationSettings + { + enabled = false, + showDebug = false, + middleGrey = 0.5f, + min = -3f, + max = 3f, + speed = 1.5f + }; + } + } + } + + public enum Tonemapper + { + ACES, + Curve, + Hable, + HejlDawson, + Photographic, + Reinhard, + Neutral + } + + [Serializable] + public struct TonemappingSettings + { + public bool enabled; + + [Tooltip("Tonemapping technique to use. ACES is the recommended one.")] + public Tonemapper tonemapper; + + [Min(0f), Tooltip("Adjusts the overall exposure of the scene.")] + public float exposure; + + [Tooltip("Custom tonemapping curve.")] + public AnimationCurve curve; + + // Neutral settings + [Range(-0.1f, 0.1f)] + public float neutralBlackIn; + + [Range(1f, 20f)] + public float neutralWhiteIn; + + [Range(-0.09f, 0.1f)] + public float neutralBlackOut; + + [Range(1f, 19f)] + public float neutralWhiteOut; + + [Range(0.1f, 20f)] + public float neutralWhiteLevel; + + [Range(1f, 10f)] + public float neutralWhiteClip; + + public static TonemappingSettings defaultSettings + { + get + { + return new TonemappingSettings + { + enabled = false, + tonemapper = Tonemapper.Neutral, + exposure = 1f, + curve = CurvesSettings.defaultCurve, + neutralBlackIn = 0.02f, + neutralWhiteIn = 10f, + neutralBlackOut = 0f, + neutralWhiteOut = 10f, + neutralWhiteLevel = 5.3f, + neutralWhiteClip = 10f + }; + } + } + } + + [Serializable] + public struct LUTSettings + { + public bool enabled; + + [Tooltip("Custom lookup texture (strip format, e.g. 256x16).")] + public Texture texture; + + [Range(0f, 1f), Tooltip("Blending factor.")] + public float contribution; + + public static LUTSettings defaultSettings + { + get + { + return new LUTSettings + { + enabled = false, + texture = null, + contribution = 1f + }; + } + } + } + + [Serializable] + public struct ColorWheelsSettings + { + [ColorUsage(false)] + public Color shadows; + + [ColorUsage(false)] + public Color midtones; + + [ColorUsage(false)] + public Color highlights; + + public static ColorWheelsSettings defaultSettings + { + get + { + return new ColorWheelsSettings + { + shadows = Color.white, + midtones = Color.white, + highlights = Color.white + }; + } + } + } + + [Serializable] + public struct BasicsSettings + { + [Range(-2f, 2f), Tooltip("Sets the white balance to a custom color temperature.")] + public float temperatureShift; + + [Range(-2f, 2f), Tooltip("Sets the white balance to compensate for a green or magenta tint.")] + public float tint; + + [Space, Range(-0.5f, 0.5f), Tooltip("Shift the hue of all colors.")] + public float hue; + + [Range(0f, 2f), Tooltip("Pushes the intensity of all colors.")] + public float saturation; + + [Range(-1f, 1f), Tooltip("Adjusts the saturation so that clipping is minimized as colors approach full saturation.")] + public float vibrance; + + [Range(0f, 10f), Tooltip("Brightens or darkens all colors.")] + public float value; + + [Space, Range(0f, 2f), Tooltip("Expands or shrinks the overall range of tonal values.")] + public float contrast; + + [Range(0.01f, 5f), Tooltip("Contrast gain curve. Controls the steepness of the curve.")] + public float gain; + + [Range(0.01f, 5f), Tooltip("Applies a pow function to the source.")] + public float gamma; + + public static BasicsSettings defaultSettings + { + get + { + return new BasicsSettings + { + temperatureShift = 0f, + tint = 0f, + contrast = 1f, + hue = 0f, + saturation = 1f, + value = 1f, + vibrance = 0f, + gain = 1f, + gamma = 1f + }; + } + } + } + + [Serializable] + public struct ChannelMixerSettings + { + public int currentChannel; + public Vector3[] channels; + + public static ChannelMixerSettings defaultSettings + { + get + { + return new ChannelMixerSettings + { + currentChannel = 0, + channels = new[] + { + new Vector3(1f, 0f, 0f), + new Vector3(0f, 1f, 0f), + new Vector3(0f, 0f, 1f) + } + }; + } + } + } + + [Serializable] + public struct CurvesSettings + { + [Curve] + public AnimationCurve master; + + [Curve(1f, 0f, 0f, 1f)] + public AnimationCurve red; + + [Curve(0f, 1f, 0f, 1f)] + public AnimationCurve green; + + [Curve(0f, 1f, 1f, 1f)] + public AnimationCurve blue; + + public static CurvesSettings defaultSettings + { + get + { + return new CurvesSettings + { + master = defaultCurve, + red = defaultCurve, + green = defaultCurve, + blue = defaultCurve + }; + } + } + + public static AnimationCurve defaultCurve + { + get { return new AnimationCurve(new Keyframe(0f, 0f, 1f, 1f), new Keyframe(1f, 1f, 1f, 1f)); } + } + } + + public enum ColorGradingPrecision + { + Normal = 16, + High = 32 + } + + [Serializable] + public struct ColorGradingSettings + { + public bool enabled; + + [Tooltip("Internal LUT precision. \"Normal\" is 256x16, \"High\" is 1024x32. Prefer \"Normal\" on mobile devices.")] + public ColorGradingPrecision precision; + + [Space, ColorWheelGroup] + public ColorWheelsSettings colorWheels; + + [Space, IndentedGroup] + public BasicsSettings basics; + + [Space, ChannelMixer] + public ChannelMixerSettings channelMixer; + + [Space, IndentedGroup] + public CurvesSettings curves; + + [Space, Tooltip("Use dithering to try and minimize color banding in dark areas.")] + public bool useDithering; + + [Tooltip("Displays the generated LUT in the top left corner of the GameView.")] + public bool showDebug; + + public static ColorGradingSettings defaultSettings + { + get + { + return new ColorGradingSettings + { + enabled = false, + useDithering = false, + showDebug = false, + precision = ColorGradingPrecision.Normal, + colorWheels = ColorWheelsSettings.defaultSettings, + basics = BasicsSettings.defaultSettings, + channelMixer = ChannelMixerSettings.defaultSettings, + curves = CurvesSettings.defaultSettings + }; + } + } + + internal void Reset() + { + curves = CurvesSettings.defaultSettings; + } + } + + [SerializeField, SettingsGroup] + private EyeAdaptationSettings m_EyeAdaptation = EyeAdaptationSettings.defaultSettings; + public EyeAdaptationSettings eyeAdaptation + { + get { return m_EyeAdaptation; } + set { m_EyeAdaptation = value; } + } + + [SerializeField, SettingsGroup] + private TonemappingSettings m_Tonemapping = TonemappingSettings.defaultSettings; + public TonemappingSettings tonemapping + { + get { return m_Tonemapping; } + set + { + m_Tonemapping = value; + SetTonemapperDirty(); + } + } + + [SerializeField, SettingsGroup] + private ColorGradingSettings m_ColorGrading = ColorGradingSettings.defaultSettings; + public ColorGradingSettings colorGrading + { + get { return m_ColorGrading; } + set + { + m_ColorGrading = value; + SetDirty(); + } + } + + [SerializeField, SettingsGroup] + private LUTSettings m_Lut = LUTSettings.defaultSettings; + public LUTSettings lut + { + get { return m_Lut; } + set { m_Lut = value; } + } + #endregion + + private Texture2D m_IdentityLut; + private RenderTexture m_InternalLut; + private Texture2D m_CurveTexture; + private Texture2D m_TonemapperCurve; + private float m_TonemapperCurveRange; + + private Texture2D identityLut + { + get + { + if (m_IdentityLut == null || m_IdentityLut.height != lutSize) + { + DestroyImmediate(m_IdentityLut); + m_IdentityLut = GenerateIdentityLut(lutSize); + } + + return m_IdentityLut; + } + } + + private RenderTexture internalLutRt + { + get + { + if (m_InternalLut == null || !m_InternalLut.IsCreated() || m_InternalLut.height != lutSize) + { + DestroyImmediate(m_InternalLut); + m_InternalLut = new RenderTexture(lutSize * lutSize, lutSize, 0, RenderTextureFormat.ARGB32) + { + name = "Internal LUT", + filterMode = FilterMode.Bilinear, + anisoLevel = 0, + hideFlags = HideFlags.DontSave + }; + } + + return m_InternalLut; + } + } + + private Texture2D curveTexture + { + get + { + if (m_CurveTexture == null) + { + m_CurveTexture = new Texture2D(256, 1, TextureFormat.ARGB32, false, true) + { + name = "Curve texture", + wrapMode = TextureWrapMode.Clamp, + filterMode = FilterMode.Bilinear, + anisoLevel = 0, + hideFlags = HideFlags.DontSave + }; + } + + return m_CurveTexture; + } + } + + private Texture2D tonemapperCurve + { + get + { + if (m_TonemapperCurve == null) + { + TextureFormat format = TextureFormat.RGB24; + if (SystemInfo.SupportsTextureFormat(TextureFormat.RFloat)) + format = TextureFormat.RFloat; + else if (SystemInfo.SupportsTextureFormat(TextureFormat.RHalf)) + format = TextureFormat.RHalf; + + m_TonemapperCurve = new Texture2D(256, 1, format, false, true) + { + name = "Tonemapper curve texture", + wrapMode = TextureWrapMode.Clamp, + filterMode = FilterMode.Bilinear, + anisoLevel = 0, + hideFlags = HideFlags.DontSave + }; + } + + return m_TonemapperCurve; + } + } + + [SerializeField] + private Shader m_Shader; + public Shader shader + { + get + { + if (m_Shader == null) + m_Shader = Shader.Find("Hidden/TonemappingColorGrading"); + + return m_Shader; + } + } + + private Material m_Material; + public Material material + { + get + { + if (m_Material == null) + m_Material = ImageEffectHelper.CheckShaderAndCreateMaterial(shader); + + return m_Material; + } + } + + public bool isGammaColorSpace + { + get { return QualitySettings.activeColorSpace == ColorSpace.Gamma; } + } + + public int lutSize + { + get { return (int)colorGrading.precision; } + } + + private enum Pass + { + LutGen, + AdaptationLog, + AdaptationExpBlend, + AdaptationExp, + TonemappingOff, + TonemappingACES, + TonemappingCurve, + TonemappingHable, + TonemappingHejlDawson, + TonemappingPhotographic, + TonemappingReinhard, + TonemappingNeutral, + AdaptationDebug + } + + public bool validRenderTextureFormat { get; private set; } + public bool validUserLutSize { get; private set; } + + private bool m_Dirty = true; + private bool m_TonemapperDirty = true; + + private RenderTexture m_SmallAdaptiveRt; + private RenderTextureFormat m_AdaptiveRtFormat; + + public void SetDirty() + { + m_Dirty = true; + } + + public void SetTonemapperDirty() + { + m_TonemapperDirty = true; + } + + private void OnEnable() + { + if (!ImageEffectHelper.IsSupported(shader, false, true, this)) + { + enabled = false; + return; + } + + SetDirty(); + SetTonemapperDirty(); + } + + private void OnDisable() + { + if (m_Material != null) + DestroyImmediate(m_Material); + + if (m_IdentityLut != null) + DestroyImmediate(m_IdentityLut); + + if (m_InternalLut != null) + DestroyImmediate(internalLutRt); + + if (m_SmallAdaptiveRt != null) + DestroyImmediate(m_SmallAdaptiveRt); + + if (m_CurveTexture != null) + DestroyImmediate(m_CurveTexture); + + if (m_TonemapperCurve != null) + DestroyImmediate(m_TonemapperCurve); + + m_Material = null; + m_IdentityLut = null; + m_InternalLut = null; + m_SmallAdaptiveRt = null; + m_CurveTexture = null; + m_TonemapperCurve = null; + } + + private void OnValidate() + { + SetDirty(); + SetTonemapperDirty(); + } + + private static Texture2D GenerateIdentityLut(int dim) + { + Color[] newC = new Color[dim * dim * dim]; + float oneOverDim = 1f / ((float)dim - 1f); + + for (int i = 0; i < dim; i++) + for (int j = 0; j < dim; j++) + for (int k = 0; k < dim; k++) + newC[i + (j * dim) + (k * dim * dim)] = new Color((float)i * oneOverDim, Mathf.Abs((float)k * oneOverDim), (float)j * oneOverDim, 1f); + + Texture2D tex2D = new Texture2D(dim * dim, dim, TextureFormat.RGB24, false, true) + { + name = "Identity LUT", + filterMode = FilterMode.Bilinear, + anisoLevel = 0, + hideFlags = HideFlags.DontSave + }; + tex2D.SetPixels(newC); + tex2D.Apply(); + + return tex2D; + } + + // An analytical model of chromaticity of the standard illuminant, by Judd et al. + // http://en.wikipedia.org/wiki/Standard_illuminant#Illuminant_series_D + // Slightly modifed to adjust it with the D65 white point (x=0.31271, y=0.32902). + private float StandardIlluminantY(float x) + { + return 2.87f * x - 3f * x * x - 0.27509507f; + } + + // CIE xy chromaticity to CAT02 LMS. + // http://en.wikipedia.org/wiki/LMS_color_space#CAT02 + private Vector3 CIExyToLMS(float x, float y) + { + float Y = 1f; + float X = Y * x / y; + float Z = Y * (1f - x - y) / y; + + float L = 0.7328f * X + 0.4296f * Y - 0.1624f * Z; + float M = -0.7036f * X + 1.6975f * Y + 0.0061f * Z; + float S = 0.0030f * X + 0.0136f * Y + 0.9834f * Z; + + return new Vector3(L, M, S); + } + + private Vector3 GetWhiteBalance() + { + float t1 = colorGrading.basics.temperatureShift; + float t2 = colorGrading.basics.tint; + + // Get the CIE xy chromaticity of the reference white point. + // Note: 0.31271 = x value on the D65 white point + float x = 0.31271f - t1 * (t1 < 0f ? 0.1f : 0.05f); + float y = StandardIlluminantY(x) + t2 * 0.05f; + + // Calculate the coefficients in the LMS space. + Vector3 w1 = new Vector3(0.949237f, 1.03542f, 1.08728f); // D65 white point + Vector3 w2 = CIExyToLMS(x, y); + return new Vector3(w1.x / w2.x, w1.y / w2.y, w1.z / w2.z); + } + + private static Color NormalizeColor(Color c) + { + float sum = (c.r + c.g + c.b) / 3f; + + if (Mathf.Approximately(sum, 0f)) + return new Color(1f, 1f, 1f, 1f); + + return new Color + { + r = c.r / sum, + g = c.g / sum, + b = c.b / sum, + a = 1f + }; + } + + private void GenerateLiftGammaGain(out Color lift, out Color gamma, out Color gain) + { + Color nLift = NormalizeColor(colorGrading.colorWheels.shadows); + Color nGamma = NormalizeColor(colorGrading.colorWheels.midtones); + Color nGain = NormalizeColor(colorGrading.colorWheels.highlights); + + float avgLift = (nLift.r + nLift.g + nLift.b) / 3f; + float avgGamma = (nGamma.r + nGamma.g + nGamma.b) / 3f; + float avgGain = (nGain.r + nGain.g + nGain.b) / 3f; + + // Magic numbers + const float liftScale = 0.1f; + const float gammaScale = 0.5f; + const float gainScale = 0.5f; + + float liftR = (nLift.r - avgLift) * liftScale; + float liftG = (nLift.g - avgLift) * liftScale; + float liftB = (nLift.b - avgLift) * liftScale; + + float gammaR = Mathf.Pow(2f, (nGamma.r - avgGamma) * gammaScale); + float gammaG = Mathf.Pow(2f, (nGamma.g - avgGamma) * gammaScale); + float gammaB = Mathf.Pow(2f, (nGamma.b - avgGamma) * gammaScale); + + float gainR = Mathf.Pow(2f, (nGain.r - avgGain) * gainScale); + float gainG = Mathf.Pow(2f, (nGain.g - avgGain) * gainScale); + float gainB = Mathf.Pow(2f, (nGain.b - avgGain) * gainScale); + + const float minGamma = 0.01f; + float invGammaR = 1f / Mathf.Max(minGamma, gammaR); + float invGammaG = 1f / Mathf.Max(minGamma, gammaG); + float invGammaB = 1f / Mathf.Max(minGamma, gammaB); + + lift = new Color(liftR, liftG, liftB); + gamma = new Color(invGammaR, invGammaG, invGammaB); + gain = new Color(gainR, gainG, gainB); + } + + private void GenCurveTexture() + { + AnimationCurve master = colorGrading.curves.master; + AnimationCurve red = colorGrading.curves.red; + AnimationCurve green = colorGrading.curves.green; + AnimationCurve blue = colorGrading.curves.blue; + + Color[] pixels = new Color[256]; + + for (float i = 0f; i <= 1f; i += 1f / 255f) + { + float m = Mathf.Clamp(master.Evaluate(i), 0f, 1f); + float r = Mathf.Clamp(red.Evaluate(i), 0f, 1f); + float g = Mathf.Clamp(green.Evaluate(i), 0f, 1f); + float b = Mathf.Clamp(blue.Evaluate(i), 0f, 1f); + pixels[(int)Mathf.Floor(i * 255f)] = new Color(r, g, b, m); + } + + curveTexture.SetPixels(pixels); + curveTexture.Apply(); + } + + private bool CheckUserLut() + { + validUserLutSize = (lut.texture.height == (int)Mathf.Sqrt(lut.texture.width)); + return validUserLutSize; + } + + private bool CheckSmallAdaptiveRt() + { + if (m_SmallAdaptiveRt != null) + return false; + + m_AdaptiveRtFormat = RenderTextureFormat.ARGBHalf; + + if (SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.RGHalf)) + m_AdaptiveRtFormat = RenderTextureFormat.RGHalf; + + m_SmallAdaptiveRt = new RenderTexture(1, 1, 0, m_AdaptiveRtFormat); + m_SmallAdaptiveRt.hideFlags = HideFlags.DontSave; + + return true; + } + + private void OnGUI() + { + if (Event.current.type != EventType.Repaint) + return; + + int yoffset = 0; + + // Color grading debug + if (m_InternalLut != null && colorGrading.enabled && colorGrading.showDebug) + { + Graphics.DrawTexture(new Rect(0f, yoffset, lutSize * lutSize, lutSize), internalLutRt); + yoffset += lutSize; + } + + // Eye Adaptation debug + if (m_SmallAdaptiveRt != null && eyeAdaptation.enabled && eyeAdaptation.showDebug) + { + m_Material.SetPass((int)Pass.AdaptationDebug); + Graphics.DrawTexture(new Rect(0f, yoffset, 256, 16), m_SmallAdaptiveRt, m_Material); + } + } + + [ImageEffectTransformsToLDR] + private void OnRenderImage(RenderTexture source, RenderTexture destination) + { +#if UNITY_EDITOR + validRenderTextureFormat = true; + + if (source.format != RenderTextureFormat.ARGBHalf && source.format != RenderTextureFormat.ARGBFloat) + validRenderTextureFormat = false; +#endif + + material.shaderKeywords = null; + + RenderTexture rtSquared = null; + RenderTexture[] rts = null; + + if (eyeAdaptation.enabled) + { + bool freshlyBrewedSmallRt = CheckSmallAdaptiveRt(); + int srcSize = source.width < source.height ? source.width : source.height; + + // Fast lower or equal power of 2 + int adaptiveSize = srcSize; + adaptiveSize |= (adaptiveSize >> 1); + adaptiveSize |= (adaptiveSize >> 2); + adaptiveSize |= (adaptiveSize >> 4); + adaptiveSize |= (adaptiveSize >> 8); + adaptiveSize |= (adaptiveSize >> 16); + adaptiveSize -= (adaptiveSize >> 1); + + rtSquared = RenderTexture.GetTemporary(adaptiveSize, adaptiveSize, 0, m_AdaptiveRtFormat); + Graphics.Blit(source, rtSquared); + + int downsample = (int)Mathf.Log(rtSquared.width, 2f); + + int div = 2; + rts = new RenderTexture[downsample]; + for (int i = 0; i < downsample; i++) + { + rts[i] = RenderTexture.GetTemporary(rtSquared.width / div, rtSquared.width / div, 0, m_AdaptiveRtFormat); + div <<= 1; + } + + // Downsample pyramid + var lumRt = rts[downsample - 1]; + Graphics.Blit(rtSquared, rts[0], material, (int)Pass.AdaptationLog); + for (int i = 0; i < downsample - 1; i++) + { + Graphics.Blit(rts[i], rts[i + 1]); + lumRt = rts[i + 1]; + } + + // Keeping luminance values between frames, RT restore expected + m_SmallAdaptiveRt.MarkRestoreExpected(); + + material.SetFloat("_AdaptationSpeed", Mathf.Max(eyeAdaptation.speed, 0.001f)); + +#if UNITY_EDITOR + if (Application.isPlaying && !freshlyBrewedSmallRt) + Graphics.Blit(lumRt, m_SmallAdaptiveRt, material, (int)Pass.AdaptationExpBlend); + else + Graphics.Blit(lumRt, m_SmallAdaptiveRt, material, (int)Pass.AdaptationExp); +#else + Graphics.Blit(lumRt, m_SmallAdaptiveRt, material, freshlyBrewedSmallRt ? (int)Pass.AdaptationExp : (int)Pass.AdaptationExpBlend); +#endif + + material.SetFloat("_MiddleGrey", eyeAdaptation.middleGrey); + material.SetFloat("_AdaptationMin", Mathf.Pow(2f, eyeAdaptation.min)); + material.SetFloat("_AdaptationMax", Mathf.Pow(2f, eyeAdaptation.max)); + material.SetTexture("_LumTex", m_SmallAdaptiveRt); + material.EnableKeyword("ENABLE_EYE_ADAPTATION"); + } + + int renderPass = (int)Pass.TonemappingOff; + + if (tonemapping.enabled) + { + if (tonemapping.tonemapper == Tonemapper.Curve) + { + if (m_TonemapperDirty) + { + float range = 1f; + + if (tonemapping.curve.length > 0) + { + range = tonemapping.curve[tonemapping.curve.length - 1].time; + + for (float i = 0f; i <= 1f; i += 1f / 255f) + { + float c = tonemapping.curve.Evaluate(i * range); + tonemapperCurve.SetPixel(Mathf.FloorToInt(i * 255f), 0, new Color(c, c, c)); + } + + tonemapperCurve.Apply(); + } + + m_TonemapperCurveRange = 1f / range; + m_TonemapperDirty = false; + } + + material.SetFloat("_ToneCurveRange", m_TonemapperCurveRange); + material.SetTexture("_ToneCurve", tonemapperCurve); + } + else if (tonemapping.tonemapper == Tonemapper.Neutral) + { + const float scaleFactor = 20f; + const float scaleFactorHalf = scaleFactor * 0.5f; + + float inBlack = tonemapping.neutralBlackIn * scaleFactor + 1f; + float outBlack = tonemapping.neutralBlackOut * scaleFactorHalf + 1f; + float inWhite = tonemapping.neutralWhiteIn / scaleFactor; + float outWhite = 1f - tonemapping.neutralWhiteOut / scaleFactor; + float blackRatio = inBlack / outBlack; + float whiteRatio = inWhite / outWhite; + + const float a = 0.2f; + float b = Mathf.Max(0f, Mathf.LerpUnclamped(0.57f, 0.37f, blackRatio)); + float c = Mathf.LerpUnclamped(0.01f, 0.24f, whiteRatio); + float d = Mathf.Max(0f, Mathf.LerpUnclamped(0.02f, 0.20f, blackRatio)); + const float e = 0.02f; + const float f = 0.30f; + + material.SetVector("_NeutralTonemapperParams1", new Vector4(a, b, c, d)); + material.SetVector("_NeutralTonemapperParams2", new Vector4(e, f, tonemapping.neutralWhiteLevel, tonemapping.neutralWhiteClip / scaleFactorHalf)); + } + + material.SetFloat("_Exposure", tonemapping.exposure); + renderPass += (int)tonemapping.tonemapper + 1; + } + + if (colorGrading.enabled) + { + if (m_Dirty || !m_InternalLut.IsCreated()) + { + Color lift, gamma, gain; + GenerateLiftGammaGain(out lift, out gamma, out gain); + GenCurveTexture(); + + material.SetVector("_WhiteBalance", GetWhiteBalance()); + material.SetVector("_Lift", lift); + material.SetVector("_Gamma", gamma); + material.SetVector("_Gain", gain); + material.SetVector("_ContrastGainGamma", new Vector3(colorGrading.basics.contrast, colorGrading.basics.gain, 1f / colorGrading.basics.gamma)); + material.SetFloat("_Vibrance", colorGrading.basics.vibrance); + material.SetVector("_HSV", new Vector4(colorGrading.basics.hue, colorGrading.basics.saturation, colorGrading.basics.value)); + material.SetVector("_ChannelMixerRed", colorGrading.channelMixer.channels[0]); + material.SetVector("_ChannelMixerGreen", colorGrading.channelMixer.channels[1]); + material.SetVector("_ChannelMixerBlue", colorGrading.channelMixer.channels[2]); + material.SetTexture("_CurveTex", curveTexture); + internalLutRt.MarkRestoreExpected(); + Graphics.Blit(identityLut, internalLutRt, material, (int)Pass.LutGen); + m_Dirty = false; + } + + material.EnableKeyword("ENABLE_COLOR_GRADING"); + + if (colorGrading.useDithering) + material.EnableKeyword("ENABLE_DITHERING"); + + material.SetTexture("_InternalLutTex", internalLutRt); + material.SetVector("_InternalLutParams", new Vector3(1f / internalLutRt.width, 1f / internalLutRt.height, internalLutRt.height - 1f)); + } + + if (lut.enabled && lut.texture != null && CheckUserLut()) + { + material.SetTexture("_UserLutTex", lut.texture); + material.SetVector("_UserLutParams", new Vector4(1f / lut.texture.width, 1f / lut.texture.height, lut.texture.height - 1f, lut.contribution)); + material.EnableKeyword("ENABLE_USER_LUT"); + } + + Graphics.Blit(source, destination, material, renderPass); + + // Cleanup for eye adaptation + if (eyeAdaptation.enabled) + { + for (int i = 0; i < rts.Length; i++) + RenderTexture.ReleaseTemporary(rts[i]); + + RenderTexture.ReleaseTemporary(rtSquared); + } + +#if UNITY_EDITOR + // If we have an on frame end callabck we need to pass a valid result texture + // if destination is null we wrote to the backbuffer so we need to copy that out. + // It's slow and not amazing, but editor only + if (onFrameEndEditorOnly != null) + { + if (destination == null) + { + RenderTexture rt = RenderTexture.GetTemporary(source.width, source.height, 0); + Graphics.Blit(source, rt, material, renderPass); + onFrameEndEditorOnly(rt); + RenderTexture.ReleaseTemporary(rt); + RenderTexture.active = null; + } + else + { + onFrameEndEditorOnly(destination); + } + } +#endif + } + + public Texture2D BakeLUT() + { + Texture2D lut = new Texture2D(internalLutRt.width, internalLutRt.height, TextureFormat.RGB24, false, true); + RenderTexture.active = internalLutRt; + lut.ReadPixels(new Rect(0f, 0f, lut.width, lut.height), 0, 0); + RenderTexture.active = null; + return lut; + } + } +} diff --git a/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/TonemappingColorGrading.cs.meta b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/TonemappingColorGrading.cs.meta new file mode 100644 index 0000000..7885e24 --- /dev/null +++ b/IronToad_UnityProject/Assets/Standard Assets/Effects/TonemappingColorGrading/TonemappingColorGrading.cs.meta @@ -0,0 +1,16 @@ +fileFormatVersion: 2 +guid: 58a7625302996c94ba07a8ca3351f668 +timeCreated: 1453901501 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: + - m_HistogramComputeShader: {fileID: 7200000, guid: 5ee4b74fa28a3e74e89423dd49705fc5, + type: 3} + - m_HistogramShader: {fileID: 4800000, guid: 9a8e838691462194482a43a02e424876, type: 3} + - m_Shader: {fileID: 4800000, guid: 964b34bbab7f5e64fa40f37eaccac1ad, type: 3} + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/IronToad_UnityProject/Assets/_Scenes/LighthouseTestScene.unity b/IronToad_UnityProject/Assets/_Scenes/LighthouseTestScene.unity index a971ab3..67939e2 100644 Binary files a/IronToad_UnityProject/Assets/_Scenes/LighthouseTestScene.unity and b/IronToad_UnityProject/Assets/_Scenes/LighthouseTestScene.unity differ