From 4f9f203ac12a12834abfb4e0cd0b5e3becc04e8d Mon Sep 17 00:00:00 2001 From: Unity Technologies <@unity.com> Date: Thu, 18 Oct 2018 00:00:00 +0200 Subject: [PATCH] com.unity.render-pipelines.core@4.1.0-preview ## [4.1.0-preview] - 2018-10-18 ### Changed - XRGraphicConfig has been changed from a read-write control of XRSettings to XRGraphics, a read-only accessor to XRSettings. This improves consistency of XR behavior between the legacy render pipeline and SRP. - XRGraphics members have been renamed to match XRSettings, and XRGraphics has been modified to only contain accessors potentially useful to SRP - You can now have up to 16 additional shadow-casting lights. ### Fixed - LWRP no longer executes shadow passes when there are no visible shadow casters in a Scene. Previously, this made the Scene render as too dark, overall. --- CHANGELOG.md | 10 +- Editor/CoreEditorDrawers.cs | 8 +- Editor/CoreEditorUtils.cs | 52 ++-- Editor/Shadow/ShadowCascadeSplitGUI.cs | 8 + Editor/XRGraphicsConfigDrawer.cs | 31 --- Runtime/Common/XRGraphics.cs | 164 +++++++++++ ...phicsConfig.cs.meta => XRGraphics.cs.meta} | 0 Runtime/Common/XRGraphicsConfig.cs | 152 ---------- Runtime/Utilities.meta | 2 +- Runtime/Utilities/CoreUtils.cs | 28 +- Runtime/Utilities/XRUtils.cs | 18 ++ .../Utilities/XRUtils.cs.meta | 2 +- Runtime/Volume/Volume.cs | 2 +- Runtime/Volume/Volume.cs.meta | 2 +- ShaderLibrary/API/PSSL.hlsl | 23 +- ShaderLibrary/API/XBoxOne.hlsl | 37 ++- ShaderLibrary/AreaLighting.hlsl | 79 +++--- ShaderLibrary/BSDF.hlsl | 109 ++++---- ShaderLibrary/Common.hlsl | 39 ++- ShaderLibrary/CommonLighting.hlsl | 17 +- ShaderLibrary/CommonMaterial.hlsl | 2 +- ShaderLibrary/DummyShaderLibrary.cs | 5 + ShaderLibrary/DummyShaderLibrary.cs.meta | 11 + ShaderLibrary/ImageBasedLighting.hlsl | 87 ++++++ ShaderLibrary/NormalSurfaceGradient.hlsl | 48 ++-- ShaderLibrary/Packing.hlsl | 9 +- ShaderLibrary/Refraction.hlsl | 2 +- .../SampleUVMappingNormalInternal.hlsl | 5 +- ....RenderPipelines.Core.ShaderLibrary.asmdef | 3 + ...erPipelines.Core.ShaderLibrary.asmdef.meta | 7 + ShaderLibrary/VolumeRendering.hlsl | 259 ++++++++++++++---- package.json | 4 +- 32 files changed, 807 insertions(+), 418 deletions(-) delete mode 100644 Editor/XRGraphicsConfigDrawer.cs create mode 100644 Runtime/Common/XRGraphics.cs rename Runtime/Common/{XRGraphicsConfig.cs.meta => XRGraphics.cs.meta} (100%) delete mode 100644 Runtime/Common/XRGraphicsConfig.cs create mode 100644 Runtime/Utilities/XRUtils.cs rename Editor/XRGraphicsConfigDrawer.cs.meta => Runtime/Utilities/XRUtils.cs.meta (83%) create mode 100644 ShaderLibrary/DummyShaderLibrary.cs create mode 100644 ShaderLibrary/DummyShaderLibrary.cs.meta create mode 100644 ShaderLibrary/Unity.RenderPipelines.Core.ShaderLibrary.asmdef create mode 100644 ShaderLibrary/Unity.RenderPipelines.Core.ShaderLibrary.asmdef.meta diff --git a/CHANGELOG.md b/CHANGELOG.md index bfac434..016199c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,9 +4,15 @@ All notable changes to this package will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). -## [4.0.1-preview] - 2018-10-01 +## [4.1.0-preview] - 2018-10-18 + +### Changed +- XRGraphicConfig has been changed from a read-write control of XRSettings to XRGraphics, a read-only accessor to XRSettings. This improves consistency of XR behavior between the legacy render pipeline and SRP. +- XRGraphics members have been renamed to match XRSettings, and XRGraphics has been modified to only contain accessors potentially useful to SRP +- You can now have up to 16 additional shadow-casting lights. ### Fixed -- Fixed compiler warnings on new mono +- LWRP no longer executes shadow passes when there are no visible shadow casters in a Scene. Previously, this made the Scene render as too dark, overall. + ## [4.0.0-preview] - 2018-09-28 ### Added diff --git a/Editor/CoreEditorDrawers.cs b/Editor/CoreEditorDrawers.cs index 7305b46..ba46ba3 100644 --- a/Editor/CoreEditorDrawers.cs +++ b/Editor/CoreEditorDrawers.cs @@ -10,7 +10,8 @@ public enum FoldoutOption { None = 0, Indent = 1 << 0, - Animate = 1 << 1 + Animate = 1 << 1, + Boxed = 1 << 2 } [Flags] @@ -182,6 +183,7 @@ class FoldoutDrawerInternal : IDrawer bool animate { get { return (m_Options & FoldoutOption.Animate) != 0; } } bool indent { get { return (m_Options & FoldoutOption.Indent) != 0; } } + bool boxed { get { return (m_Options & FoldoutOption.Boxed) != 0; } } public FoldoutDrawerInternal(string title, AnimBoolGetter isExpanded, FoldoutOption options, params IDrawer[] bodies) { @@ -194,8 +196,8 @@ public FoldoutDrawerInternal(string title, AnimBoolGetter isExpanded, FoldoutOpt public void Draw(TUIState s, TData p, Editor owner) { var r = m_IsExpanded(s, p, owner); - CoreEditorUtils.DrawSplitter(); - r.target = CoreEditorUtils.DrawHeaderFoldout(m_Title, r.target); + CoreEditorUtils.DrawSplitter(boxed); + r.target = CoreEditorUtils.DrawHeaderFoldout(m_Title, r.target, boxed); // We must start with a layout group here // Otherwise, nested FadeGroup won't work GUILayout.BeginVertical(); diff --git a/Editor/CoreEditorUtils.cs b/Editor/CoreEditorUtils.cs index 622f3f2..90f3638 100644 --- a/Editor/CoreEditorUtils.cs +++ b/Editor/CoreEditorUtils.cs @@ -89,13 +89,19 @@ public static void DrawMultipleFields(string label, SerializedProperty[] ppts, G EditorGUIUtility.labelWidth = labelWidth; } - public static void DrawSplitter() + public static void DrawSplitter(bool isBoxed = false) { var rect = GUILayoutUtility.GetRect(1f, 1f); // Splitter rect should be full-width rect.xMin = 0f; rect.width += 4f; + + if (isBoxed) + { + rect.xMin = EditorGUIUtility.singleLineHeight - 2; + rect.width -= 1; + } if (Event.current.type != EventType.Repaint) return; @@ -130,7 +136,7 @@ public static void DrawHeader(string title) EditorGUI.LabelField(labelRect, title, EditorStyles.boldLabel); } - public static bool DrawHeaderFoldout(string title, bool state) + public static bool DrawHeaderFoldout(string title, bool state, bool isBoxed = false) { var backgroundRect = GUILayoutUtility.GetRect(1f, 17f); @@ -147,6 +153,14 @@ public static bool DrawHeaderFoldout(string title, bool state) backgroundRect.xMin = 0f; backgroundRect.width += 4f; + if (isBoxed) + { + labelRect.xMin += 5; + foldoutRect.xMin += 5; + backgroundRect.xMin = EditorGUIUtility.singleLineHeight; + backgroundRect.width -= 3; + } + // Background float backgroundTint = EditorGUIUtility.isProSkin ? 0.1f : 1f; EditorGUI.DrawRect(backgroundRect, new Color(backgroundTint, backgroundTint, backgroundTint, 0.2f)); @@ -248,39 +262,39 @@ public static bool DrawHeaderToggle(string title, SerializedProperty group, Seri const int k_DrawVector6Slider_LabelSize = 60; const int k_DrawVector6Slider_FieldSize = 80; - public static void DrawVector6(GUIContent label, SerializedProperty positive, SerializedProperty negative, Vector3 min, Vector3 max, Color[][] colors = null) + public static void DrawVector6(GUIContent label, ref Vector3 positive, ref Vector3 negative, Vector3 min, Vector3 max, Color[] colors = null) { - if (colors != null && (colors.Length != 2 || colors[0].Length != 3 || colors[1].Length != 3)) - throw new System.ArgumentException("Colors must be a 2x3 array."); + if (colors != null && (colors.Length != 6)) + throw new System.ArgumentException("Colors must be a 6 element array. [+X, +Y, +X, -X, -Y, -Z]"); GUILayout.BeginVertical(); Rect rect = EditorGUI.IndentedRect(GUILayoutUtility.GetRect(0, float.MaxValue, EditorGUIUtility.singleLineHeight, EditorGUIUtility.singleLineHeight)); if (label != GUIContent.none) { var labelRect = rect; - labelRect.x -= 12f; + labelRect.x -= 11f * EditorGUI.indentLevel; labelRect.width = EditorGUIUtility.labelWidth; EditorGUI.LabelField(labelRect, label); - rect.x += EditorGUIUtility.labelWidth - 12f; - rect.width -= EditorGUIUtility.labelWidth - 12f; + rect.x += EditorGUIUtility.labelWidth - 1f - 11f * EditorGUI.indentLevel; + rect.width -= EditorGUIUtility.labelWidth - 1f - 11f * EditorGUI.indentLevel; } - var v = positive.vector3Value; + var v = positive; EditorGUI.BeginChangeCheck(); - v = DrawVector3(rect, k_DrawVector6_Label, v, min, max, false, colors == null ? null : colors[0]); + v = DrawVector3(rect, k_DrawVector6_Label, v, min, max, false, colors == null ? null : new Color[] { colors[0], colors[1], colors[2] }); if (EditorGUI.EndChangeCheck()) - positive.vector3Value = v; + positive = v; GUILayout.Space(EditorGUIUtility.standardVerticalSpacing); rect = EditorGUI.IndentedRect(GUILayoutUtility.GetRect(0, float.MaxValue, EditorGUIUtility.singleLineHeight, EditorGUIUtility.singleLineHeight)); - rect.x += EditorGUIUtility.labelWidth - 12f; - rect.width -= EditorGUIUtility.labelWidth - 12f; - v = negative.vector3Value; + rect.x += EditorGUIUtility.labelWidth - 1f - 11f * EditorGUI.indentLevel; + rect.width -= EditorGUIUtility.labelWidth - 1f - 11f * EditorGUI.indentLevel; + v = negative; EditorGUI.BeginChangeCheck(); - v = DrawVector3(rect, k_DrawVector6_Label, v, min, max, true, colors == null ? null : colors[1]); + v = DrawVector3(rect, k_DrawVector6_Label, v, min, max, true, colors == null ? null : new Color[] { colors[3], colors[4], colors[5] }); if (EditorGUI.EndChangeCheck()) - negative.vector3Value = v; + negative = v; GUILayout.EndVertical(); } @@ -301,7 +315,7 @@ static Vector3 DrawVector3(Rect rect, GUIContent[] labels, Vector3 value, Vector //Suffix is a hack as sublabel only work with 1 character if(addMinusPrefix) { - Rect suffixRect = new Rect(rect.x-19, rect.y, 100, rect.height); + Rect suffixRect = new Rect(rect.x - 4 - 15 * EditorGUI.indentLevel, rect.y, 100, rect.height); for(int i = 0; i < 3; ++i) { EditorGUI.LabelField(suffixRect, "-"); @@ -315,7 +329,7 @@ static Vector3 DrawVector3(Rect rect, GUIContent[] labels, Vector3 value, Vector if (colors.Length != 3) throw new System.ArgumentException("colors must have 3 elements."); - Rect suffixRect = new Rect(rect.x - 8, rect.y, 100, rect.height); + Rect suffixRect = new Rect(rect.x + 7 - 15 * EditorGUI.indentLevel, rect.y, 100, rect.height); GUIStyle colorMark = new GUIStyle(EditorStyles.label); colorMark.normal.textColor = colors[0]; EditorGUI.LabelField(suffixRect, "|", colorMark); @@ -326,7 +340,7 @@ static Vector3 DrawVector3(Rect rect, GUIContent[] labels, Vector3 value, Vector EditorGUI.LabelField(suffixRect, "|", colorMark); suffixRect.x += 1; EditorGUI.LabelField(suffixRect, "|", colorMark); - suffixRect.x += fieldWidth + .5f; + suffixRect.x += fieldWidth; colorMark.normal.textColor = colors[2]; EditorGUI.LabelField(suffixRect, "|", colorMark); suffixRect.x += 1; diff --git a/Editor/Shadow/ShadowCascadeSplitGUI.cs b/Editor/Shadow/ShadowCascadeSplitGUI.cs index c7aeee3..7067c1f 100644 --- a/Editor/Shadow/ShadowCascadeSplitGUI.cs +++ b/Editor/Shadow/ShadowCascadeSplitGUI.cs @@ -167,7 +167,11 @@ public static void HandleCascadeSliderGUI(ref float[] normalizedCascadePartition if (s_RestoreSceneView != null) { s_OldSceneDrawMode = s_RestoreSceneView.cameraMode; +#if UNITY_2019_1_OR_NEWER + s_OldSceneLightingMode = s_RestoreSceneView.sceneLighting; +#else s_OldSceneLightingMode = s_RestoreSceneView.m_SceneLighting; +#endif s_RestoreSceneView.cameraMode = SceneView.GetBuiltinCameraMode(DrawCameraMode.ShadowCascades); } } @@ -187,7 +191,11 @@ public static void HandleCascadeSliderGUI(ref float[] normalizedCascadePartition if (s_RestoreSceneView != null) { s_RestoreSceneView.cameraMode = s_OldSceneDrawMode; +#if UNITY_2019_1_OR_NEWER + s_RestoreSceneView.sceneLighting = s_OldSceneLightingMode; +#else s_RestoreSceneView.m_SceneLighting = s_OldSceneLightingMode; +#endif s_RestoreSceneView = null; } break; diff --git a/Editor/XRGraphicsConfigDrawer.cs b/Editor/XRGraphicsConfigDrawer.cs deleted file mode 100644 index ef67269..0000000 --- a/Editor/XRGraphicsConfigDrawer.cs +++ /dev/null @@ -1,31 +0,0 @@ -using UnityEditor; - -namespace UnityEngine.Experimental.Rendering -{ - [CustomPropertyDrawer(typeof(XRGraphicsConfig))] - public class XRGraphicsConfigDrawer : PropertyDrawer - { - internal class Styles - { - public static GUIContent XRSettingsLabel = new GUIContent("XR Config", "Enable XR in Player Settings. Then SetConfig can be used to set this configuration to XRSettings."); - public static GUIContent useOcclusionMeshLabel = new GUIContent("Use Occlusion Mesh", "Determines whether or not to draw the occlusion mesh (goggles-shaped overlay) when rendering"); - public static GUIContent occlusionScaleLabel = new GUIContent("Occlusion Mesh Scale", "Scales the occlusion mesh"); - - } - // Draw the property inside the given rect - public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) - { - var drawUseOcclusionMesh = property.FindPropertyRelative("useOcclusionMesh"); - var drawOcclusionMaskScale = property.FindPropertyRelative("occlusionMaskScale"); - - EditorGUI.BeginDisabledGroup(!XRGraphicsConfig.tryEnable); - EditorGUILayout.LabelField(Styles.XRSettingsLabel, EditorStyles.boldLabel); - EditorGUI.indentLevel++; - EditorGUILayout.PropertyField(drawUseOcclusionMesh, Styles.useOcclusionMeshLabel); - EditorGUILayout.PropertyField(drawOcclusionMaskScale, Styles.occlusionScaleLabel); - EditorGUI.indentLevel--; - EditorGUILayout.Space(); - EditorGUI.EndDisabledGroup(); - } - } -} diff --git a/Runtime/Common/XRGraphics.cs b/Runtime/Common/XRGraphics.cs new file mode 100644 index 0000000..4087c79 --- /dev/null +++ b/Runtime/Common/XRGraphics.cs @@ -0,0 +1,164 @@ +using System; +using UnityEditor; +#if UNITY_2017_2_OR_NEWER +using UnityEngine.XR; +using XRSettings = UnityEngine.XR.XRSettings; +#elif UNITY_5_6_OR_NEWER +using UnityEngine.VR; +using XRSettings = UnityEngine.VR.VRSettings; +#endif + +namespace UnityEngine.Experimental.Rendering +{ + [Serializable] + public class XRGraphics + { // XRGraphics insulates SRP from API changes across platforms, Editor versions, and as XR transitions into XR SDK + + public enum StereoRenderingMode + { + MultiPass = 0, + SinglePass, + SinglePassInstanced, + SinglePassMultiView + }; + + public static float eyeTextureResolutionScale + { + get + { + if (!enabled) + return 1.0f; + else + return XRSettings.eyeTextureResolutionScale; + } + } + + public static float renderViewportScale + { + get + { + if (!enabled) + return 1.0f; + else + return XRSettings.renderViewportScale; + } + } + +#if UNITY_EDITOR + public static bool tryEnable + { // TryEnable gets updated before "play" is pressed- we use this for updating GUI only. + get { return PlayerSettings.virtualRealitySupported; } + } +#endif + + public static bool enabled + { // SRP should use this to safely determine whether XR is enabled at runtime. + get + { +#if ENABLE_VR + return XRSettings.enabled; +#else + return false; +#endif + } + } + + public static bool isDeviceActive + { + get + { + if (!enabled) + return false; + return XRSettings.isDeviceActive; + } + } + + public static string loadedDeviceName + { + get + { + if (!enabled) + return "No XR device loaded"; + return XRSettings.loadedDeviceName; + } + } + + public static string[] supportedDevices + { + get + { + if (!enabled) + return new string[1]; + return XRSettings.supportedDevices; + } + } + + public static StereoRenderingMode stereoRenderingMode + { + get + { + if (!enabled) + return StereoRenderingMode.SinglePass; +#if UNITY_2018_3_OR_NEWER + return (StereoRenderingMode)XRSettings.stereoRenderingMode; +#else // Reverse engineer it + if (!enabled) + return StereoRenderingMode.SinglePassMultiView; + if (eyeTextureDesc.vrUsage == VRTextureUsage.TwoEyes) + { + if (eyeTextureDesc.dimension == UnityEngine.Rendering.TextureDimension.Tex2DArray) + return StereoRenderingMode.SinglePassInstanced; + return StereoRenderingMode.SinglePassDoubleWide; + } + else + return StereoRenderingMode.MultiPass; +#endif + } + } + public static uint GetPixelOffset(uint eye) + { + if (!enabled || stereoRenderingMode != StereoRenderingMode.SinglePass) + return 0; + return (uint)(Mathf.CeilToInt((eye * XRSettings.eyeTextureWidth) / 2)); + } + + public static RenderTextureDescriptor eyeTextureDesc + { + get + { + if (!enabled) + { + return new RenderTextureDescriptor(0, 0); + } + + return XRSettings.eyeTextureDesc; + } + } + + public static int eyeTextureWidth + { + get + { + if (!enabled) + { + return 0; + } + + return XRSettings.eyeTextureWidth; + } + } + public static int eyeTextureHeight + { + get + { + if (!enabled) + { + return 0; + } + + return XRSettings.eyeTextureHeight; + } + } + + } +} diff --git a/Runtime/Common/XRGraphicsConfig.cs.meta b/Runtime/Common/XRGraphics.cs.meta similarity index 100% rename from Runtime/Common/XRGraphicsConfig.cs.meta rename to Runtime/Common/XRGraphics.cs.meta diff --git a/Runtime/Common/XRGraphicsConfig.cs b/Runtime/Common/XRGraphicsConfig.cs deleted file mode 100644 index 34be2e4..0000000 --- a/Runtime/Common/XRGraphicsConfig.cs +++ /dev/null @@ -1,152 +0,0 @@ -using System; -using UnityEditor; -#if UNITY_2017_2_OR_NEWER -using UnityEngine.XR; -using XRSettings = UnityEngine.XR.XRSettings; -#elif UNITY_5_6_OR_NEWER -using UnityEngine.VR; -using XRSettings = UnityEngine.VR.VRSettings; -#endif - -namespace UnityEngine.Experimental.Rendering -{ - [Serializable] - public class XRGraphicsConfig - { // XRGConfig stores the desired XR settings for a given SRP asset. - - public float renderScale; - public float viewportScale; - public bool useOcclusionMesh; - public float occlusionMaskScale; - - public void SetConfig() - { // If XR is enabled, sets XRSettings from our saved config - if (!enabled) - return; - - XRSettings.eyeTextureResolutionScale = renderScale; - XRSettings.renderViewportScale = viewportScale; - XRSettings.useOcclusionMesh = useOcclusionMesh; - XRSettings.occlusionMaskScale = occlusionMaskScale; - } - public void SetViewportScale(float viewportScale) - { // Only sets viewport- since this is probably the only thing getting updated every frame - if (!enabled) - return; - - XRSettings.renderViewportScale = viewportScale; - } - - public static readonly XRGraphicsConfig s_DefaultXRConfig = new XRGraphicsConfig - { - renderScale = 1.0f, - viewportScale = 1.0f, - useOcclusionMesh = true, - occlusionMaskScale = 1.0f, - }; - - public static XRGraphicsConfig GetActualXRSettings() - { - XRGraphicsConfig getXRSettings = new XRGraphicsConfig(); - - if (!enabled) - { - return getXRSettings; - } - - getXRSettings.renderScale = XRSettings.eyeTextureResolutionScale; - getXRSettings.viewportScale = XRSettings.renderViewportScale; - getXRSettings.useOcclusionMesh = XRSettings.useOcclusionMesh; - getXRSettings.occlusionMaskScale = XRSettings.occlusionMaskScale; - return getXRSettings; - } - -#if UNITY_EDITOR - public static bool tryEnable - { // TryEnable gets updated before "play" is pressed- we use this for updating GUI only. - get { return PlayerSettings.virtualRealitySupported; } - } -#endif - - public static bool enabled - { // SRP should use this to safely determine whether XR is enabled at runtime. - get - { -#if ENABLE_VR - return XRSettings.enabled; -#else - return false; -#endif - } - } - -#if UNITY_EDITOR - // FIXME: We should probably have StereoREnderingPath defined in UnityEngine.XR, not UnityEditor... - public static StereoRenderingPath stereoRenderingMode - { - get - { - if (!enabled) - { - return StereoRenderingPath.SinglePass; - } -#if UNITY_2018_3_OR_NEWER - return (StereoRenderingPath)XRSettings.stereoRenderingMode; -#else - if (eyeTextureDesc.vrUsage == VRTextureUsage.TwoEyes) - return StereoRenderingPath.SinglePass; - else if (eyeTextureDesc.dimension == UnityEngine.Rendering.TextureDimension.Tex2DArray) - return StereoRenderingPath.Instancing; - else - return StereoRenderingPath.MultiPass; -#endif - } - } -#endif - - public static uint GetPixelOffset(uint eye) - { - if (!enabled || eyeTextureDesc.vrUsage != VRTextureUsage.TwoEyes) - return 0; - return (uint)(Mathf.CeilToInt((eye * XRSettings.eyeTextureWidth) / 2)); - } - - public static RenderTextureDescriptor eyeTextureDesc - { - get - { - if (!enabled) - { - return new RenderTextureDescriptor(0, 0); - } - - return XRSettings.eyeTextureDesc; - } - } - - public static int eyeTextureWidth - { - get - { - if (!enabled) - { - return 0; - } - - return XRSettings.eyeTextureWidth; - } - } - public static int eyeTextureHeight - { - get - { - if (!enabled) - { - return 0; - } - - return XRSettings.eyeTextureHeight; - } - } - } -} diff --git a/Runtime/Utilities.meta b/Runtime/Utilities.meta index e8d3b9f..0d05ac5 100644 --- a/Runtime/Utilities.meta +++ b/Runtime/Utilities.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: f57623255fe8c064bb8297404521464a +guid: 143a724c7d97a19439bac5e37bfbba35 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Runtime/Utilities/CoreUtils.cs b/Runtime/Utilities/CoreUtils.cs index 6a84ce0..abf551b 100644 --- a/Runtime/Utilities/CoreUtils.cs +++ b/Runtime/Utilities/CoreUtils.cs @@ -468,7 +468,7 @@ public static void DisplayUnsupportedMessage(string msg) Debug.LogError(msg); #if UNITY_EDITOR - foreach (UnityEditor.SceneView sv in Resources.FindObjectsOfTypeAll(typeof(UnityEditor.SceneView))) + foreach (UnityEditor.SceneView sv in UnityEditor.SceneView.sceneViews) sv.ShowNotification(new GUIContent(msg)); #endif } @@ -477,12 +477,15 @@ public static void DisplayUnsupportedAPIMessage() { // If we are in the editor they are many possible targets that does not matches the current OS so we use the active build target instead #if UNITY_EDITOR - string currentPlatform = UnityEditor.EditorUserBuildSettings.activeBuildTarget.ToString(); + var buildTarget = UnityEditor.EditorUserBuildSettings.activeBuildTarget; + string currentPlatform = buildTarget.ToString(); + string graphicAPI = UnityEditor.PlayerSettings.GetGraphicsAPIs(buildTarget).First().ToString(); #else string currentPlatform = SystemInfo.operatingSystem; + string graphicAPI = SystemInfo.graphicsDeviceType.ToString(); #endif - string msg = "Platform " + currentPlatform + " with device " + SystemInfo.graphicsDeviceType.ToString() + " is not supported, no rendering will occur"; + string msg = "Platform " + currentPlatform + " with device " + graphicAPI + " is not supported, no rendering will occur"; DisplayUnsupportedMessage(msg); } @@ -505,7 +508,7 @@ public static bool AreAnimatedMaterialsEnabled(Camera camera) animateMaterials = false; // Determine whether the "Animated Materials" checkbox is checked for the current view. - foreach (UnityEditor.SceneView sv in Resources.FindObjectsOfTypeAll(typeof(UnityEditor.SceneView))) + foreach (UnityEditor.SceneView sv in UnityEditor.SceneView.sceneViews) { if (sv.camera == camera && sv.sceneViewState.showMaterialUpdate) { @@ -519,7 +522,7 @@ public static bool AreAnimatedMaterialsEnabled(Camera camera) animateMaterials = false; // Determine whether the "Animated Materials" checkbox is checked for the current view. - foreach (UnityEditor.MaterialEditor med in Resources.FindObjectsOfTypeAll(typeof(UnityEditor.MaterialEditor))) + foreach (UnityEditor.MaterialEditor med in materialEditors()) { // Warning: currently, there's no way to determine whether a given camera corresponds to this MaterialEditor. // Therefore, if at least one of the visible MaterialEditors is in Play Mode, all of them will play. @@ -551,6 +554,19 @@ public static bool AreAnimatedMaterialsEnabled(Camera camera) return animateMaterials; } +#if UNITY_EDITOR + static Func> materialEditors; + + static CoreUtils() + { + //quicker than standard reflection as it is compilated + System.Reflection.FieldInfo field = typeof(UnityEditor.MaterialEditor).GetField("s_MaterialEditors", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static); + var fieldExpression = System.Linq.Expressions.Expression.Field(null, field); + var lambda = System.Linq.Expressions.Expression.Lambda>>(fieldExpression); + materialEditors = lambda.Compile(); + } +#endif + public static bool IsSceneViewFogEnabled(Camera camera) { bool fogEnable = true; @@ -561,7 +577,7 @@ public static bool IsSceneViewFogEnabled(Camera camera) fogEnable = false; // Determine whether the "Animated Materials" checkbox is checked for the current view. - foreach (UnityEditor.SceneView sv in Resources.FindObjectsOfTypeAll(typeof(UnityEditor.SceneView))) + foreach (UnityEditor.SceneView sv in UnityEditor.SceneView.sceneViews) { if (sv.camera == camera && sv.sceneViewState.showFog) { diff --git a/Runtime/Utilities/XRUtils.cs b/Runtime/Utilities/XRUtils.cs new file mode 100644 index 0000000..39f99ab --- /dev/null +++ b/Runtime/Utilities/XRUtils.cs @@ -0,0 +1,18 @@ +using UnityEngine.Rendering; + +namespace UnityEngine.Experimental.Rendering +{ + public static class XRUtils + { + public static void DrawOcclusionMesh(CommandBuffer cmd, Camera camera, bool stereoEnabled = true) // Optional stereoEnabled is for SRP-specific stereo logic + { +#if UNITY_2019_1_OR_NEWER + if ((!XRGraphics.enabled) || (!camera.stereoEnabled) || (!stereoEnabled)) + return; + UnityEngine.RectInt normalizedCamViewport = new UnityEngine.RectInt(0, 0, camera.pixelWidth, camera.pixelHeight); + cmd.DrawOcclusionMesh(normalizedCamViewport); +#endif + } + + } +} diff --git a/Editor/XRGraphicsConfigDrawer.cs.meta b/Runtime/Utilities/XRUtils.cs.meta similarity index 83% rename from Editor/XRGraphicsConfigDrawer.cs.meta rename to Runtime/Utilities/XRUtils.cs.meta index 39b7fe2..d4095a3 100644 --- a/Editor/XRGraphicsConfigDrawer.cs.meta +++ b/Runtime/Utilities/XRUtils.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 13808e183ad30844691007de19af9512 +guid: b1b72c283e495bd48bd9ef8b68575627 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Runtime/Volume/Volume.cs b/Runtime/Volume/Volume.cs index 89e0004..e2996cd 100644 --- a/Runtime/Volume/Volume.cs +++ b/Runtime/Volume/Volume.cs @@ -2,7 +2,7 @@ namespace UnityEngine.Experimental.Rendering { - [ExecuteInEditMode] + [ExecuteAlways] public class Volume : MonoBehaviour { [Tooltip("A global volume is applied to the whole scene.")] diff --git a/Runtime/Volume/Volume.cs.meta b/Runtime/Volume/Volume.cs.meta index e3aa1d2..3b1af3e 100644 --- a/Runtime/Volume/Volume.cs.meta +++ b/Runtime/Volume/Volume.cs.meta @@ -5,7 +5,7 @@ MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 - icon: {instanceID: 0} + icon: {fileID: 2800000, guid: 188dfe7e559f13248ba2c41eb5a59328, type: 3} userData: assetBundleName: assetBundleVariant: diff --git a/ShaderLibrary/API/PSSL.hlsl b/ShaderLibrary/API/PSSL.hlsl index ddfc68e..09c351c 100644 --- a/ShaderLibrary/API/PSSL.hlsl +++ b/ShaderLibrary/API/PSSL.hlsl @@ -1,5 +1,7 @@ // This file assume SHADER_API_D3D11 is defined +#define SUPPORTS_WAVE_INTRINSICS + #define INTRINSIC_BITFIELD_EXTRACT #define BitFieldExtract __v_bfe_u32 #define INTRINSIC_BITFIELD_EXTRACT_SIGN_EXTEND @@ -9,11 +11,28 @@ #define INTRINSIC_WAVEREADFIRSTLANE #define WaveReadFirstLane ReadFirstLane #define INTRINSIC_MAD24 -#define Mad24 mad24 +#define Mad24Int mad24 +#define Mad24Uint mad24 #define INTRINSIC_MINMAX3 #define Min3 min3 #define Max3 max3 #define INTRINSIC_CUBEMAP_FACE_ID +#define INTRINSIC_WAVE_MINMAX +#define WaveMinInt CrossLaneMin +#define WaveMinUint CrossLaneMin +#define WaveMinFloat CrossLaneMin +#define WaveMaxInt CrossLaneMax +#define WaveMaxUint CrossLaneMax +#define WaveMaxFloat CrossLaneMax +#define INTRINSIC_BALLOT +#define Ballot ballot +#define INTRINSIC_WAVE_SUM +#define WaveAdd CrossLaneAdd +#define INTRINSIC_WAVE_LOGICAL_OPS +#define WaveAnd CrossLaneAnd +#define WaveOr CrossLaneOr + + #define UNITY_UV_STARTS_AT_TOP 1 #define UNITY_REVERSED_Z 1 @@ -141,4 +160,4 @@ #define GATHER_RED_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherRed(samplerName, coord2) #define GATHER_GREEN_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherGreen(samplerName, coord2) #define GATHER_BLUE_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherBlue(samplerName, coord2) -#define GATHER_ALPHA_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherAlpha(samplerName, coord2) +#define GATHER_ALPHA_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherAlpha(samplerName, coord2) \ No newline at end of file diff --git a/ShaderLibrary/API/XBoxOne.hlsl b/ShaderLibrary/API/XBoxOne.hlsl index ee56fea..3b20f6c 100644 --- a/ShaderLibrary/API/XBoxOne.hlsl +++ b/ShaderLibrary/API/XBoxOne.hlsl @@ -1,5 +1,4 @@ -// This file assume SHADER_API_D3D11 is defined -// TODO: This is a straight copy from D3D11.hlsl. Go through all this stuff and adjust where needed. +// This file assume SHADER_API_XBOXONE is defined #define UNITY_UV_STARTS_AT_TOP 1 #define UNITY_REVERSED_Z 1 @@ -15,6 +14,38 @@ #define CBUFFER_START(name) cbuffer name { #define CBUFFER_END }; +// Intrinsics +#define SUPPORTS_WAVE_INTRINSICS + +#define INTRINSIC_WAVEREADFIRSTLANE +#define WaveReadFirstLane __XB_MakeUniform +#define INTRINSIC_MINMAX3 +#define Min3 __XB_Min3_F32 +#define Max3 __XB_Max3_F32 +#define INTRINSIC_MAD24 +#define Mad24Int __XB_MadI24 +#define Mad24Uint __XB_MadU24 +#define INTRINSIC_BITFIELD_EXTRACT +#define BitFieldExtract __XB_UBFE +#define INTRINSIC_BITFIELD_EXTRACT_SIGN_EXTEND +#define BitFieldExtractSignExtend __XB_IBFE +#define INTRINSIC_BITFIELD_INSERT +#define BitFieldInsert __XB_BFI +#define INTRINSIC_WAVE_MINMAX +#define WaveMinInt __XB_WaveMin_I32 +#define WaveMinUint __XB_WaveMin_U32 +#define WaveMinFloat __XB_WaveMin_F32 +#define WaveMaxInt __XB_WaveMax_I32 +#define WaveMaxUint __XB_WaveMax_U32 +#define WaveMaxFloat __XB_WaveMax_F32 +#define INTRINSIC_BALLOT +#define Ballot __XB_Ballot64 +#define INTRINSIC_WAVE_SUM +#define WaveAdd __XB_WaveAdd_F32 +#define INTRINSIC_WAVE_LOGICAL_OPS +#define WaveAnd __XB_WaveAND +#define WaveOr __XB_WaveOR + // flow control attributes #define UNITY_BRANCH [branch] #define UNITY_FLATTEN [flatten] @@ -127,4 +158,4 @@ #define GATHER_RED_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherRed(samplerName, coord2) #define GATHER_GREEN_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherGreen(samplerName, coord2) #define GATHER_BLUE_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherBlue(samplerName, coord2) -#define GATHER_ALPHA_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherAlpha(samplerName, coord2) +#define GATHER_ALPHA_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherAlpha(samplerName, coord2) \ No newline at end of file diff --git a/ShaderLibrary/AreaLighting.hlsl b/ShaderLibrary/AreaLighting.hlsl index 10f8d97..3c030a5 100644 --- a/ShaderLibrary/AreaLighting.hlsl +++ b/ShaderLibrary/AreaLighting.hlsl @@ -347,51 +347,54 @@ real ComputeLineWidthFactor(real3x3 invM, real3 ortho) // For line lights. real LTCEvaluate(real3 P1, real3 P2, real3 B, real3x3 invM) { + real result = 0.0; // Inverse-transform the endpoints. P1 = mul(P1, invM); P2 = mul(P2, invM); // Terminate the algorithm if both points are below the horizon. - if (P1.z <= 0.0 && P2.z <= 0.0) return 0.0; - - real width = ComputeLineWidthFactor(invM, B); - - if (P1.z > P2.z) - { - // Convention: 'P2' is above 'P1', with the tangent pointing upwards. - Swap(P1, P2); - } - - // Recompute the length and the tangent in the new coordinate system. - real len = length(P2 - P1); - real3 T = normalize(P2 - P1); - - // Clip the part of the light below the horizon. - if (P1.z <= 0.0) + if (!(P1.z <= 0.0 && P2.z <= 0.0)) { - // P = P1 + t * T; P.z == 0. - real t = -P1.z / T.z; - P1 = real3(P1.xy + t * T.xy, 0.0); - - // Set the length of the visible part of the light. - len -= t; + real width = ComputeLineWidthFactor(invM, B); + + if (P1.z > P2.z) + { + // Convention: 'P2' is above 'P1', with the tangent pointing upwards. + Swap(P1, P2); + } + + // Recompute the length and the tangent in the new coordinate system. + real len = length(P2 - P1); + real3 T = normalize(P2 - P1); + + // Clip the part of the light below the horizon. + if (P1.z <= 0.0) + { + // P = P1 + t * T; P.z == 0. + real t = -P1.z / T.z; + P1 = real3(P1.xy + t * T.xy, 0.0); + + // Set the length of the visible part of the light. + len -= t; + } + + // Compute the normal direction to the line, s.t. it is the shortest vector + // between the shaded point and the line, pointing away from the shaded point. + // Can be interpreted as a point on the line, since the shaded point is at the origin. + real proj = dot(P1, T); + real3 P0 = P1 - proj * T; + + // Compute the parameterization: distances from 'P1' and 'P2' to 'P0'. + real l1 = proj; + real l2 = l1 + len; + + // Integrate the clamped cosine over the line segment. + real irradiance = LineIrradiance(l1, l2, P0, T); + + // Guard against numerical precision issues. + result = max(INV_PI * width * irradiance, 0.0); } - - // Compute the normal direction to the line, s.t. it is the shortest vector - // between the shaded point and the line, pointing away from the shaded point. - // Can be interpreted as a point on the line, since the shaded point is at the origin. - real proj = dot(P1, T); - real3 P0 = P1 - proj * T; - - // Compute the parameterization: distances from 'P1' and 'P2' to 'P0'. - real l1 = proj; - real l2 = l1 + len; - - // Integrate the clamped cosine over the line segment. - real irradiance = LineIrradiance(l1, l2, P0, T); - - // Guard against numerical precision issues. - return max(INV_PI * width * irradiance, 0.0); + return result; } #endif // UNITY_AREA_LIGHTING_INCLUDED diff --git a/ShaderLibrary/BSDF.hlsl b/ShaderLibrary/BSDF.hlsl index d055a66..8ac8641 100644 --- a/ShaderLibrary/BSDF.hlsl +++ b/ShaderLibrary/BSDF.hlsl @@ -413,6 +413,8 @@ real3 EvalSensitivity(real opd, real shift) // Evaluate the reflectance for a thin-film layer on top of a dielectric medum. real3 EvalIridescence(real eta_1, real cosTheta1, real iridescenceThickness, real3 baseLayerFresnel0, real iorOverBaseLayer = 0.0) { + real3 I; + // iridescenceThickness unit is micrometer for this equation here. Mean 0.5 is 500nm. real Dinc = 3.0 * iridescenceThickness; @@ -432,61 +434,64 @@ real3 EvalIridescence(real eta_1, real cosTheta1, real iridescenceThickness, rea // Handle TIR if (sinTheta2 > 1.0) - return real3(1.0, 1.0, 1.0); - //Or use this "artistic hack" to get more continuity even though wrong (test with dual normal maps to understand the difference) - //if( sinTheta2 > 1.0 ) { sinTheta2 = 2 - sinTheta2; } - - real cosTheta2 = sqrt(1.0 - sinTheta2); - - // First interface - real R0 = IorToFresnel0(eta_2, eta_1); - real R12 = F_Schlick(R0, cosTheta1); - real R21 = R12; - real T121 = 1.0 - R12; - real phi12 = 0.0; - real phi21 = PI - phi12; - - // Second interface - // The f0 or the base should account for the new computed eta_2 on top. - // This is optionally done if we are given the needed current ior over the base layer that is accounted for - // in the baseLayerFresnel0 parameter: - if (iorOverBaseLayer > 0.0) + I = real3(1.0, 1.0, 1.0); + else { - // Fresnel0ToIor will give us a ratio of baseIor/topIor, hence we * iorOverBaseLayer to get the baseIor - real3 baseIor = iorOverBaseLayer * Fresnel0ToIor(baseLayerFresnel0 + 0.0001); // guard against 1.0 - baseLayerFresnel0 = IorToFresnel0(baseIor, eta_2); + //Or use this "artistic hack" to get more continuity even though wrong (test with dual normal maps to understand the difference) + //if( sinTheta2 > 1.0 ) { sinTheta2 = 2 - sinTheta2; } + + real cosTheta2 = sqrt(1.0 - sinTheta2); + + // First interface + real R0 = IorToFresnel0(eta_2, eta_1); + real R12 = F_Schlick(R0, cosTheta1); + real R21 = R12; + real T121 = 1.0 - R12; + real phi12 = 0.0; + real phi21 = PI - phi12; + + // Second interface + // The f0 or the base should account for the new computed eta_2 on top. + // This is optionally done if we are given the needed current ior over the base layer that is accounted for + // in the baseLayerFresnel0 parameter: + if (iorOverBaseLayer > 0.0) + { + // Fresnel0ToIor will give us a ratio of baseIor/topIor, hence we * iorOverBaseLayer to get the baseIor + real3 baseIor = iorOverBaseLayer * Fresnel0ToIor(baseLayerFresnel0 + 0.0001); // guard against 1.0 + baseLayerFresnel0 = IorToFresnel0(baseIor, eta_2); + } + + real3 R23 = F_Schlick(baseLayerFresnel0, cosTheta2); + real phi23 = 0.0; + + // Phase shift + real OPD = Dinc * cosTheta2; + real phi = phi21 + phi23; + + // Compound terms + real3 R123 = R12 * R23; + real3 r123 = sqrt(R123); + real3 Rs = Sq(T121) * R23 / (real3(1.0, 1.0, 1.0) - R123); + + // Reflectance term for m = 0 (DC term amplitude) + real3 C0 = R12 + Rs; + I = C0; + + // Reflectance term for m > 0 (pairs of diracs) + real3 Cm = Rs - T121; + for (int m = 1; m <= 2; ++m) + { + Cm *= r123; + real3 Sm = 2.0 * EvalSensitivity(m * OPD, m * phi); + //vec3 SmP = 2.0 * evalSensitivity(m*OPD, m*phi2.y); + I += Cm * Sm; + } + + // Convert back to RGB reflectance + //I = clamp(mul(I, XYZ_TO_RGB), real3(0.0, 0.0, 0.0), real3(1.0, 1.0, 1.0)); + //I = mul(XYZ_TO_RGB, I); } - real3 R23 = F_Schlick(baseLayerFresnel0, cosTheta2); - real phi23 = 0.0; - - // Phase shift - real OPD = Dinc * cosTheta2; - real phi = phi21 + phi23; - - // Compound terms - real3 R123 = R12 * R23; - real3 r123 = sqrt(R123); - real3 Rs = Sq(T121) * R23 / (real3(1.0, 1.0, 1.0) - R123); - - // Reflectance term for m = 0 (DC term amplitude) - real3 C0 = R12 + Rs; - real3 I = C0; - - // Reflectance term for m > 0 (pairs of diracs) - real3 Cm = Rs - T121; - for (int m = 1; m <= 2; ++m) - { - Cm *= r123; - real3 Sm = 2.0 * EvalSensitivity(m * OPD, m * phi); - //vec3 SmP = 2.0 * evalSensitivity(m*OPD, m*phi2.y); - I += Cm * Sm; - } - - // Convert back to RGB reflectance - //I = clamp(mul(I, XYZ_TO_RGB), real3(0.0, 0.0, 0.0), real3(1.0, 1.0, 1.0)); - //I = mul(XYZ_TO_RGB, I); - return I; } diff --git a/ShaderLibrary/Common.hlsl b/ShaderLibrary/Common.hlsl index ba6b579..79f93ef 100644 --- a/ShaderLibrary/Common.hlsl +++ b/ShaderLibrary/Common.hlsl @@ -139,12 +139,12 @@ #endif // Include language header -#if defined(SHADER_API_D3D11) -#include "API/D3D11.hlsl" +#if defined(SHADER_API_XBOXONE) +#include "API/XBoxOne.hlsl" #elif defined(SHADER_API_PSSL) #include "API/PSSL.hlsl" -#elif defined(SHADER_API_XBOXONE) -#include "API/XBoxOne.hlsl" +#elif defined(SHADER_API_D3D11) +#include "API/D3D11.hlsl" #elif defined(SHADER_API_METAL) #include "API/Metal.hlsl" #elif defined(SHADER_API_VULKAN) @@ -180,6 +180,20 @@ #define LODDitheringTransition ERROR_ON_UNSUPPORTED_FUNC(LODDitheringTransition) #endif +// On everything but GCN consoles we error on cross-lane operations +#ifndef SUPPORTS_WAVE_INTRINSICS +#define WaveMinInt ERROR_ON_UNSUPPORTED_FUNC(WaveMinInt) +#define WaveMinUint ERROR_ON_UNSUPPORTED_FUNC(WaveMinUint) +#define WaveMinFloat ERROR_ON_UNSUPPORTED_FUNC(WaveMinFloat) +#define WaveMaxInt ERROR_ON_UNSUPPORTED_FUNC(WaveMaxInt) +#define WaveMaxUint ERROR_ON_UNSUPPORTED_FUNC(WaveMaxUint) +#define WaveMaxFloat ERROR_ON_UNSUPPORTED_FUNC(WaveMaxFloat) +#define Ballot ERROR_ON_UNSUPPORTED_FUNC(Ballot) +#define WaveAdd ERROR_ON_UNSUPPORTED_FUNC(WaveAdd) +#define WaveAnd ERROR_ON_UNSUPPORTED_FUNC(WaveAnd) +#define WaveOr ERROR_ON_UNSUPPORTED_FUNC(WaveOr) +#endif + #if !defined(SHADER_API_GLES) #ifndef INTRINSIC_BITFIELD_EXTRACT @@ -247,7 +261,8 @@ void ToggleBit(inout uint data, uint offset) #endif // INTRINSIC_MUL24 #ifndef INTRINSIC_MAD24 - TEMPLATE_3_INT(Mad24, a, b, c, return a * b + c) + TEMPLATE_3_INT(Mad24Int, a, b, c, return a * b + c) + TEMPLATE_3_INT(Mad24Uint, a, b, c, return a * b + c) #endif // INTRINSIC_MAD24 #ifndef INTRINSIC_MINMAX3 @@ -376,13 +391,6 @@ real FastATanPos(real x) return (x < 1.0) ? poly : HALF_PI - poly; } -#if (SHADER_TARGET >= 45) -uint FastLog2(uint x) -{ - return firstbithigh(x); -} -#endif - // 4 VGPR, 16 FR (12 FR, 1 QR), 2 scalar // input [-infinity, infinity] and output [-PI/2, PI/2] real FastATan(real x) @@ -391,6 +399,13 @@ real FastATan(real x) return (x < 0.0) ? -t0 : t0; } +#if (SHADER_TARGET >= 45) +uint FastLog2(uint x) +{ + return firstbithigh(x); +} +#endif + // Using pow often result to a warning like this // "pow(f, e) will not work for negative f, use abs(f) or conditionally handle negative values if you expect them" // PositivePow remove this warning when you know the value is positive or 0 and avoid inf/NAN. diff --git a/ShaderLibrary/CommonLighting.hlsl b/ShaderLibrary/CommonLighting.hlsl index 7448b3e..898f8b8 100644 --- a/ShaderLibrary/CommonLighting.hlsl +++ b/ShaderLibrary/CommonLighting.hlsl @@ -166,15 +166,19 @@ real EllipsoidalDistanceAttenuation(real3 unL, real3 invHalfDim, real BoxDistanceAttenuation(real3 unL, real3 invHalfDim, real rangeAttenuationScale, real rangeAttenuationBias) { + float attenuation = 0.0; + // Transform the light vector so that we can work with // with the box as if it was a [-1, 1]^2 cube. unL *= invHalfDim; // Our algorithm expects the input vector to be within the cube. - if (Max3(abs(unL.x), abs(unL.y), abs(unL.z)) > 1.0) return 0.0; - - real sqDist = ComputeCubeToSphereMapSqMagnitude(unL); - return SmoothDistanceWindowing(sqDist, rangeAttenuationScale, rangeAttenuationBias); + if (!(Max3(abs(unL.x), abs(unL.y), abs(unL.z)) > 1.0)) + { + real sqDist = ComputeCubeToSphereMapSqMagnitude(unL); + attenuation = SmoothDistanceWindowing(sqDist, rangeAttenuationScale, rangeAttenuationBias); + } + return attenuation; } //----------------------------------------------------------------------------- @@ -280,14 +284,13 @@ real ComputeWrappedDiffuseLighting(real NdotL, real w) } // Ref: The Technical Art of Uncharted 4 - Brinck and Maximov 2016 -real GetMicroshadowing(real NdotL, real AO, real opacity) +real ComputeMicroShadowing(real AO, real NdotL, real opacity) { real aperture = 2.0 * AO * AO; real microshadow = saturate(NdotL + aperture - 1.0); return lerp(1.0, microshadow, opacity); } - //----------------------------------------------------------------------------- // Helper functions //----------------------------------------------------------------------------- @@ -303,7 +306,7 @@ void GetBSDFAngle(float3 V, float3 L, float NdotL, float unclampNdotV, out float { // Optimized math. Ref: PBR Diffuse Lighting for GGX + Smith Microsurfaces (slide 114). LdotV = dot(L, V); - invLenLV = rsqrt(max(2.0 * LdotV + 2.0, FLT_EPS)); // invLenLV = rcp(length(L + V)), clamp to avoid rsqrt(0) = NaN + invLenLV = rsqrt(max(2.0 * LdotV + 2.0, FLT_EPS)); // invLenLV = rcp(length(L + V)), clamp to avoid rsqrt(0) = inf, inf * 0 = NaN NdotH = saturate((NdotL + unclampNdotV) * invLenLV); // Do not clamp NdotV here LdotH = saturate(invLenLV * LdotV + invLenLV); clampNdotV = ClampNdotV(unclampNdotV); diff --git a/ShaderLibrary/CommonMaterial.hlsl b/ShaderLibrary/CommonMaterial.hlsl index a8401ea..d03e848 100644 --- a/ShaderLibrary/CommonMaterial.hlsl +++ b/ShaderLibrary/CommonMaterial.hlsl @@ -233,7 +233,7 @@ void GetTriplanarCoordinate(float3 position, out float2 uvXZ, out float2 uvXY, o { // Caution: This must follow the same rule as what is use for SurfaceGradient triplanar // TODO: Currently the normal mapping looks wrong without SURFACE_GRADIENT option because we don't handle corretly the tangent space - uvXZ = float2(position.z, position.x); + uvXZ = float2(position.x, position.z); uvXY = float2(position.x, position.y); uvZY = float2(position.z, position.y); } diff --git a/ShaderLibrary/DummyShaderLibrary.cs b/ShaderLibrary/DummyShaderLibrary.cs new file mode 100644 index 0000000..e11a749 --- /dev/null +++ b/ShaderLibrary/DummyShaderLibrary.cs @@ -0,0 +1,5 @@ +// This file is only to force Unity to load the ShaderLibrary's hlsl files in visual studio project via asmdef file, so they can be browse. +class DummyShaderLibrary +{ + +} diff --git a/ShaderLibrary/DummyShaderLibrary.cs.meta b/ShaderLibrary/DummyShaderLibrary.cs.meta new file mode 100644 index 0000000..ff97e84 --- /dev/null +++ b/ShaderLibrary/DummyShaderLibrary.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0e625d3de4b77c14b9a31bc7b56dfde7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/ShaderLibrary/ImageBasedLighting.hlsl b/ShaderLibrary/ImageBasedLighting.hlsl index 76acfa8..58ea538 100644 --- a/ShaderLibrary/ImageBasedLighting.hlsl +++ b/ShaderLibrary/ImageBasedLighting.hlsl @@ -542,6 +542,93 @@ real4 IntegrateLD(TEXTURECUBE_ARGS(tex, sampl), return real4(lightInt / cbsdfInt, 1.0); } +real4 IntegrateLDCharlie(TEXTURECUBE_ARGS(tex, sampl), + real3 V, + real3 N, + real roughness, + uint sampleCount, + real invOmegaP, + bool prefilter) +{ + // Local frame for the local to world sample transformation + real3x3 localToWorld = GetLocalFrame(N); + float NdotV = 1; + + // Cumulative values + real3 lightInt = real3(0.0, 0.0, 0.0); + real cbsdfInt = 0.0; + + for (uint i = 0; i < sampleCount; ++i) + { + // Generate a new random number + real2 u = Hammersley2d(i, sampleCount); + + // Generate the matching direction with a cosine importance sampling + float3 localL = SampleHemisphereCosine(u.x, u.y); + + // Convert it to world space + real3 L = mul(localL, localToWorld); + float NdotL = saturate(dot(N, L)); + + // Are we in the hemisphere? + if (NdotL <= 0) continue; // Note that some samples will have 0 contribution + + // The goal of this function is to use Monte-Carlo integration to find + // X = Integral{Radiance(L) * CBSDF(L, N, V) dL} / Integral{CBSDF(L, N, V) dL}. + // Note: Integral{CBSDF(L, N, V) dL} is given by the FDG texture. + // CBSDF = F * D * V * NdotL. + // PDF = 1.0 / NdotL + // Weight = CBSDF / PDF = F * D * V + // Since we perform filtering with the assumption that (V == N), + // (LdotH == NdotH) && (NdotV == 1) && (Weight == F * D * V) + // Therefore, after the Monte Carlo expansion of the integrals, + // X = Sum(Radiance(L) * Weight) / Sum(Weight) = Sum(Radiance(L) * F * D * V) / Sum(F * D * V). + + // We are in the supposition that N == V + float LdotV, NdotH, LdotH, invLenLV; + GetBSDFAngle(V, L, NdotL, NdotV, LdotV, NdotH, LdotH, NdotV, invLenLV); + + // BRDF data + real F = 1; + real D = D_Charlie(NdotH, roughness); + real Vis = V_Charlie(NdotL, NdotV, roughness); + + real mipLevel = 0; + if (prefilter) // Prefiltered BRDF importance sampling + { + // Use lower MIP-map levels for fetching samples with low probabilities + // in order to reduce the variance. + // Ref: http://http.developer.nvidia.com/GPUGems3/gpugems3_ch20.html + // + // - OmegaS: Solid angle associated with the sample + // - OmegaP: Solid angle associated with the texel of the cubemap + + real omegaS; + + // real PDF = 1.0f / NdotL + // Since (N == V), NdotH == LdotH. + real pdf = 1.0 / NdotL; + // TODO: improve the accuracy of the sample's solid angle fit for GGX. + omegaS = rcp(sampleCount) * rcp(pdf); + + // 'invOmegaP' is precomputed on CPU and provided as a parameter to the function. + // real omegaP = FOUR_PI / (6.0 * cubemapWidth * cubemapWidth); + const real mipBias = roughness; + mipLevel = 0.5 * log2(omegaS * invOmegaP) + mipBias; + } + + // TODO: use a Gaussian-like filter to generate the MIP pyramid. + real3 val = SAMPLE_TEXTURECUBE_LOD(tex, sampl, L, mipLevel).rgb; + + // Use the approximation from "Real Shading in Unreal Engine 4": Weight ≈ NdotL. + lightInt += val * F * D * Vis; + cbsdfInt += F * D * Vis; + } + + return real4(lightInt / cbsdfInt, 1.0); +} + + // Searches the row 'j' containing 'n' elements of 'haystack' and // returns the index of the first element greater or equal to 'needle'. uint BinarySearchRow(uint j, real needle, TEXTURE2D(haystack), uint n) diff --git a/ShaderLibrary/NormalSurfaceGradient.hlsl b/ShaderLibrary/NormalSurfaceGradient.hlsl index b629022..979bd1e 100644 --- a/ShaderLibrary/NormalSurfaceGradient.hlsl +++ b/ShaderLibrary/NormalSurfaceGradient.hlsl @@ -60,38 +60,34 @@ real3 SurfaceGradientResolveNormal(real3 nrmVertexNormal, real3 surfGrad) return normalize(nrmVertexNormal - surfGrad); } -// The 128 means the derivative will come out no greater than 128 numerically (where 1 is 45 degrees so 128 is very steap). You can increase it if u like of course -// Basically tan(angle) limited to 128 -// So a max angle of 89.55 degrees ;) id argue thats close enough to the vertical limit at 90 degrees -// vT is channels.xy of a tangent space normal in[-1; 1] -// out: convert vT to a derivative +real2 ConvertTangentSpaceNormalToHeightMapGradient(real2 normalXY, real rcpNormalZ, real scale) +{ + // scale * (-normal.xy / normal.z) + return normalXY * (-rcpNormalZ * scale); +} + +// Converts tangent space normal to slopes (height map gradient). +real2 UnpackDerivativeNormalRGB(real4 packedNormal, real scale = 1.0) +{ + real3 vT = packedNormal.rgb * 2.0 - 1.0; // Unsigned to signed + real rcpZ = rcp(max(vT.z, FLT_EPS)); // Clamp to avoid INF + + return ConvertTangentSpaceNormalToHeightMapGradient(vT.xy, rcpZ, scale); +} + +// Converts tangent space normal to slopes (height map gradient). real2 UnpackDerivativeNormalAG(real4 packedNormal, real scale = 1.0) { - const real fS = 1.0 / (128.0 * 128.0); - real2 vT = packedNormal.wy * 2.0 - 1.0; - real2 vTsq = vT * vT; - real nz_sq = 1 - vTsq.x - vTsq.y; - real maxcompxy_sq = fS * max(vTsq.x, vTsq.y); - real z_inv = rsqrt(max(nz_sq, maxcompxy_sq)); - real2 deriv = -z_inv * real2(vT.x, vT.y); - return deriv * scale; + real2 vT = packedNormal.ag * 2.0 - 1.0; // Unsigned to signed + real rcpZ = rsqrt(max(1 - Sq(vT.x) - Sq(vT.y), Sq(FLT_EPS))); // Clamp to avoid INF + + return ConvertTangentSpaceNormalToHeightMapGradient(vT.xy, rcpZ, scale); } // Unpack normal as DXT5nm (1, y, 0, x) or BC5 (x, y, 0, 1) real2 UnpackDerivativeNormalRGorAG(real4 packedNormal, real scale = 1.0) { - // This do the trick - packedNormal.w *= packedNormal.x; + // Convert to (?, y, 0, x) + packedNormal.a *= packedNormal.r; return UnpackDerivativeNormalAG(packedNormal, scale); } - -real2 UnpackDerivativeNormalRGB(real4 packedNormal, real scale = 1.0) -{ - const real fS = 1.0 / (128.0 * 128.0); - real3 vT = packedNormal.xyz * 2.0 - 1.0; - real3 vTsq = vT * vT; - real maxcompxy_sq = fS * max(vTsq.x, vTsq.y); - real z_inv = rsqrt(max(vTsq.z, maxcompxy_sq)); - real2 deriv = -z_inv * real2(vT.x, vT.y); - return deriv * scale; -} diff --git a/ShaderLibrary/Packing.hlsl b/ShaderLibrary/Packing.hlsl index 53f1897..76ce023 100644 --- a/ShaderLibrary/Packing.hlsl +++ b/ShaderLibrary/Packing.hlsl @@ -7,8 +7,7 @@ real3 PackNormalMaxComponent(real3 n) { - // TODO: use max3 - return (n / max(abs(n.x), max(abs(n.y), abs(n.z)))) * 0.5 + 0.5; + return (n / Max3(abs(n.x), abs(n.y), abs(n.z))) * 0.5 + 0.5; } real3 UnpackNormalMaxComponent(real3 n) @@ -177,7 +176,7 @@ real3 UnpackNormalRGBNoScale(real4 packedNormal) real3 UnpackNormalAG(real4 packedNormal, real scale = 1.0) { real3 normal; - normal.xy = packedNormal.wy * 2.0 - 1.0; + normal.xy = packedNormal.ag * 2.0 - 1.0; normal.xy *= scale; normal.z = sqrt(1.0 - saturate(dot(normal.xy, normal.xy))); return normal; @@ -186,8 +185,8 @@ real3 UnpackNormalAG(real4 packedNormal, real scale = 1.0) // Unpack normal as DXT5nm (1, y, 0, x) or BC5 (x, y, 0, 1) real3 UnpackNormalmapRGorAG(real4 packedNormal, real scale = 1.0) { - // This do the trick - packedNormal.w *= packedNormal.x; + // Convert to (?, y, 0, x) + packedNormal.a *= packedNormal.r; return UnpackNormalAG(packedNormal, scale); } diff --git a/ShaderLibrary/Refraction.hlsl b/ShaderLibrary/Refraction.hlsl index fbe837c..5c9a9ac 100644 --- a/ShaderLibrary/Refraction.hlsl +++ b/ShaderLibrary/Refraction.hlsl @@ -48,7 +48,7 @@ RefractionModelResult RefractionModelSphere(real3 V, float3 positionWS, real3 no return result; } -RefractionModelResult RefractionModelPlane(real3 V, float3 positionWS, real3 normalWS, real ior, real thickness) +RefractionModelResult RefractionModelBox(real3 V, float3 positionWS, real3 normalWS, real ior, real thickness) { // Plane shape model: // We approximate locally the shape of the object as a plane with normal {normalWS} at {positionWS} diff --git a/ShaderLibrary/Sampling/SampleUVMappingNormalInternal.hlsl b/ShaderLibrary/Sampling/SampleUVMappingNormalInternal.hlsl index dfb6c31..cb162c0 100644 --- a/ShaderLibrary/Sampling/SampleUVMappingNormalInternal.hlsl +++ b/ShaderLibrary/Sampling/SampleUVMappingNormalInternal.hlsl @@ -5,6 +5,7 @@ real3 ADD_FUNC_SUFFIX(ADD_NORMAL_FUNC_SUFFIX(SampleUVMappingNormal))(TEXTURE2D_A real3 triplanarWeights = uvMapping.triplanarWeights; #ifdef SURFACE_GRADIENT + // Height map gradient. Basically, it encodes height map slopes along S and T axes. real2 derivXplane; real2 derivYPlane; real2 derivZPlane; @@ -19,7 +20,7 @@ real3 ADD_FUNC_SUFFIX(ADD_NORMAL_FUNC_SUFFIX(SampleUVMappingNormal))(TEXTURE2D_A // Assume derivXplane, derivYPlane and derivZPlane sampled using (z,y), (z,x) and (x,y) respectively. // TODO: Check with morten convention! Do it follow ours ? - real3 volumeGrad = real3(derivZPlane.x + derivYPlane.y, derivZPlane.y + derivXplane.y, derivXplane.x + derivYPlane.x); + real3 volumeGrad = real3(derivZPlane.x + derivYPlane.x, derivZPlane.y + derivXplane.y, derivXplane.x + derivYPlane.y); return SurfaceGradientFromVolumeGradient(uvMapping.normalWS, volumeGrad); #else real3 val = real3(0.0, 0.0, 0.0); @@ -40,7 +41,7 @@ real3 ADD_FUNC_SUFFIX(ADD_NORMAL_FUNC_SUFFIX(SampleUVMappingNormal))(TEXTURE2D_A // Note: Planar is on uv coordinate (and not uvXZ) real2 derivYPlane = UNPACK_DERIVATIVE_FUNC(SAMPLE_TEXTURE_FUNC(textureName, samplerName, uvMapping.uv, param), scale); // See comment above - real3 volumeGrad = real3(derivYPlane.y, 0.0, derivYPlane.x); + real3 volumeGrad = real3(derivYPlane.x, 0.0, derivYPlane.y); return SurfaceGradientFromVolumeGradient(uvMapping.normalWS, volumeGrad); } #endif diff --git a/ShaderLibrary/Unity.RenderPipelines.Core.ShaderLibrary.asmdef b/ShaderLibrary/Unity.RenderPipelines.Core.ShaderLibrary.asmdef new file mode 100644 index 0000000..9db50b6 --- /dev/null +++ b/ShaderLibrary/Unity.RenderPipelines.Core.ShaderLibrary.asmdef @@ -0,0 +1,3 @@ +{ + "name": "Unity.RenderPipelines.Core.ShaderLibrary" +} \ No newline at end of file diff --git a/ShaderLibrary/Unity.RenderPipelines.Core.ShaderLibrary.asmdef.meta b/ShaderLibrary/Unity.RenderPipelines.Core.ShaderLibrary.asmdef.meta new file mode 100644 index 0000000..6a19c96 --- /dev/null +++ b/ShaderLibrary/Unity.RenderPipelines.Core.ShaderLibrary.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 46a67ded66a63de48b9329c593fc08de +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/ShaderLibrary/VolumeRendering.hlsl b/ShaderLibrary/VolumeRendering.hlsl index adc301a..e1983e6 100644 --- a/ShaderLibrary/VolumeRendering.hlsl +++ b/ShaderLibrary/VolumeRendering.hlsl @@ -2,53 +2,179 @@ #define UNITY_VOLUME_RENDERING_INCLUDED // Reminder: -// Optical_Depth(x, y) = Integral{x, y}{Extinction(t) dt} -// Transmittance(x, y) = Exp(-Optical_Depth(x, y)) +// OpticalDepth(x, y) = Integral{x, y}{Extinction(t) dt} +// Transmittance(x, y) = Exp(-OpticalDepth(x, y)) // Transmittance(x, z) = Transmittance(x, y) * Transmittance(y, z) -// Integral{a, b}{Transmittance(0, t) * L_s(t) dt} = Transmittance(0, a) * Integral{a, b}{Transmittance(0, t - a) * L_s(t) dt}. +// Integral{a, b}{Transmittance(0, t) dt} = Transmittance(0, a) * Integral{a, b}{Transmittance(0, t - a) dt} -real OpticalDepthHomogeneousMedium(real extinction, real intervalLength) +real TransmittanceFromOpticalDepth(real opticalDepth) { - return extinction * intervalLength; + return exp(-opticalDepth); } -real3 OpticalDepthHomogeneousMedium(real3 extinction, real intervalLength) +real OpacityFromOpticalDepth(real opticalDepth) { - return extinction * intervalLength; + return 1 - TransmittanceFromOpticalDepth(opticalDepth); } -real Transmittance(real opticalDepth) +// +// ---------------------------------- Deep Pixel Compositing --------------------------------------- +// + +// TODO: it would be good to improve the perf and numerical stability +// of approximations below by finding a polynomial approximation. + +// input = {radiance, opacity} +// Note that opacity must be less than 1 (not fully opaque). +real4 LinearizeRGBA(real4 value) { - return exp(-opticalDepth); + // See "Deep Compositing Using Lie Algebras". + // log(A) = {OpticalDepthFromOpacity(A.a) / A.a * A.rgb, -OpticalDepthFromOpacity(A.a)}. + // We drop redundant negations. + real a = value.a; + real d = -log(1 - a); + real r = (a >= FLT_EPS) ? (d * rcp(a)) : 1; // Prevent numerical explosion + return real4(r * value.rgb, d); } -real3 Transmittance(real3 opticalDepth) +// input = {radiance, optical_depth} +// Note that opacity must be less than 1 (not fully opaque). +real4 LinearizeRGBD(real4 value) { - return exp(-opticalDepth); + // See "Deep Compositing Using Lie Algebras". + // log(A) = {A.a / OpacityFromOpticalDepth(A.a) * A.rgb, -A.a}. + // We drop redundant negations. + real d = value.a; + real a = 1 - exp(-d); + real r = (a >= FLT_EPS) ? (d * rcp(a)) : 1; // Prevent numerical explosion + return real4(r * value.rgb, d); } -real TransmittanceHomogeneousMedium(real extinction, real intervalLength) +// output = {radiance, opacity} +// Note that opacity must be less than 1 (not fully opaque). +real4 DelinearizeRGBA(real4 value) { - return Transmittance(OpticalDepthHomogeneousMedium(extinction, intervalLength)); + // See "Deep Compositing Using Lie Algebras". + // exp(B) = {OpacityFromOpticalDepth(-B.a) / -B.a * B.rgb, OpacityFromOpticalDepth(-B.a)}. + // We drop redundant negations. + real d = value.a; + real a = 1 - exp(-d); + real i = (a >= FLT_EPS) ? (a * rcp(d)) : 1; // Prevent numerical explosion + return real4(i * value.rgb, a); } -real3 TransmittanceHomogeneousMedium(real3 extinction, real intervalLength) +// input = {radiance, optical_depth} +// Note that opacity must be less than 1 (not fully opaque). +real4 DelinearizeRGBD(real4 value) { - return Transmittance(OpticalDepthHomogeneousMedium(extinction, intervalLength)); + // See "Deep Compositing Using Lie Algebras". + // exp(B) = {OpacityFromOpticalDepth(-B.a) / -B.a * B.rgb, -B.a}. + // We drop redundant negations. + real d = value.a; + real a = 1 - exp(-d); + real i = (a >= FLT_EPS) ? (a * rcp(d)) : 1; // Prevent numerical explosion + return real4(i * value.rgb, d); } -// Integral{a, b}{Transmittance(0, t - a) dt}. +// +// ----------------------------- Homogeneous Participating Media ----------------------------------- +// + +real OpticalDepthHomogeneousMedium(real extinction, real intervalLength) +{ + return extinction * intervalLength; +} + +real TransmittanceHomogeneousMedium(real extinction, real intervalLength) +{ + return TransmittanceFromOpticalDepth(OpticalDepthHomogeneousMedium(extinction, intervalLength)); +} + +// Integral{a, b}{TransmittanceFromOpticalDepth(0, t - a) dt}. real TransmittanceIntegralHomogeneousMedium(real extinction, real intervalLength) { + // Note: when multiplied by the extinction coefficient, it becomes + // Albedo * (1 - TransmittanceFromOpticalDepth(d)) = Albedo * Opacity(d). return rcp(extinction) - rcp(extinction) * exp(-extinction * intervalLength); } -// Integral{a, b}{Transmittance(0, t - a) dt}. -real3 TransmittanceIntegralHomogeneousMedium(real3 extinction, real intervalLength) +// +// ----------------------------------- Height Fog -------------------------------------------------- +// + +// Can be used to scale base extinction and scattering coefficients. +real ComputeHeightFogMultiplier(real height, real baseHeight, real2 heightExponents) { - return rcp(extinction) - rcp(extinction) * exp(-extinction * intervalLength); + real h = max(height - baseHeight, 0); + real rcpH = heightExponents.x; + + return exp(-h * rcpH); +} + +// Optical depth between two endpoints. +real OpticalDepthHeightFog(real baseExtinction, real baseHeight, real2 heightExponents, + real cosZenith, real startHeight, real intervalLength) +{ + // Height fog is composed of two slices of optical depth: + // - homogeneous fog below 'baseHeight': d = k * t + // - exponential fog above 'baseHeight': d = Integrate[k * e^(-(h + z * x) / H) dx, {x, 0, t}] + + real H = heightExponents.y; + real rcpH = heightExponents.x; + real Z = cosZenith; + real absZ = max(abs(cosZenith), FLT_EPS); + real rcpAbsZ = rcp(absZ); + + real endHeight = startHeight + intervalLength * Z; + real minHeight = min(startHeight, endHeight); + real h = max(minHeight - baseHeight, 0); + + real homFogDist = clamp((baseHeight - minHeight) * rcpAbsZ, 0, intervalLength); + real expFogDist = intervalLength - homFogDist; + real expFogMult = exp(-h * rcpH) * (1 - exp(-expFogDist * absZ * rcpH)) * (rcpAbsZ * H); + + return baseExtinction * (homFogDist + expFogMult); +} + +// This version of the function assumes the interval of infinite length. +real OpticalDepthHeightFog(real baseExtinction, real baseHeight, real2 heightExponents, + real cosZenith, real startHeight) +{ + real H = heightExponents.y; + real rcpH = heightExponents.x; + real Z = cosZenith; + real absZ = max(abs(cosZenith), FLT_EPS); + real rcpAbsZ = rcp(absZ); + + real minHeight = (Z >= 0) ? startHeight : -rcp(FLT_EPS); + real h = max(minHeight - baseHeight, 0); + + real homFogDist = max((baseHeight - minHeight) * rcpAbsZ, 0); + real expFogMult = exp(-h * rcpH) * (rcpAbsZ * H); + + return baseExtinction * (homFogDist + expFogMult); +} + +real TransmittanceHeightFog(real baseExtinction, real baseHeight, real2 heightExponents, + real cosZenith, real startHeight, real intervalLength) +{ + real od = OpticalDepthHeightFog(baseExtinction, baseHeight, heightExponents, + cosZenith, startHeight, intervalLength); + return TransmittanceFromOpticalDepth(od); } +real TransmittanceHeightFog(real baseExtinction, real baseHeight, real2 heightExponents, + real cosZenith, real startHeight) +{ + real od = OpticalDepthHeightFog(baseExtinction, baseHeight, heightExponents, + cosZenith, startHeight); + return TransmittanceFromOpticalDepth(od); +} + +// +// ----------------------------------- Phase Functions --------------------------------------------- +// + real IsotropicPhaseFunction() { return INV_FOUR_PI; @@ -64,7 +190,7 @@ real HenyeyGreensteinPhasePartConstant(real anisotropy) real HenyeyGreensteinPhasePartVarying(real anisotropy, real cosTheta) { real g = anisotropy; - real f = rsqrt(1 + g * g - 2 * g * cosTheta); // x^(-1/2) + real f = rsqrt(saturate(1 + g * g - 2 * g * cosTheta)); // x^(-1/2) return f * f * f; // x^(-3/2) } @@ -85,10 +211,14 @@ real CornetteShanksPhasePartConstant(real anisotropy) real CornetteShanksPhasePartVarying(real anisotropy, real cosTheta) { real g = anisotropy; - real f = rsqrt(1 + g * g - 2 * g * cosTheta); // x^(-1/2) + real f = rsqrt(saturate(1 + g * g - 2 * g * cosTheta)); // x^(-1/2) real h = (1 + cosTheta * cosTheta); - return h * (f * f * f); // h * f^(-3/2) + // Note that this function is not perfectly isotropic for (g = 0). We force it to be. + // TODO: in the future, when (g = 0), specialize the Volumetric Lighting kernel + // to not do anything anisotropy-specific. This way we could avoid this test + // (along with tons of other overhead and hacks). + return (g == 0) ? 1.33333333 : h * (f * f * f); // h * x^(-3/2) } // A better approximation of the Mie phase function. @@ -99,16 +229,23 @@ real CornetteShanksPhaseFunction(real anisotropy, real cosTheta) CornetteShanksPhasePartVarying(anisotropy, cosTheta); } +// +// --------------------------------- Importance Sampling ------------------------------------------- +// + // Samples the interval of homogeneous participating medium using the closed-form tracking approach // (proportionally to the transmittance). // Returns the offset from the start of the interval and the weight = (transmittance / pdf). // Ref: Monte Carlo Methods for Volumetric Light Transport Simulation, p. 5. void ImportanceSampleHomogeneousMedium(real rndVal, real extinction, real intervalLength, - out real offset, out real weight) + out real offset, out real weight) { - // pdf = extinction * exp(extinction * (intervalLength - t)) / (exp(intervalLength * extinction - 1) + // pdf = extinction * exp(extinction * (intervalLength - t)) / (exp(intervalLength * extinction) - 1) + // pdf = extinction * exp(-extinction * t) / (1 - exp(-extinction * intervalLength)) + // weight = TransmittanceFromOpticalDepth(t) / pdf // weight = exp(-extinction * t) / pdf // weight = (1 - exp(-extinction * intervalLength)) / extinction + // weight = OpacityFromOpticalDepth(extinction * intervalLength) / extinction real x = 1 - exp(-extinction * intervalLength); real c = rcp(extinction); @@ -118,38 +255,60 @@ void ImportanceSampleHomogeneousMedium(real rndVal, real extinction, real interv } // Implements equiangular light sampling. -// Returns the distance from the origin of the ray, the squared (radial) distance from the light, +// Returns the distance from the origin of the ray, the squared distance from the light, // and the reciprocal of the PDF. // Ref: Importance Sampling of Area Lights in Participating Medium. -void ImportanceSamplePunctualLight(real rndVal, real3 lightPosition, +void ImportanceSamplePunctualLight(real rndVal, real3 lightPosition, real lightSqRadius, real3 rayOrigin, real3 rayDirection, real tMin, real tMax, - out real dist, out real rSq, out real rcpPdf, - real minDistSq = FLT_EPS) -{ - real3 originToLight = lightPosition - rayOrigin; - real originToLightProj = dot(originToLight, rayDirection); - real originToLightDistSq = dot(originToLight, originToLight); - real rayToLightDistSq = max(originToLightDistSq - originToLightProj * originToLightProj, minDistSq); - - real a = tMin - originToLightProj; - real b = tMax - originToLightProj; - real dSq = rayToLightDistSq; - real dRcp = rsqrt(dSq); - real d = dSq * dRcp; - - // TODO: optimize me. :-( - real theta0 = FastATan(a * dRcp); - real theta1 = FastATan(b * dRcp); - real gamma = theta1 - theta0; - real theta = lerp(theta0, theta1, rndVal); - real t = d * tan(theta); - - dist = originToLightProj + t; - rSq = dSq + t * t; - rcpPdf = gamma * rSq * dRcp; + out real t, out real sqDist, out real rcpPdf) +{ + real3 originToLight = lightPosition - rayOrigin; + real originToLightProjDist = dot(originToLight, rayDirection); + real originToLightSqDist = dot(originToLight, originToLight); + real rayToLightSqDist = originToLightSqDist - originToLightProjDist * originToLightProjDist; + + // Virtually offset the light to modify the PDF distribution. + real sqD = max(rayToLightSqDist + lightSqRadius, FLT_EPS); + real rcpD = rsqrt(sqD); + real d = sqD * rcpD; + real a = tMin - originToLightProjDist; + real b = tMax - originToLightProjDist; + real x = a * rcpD; + real y = b * rcpD; + +#if 0 + real theta0 = FastATan(x); + real theta1 = FastATan(y); + real gamma = theta1 - theta0; + real tanTheta = tan(theta0 + rndVal * gamma); +#else + // Same but faster: + // atan(y) - atan(x) = atan((y - x) / (1 + x * y)) + // tan(atan(x) + z) = (x * cos(z) + sin(z)) / (cos(z) - x * sin(z)) + // Both the tangent and the angle cannot be negative. + real tanGamma = abs((y - x) * rcp(max(0, 1 + x * y))); + real gamma = FastATanPos(tanGamma); + real z = rndVal * gamma; + real numer = x * cos(z) + sin(z); + real denom = cos(z) - x * sin(z); + real tanTheta = numer * rcp(denom); +#endif + + real tRelative = d * tanTheta; + + sqDist = sqD + tRelative * tRelative; + rcpPdf = gamma * rcpD * sqDist; + t = originToLightProjDist + tRelative; + + // Remove the virtual light offset to obtain the real geometric distance. + sqDist = max(sqDist - lightSqRadius, FLT_EPS); } +// +// ------------------------------------ Miscellaneous ---------------------------------------------- +// + // Absorption coefficient from Disney: http://blog.selfshadow.com/publications/s2015-shading-course/burley/s2015_pbs_disney_bsdf_notes.pdf real3 TransmittanceColorAtDistanceToAbsorption(real3 transmittanceColor, real atDistance) { diff --git a/package.json b/package.json index 1817f60..fae880b 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "description": "Helper library for SRP that contains a new Shader Library, and utility functions that can be used to implement a custom SRP. This library is currently used by both the High Definition Render Pipeline and the Lightweight Render Pipeline.", "displayName": "Core RP Library", - "gitHead": "ba38b31bee11444f561fc3db2acc49d95a0ec0eb", + "gitHead": "737b5dd3a7a25344fabf75b9eb89f15ac641c95b", "name": "com.unity.render-pipelines.core", "repoPackagePath": "com.unity.render-pipelines.core", "repository": { @@ -9,5 +9,5 @@ "url": "ssh://git@github.com/Unity-Technologies/ScriptableRenderLoop.git" }, "unity": "2018.3", - "version": "4.0.1-preview" + "version": "4.1.0-preview" } \ No newline at end of file