Merge remote-tracking branch 'origin/master' into gi
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -6,6 +6,10 @@
|
||||
#include "./Flax/LightingCommon.hlsl"
|
||||
#if USE_REFLECTIONS
|
||||
#include "./Flax/ReflectionsCommon.hlsl"
|
||||
#define MATERIAL_REFLECTIONS_SSR 1
|
||||
#if MATERIAL_REFLECTIONS == MATERIAL_REFLECTIONS_SSR
|
||||
#include "./Flax/SSR.hlsl"
|
||||
#endif
|
||||
#endif
|
||||
#include "./Flax/Lighting.hlsl"
|
||||
#include "./Flax/ShadowsSampling.hlsl"
|
||||
@@ -93,9 +97,29 @@ float4 PS_Forward(PixelInput input) : SV_Target0
|
||||
light += GetLighting(ViewPos, localLight, gBuffer, shadowMask, true, isSpotLight);
|
||||
}
|
||||
|
||||
#if USE_REFLECTIONS
|
||||
// Calculate reflections
|
||||
light.rgb += GetEnvProbeLighting(ViewPos, EnvProbe, EnvironmentProbe, gBuffer) * light.a;
|
||||
#if USE_REFLECTIONS
|
||||
float3 reflections = SampleReflectionProbe(ViewPos, EnvProbe, EnvironmentProbe, gBuffer.WorldPos, gBuffer.Normal, gBuffer.Roughness).rgb;
|
||||
|
||||
#if MATERIAL_REFLECTIONS == MATERIAL_REFLECTIONS_SSR
|
||||
// Screen Space Reflections
|
||||
Texture2D sceneDepthTexture = MATERIAL_REFLECTIONS_SSR_DEPTH; // Material Generator inserts depth and color buffers and plugs it via internal define
|
||||
Texture2D sceneColorTexture = MATERIAL_REFLECTIONS_SSR_COLOR;
|
||||
float2 screenUV = materialInput.SvPosition.xy * ScreenSize.zw;
|
||||
float stepSize = ScreenSize.z; // 1 / screenWidth
|
||||
float maxSamples = 32;
|
||||
float worldAntiSelfOcclusionBias = 0.1f;
|
||||
float brdfBias = 0.82f;
|
||||
float drawDistance = 5000.0f;
|
||||
float3 hit = TraceSceenSpaceReflection(screenUV, gBuffer, sceneDepthTexture, ViewPos, ViewMatrix, ViewProjectionMatrix, stepSize, maxSamples, false, 0.0f, worldAntiSelfOcclusionBias, brdfBias, drawDistance);
|
||||
if (hit.z > 0)
|
||||
{
|
||||
float3 screenColor = sceneColorTexture.SampleLevel(SamplerPointClamp, hit.xy, 0).rgb;
|
||||
reflections = lerp(reflections, screenColor, hit.z);
|
||||
}
|
||||
#endif
|
||||
|
||||
light.rgb += reflections * GetReflectionSpecularLighting(ViewPos, gBuffer) * light.a;
|
||||
#endif
|
||||
|
||||
// Add lighting (apply ambient occlusion)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
@@ -689,6 +689,30 @@ namespace FlaxEditor.Content.GUI
|
||||
return base.OnKeyDown(key);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnCharInput(char c)
|
||||
{
|
||||
if (base.OnCharInput(c))
|
||||
return true;
|
||||
|
||||
if (char.IsLetterOrDigit(c) && _items.Count != 0)
|
||||
{
|
||||
// Jump to the item starting with this character
|
||||
c = char.ToLowerInvariant(c);
|
||||
for (int i = 0; i < _items.Count; i++)
|
||||
{
|
||||
var name = _items[i].ShortName;
|
||||
if (!string.IsNullOrEmpty(name) && char.ToLowerInvariant(name[0]) == c)
|
||||
{
|
||||
Select(_items[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void PerformLayoutBeforeChildren()
|
||||
{
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace FlaxEditor.CustomEditors
|
||||
/// Enables using prefab-related features of the properties editor (eg. revert to prefab option).
|
||||
/// </summary>
|
||||
UsePrefab = 1 << 1,
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Enables using default-value-related features of the properties editor (eg. revert to default option).
|
||||
/// </summary>
|
||||
@@ -88,7 +88,6 @@ namespace FlaxEditor.CustomEditors
|
||||
/// <seealso cref="FlaxEditor.CustomEditors.SyncPointEditor" />
|
||||
protected class RootEditor : SyncPointEditor
|
||||
{
|
||||
private readonly string _noSelectionText;
|
||||
private CustomEditor _overrideEditor;
|
||||
|
||||
/// <summary>
|
||||
@@ -109,13 +108,18 @@ namespace FlaxEditor.CustomEditors
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The text to show when no object is selected.
|
||||
/// </summary>
|
||||
public string NoSelectionText;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RootEditor"/> class.
|
||||
/// </summary>
|
||||
/// <param name="noSelectionText">The text to show when no item is selected.</param>
|
||||
public RootEditor(string noSelectionText)
|
||||
{
|
||||
_noSelectionText = noSelectionText ?? "No selection";
|
||||
NoSelectionText = noSelectionText ?? "No selection";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -154,7 +158,7 @@ namespace FlaxEditor.CustomEditors
|
||||
}
|
||||
else
|
||||
{
|
||||
var label = layout.Label(_noSelectionText, TextAlignment.Center);
|
||||
var label = layout.Label(NoSelectionText, TextAlignment.Center);
|
||||
label.Label.Height = 20.0f;
|
||||
}
|
||||
|
||||
@@ -251,6 +255,20 @@ namespace FlaxEditor.CustomEditors
|
||||
/// </summary>
|
||||
public object Owner;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the text to show when no object is selected.
|
||||
/// </summary>
|
||||
public string NoSelectionText
|
||||
{
|
||||
get => Editor.NoSelectionText;
|
||||
set
|
||||
{
|
||||
Editor.NoSelectionText = value;
|
||||
if (SelectionCount == 0)
|
||||
BuildLayoutOnUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
private bool _buildOnUpdate;
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -49,10 +49,10 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
Parent = this,
|
||||
Bounds = new Rectangle((Width - addScriptButtonWidth) / 2, 1, addScriptButtonWidth, 18),
|
||||
};
|
||||
addScriptButton.ButtonClicked += AddScriptButtonOnClicked;
|
||||
addScriptButton.ButtonClicked += OnAddScriptButtonClicked;
|
||||
}
|
||||
|
||||
private void AddScriptButtonOnClicked(Button button)
|
||||
private void OnAddScriptButtonClicked(Button button)
|
||||
{
|
||||
var scripts = Editor.Instance.CodeEditing.Scripts.Get();
|
||||
if (scripts.Count == 0)
|
||||
|
||||
@@ -716,7 +716,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
|
||||
// Header
|
||||
if (item.Header != null)
|
||||
itemLayout.Header(item.Header.Text);
|
||||
itemLayout.Header(item.Header);
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
@@ -279,6 +279,16 @@ namespace FlaxEditor.CustomEditors
|
||||
return element;
|
||||
}
|
||||
|
||||
internal LabelElement Header(HeaderAttribute header)
|
||||
{
|
||||
var element = Header(header.Text);
|
||||
if (header.FontSize != -1)
|
||||
element.Label.Font = new FontReference(element.Label.Font.Font, header.FontSize);
|
||||
if (header.Color != 0)
|
||||
element.Label.TextColor = Color.FromRGBA(header.Color);
|
||||
return element;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds new text box element.
|
||||
/// </summary>
|
||||
|
||||
@@ -258,6 +258,24 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
NodeElementArchetype.Factory.Output(0, string.Empty, null, 1)
|
||||
}
|
||||
},
|
||||
new NodeArchetype
|
||||
{
|
||||
TypeID = 14,
|
||||
Title = "Array Add Unique",
|
||||
Description = "Adds the unique item to the array (to the end). Does nothing it specified item was already added.",
|
||||
Flags = NodeFlags.VisualScriptGraph | NodeFlags.AnimGraph,
|
||||
Size = new Vector2(170, 40),
|
||||
ConnectionsHints = ConnectionsHint.Array,
|
||||
IndependentBoxes = new int[] { 0 },
|
||||
DependentBoxes = new int[] { 1, 2 },
|
||||
DependentBoxFilter = GetArrayItemType,
|
||||
Elements = new[]
|
||||
{
|
||||
NodeElementArchetype.Factory.Input(0, "Array", true, null, 0),
|
||||
NodeElementArchetype.Factory.Input(1, "Item", true, typeof(object), 1),
|
||||
NodeElementArchetype.Factory.Output(0, string.Empty, null, 2)
|
||||
}
|
||||
},
|
||||
// first 100 IDs reserved for arrays
|
||||
};
|
||||
}
|
||||
|
||||
@@ -192,7 +192,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
GetBox(MaterialNodeBoxes.SubsurfaceColor).Enabled = false;
|
||||
break;
|
||||
}
|
||||
default: throw new ArgumentOutOfRangeException();
|
||||
default: throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -807,7 +807,26 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
NodeElementArchetype.Factory.Input(0, "RGB", true, typeof(Vector3), 0, 0),
|
||||
NodeElementArchetype.Factory.Output(0, "HSV", typeof(Vector3), 1),
|
||||
}
|
||||
}
|
||||
},
|
||||
new NodeArchetype
|
||||
{
|
||||
TypeID = 38,
|
||||
Title = "Custom Global Code",
|
||||
Description = "Custom global HLSL shader code expression (placed before material shader code). Can contain includes to shader utilities or declare functions to reuse later.",
|
||||
Flags = NodeFlags.MaterialGraph,
|
||||
Size = new Vector2(300, 220),
|
||||
DefaultValues = new object[]
|
||||
{
|
||||
"// Here you can add HLSL code\nfloat4 GetCustomColor()\n{\n\treturn float4(1, 0, 0, 1);\n}",
|
||||
true,
|
||||
},
|
||||
Elements = new[]
|
||||
{
|
||||
NodeElementArchetype.Factory.Bool(0, 0, 1),
|
||||
NodeElementArchetype.Factory.Text(20, 0, "Enabled"),
|
||||
NodeElementArchetype.Factory.TextBox(0, 20, 300, 200, 0),
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,7 +317,7 @@ namespace FlaxEditor.Surface
|
||||
|
||||
// Header
|
||||
if (e.Header != null)
|
||||
itemLayout.Header(e.Header.Text);
|
||||
itemLayout.Header(e.Header);
|
||||
|
||||
// Values container
|
||||
var valueType = new ScriptType(e.Type);
|
||||
|
||||
@@ -410,7 +410,7 @@ namespace FlaxEditor.Surface
|
||||
// Header
|
||||
var header = (HeaderAttribute)attributes.FirstOrDefault(x => x is HeaderAttribute);
|
||||
if (header != null)
|
||||
itemLayout.Header(header.Text);
|
||||
itemLayout.Header(header);
|
||||
|
||||
var propertyValue = new CustomValueContainer
|
||||
(
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using FlaxEditor.Content;
|
||||
using FlaxEditor.CustomEditors;
|
||||
using FlaxEditor.GUI;
|
||||
@@ -106,13 +107,36 @@ namespace FlaxEditor.Windows.Assets
|
||||
/// <inheritdoc />
|
||||
protected override void OnAssetLoaded()
|
||||
{
|
||||
_object = Asset.CreateInstance();
|
||||
_object = Asset.Instance;
|
||||
if (_object == null)
|
||||
{
|
||||
// Hint developer about cause of failure
|
||||
var dataTypeName = Asset.DataTypeName;
|
||||
var type = Type.GetType(dataTypeName);
|
||||
if (type != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var obj = Activator.CreateInstance(type);
|
||||
var data = Asset.Data;
|
||||
FlaxEngine.Json.JsonSerializer.Deserialize(obj, data);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_presenter.NoSelectionText = "Failed to load asset. See log for more. " + ex.Message.Replace('\n', ' ');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_presenter.NoSelectionText = string.Format("Missing type '{0}'.", dataTypeName);
|
||||
}
|
||||
}
|
||||
_presenter.Select(_object);
|
||||
_undo.Clear();
|
||||
ClearEditedFlag();
|
||||
|
||||
// Auto-close on scripting reload if json asset is from game scripts (it might be reloaded)
|
||||
if (_object != null && FlaxEngine.Scripting.IsTypeFromGameScripts(_object.GetType()) && !_isRegisteredForScriptsReload)
|
||||
if ((_object == null || FlaxEngine.Scripting.IsTypeFromGameScripts(_object.GetType())) && !_isRegisteredForScriptsReload)
|
||||
{
|
||||
_isRegisteredForScriptsReload = true;
|
||||
ScriptsBuilder.ScriptsReloadBegin += OnScriptsReloadBegin;
|
||||
@@ -121,6 +145,14 @@ namespace FlaxEditor.Windows.Assets
|
||||
base.OnAssetLoaded();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnAssetLoadFailed()
|
||||
{
|
||||
_presenter.NoSelectionText = "Failed to load the asset.";
|
||||
|
||||
base.OnAssetLoadFailed();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnItemReimported(ContentItem item)
|
||||
{
|
||||
|
||||
@@ -77,6 +77,10 @@ namespace FlaxEditor.Windows.Assets
|
||||
[EditorOrder(200), DefaultValue(true), EditorDisplay("Transparency"), Tooltip("Enables reflections when rendering material.")]
|
||||
public bool EnableReflections;
|
||||
|
||||
[VisibleIf(nameof(EnableReflections))]
|
||||
[EditorOrder(210), DefaultValue(false), EditorDisplay("Transparency"), Tooltip("Enables Screen Space Reflections when rendering material.")]
|
||||
public bool EnableScreenSpaceReflections;
|
||||
|
||||
[EditorOrder(210), DefaultValue(true), EditorDisplay("Transparency"), Tooltip("Enables fog effects when rendering material.")]
|
||||
public bool EnableFog;
|
||||
|
||||
@@ -142,6 +146,7 @@ namespace FlaxEditor.Windows.Assets
|
||||
DepthTest = (info.FeaturesFlags & MaterialFeaturesFlags.DisableDepthTest) == 0;
|
||||
DepthWrite = (info.FeaturesFlags & MaterialFeaturesFlags.DisableDepthWrite) == 0;
|
||||
EnableReflections = (info.FeaturesFlags & MaterialFeaturesFlags.DisableReflections) == 0;
|
||||
EnableScreenSpaceReflections = (info.FeaturesFlags & MaterialFeaturesFlags.ScreenSpaceReflections) != 0;
|
||||
EnableFog = (info.FeaturesFlags & MaterialFeaturesFlags.DisableFog) == 0;
|
||||
EnableDistortion = (info.FeaturesFlags & MaterialFeaturesFlags.DisableDistortion) == 0;
|
||||
PixelNormalOffsetRefraction = (info.FeaturesFlags & MaterialFeaturesFlags.PixelNormalOffsetRefraction) != 0;
|
||||
@@ -177,6 +182,8 @@ namespace FlaxEditor.Windows.Assets
|
||||
info.FeaturesFlags |= MaterialFeaturesFlags.DisableDepthWrite;
|
||||
if (!EnableReflections)
|
||||
info.FeaturesFlags |= MaterialFeaturesFlags.DisableReflections;
|
||||
if (EnableScreenSpaceReflections)
|
||||
info.FeaturesFlags |= MaterialFeaturesFlags.ScreenSpaceReflections;
|
||||
if (!EnableFog)
|
||||
info.FeaturesFlags |= MaterialFeaturesFlags.DisableFog;
|
||||
if (!EnableDistortion)
|
||||
|
||||
@@ -111,6 +111,8 @@ void SlotBucketInit(AnimGraphInstanceData::Bucket& bucket)
|
||||
bucket.Slot.TimePosition = 0.0f;
|
||||
bucket.Slot.BlendInPosition = 0.0f;
|
||||
bucket.Slot.BlendOutPosition = 0.0f;
|
||||
bucket.Slot.LoopsDone = 0;
|
||||
bucket.Slot.LoopsLeft = 0;
|
||||
}
|
||||
|
||||
bool SortMultiBlend1D(const byte& a, const byte& b, AnimGraphNode* n)
|
||||
|
||||
@@ -260,6 +260,7 @@ struct FLAXENGINE_API AnimGraphSlot
|
||||
float Speed = 1.0f;
|
||||
float BlendInTime = 0.0f;
|
||||
float BlendOutTime = 0.0f;
|
||||
int32 LoopCount = 0;
|
||||
bool Pause = false;
|
||||
};
|
||||
|
||||
@@ -314,6 +315,8 @@ public:
|
||||
float TimePosition;
|
||||
float BlendInPosition;
|
||||
float BlendOutPosition;
|
||||
int32 LoopsDone;
|
||||
int32 LoopsLeft;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1924,6 +1924,8 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu
|
||||
bucket.TimePosition = 0.0f;
|
||||
bucket.BlendInPosition = 0.0f;
|
||||
bucket.BlendOutPosition = 0.0f;
|
||||
bucket.LoopsDone = 0;
|
||||
bucket.LoopsLeft = slot.LoopCount;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1940,18 +1942,27 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu
|
||||
ASSERT(slot.Animation && slot.Animation->IsLoaded());
|
||||
const float deltaTime = slot.Pause ? 0.0f : context.DeltaTime * slot.Speed;
|
||||
const float length = anim->GetLength();
|
||||
const bool loop = bucket.LoopsLeft != 0;
|
||||
float newTimePos = bucket.TimePosition + deltaTime;
|
||||
if (newTimePos >= length)
|
||||
{
|
||||
// End playing animation
|
||||
value = tryGetValue(node->GetBox(1), Value::Null);
|
||||
bucket.Index = -1;
|
||||
slot.Animation = nullptr;
|
||||
return;
|
||||
if (bucket.LoopsLeft == 0)
|
||||
{
|
||||
// End playing animation
|
||||
value = tryGetValue(node->GetBox(1), Value::Null);
|
||||
bucket.Index = -1;
|
||||
slot.Animation = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
// Loop animation
|
||||
if (bucket.LoopsLeft > 0)
|
||||
bucket.LoopsLeft--;
|
||||
bucket.LoopsDone++;
|
||||
}
|
||||
value = SampleAnimation(node, false, length, 0.0f, bucket.TimePosition, newTimePos, anim, slot.Speed);
|
||||
value = SampleAnimation(node, loop, length, 0.0f, bucket.TimePosition, newTimePos, anim, slot.Speed);
|
||||
bucket.TimePosition = newTimePos;
|
||||
if (slot.BlendOutTime > 0.0f && length - slot.BlendOutTime < bucket.TimePosition)
|
||||
if (bucket.LoopsLeft == 0 && slot.BlendOutTime > 0.0f && length - slot.BlendOutTime < bucket.TimePosition)
|
||||
{
|
||||
// Blend out
|
||||
auto input = tryGetValue(node->GetBox(1), Value::Null);
|
||||
@@ -1959,7 +1970,7 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu
|
||||
const float alpha = Math::Saturate(bucket.BlendOutPosition / slot.BlendOutTime);
|
||||
value = Blend(node, value, input, alpha, AlphaBlendMode::HermiteCubic);
|
||||
}
|
||||
else if (slot.BlendInTime > 0.0f && bucket.BlendInPosition < slot.BlendInTime)
|
||||
else if (bucket.LoopsDone == 0 && slot.BlendInTime > 0.0f && bucket.BlendInPosition < slot.BlendInTime)
|
||||
{
|
||||
// Blend in
|
||||
auto input = tryGetValue(node->GetBox(1), Value::Null);
|
||||
|
||||
@@ -430,6 +430,8 @@ void Material::InitCompilationOptions(ShaderCompilationOptions& options)
|
||||
options.Macros.Add({ "USE_DITHERED_LOD_TRANSITION", Numbers[info.FeaturesFlags & MaterialFeaturesFlags::DitheredLODTransition ? 1 : 0] });
|
||||
options.Macros.Add({ "USE_GBUFFER_CUSTOM_DATA", Numbers[useCustomData ? 1 : 0] });
|
||||
options.Macros.Add({ "USE_REFLECTIONS", Numbers[info.FeaturesFlags & MaterialFeaturesFlags::DisableReflections ? 0 : 1] });
|
||||
if (!(info.FeaturesFlags & MaterialFeaturesFlags::DisableReflections) && info.FeaturesFlags & MaterialFeaturesFlags::ScreenSpaceReflections)
|
||||
options.Macros.Add({ "MATERIAL_REFLECTIONS", Numbers[1]});
|
||||
options.Macros.Add({ "USE_FOG", Numbers[info.FeaturesFlags & MaterialFeaturesFlags::DisableFog ? 0 : 1] });
|
||||
if (useForward)
|
||||
options.Macros.Add({ "USE_PIXEL_NORMAL_OFFSET_REFRACTION", Numbers[info.FeaturesFlags & MaterialFeaturesFlags::PixelNormalOffsetRefraction ? 1 : 0] });
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
#include "Engine/Debug/Exceptions/JsonParseException.h"
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
#include "Engine/Scripting/Scripting.h"
|
||||
#include "Engine/Scripting/ManagedCLR/MClass.h"
|
||||
#include "Engine/Scripting/ManagedCLR/MField.h"
|
||||
#include "Engine/Utilities/StringConverter.h"
|
||||
|
||||
JsonAssetBase::JsonAssetBase(const SpawnParams& params, const AssetInfo* info)
|
||||
@@ -212,13 +214,11 @@ Asset::LoadResult JsonAsset::loadAsset()
|
||||
|
||||
if (CreateInstance())
|
||||
return LoadResult::Failed;
|
||||
|
||||
#if USE_EDITOR
|
||||
if (Instance)
|
||||
{
|
||||
// Reload instance when module with this type gets reloaded
|
||||
Level::ScriptsReloadStart.Bind<JsonAsset, &JsonAsset::OnScriptsReloadStart>(this);
|
||||
Level::ScriptsReloaded.Bind<JsonAsset, &JsonAsset::OnScriptsReloaded>(this);
|
||||
}
|
||||
// Reload instance when module with this type gets reloaded
|
||||
Level::ScriptsReloadStart.Bind<JsonAsset, &JsonAsset::OnScriptsReloadStart>(this);
|
||||
Level::ScriptsReloaded.Bind<JsonAsset, &JsonAsset::OnScriptsReloaded>(this);
|
||||
#endif
|
||||
|
||||
return LoadResult::Ok;
|
||||
@@ -226,14 +226,11 @@ Asset::LoadResult JsonAsset::loadAsset()
|
||||
|
||||
void JsonAsset::unload(bool isReloading)
|
||||
{
|
||||
if (Instance)
|
||||
{
|
||||
#if USE_EDITOR
|
||||
Level::ScriptsReloadStart.Unbind<JsonAsset, &JsonAsset::OnScriptsReloadStart>(this);
|
||||
Level::ScriptsReloaded.Unbind<JsonAsset, &JsonAsset::OnScriptsReloaded>(this);
|
||||
Level::ScriptsReloadStart.Unbind<JsonAsset, &JsonAsset::OnScriptsReloadStart>(this);
|
||||
Level::ScriptsReloaded.Unbind<JsonAsset, &JsonAsset::OnScriptsReloaded>(this);
|
||||
#endif
|
||||
DeleteInstance();
|
||||
}
|
||||
DeleteInstance();
|
||||
|
||||
JsonAssetBase::unload(isReloading);
|
||||
}
|
||||
@@ -281,6 +278,13 @@ bool JsonAsset::CreateInstance()
|
||||
|
||||
void JsonAsset::DeleteInstance()
|
||||
{
|
||||
// C# instance
|
||||
if (MObject* object = GetManagedInstance())
|
||||
{
|
||||
GetClass()->GetField("_instance")->SetValue(object, nullptr);
|
||||
}
|
||||
|
||||
// C++ instance
|
||||
if (!Instance || !_dtor)
|
||||
return;
|
||||
_dtor(Instance);
|
||||
|
||||
@@ -7,27 +7,35 @@ namespace FlaxEngine
|
||||
{
|
||||
partial class JsonAsset
|
||||
{
|
||||
private object _instance;
|
||||
|
||||
/// <summary>
|
||||
/// Creates the serialized object instance from the json asset data.
|
||||
/// Gets the instance of the serialized object from the json asset data. Cached internally.
|
||||
/// </summary>
|
||||
/// <returns>The created object or null.</returns>
|
||||
public object Instance => _instance ?? (_instance = CreateInstance());
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the serialized object from the json asset data.
|
||||
/// </summary>
|
||||
/// <remarks>Use <see cref="Instance"/> to get cached object.</remarks>
|
||||
/// <returns>The new object or null if failed.</returns>
|
||||
public T CreateInstance<T>()
|
||||
{
|
||||
return (T)CreateInstance();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the serialized object instance from the json asset data.
|
||||
/// Creates a new instance of the serialized object from the json asset data.
|
||||
/// </summary>
|
||||
/// <returns>The created object or null.</returns>
|
||||
/// <remarks>Use <see cref="Instance"/> to get cached object.</remarks>
|
||||
/// <returns>The new object or null if failed.</returns>
|
||||
public object CreateInstance()
|
||||
{
|
||||
if (WaitForLoaded())
|
||||
return null;
|
||||
|
||||
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
|
||||
var dataTypeName = DataTypeName;
|
||||
|
||||
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
|
||||
for (int i = 0; i < assemblies.Length; i++)
|
||||
{
|
||||
var assembly = assemblies[i];
|
||||
@@ -48,14 +56,14 @@ namespace FlaxEngine
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogException(ex);
|
||||
Debug.LogException(ex, this);
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Debug.LogError(string.Format("Missing type '{0}' to create Json Asset instance.", dataTypeName), this);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ CreateAssetResult CreateMaterial::Create(CreateAssetContext& context)
|
||||
if (context.AllocateChunk(SHADER_FILE_CHUNK_VISJECT_SURFACE))
|
||||
return CreateAssetResult::CannotAllocateChunk;
|
||||
layer->Graph.Nodes.EnsureCapacity(32);
|
||||
layer->Root = (MaterialGraphNode*)&layer->Graph.Nodes[0];
|
||||
layer->Root = &layer->Graph.Nodes[0];
|
||||
for (auto& box : layer->Root->Boxes)
|
||||
box.Parent = layer->Root;
|
||||
Meta11 meta;
|
||||
|
||||
@@ -202,7 +202,7 @@ namespace FlaxEditor.Content.Settings
|
||||
var asset = FlaxEngine.Content.LoadAsync<JsonAsset>(GameSettingsAssetPath);
|
||||
if (asset && !asset.WaitForLoaded())
|
||||
{
|
||||
if (asset.CreateInstance() is GameSettings result)
|
||||
if (asset.Instance is GameSettings result)
|
||||
return result;
|
||||
}
|
||||
return new GameSettings();
|
||||
@@ -212,7 +212,7 @@ namespace FlaxEditor.Content.Settings
|
||||
{
|
||||
if (asset && !asset.WaitForLoaded())
|
||||
{
|
||||
if (asset.CreateInstance() is T result)
|
||||
if (asset.Instance is T result)
|
||||
return result;
|
||||
}
|
||||
return new T();
|
||||
@@ -222,7 +222,7 @@ namespace FlaxEditor.Content.Settings
|
||||
{
|
||||
if (asset && !asset.WaitForLoaded() && asset.DataTypeName == typename)
|
||||
{
|
||||
if (asset.CreateInstance() is SettingsBase result)
|
||||
if (asset.Instance is SettingsBase result)
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
@@ -314,7 +314,7 @@ namespace FlaxEditor.Content.Settings
|
||||
{
|
||||
if (e.Value && !e.Value.WaitForLoaded() && e.Value.DataTypeName == type.FullName)
|
||||
{
|
||||
var custom = e.Value.CreateInstance();
|
||||
var custom = e.Value.Instance;
|
||||
if (custom is T result)
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -405,6 +405,59 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Binds a static function (if not binded yet).
|
||||
/// </summary>
|
||||
template<void(*Method)(Params ...)>
|
||||
void BindUnique()
|
||||
{
|
||||
FunctionType f;
|
||||
f.template Bind<Method>();
|
||||
BindUnique(f);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Binds a member function (if not binded yet).
|
||||
/// </summary>
|
||||
/// <param name="callee">The object instance.</param>
|
||||
template<class T, void(T::*Method)(Params ...)>
|
||||
void BindUnique(T* callee)
|
||||
{
|
||||
FunctionType f;
|
||||
f.template Bind<T, Method>(callee);
|
||||
BindUnique(f);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Binds a function (if not binded yet).
|
||||
/// </summary>
|
||||
/// <param name="method">The method.</param>
|
||||
void BindUnique(Signature method)
|
||||
{
|
||||
FunctionType f(method);
|
||||
BindUnique(f);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Binds a function (if not binded yet).
|
||||
/// </summary>
|
||||
/// <param name="f">The function to bind.</param>
|
||||
void BindUnique(const FunctionType& f)
|
||||
{
|
||||
const intptr size = Platform::AtomicRead(&_size);
|
||||
FunctionType* bindings = (FunctionType*)Platform::AtomicRead(&_ptr);
|
||||
if (bindings)
|
||||
{
|
||||
// Skip if already binded
|
||||
for (intptr i = 0; i < size; i++)
|
||||
{
|
||||
if (Platform::AtomicRead((intptr volatile*)&bindings[i]._callee) == (intptr)f._callee && Platform::AtomicRead((intptr volatile*)&bindings[i]._function) == (intptr)f._function)
|
||||
return;
|
||||
}
|
||||
}
|
||||
Bind(f);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unbinds a static function.
|
||||
/// </summary>
|
||||
|
||||
@@ -230,6 +230,20 @@ namespace FlaxEngine
|
||||
a);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates <see cref="Color"/> from the RGBA value.
|
||||
/// </summary>
|
||||
/// <param name="rgb">The packed RGBA value.</param>
|
||||
/// <returns>The color.</returns>
|
||||
public static Color FromRGBA(uint rgb)
|
||||
{
|
||||
return new Color(
|
||||
((rgb >> 16) & 0xff) / 255.0f,
|
||||
((rgb >> 8) & 0xff) / 255.0f,
|
||||
(rgb & 0xff) / 255.0f,
|
||||
((rgb >> 24) & 0xff) / 255.0f);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the color value as the hexadecimal string.
|
||||
/// </summary>
|
||||
|
||||
@@ -70,7 +70,7 @@ void ForwardMaterialShader::Bind(BindParameters& params)
|
||||
MaterialParameter::BindMeta bindMeta;
|
||||
bindMeta.Context = context;
|
||||
bindMeta.Constants = cb;
|
||||
bindMeta.Input = nullptr; // forward pass materials cannot sample scene color for now
|
||||
bindMeta.Input = params.Input;
|
||||
bindMeta.Buffers = params.RenderContext.Buffers;
|
||||
bindMeta.CanSampleDepth = GPUDevice::Instance->Limits.HasReadOnlyDepth;
|
||||
bindMeta.CanSampleGBuffer = true;
|
||||
|
||||
@@ -272,6 +272,11 @@ API_ENUM(Attributes="Flags") enum class MaterialFeaturesFlags : uint32
|
||||
/// The flag used to enable refraction offset based on the difference between the per-pixel normal and the per-vertex normal. Useful for large water-like surfaces.
|
||||
/// </summary>
|
||||
PixelNormalOffsetRefraction = 1 << 9,
|
||||
|
||||
/// <summary>
|
||||
/// The flag used to enable high-quality reflections based on the screen space raytracing. Useful for large water-like surfaces. The Forward Pass materials option.
|
||||
/// </summary>
|
||||
ScreenSpaceReflections = 1 << 10,
|
||||
};
|
||||
|
||||
DECLARE_ENUM_OPERATORS(MaterialFeaturesFlags);
|
||||
|
||||
@@ -406,11 +406,13 @@ void MaterialParameter::Bind(BindMeta& meta) const
|
||||
{
|
||||
case MaterialSceneTextures::SceneDepth:
|
||||
view = meta.CanSampleDepth
|
||||
? (GPUDevice::Instance->Limits.HasReadOnlyDepth ? meta.Buffers->DepthBuffer->ViewReadOnlyDepth() : meta.Buffers->DepthBuffer->View())
|
||||
? meta.Buffers->DepthBuffer->GetDescription().Flags & GPUTextureFlags::ReadOnlyDepthView ? meta.Buffers->DepthBuffer->ViewReadOnlyDepth() : meta.Buffers->DepthBuffer->View()
|
||||
: GPUDevice::Instance->GetDefaultWhiteTexture()->View();
|
||||
break;
|
||||
case MaterialSceneTextures::AmbientOcclusion:
|
||||
case MaterialSceneTextures::BaseColor:
|
||||
case MaterialSceneTextures::DiffuseColor:
|
||||
case MaterialSceneTextures::SpecularColor:
|
||||
view = meta.CanSampleGBuffer ? meta.Buffers->GBuffer0->View() : nullptr;
|
||||
break;
|
||||
case MaterialSceneTextures::WorldNormal:
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
/// <summary>
|
||||
/// Current materials shader version.
|
||||
/// </summary>
|
||||
#define MATERIAL_GRAPH_VERSION 150
|
||||
#define MATERIAL_GRAPH_VERSION 151
|
||||
|
||||
class Material;
|
||||
class GPUShader;
|
||||
|
||||
@@ -419,6 +419,17 @@ Array<Actor*> Actor::GetChildren(const MClass* type) const
|
||||
return result;
|
||||
}
|
||||
|
||||
void Actor::DestroyChildren(float timeLeft)
|
||||
{
|
||||
Array<Actor*> children = Children;
|
||||
const bool useGameTime = timeLeft > ZeroTolerance;
|
||||
for (Actor* child : children)
|
||||
{
|
||||
child->SetParent(nullptr, false, false);
|
||||
child->DeleteObject(timeLeft, useGameTime);
|
||||
}
|
||||
}
|
||||
|
||||
bool Actor::HasTag(const StringView& tag) const
|
||||
{
|
||||
return HasTag() && tag == Level::Tags[_tag];
|
||||
|
||||
@@ -296,23 +296,6 @@ namespace FlaxEngine
|
||||
return output;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destroys the children. Calls Object.Destroy on every child actor and unlink them for the parent.
|
||||
/// </summary>
|
||||
/// <param name="timeLeft">The time left to destroy object (in seconds).</param>
|
||||
[NoAnimate]
|
||||
public void DestroyChildren(float timeLeft = 0.0f)
|
||||
{
|
||||
if (ChildrenCount == 0)
|
||||
return;
|
||||
Actor[] children = Children;
|
||||
for (var i = 0; i < children.Length; i++)
|
||||
{
|
||||
children[i].Parent = null;
|
||||
Destroy(children[i], timeLeft);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the matrix that transforms a point from the world space to local space of the actor.
|
||||
/// </summary>
|
||||
|
||||
@@ -244,6 +244,12 @@ public:
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destroys the children. Calls Object.Destroy on every child actor and unlinks them for this actor.
|
||||
/// </summary>
|
||||
/// <param name="timeLeft">The time left to destroy object (in seconds).</param>
|
||||
API_FUNCTION(Attributes="NoAnimate") void DestroyChildren(float timeLeft = 0.0f);
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -325,7 +325,7 @@ void AnimatedModel::ClearBlendShapeWeights()
|
||||
_blendShapes.Clear();
|
||||
}
|
||||
|
||||
void AnimatedModel::PlaySlotAnimation(const StringView& slotName, Animation* anim, float speed, float blendInTime, float blendOutTime)
|
||||
void AnimatedModel::PlaySlotAnimation(const StringView& slotName, Animation* anim, float speed, float blendInTime, float blendOutTime, int32 loopCount)
|
||||
{
|
||||
CHECK(anim);
|
||||
for (auto& slot : GraphInstance.Slots)
|
||||
@@ -334,6 +334,7 @@ void AnimatedModel::PlaySlotAnimation(const StringView& slotName, Animation* ani
|
||||
{
|
||||
slot.Pause = false;
|
||||
slot.BlendInTime = blendInTime;
|
||||
slot.LoopCount = loopCount;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -351,6 +352,7 @@ void AnimatedModel::PlaySlotAnimation(const StringView& slotName, Animation* ani
|
||||
slot.Speed = speed;
|
||||
slot.BlendInTime = blendInTime;
|
||||
slot.BlendOutTime = blendOutTime;
|
||||
slot.LoopCount = loopCount;
|
||||
}
|
||||
|
||||
void AnimatedModel::StopSlotAnimation()
|
||||
|
||||
@@ -313,7 +313,8 @@ public:
|
||||
/// <param name="speed">The playback speed.</param>
|
||||
/// <param name="blendInTime">The animation blending in time (in seconds). Cam be used to smooth the slot animation playback with the input pose when starting the animation.</param>
|
||||
/// <param name="blendOutTime">The animation blending out time (in seconds). Cam be used to smooth the slot animation playback with the input pose when ending animation.</param>
|
||||
API_FUNCTION() void PlaySlotAnimation(const StringView& slotName, Animation* anim, float speed = 1.0f, float blendInTime = 0.2f, float blendOutTime = 0.2f);
|
||||
/// <param name="loopCount">The amount of loops to play the animation: 0 to play once, -1 to play infinite, 1 or higher to loop once or more.</param>
|
||||
API_FUNCTION() void PlaySlotAnimation(const StringView& slotName, Animation* anim, float speed = 1.0f, float blendInTime = 0.2f, float blendOutTime = 0.2f, int32 loopCount = 0);
|
||||
|
||||
/// <summary>
|
||||
/// Stops all the animations playback on the all slots in Anim Graph.
|
||||
|
||||
@@ -96,7 +96,7 @@ namespace FlaxEngine
|
||||
/// <summary>
|
||||
/// Gets the font object described by the structure.
|
||||
/// </summary>
|
||||
/// <returns>Th font or null if descriptor is invalid.</returns>
|
||||
/// <returns>The font or null if descriptor is invalid.</returns>
|
||||
public Font GetFont()
|
||||
{
|
||||
if (_cachedFont)
|
||||
|
||||
@@ -74,10 +74,7 @@ void ForwardPass::Dispose()
|
||||
void ForwardPass::Render(RenderContext& renderContext, GPUTexture* input, GPUTexture* output)
|
||||
{
|
||||
PROFILE_GPU_CPU("Forward");
|
||||
|
||||
// Cache data
|
||||
auto device = GPUDevice::Instance;
|
||||
auto context = device->GetMainContext();
|
||||
auto context = GPUDevice::Instance->GetMainContext();
|
||||
auto& view = renderContext.View;
|
||||
auto mainCache = renderContext.List;
|
||||
|
||||
@@ -141,6 +138,6 @@ void ForwardPass::Render(RenderContext& renderContext, GPUTexture* input, GPUTex
|
||||
// Run forward pass
|
||||
view.Pass = DrawPass::Forward;
|
||||
context->SetRenderTarget(depthBufferHandle, output->View());
|
||||
mainCache->ExecuteDrawCalls(renderContext, forwardList);
|
||||
mainCache->ExecuteDrawCalls(renderContext, forwardList, input->View());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -554,7 +554,7 @@ bool CanUseInstancing(DrawPass pass)
|
||||
return pass == DrawPass::GBuffer || pass == DrawPass::Depth;
|
||||
}
|
||||
|
||||
void RenderList::ExecuteDrawCalls(const RenderContext& renderContext, DrawCallsList& list)
|
||||
void RenderList::ExecuteDrawCalls(const RenderContext& renderContext, DrawCallsList& list, GPUTextureView* input)
|
||||
{
|
||||
if (list.IsEmpty())
|
||||
return;
|
||||
@@ -626,6 +626,7 @@ DRAW:
|
||||
|
||||
// Execute draw calls
|
||||
MaterialBase::BindParameters bindParams(context, renderContext);
|
||||
bindParams.Input = input;
|
||||
if (useInstancing)
|
||||
{
|
||||
int32 instanceBufferOffset = 0;
|
||||
|
||||
@@ -570,9 +570,10 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="renderContext">The rendering context.</param>
|
||||
/// <param name="listType">The collected draw calls list type.</param>
|
||||
API_FUNCTION() FORCE_INLINE void ExecuteDrawCalls(API_PARAM(Ref) const RenderContext& renderContext, DrawCallsListType listType)
|
||||
/// <param name="input">The input scene color. It's optional and used in forward/postFx rendering.</param>
|
||||
API_FUNCTION() FORCE_INLINE void ExecuteDrawCalls(API_PARAM(Ref) const RenderContext& renderContext, DrawCallsListType listType, GPUTextureView* input = nullptr)
|
||||
{
|
||||
ExecuteDrawCalls(renderContext, DrawCallsLists[(int32)listType]);
|
||||
ExecuteDrawCalls(renderContext, DrawCallsLists[(int32)listType], input);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -580,7 +581,8 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="renderContext">The rendering context.</param>
|
||||
/// <param name="list">The collected draw calls list.</param>
|
||||
void ExecuteDrawCalls(const RenderContext& renderContext, DrawCallsList& list);
|
||||
/// <param name="input">The input scene color. It's optional and used in forward/postFx rendering.</param>
|
||||
void ExecuteDrawCalls(const RenderContext& renderContext, DrawCallsList& list, GPUTextureView* input = nullptr);
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -448,8 +448,9 @@ void RenderInner(SceneRenderTask* task, RenderContext& renderContext)
|
||||
}
|
||||
|
||||
// Run forward pass
|
||||
auto forwardPassResult = renderContext.Buffers->RT1_FloatRGB;
|
||||
ForwardPass::Instance()->Render(renderContext, lightBuffer, forwardPassResult);
|
||||
GPUTexture* frameBuffer = renderContext.Buffers->RT1_FloatRGB;
|
||||
GPUTexture* tempBuffer = renderContext.Buffers->RT2_FloatRGB;
|
||||
ForwardPass::Instance()->Render(renderContext, lightBuffer, frameBuffer);
|
||||
|
||||
// Cleanup
|
||||
context->ResetRenderTarget();
|
||||
@@ -462,16 +463,10 @@ void RenderInner(SceneRenderTask* task, RenderContext& renderContext)
|
||||
{
|
||||
context->SetRenderTarget(task->GetOutputView());
|
||||
context->SetViewportAndScissors(task->GetOutputViewport());
|
||||
context->Draw(forwardPassResult);
|
||||
context->Draw(frameBuffer);
|
||||
return;
|
||||
}
|
||||
|
||||
// Prepare buffers for post processing frame
|
||||
GPUTexture* frameBuffer = renderContext.Buffers->RT1_FloatRGB;
|
||||
GPUTexture* tempBuffer = renderContext.Buffers->RT2_FloatRGB;
|
||||
if (forwardPassResult == tempBuffer)
|
||||
Swap(frameBuffer, tempBuffer);
|
||||
|
||||
// Material and Custom PostFx
|
||||
renderContext.List->RunMaterialPostFxPass(context, renderContext, MaterialPostFxLocation::BeforePostProcessingPass, frameBuffer, tempBuffer);
|
||||
renderContext.List->RunCustomPostFxPass(context, renderContext, PostProcessEffectLocation::BeforePostProcessingPass, frameBuffer, tempBuffer);
|
||||
|
||||
@@ -42,13 +42,10 @@ PACK_STRUCT(struct Data
|
||||
float TemporalScale;
|
||||
|
||||
float RayTraceStep;
|
||||
float NoTemporalEffect;
|
||||
float TemporalEffect;
|
||||
float Intensity;
|
||||
float FadeOutDistance;
|
||||
|
||||
Vector3 Dummy0;
|
||||
float InvFadeDistance;
|
||||
|
||||
Matrix ViewMatrix;
|
||||
Matrix ViewProjectionMatrix;
|
||||
});
|
||||
@@ -248,11 +245,10 @@ void ScreenSpaceReflectionsPass::Render(RenderContext& renderContext, GPUTexture
|
||||
data.MaxColorMiplevel = settings.UseColorBufferMips ? (float)colorBufferMips - 2.0f : 0.0f;
|
||||
data.RayTraceStep = static_cast<float>(settings.DepthResolution) / (float)width;
|
||||
data.Intensity = settings.Intensity;
|
||||
data.FadeOutDistance = settings.FadeOutDistance;
|
||||
data.InvFadeDistance = 1.0f / settings.FadeDistance;
|
||||
data.FadeOutDistance = Math::Max(settings.FadeOutDistance, 100.0f);
|
||||
data.TemporalScale = settings.TemporalScale;
|
||||
data.TemporalResponse = settings.TemporalResponse;
|
||||
data.NoTemporalEffect = useTemporal ? 0.0f : 1.0f;
|
||||
data.TemporalEffect = useTemporal ? 1.0f : 0.0f;
|
||||
if (useTemporal)
|
||||
{
|
||||
const float time = Time::Draw.UnscaledTime.GetTotalSeconds();
|
||||
|
||||
@@ -17,6 +17,16 @@ namespace FlaxEngine
|
||||
/// </summary>
|
||||
public string Text;
|
||||
|
||||
/// <summary>
|
||||
/// The custom header font size.
|
||||
/// </summary>
|
||||
public int FontSize;
|
||||
|
||||
/// <summary>
|
||||
/// The custom header color (as 32-bit uint).
|
||||
/// </summary>
|
||||
public uint Color;
|
||||
|
||||
private HeaderAttribute()
|
||||
{
|
||||
}
|
||||
@@ -25,9 +35,13 @@ namespace FlaxEngine
|
||||
/// Initializes a new instance of the <see cref="HeaderAttribute"/> class.
|
||||
/// </summary>
|
||||
/// <param name="text">The header text.</param>
|
||||
public HeaderAttribute(string text)
|
||||
/// <param name="fontSize">The header text font size (-1 to use default which is 14).</param>
|
||||
/// <param name="color">The header color (as 32-bit uint, 0 to use default).</param>
|
||||
public HeaderAttribute(string text, int fontSize = -1, uint color = 0)
|
||||
{
|
||||
Text = text;
|
||||
FontSize = fontSize;
|
||||
Color = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace FlaxEngine
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="HeaderAttribute"/> class.
|
||||
/// Initializes a new instance of the <see cref="VisibleIfAttribute"/> class.
|
||||
/// </summary>
|
||||
/// <param name="memberName">The name of the field or property of the object. Must be a bool type.</param>
|
||||
/// <param name="invert">True if invert member value when computing the visibility value.</param>
|
||||
|
||||
@@ -9,7 +9,7 @@ MaterialValue* MaterialGenerator::sampleTextureRaw(Node* caller, Value& value, B
|
||||
ASSERT(texture && box);
|
||||
|
||||
// Cache data
|
||||
const auto parent = box->GetParent<MaterialGraphNode>();
|
||||
const auto parent = box->GetParent<ShaderGraphNode<>>();
|
||||
const bool isCubemap = texture->Type == MaterialParameterType::CubeTexture;
|
||||
const bool isArray = texture->Type == MaterialParameterType::GPUTextureArray;
|
||||
const bool isVolume = texture->Type == MaterialParameterType::GPUTextureVolume;
|
||||
|
||||
@@ -163,7 +163,7 @@ bool MaterialGenerator::Generate(WriteStream& source, MaterialInfo& materialInfo
|
||||
|
||||
// Cache data
|
||||
MaterialLayer* baseLayer = GetRootLayer();
|
||||
MaterialGraphNode* baseNode = baseLayer->Root;
|
||||
auto* baseNode = baseLayer->Root;
|
||||
_treeLayerVarName = baseLayer->GetVariableName(nullptr);
|
||||
_treeLayer = baseLayer;
|
||||
_graphStack.Add(&_treeLayer->Graph);
|
||||
@@ -398,6 +398,14 @@ bool MaterialGenerator::Generate(WriteStream& source, MaterialInfo& materialInfo
|
||||
_writer.Write(TEXT("#define MATERIAL_MASK_THRESHOLD ({0})\n"), baseLayer->MaskThreshold);
|
||||
_writer.Write(TEXT("#define CUSTOM_VERTEX_INTERPOLATORS_COUNT ({0})\n"), _vsToPsInterpolants.Count());
|
||||
_writer.Write(TEXT("#define MATERIAL_OPACITY_THRESHOLD ({0})\n"), baseLayer->OpacityThreshold);
|
||||
if (materialInfo.BlendMode != MaterialBlendMode::Opaque && !(materialInfo.FeaturesFlags & MaterialFeaturesFlags::DisableReflections) && materialInfo.FeaturesFlags & MaterialFeaturesFlags::ScreenSpaceReflections)
|
||||
{
|
||||
// Inject depth and color buffers for Screen Space Reflections used by transparent material
|
||||
auto sceneDepthTexture = findOrAddSceneTexture(MaterialSceneTextures::SceneDepth);
|
||||
auto sceneColorTexture = findOrAddSceneTexture(MaterialSceneTextures::SceneColor);
|
||||
_writer.Write(TEXT("#define MATERIAL_REFLECTIONS_SSR_DEPTH ({0})\n"), sceneDepthTexture.ShaderName);
|
||||
_writer.Write(TEXT("#define MATERIAL_REFLECTIONS_SSR_COLOR ({0})\n"), sceneColorTexture.ShaderName);
|
||||
}
|
||||
WRITE_FEATURES(Defines);
|
||||
inputs[In_Defines] = _writer.ToString();
|
||||
_writer.Clear();
|
||||
@@ -447,6 +455,7 @@ bool MaterialGenerator::Generate(WriteStream& source, MaterialInfo& materialInfo
|
||||
}
|
||||
for (auto f : features)
|
||||
{
|
||||
// Process SRV slots used in template
|
||||
const auto& text = Features[f].Inputs[(int32)FeatureTemplateInputsMapping::Resources];
|
||||
const Char* str = text.Get();
|
||||
int32 prevIdx = 0, idx = 0;
|
||||
@@ -483,6 +492,21 @@ bool MaterialGenerator::Generate(WriteStream& source, MaterialInfo& materialInfo
|
||||
// Utilities
|
||||
{
|
||||
WRITE_FEATURES(Utilities);
|
||||
Array<Graph*, InlinedAllocation<8>> graphs;
|
||||
_functions.GetValues(graphs);
|
||||
for (MaterialLayer* layer : _layers)
|
||||
graphs.Add(&layer->Graph);
|
||||
for (Graph* graph : graphs)
|
||||
{
|
||||
for (const MaterialGraph::Node& node : graph->Nodes)
|
||||
{
|
||||
if (node.Type == GRAPH_NODE_MAKE_TYPE(1, 38) && (bool)node.Values[1])
|
||||
{
|
||||
// Custom Global Code
|
||||
_writer.Write((StringView)node.Values[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
inputs[In_Utilities] = _writer.ToString();
|
||||
_writer.Clear();
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ void MaterialLayer::Prepare()
|
||||
const auto node = &Graph.Nodes[i];
|
||||
if (node->Type == ROOT_NODE_TYPE)
|
||||
{
|
||||
Root = (MaterialGraphNode*)node;
|
||||
Root = node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -159,7 +159,7 @@ MaterialLayer* MaterialLayer::Load(const Guid& id, ReadStream* graphData, const
|
||||
{
|
||||
if (layer->Graph.Nodes[i].Type == ROOT_NODE_TYPE)
|
||||
{
|
||||
layer->Root = (MaterialGraphNode*)&layer->Graph.Nodes[i];
|
||||
layer->Root = &layer->Graph.Nodes[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -233,7 +233,7 @@ void MaterialLayer::createRootNode()
|
||||
#undef INIT_BOX
|
||||
|
||||
// Mark as root
|
||||
Root = (MaterialGraphNode*)&rootNode;
|
||||
Root = &rootNode;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -50,7 +50,7 @@ public:
|
||||
/// <summary>
|
||||
/// Root node
|
||||
/// </summary>
|
||||
MaterialGraphNode* Root;
|
||||
MaterialGraph::Node* Root;
|
||||
|
||||
/// <summary>
|
||||
/// Material structure variable name (different for every layer sampling with different UVs, default UVs are a first index)
|
||||
|
||||
@@ -7,10 +7,6 @@
|
||||
#include "Engine/Core/Enums.h"
|
||||
#include "Engine/Visject/ShaderGraph.h"
|
||||
|
||||
class MaterialGraphNode : public ShaderGraphNode<>
|
||||
{
|
||||
};
|
||||
|
||||
class MaterialGraph : public ShaderGraph<>
|
||||
{
|
||||
};
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace FlaxEngine.Utilities
|
||||
/// Requests the mesh data.
|
||||
/// </summary>
|
||||
/// <param name="model">The model to get it's data.</param>
|
||||
/// <returns>True if ahs valid data to access, otherwise false if it's during downloading.</returns>
|
||||
/// <returns>True if has valid data to access, otherwise false if it's during downloading.</returns>
|
||||
public bool RequestMeshData(Model model)
|
||||
{
|
||||
if (model == null)
|
||||
|
||||
@@ -1350,6 +1350,13 @@ void VisjectExecutor::ProcessGroupCollections(Box* box, Node* node, Value& value
|
||||
array.Reverse();
|
||||
value = MoveTemp(v);
|
||||
break;
|
||||
// Add Unique
|
||||
case 14:
|
||||
b = node->GetBox(1);
|
||||
ENSURE(b->HasConnection(), TEXT("Missing value to add."));
|
||||
array.AddUnique(eatBox(b->GetParent<Node>(), b->FirstConnection()));
|
||||
value = MoveTemp(v);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,18 +42,13 @@ float4 SampleReflectionProbe(float3 viewPos, TextureCube probe, ProbeData data,
|
||||
return probeSample * fade;
|
||||
}
|
||||
|
||||
float3 GetEnvProbeLighting(float3 viewPos, TextureCube probe, ProbeData data, GBufferSample gBuffer)
|
||||
// Calculates the reflective environment lighting to multiply the raw reflection color for the specular light (eg. from Env Probe or SSR).
|
||||
float3 GetReflectionSpecularLighting(float3 viewPos, GBufferSample gBuffer)
|
||||
{
|
||||
// Calculate reflections
|
||||
float3 reflections = SampleReflectionProbe(viewPos, probe, data, gBuffer.WorldPos, gBuffer.Normal, gBuffer.Roughness).rgb;
|
||||
|
||||
// Calculate specular color
|
||||
float3 specularColor = GetSpecularColor(gBuffer);
|
||||
|
||||
// Calculate reflecion color
|
||||
float3 V = normalize(viewPos - gBuffer.WorldPos);
|
||||
float NoV = saturate(dot(gBuffer.Normal, V));
|
||||
return reflections * EnvBRDFApprox(specularColor, gBuffer.Roughness, NoV);
|
||||
return EnvBRDFApprox(specularColor, gBuffer.Roughness, NoV);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "./Flax/Common.hlsl"
|
||||
#include "./Flax/BRDF.hlsl"
|
||||
#include "./Flax/Random.hlsl"
|
||||
#include "./Flax/MonteCarlo.hlsl"
|
||||
#include "./Flax/GBufferCommon.hlsl"
|
||||
|
||||
float max2(float2 v)
|
||||
{
|
||||
return max(v.x, v.y);
|
||||
}
|
||||
|
||||
float2 RandN2(float2 pos, float2 random)
|
||||
{
|
||||
return frac(sin(dot(pos.xy + random, float2(12.9898, 78.233))) * float2(43758.5453, 28001.8384));
|
||||
}
|
||||
|
||||
// 1:-1 to 0:1
|
||||
float2 ClipToUv(float2 clipPos)
|
||||
{
|
||||
return clipPos * float2(0.5, -0.5) + float2(0.5, 0.5);
|
||||
}
|
||||
|
||||
// go into clip space (-1:1 from bottom/left to up/right)
|
||||
float3 ProjectWorldToClip(float3 wsPos, float4x4 viewProjectionMatrix)
|
||||
{
|
||||
float4 clipPos = mul(float4(wsPos, 1), viewProjectionMatrix);
|
||||
return clipPos.xyz / clipPos.w;
|
||||
}
|
||||
|
||||
// go into UV space. (0:1 from top/left to bottom/right)
|
||||
float3 ProjectWorldToUv(float3 wsPos, float4x4 viewProjectionMatrix)
|
||||
{
|
||||
float3 clipPos = ProjectWorldToClip(wsPos, viewProjectionMatrix);
|
||||
return float3(ClipToUv(clipPos.xy), clipPos.z);
|
||||
}
|
||||
|
||||
float3 TangentToWorld(float3 N, float4 H)
|
||||
{
|
||||
float3 upVector = abs(N.z) < 0.999 ? float3(0.0, 0.0, 1.0) : float3(1.0, 0.0, 0.0);
|
||||
float3 T = normalize(cross(upVector, N));
|
||||
float3 B = cross(N, T);
|
||||
return float3((T * H.x) + (B * H.y) + (N * H.z));
|
||||
}
|
||||
|
||||
float RayAttenBorder(float2 pos, float value)
|
||||
{
|
||||
float borderDist = min(1.0 - max(pos.x, pos.y), min(pos.x, pos.y));
|
||||
return saturate(borderDist > value ? 1.0 : borderDist / value);
|
||||
}
|
||||
|
||||
// Screen Space Reflection ray tracing utility.
|
||||
// Returns: xy: hitUV, z: hitMask, where hitUV is the result UV of hit pixel, hitMask is the normalized sample weight (0 if no hit).
|
||||
float3 TraceSceenSpaceReflection(float2 uv, GBufferSample gBuffer, Texture2D depthBuffer, float3 viewPos, float4x4 viewMatrix, float4x4 viewProjectionMatrix, float stepSize, float maxSamples = 20, bool temporal = false, float temporalTime = 0.0f, float worldAntiSelfOcclusionBias = 0.1f, float brdfBias = 0.82f, float drawDistance = 5000.0f, float roughnessThreshold = 0.4f, float edgeFade = 0.1f)
|
||||
{
|
||||
// Reject invalid pixels
|
||||
if (gBuffer.ShadingModel == SHADING_MODEL_UNLIT || gBuffer.Roughness > roughnessThreshold || gBuffer.ViewPos.z > drawDistance)
|
||||
return 0;
|
||||
|
||||
// Calculate view space normal vector
|
||||
float3 normalVS = mul(gBuffer.Normal, (float3x3)viewMatrix);
|
||||
|
||||
// Randomize it a little
|
||||
float2 jitter = RandN2(uv, temporalTime);
|
||||
float2 Xi = jitter;
|
||||
Xi.y = lerp(Xi.y, 0.0, brdfBias);
|
||||
float3 H = temporal ? TangentToWorld(gBuffer.Normal, ImportanceSampleGGX(Xi, gBuffer.Roughness)) : gBuffer.Normal;
|
||||
|
||||
// Calculate normalized view space reflection vector
|
||||
float3 reflectVS = normalize(reflect(gBuffer.ViewPos, normalVS));
|
||||
if (gBuffer.ViewPos.z < 1.0 && reflectVS.z < 0.4)
|
||||
return 0;
|
||||
|
||||
float3 viewWS = normalize(gBuffer.WorldPos - viewPos);
|
||||
float3 reflectWS = reflect(viewWS, H.xyz);
|
||||
|
||||
float3 startWS = gBuffer.WorldPos + gBuffer.Normal * worldAntiSelfOcclusionBias;
|
||||
float3 startUV = ProjectWorldToUv(startWS, viewProjectionMatrix);
|
||||
float3 endUV = ProjectWorldToUv(startWS + reflectWS, viewProjectionMatrix);
|
||||
|
||||
float3 rayUV = endUV - startUV;
|
||||
rayUV *= stepSize / max2(abs(rayUV.xy));
|
||||
float3 startUv = startUV + rayUV * 2;
|
||||
|
||||
float3 currOffset = startUv;
|
||||
float3 rayStep = rayUV * 2;
|
||||
|
||||
// Calculate number of samples
|
||||
float3 samplesToEdge = ((sign(rayStep.xyz) * 0.5 + 0.5) - currOffset.xyz) / rayStep.xyz;
|
||||
samplesToEdge.x = min(samplesToEdge.x, min(samplesToEdge.y, samplesToEdge.z)) * 1.05f;
|
||||
float numSamples = min(maxSamples, samplesToEdge.x);
|
||||
rayStep *= samplesToEdge.x / numSamples;
|
||||
|
||||
// Calculate depth difference error
|
||||
float depthDiffError = 1.3f * abs(rayStep.z);
|
||||
|
||||
// Ray trace
|
||||
float currSampleIndex = 0;
|
||||
float currSample, depthDiff;
|
||||
LOOP
|
||||
while (currSampleIndex < numSamples)
|
||||
{
|
||||
// Sample depth buffer and calculate depth difference
|
||||
currSample = SAMPLE_RT(depthBuffer, currOffset.xy).r;
|
||||
depthDiff = currOffset.z - currSample;
|
||||
|
||||
// Check intersection
|
||||
if (depthDiff >= 0)
|
||||
{
|
||||
if (depthDiff < depthDiffError)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
currOffset -= rayStep;
|
||||
rayStep *= 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
// Move forward
|
||||
currOffset += rayStep;
|
||||
currSampleIndex++;
|
||||
}
|
||||
|
||||
// Check if has valid result after ray tracing
|
||||
if (currSampleIndex >= numSamples)
|
||||
{
|
||||
// All samples done but no result
|
||||
return 0;
|
||||
}
|
||||
|
||||
float2 hitUV = currOffset.xy;
|
||||
|
||||
// Fade rays close to screen edge
|
||||
const float fadeStart = 0.9f;
|
||||
const float fadeEnd = 1.0f;
|
||||
const float fadeDiffRcp = 1.0f / (fadeEnd - fadeStart);
|
||||
float2 boundary = abs(hitUV - float2(0.5f, 0.5f)) * 2.0f;
|
||||
float fadeOnBorder = 1.0f - saturate((boundary.x - fadeStart) * fadeDiffRcp);
|
||||
fadeOnBorder *= 1.0f - saturate((boundary.y - fadeStart) * fadeDiffRcp);
|
||||
fadeOnBorder = smoothstep(0.0f, 1.0f, fadeOnBorder);
|
||||
fadeOnBorder *= RayAttenBorder(hitUV, edgeFade);
|
||||
|
||||
// Fade rays on high roughness
|
||||
float roughnessFade = saturate((roughnessThreshold - gBuffer.Roughness) * 20);
|
||||
|
||||
// Fade on distance
|
||||
float distanceFade = saturate((drawDistance - gBuffer.ViewPos.z) / drawDistance);
|
||||
|
||||
// Output: xy: hitUV, z: hitMask
|
||||
return float3(hitUV, fadeOnBorder * roughnessFade * distanceFade);
|
||||
}
|
||||
+7
-154
@@ -1,13 +1,10 @@
|
||||
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "./Flax/Common.hlsl"
|
||||
#include "./Flax/BRDF.hlsl"
|
||||
#include "./Flax/Random.hlsl"
|
||||
#include "./Flax/MonteCarlo.hlsl"
|
||||
#include "./Flax/LightingCommon.hlsl"
|
||||
#include "./Flax/GBuffer.hlsl"
|
||||
#include "./Flax/ReflectionsCommon.hlsl"
|
||||
#include "./Flax/BRDF.hlsl"
|
||||
#include "./Flax/SSR.hlsl"
|
||||
#include "./Flax/GBuffer.hlsl"
|
||||
|
||||
// Enable/disable luminance filter to reduce reflections highlights
|
||||
#define SSR_REDUCE_HIGHLIGHTS 1
|
||||
@@ -34,13 +31,10 @@ float TemporalResponse;
|
||||
float TemporalScale;
|
||||
|
||||
float RayTraceStep;
|
||||
float NoTemporalEffect;
|
||||
float TemporalEffect;
|
||||
float Intensity;
|
||||
float FadeOutDistance;
|
||||
|
||||
float3 Dummy0;
|
||||
float InvFadeDistance;
|
||||
|
||||
float4x4 ViewMatrix;
|
||||
float4x4 ViewProjectionMatrix;
|
||||
|
||||
@@ -52,50 +46,6 @@ Texture2D Texture0 : register(t4);
|
||||
Texture2D Texture1 : register(t5);
|
||||
Texture2D Texture2 : register(t6);
|
||||
|
||||
float max2(float2 v)
|
||||
{
|
||||
return max(v.x, v.y);
|
||||
}
|
||||
|
||||
float2 RandN2(float2 pos, float2 random)
|
||||
{
|
||||
return frac(sin(dot(pos.xy + random, float2(12.9898, 78.233))) * float2(43758.5453, 28001.8384));
|
||||
}
|
||||
|
||||
// 1:-1 to 0:1
|
||||
float2 ClipToUv(float2 clipPos)
|
||||
{
|
||||
return clipPos * float2(0.5, -0.5) + float2(0.5, 0.5);
|
||||
}
|
||||
|
||||
// go into clip space (-1:1 from bottom/left to up/right)
|
||||
float3 ProjectWorldToClip(float3 wsPos)
|
||||
{
|
||||
float4 clipPos = mul(float4(wsPos, 1), ViewProjectionMatrix);
|
||||
return clipPos.xyz / clipPos.w;
|
||||
}
|
||||
|
||||
// go into UV space. (0:1 from top/left to bottom/right)
|
||||
float3 ProjectWorldToUv(float3 wsPos)
|
||||
{
|
||||
float3 clipPos = ProjectWorldToClip(wsPos);
|
||||
return float3(ClipToUv(clipPos.xy), clipPos.z);
|
||||
}
|
||||
|
||||
float4 TangentToWorld(float3 N, float4 H)
|
||||
{
|
||||
float3 upVector = abs(N.z) < 0.999 ? float3(0.0, 0.0, 1.0) : float3(1.0, 0.0, 0.0);
|
||||
float3 T = normalize(cross(upVector, N));
|
||||
float3 B = cross(N, T);
|
||||
return float4((T * H.x) + (B * H.y) + (N * H.z), H.w);
|
||||
}
|
||||
|
||||
float RayAttenBorder(float2 pos, float value)
|
||||
{
|
||||
float borderDist = min(1.0 - max(pos.x, pos.y), min(pos.x, pos.y));
|
||||
return saturate(borderDist > value ? 1.0 : borderDist / value);
|
||||
}
|
||||
|
||||
// Pixel Shader for screen space reflections rendering - combine pass
|
||||
META_PS(true, FEATURE_LEVEL_ES2)
|
||||
float4 PS_CombinePass(Quad_VS2PS input) : SV_Target0
|
||||
@@ -135,112 +85,15 @@ float4 PS_CombinePass(Quad_VS2PS input) : SV_Target0
|
||||
META_PS(true, FEATURE_LEVEL_ES2)
|
||||
float4 PS_RayTracePass(Quad_VS2PS input) : SV_Target0
|
||||
{
|
||||
float2 uv = input.TexCoord;
|
||||
|
||||
// Sample GBuffer
|
||||
GBufferData gBufferData = GetGBufferData();
|
||||
GBufferSample gBuffer = SampleGBuffer(gBufferData, uv);
|
||||
GBufferSample gBuffer = SampleGBuffer(gBufferData, input.TexCoord);
|
||||
|
||||
// Reject invalid pixels
|
||||
if (gBuffer.ShadingModel == SHADING_MODEL_UNLIT || gBuffer.Roughness > RoughnessFade || gBuffer.ViewPos.z > FadeOutDistance)
|
||||
return 0;
|
||||
|
||||
// Calculate view space normal vector
|
||||
float3 normalVS = mul(gBuffer.Normal, (float3x3)ViewMatrix);
|
||||
|
||||
// Randomize it a little
|
||||
float2 jitter = RandN2(uv, TemporalTime);
|
||||
float2 Xi = jitter;
|
||||
Xi.y = lerp(Xi.y, 0.0, BRDFBias);
|
||||
|
||||
float4 H = TangentToWorld(gBuffer.Normal, ImportanceSampleGGX(Xi, gBuffer.Roughness));
|
||||
if (NoTemporalEffect)
|
||||
H.xyz = gBuffer.Normal;
|
||||
|
||||
// Calculate normalized view space reflection vector
|
||||
float3 reflectVS = normalize(reflect(gBuffer.ViewPos, normalVS));
|
||||
if (gBuffer.ViewPos.z < 1.0 && reflectVS.z < 0.4)
|
||||
return 0;
|
||||
|
||||
float3 viewWS = normalize(gBuffer.WorldPos - GBuffer.ViewPos);
|
||||
float3 reflectWS = reflect(viewWS, H.xyz);
|
||||
|
||||
float3 startWS = gBuffer.WorldPos + gBuffer.Normal * WorldAntiSelfOcclusionBias;
|
||||
float3 startUV = ProjectWorldToUv(startWS);
|
||||
float3 endUV = ProjectWorldToUv(startWS + reflectWS);
|
||||
|
||||
float3 rayUV = endUV - startUV;
|
||||
rayUV *= RayTraceStep / max2(abs(rayUV.xy));
|
||||
float3 startUv = startUV + rayUV * 2;
|
||||
|
||||
float3 currOffset = startUv;
|
||||
float3 rayStep = rayUV * 2;
|
||||
|
||||
// Calculate number of samples
|
||||
float3 samplesToEdge = ((sign(rayStep.xyz) * 0.5 + 0.5) - currOffset.xyz) / rayStep.xyz;
|
||||
samplesToEdge.x = min(samplesToEdge.x, min(samplesToEdge.y, samplesToEdge.z)) * 1.05f;
|
||||
float numSamples = min(MaxTraceSamples, samplesToEdge.x);
|
||||
rayStep *= samplesToEdge.x / numSamples;
|
||||
|
||||
// Calculate depth difference error
|
||||
float depthDiffError = 1.3f * abs(rayStep.z);
|
||||
|
||||
// Ray trace
|
||||
float currSampleIndex = 0;
|
||||
float currSample, depthDiff;
|
||||
LOOP
|
||||
while (currSampleIndex < numSamples)
|
||||
{
|
||||
// Sample depth buffer and calculate depth difference
|
||||
currSample = SampleZ(currOffset.xy);
|
||||
depthDiff = currOffset.z - currSample;
|
||||
|
||||
// Check intersection
|
||||
if (depthDiff >= 0)
|
||||
{
|
||||
if (depthDiff < depthDiffError)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
currOffset -= rayStep;
|
||||
rayStep *= 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
// Move forward
|
||||
currOffset += rayStep;
|
||||
currSampleIndex++;
|
||||
}
|
||||
|
||||
// Check if has valid result after ray tracing
|
||||
if (currSampleIndex >= numSamples)
|
||||
{
|
||||
// All samples done but no result
|
||||
return 0;
|
||||
}
|
||||
|
||||
float2 hitUV = currOffset.xy;
|
||||
|
||||
// Fade rays close to screen edge
|
||||
const float fadeStart = 0.9f;
|
||||
const float fadeEnd = 1.0f;
|
||||
const float fadeDiffRcp = 1.0f / (fadeEnd - fadeStart);
|
||||
float2 boundary = abs(hitUV - float2(0.5f, 0.5f)) * 2.0f;
|
||||
float fadeOnBorder = 1.0f - saturate((boundary.x - fadeStart) * fadeDiffRcp);
|
||||
fadeOnBorder *= 1.0f - saturate((boundary.y - fadeStart) * fadeDiffRcp);
|
||||
fadeOnBorder = smoothstep(0.0f, 1.0f, fadeOnBorder);
|
||||
fadeOnBorder *= RayAttenBorder(hitUV, EdgeFadeFactor);
|
||||
|
||||
// Fade rays on high roughness
|
||||
float roughnessFade = saturate((RoughnessFade - gBuffer.Roughness) * 20);
|
||||
|
||||
// Fade on distance
|
||||
float distanceFade = saturate((FadeOutDistance - gBuffer.ViewPos.z) * InvFadeDistance);
|
||||
// Trace depth buffer to find intersection
|
||||
float3 hit = TraceSceenSpaceReflection(input.TexCoord, gBuffer, Depth, gBufferData.ViewPos, ViewMatrix, ViewProjectionMatrix, RayTraceStep, MaxTraceSamples, TemporalEffect, TemporalTime, WorldAntiSelfOcclusionBias, BRDFBias, FadeOutDistance, RoughnessFade, EdgeFadeFactor);
|
||||
|
||||
// Output: xy: hitUV, z: hitMask, w: unused
|
||||
return float4(hitUV, fadeOnBorder * roughnessFade * distanceFade * Intensity, 0);
|
||||
return float4(hit.xy, hit.z * Intensity, 0);
|
||||
}
|
||||
|
||||
#ifndef RESOLVE_SAMPLES
|
||||
|
||||
Reference in New Issue
Block a user