diff --git a/Content/Editor/MaterialTemplates/Features/ForwardShading.hlsl b/Content/Editor/MaterialTemplates/Features/ForwardShading.hlsl
index 2db55111b..22d9ca9b4 100644
--- a/Content/Editor/MaterialTemplates/Features/ForwardShading.hlsl
+++ b/Content/Editor/MaterialTemplates/Features/ForwardShading.hlsl
@@ -143,9 +143,9 @@ void PS_Forward(
#endif
-#if USE_FOG
+#if USE_FOG && MATERIAL_SHADING_MODEL != SHADING_MODEL_UNLIT
// Calculate exponential height fog
- float4 fog = GetExponentialHeightFog(ExponentialHeightFog, materialInput.WorldPosition, ViewPos, 0);
+ float4 fog = GetExponentialHeightFog(ExponentialHeightFog, materialInput.WorldPosition, ViewPos, 0, gBuffer.ViewPos.z);
// Apply fog to the output color
#if MATERIAL_BLEND == MATERIAL_BLEND_OPAQUE
diff --git a/Content/Editor/Particles/Smoke Material.flax b/Content/Editor/Particles/Smoke Material.flax
index bd8c1c0e9..d5b8cb872 100644
--- a/Content/Editor/Particles/Smoke Material.flax
+++ b/Content/Editor/Particles/Smoke Material.flax
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:6097a8ca31dbe7a985b5c512d2049d2d22c73175551965c75d6b360323505491
-size 38427
+oid sha256:a16a3fa5bed3bc8030c40fbe0e946f2bdec28745542bf08db1d7b4a43180f785
+size 38900
diff --git a/Content/Shaders/Fog.flax b/Content/Shaders/Fog.flax
index 75590f84d..3f934412c 100644
--- a/Content/Shaders/Fog.flax
+++ b/Content/Shaders/Fog.flax
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:7735a770a87483d4df5e4e653373067c26469de8088f071ca092ed3e797bf461
-size 2785
+oid sha256:e83f9dbbcf84550de09e7c63bbdd3acc6591cf6ba1bcce2a2699772122ae07f4
+size 2633
diff --git a/Flax.sln.DotSettings b/Flax.sln.DotSettings
index 86647d380..3611934dd 100644
--- a/Flax.sln.DotSettings
+++ b/Flax.sln.DotSettings
@@ -267,6 +267,7 @@
True
True
True
+ True
True
True
True
diff --git a/Source/Editor/CustomEditors/Editors/TagEditor.cs b/Source/Editor/CustomEditors/Editors/TagEditor.cs
index 79f700a2b..60639a8cb 100644
--- a/Source/Editor/CustomEditors/Editors/TagEditor.cs
+++ b/Source/Editor/CustomEditors/Editors/TagEditor.cs
@@ -604,6 +604,9 @@ namespace FlaxEditor.CustomEditors.Editors
root.SortChildrenRecursive();
root.Expand(true);
+ if (Input.GetKey(KeyboardKeys.Shift))
+ root.ExpandAll(true);
+
return menu;
}
}
diff --git a/Source/Editor/GUI/ItemsListContextMenu.cs b/Source/Editor/GUI/ItemsListContextMenu.cs
index 58f8c2eb4..6cb5a84fb 100644
--- a/Source/Editor/GUI/ItemsListContextMenu.cs
+++ b/Source/Editor/GUI/ItemsListContextMenu.cs
@@ -227,9 +227,8 @@ namespace FlaxEditor.GUI
{
int order = -1 * SortScore.CompareTo(otherItem.SortScore);
if (order == 0)
- {
order = string.Compare(Name, otherItem.Name, StringComparison.Ordinal);
- }
+
return order;
}
return base.Compare(other);
@@ -509,7 +508,7 @@ namespace FlaxEditor.GUI
OnSearchFilterChanged();
}
- private List- GetVisibleItems()
+ private List
- GetVisibleItems(bool ignoreFoldedCategories)
{
var result = new List
- ();
var items = ItemsPanel.Children;
@@ -523,7 +522,7 @@ namespace FlaxEditor.GUI
for (int i = 0; i < _categoryPanels.Count; i++)
{
var category = _categoryPanels[i];
- if (!category.Visible)
+ if (!category.Visible || (ignoreFoldedCategories && category is DropPanel panel && panel.IsClosed))
continue;
for (int j = 0; j < category.Children.Count; j++)
{
@@ -535,6 +534,12 @@ namespace FlaxEditor.GUI
return result;
}
+ private void ExpandToItem(Item item)
+ {
+ if (item.Parent is DropPanel dropPanel)
+ dropPanel.Open(false);
+ }
+
///
protected override void OnShow()
{
@@ -564,7 +569,7 @@ namespace FlaxEditor.GUI
Hide();
return true;
case KeyboardKeys.Backspace:
- // Alow the user to quickly focus the searchbar
+ // Allow the user to quickly focus the searchbar
if (_searchBox != null && !_searchBox.IsFocused)
{
_searchBox.Focus();
@@ -582,14 +587,25 @@ namespace FlaxEditor.GUI
}
// Get the next item
- var items = GetVisibleItems();
+ bool controlDown = Root.GetKey(KeyboardKeys.Control);
+ var items = GetVisibleItems(!controlDown);
var focusedIndex = items.IndexOf(focusedItem);
+
+ // If the user hasn't selected anything yet and is holding control, focus first folded item
+ if (focusedIndex == -1 && controlDown)
+ focusedIndex = GetVisibleItems(true).Count - 1;
+
int delta = key == KeyboardKeys.ArrowDown ? -1 : 1;
int nextIndex = Mathf.Wrap(focusedIndex - delta, 0, items.Count - 1);
var nextItem = items[nextIndex];
// Focus the next item
nextItem.Focus();
+
+ // Allow the user to expand groups while scrolling
+ if (controlDown)
+ ExpandToItem(nextItem);
+
_scrollPanel.ScrollViewTo(nextItem);
return true;
case KeyboardKeys.Return:
@@ -601,7 +617,7 @@ namespace FlaxEditor.GUI
else
{
// Select first item if no item is focused (most likely to be the best result), saves the user from pressing arrow down first
- var visibleItems = GetVisibleItems();
+ var visibleItems = GetVisibleItems(true);
if (visibleItems.Count > 0)
{
OnClickItem(visibleItems[0]);
diff --git a/Source/Editor/States/ChangingScenesState.cs b/Source/Editor/States/ChangingScenesState.cs
index a146b7fa9..72259e832 100644
--- a/Source/Editor/States/ChangingScenesState.cs
+++ b/Source/Editor/States/ChangingScenesState.cs
@@ -19,6 +19,7 @@ namespace FlaxEditor.States
private readonly List _scenesToLoad = new List();
private readonly List _scenesToUnload = new List();
private Guid _lastSceneFromRequest;
+ private bool _sameSceneReload = false;
internal ChangingScenesState(Editor editor)
: base(editor)
@@ -164,10 +165,22 @@ namespace FlaxEditor.States
{
Assert.AreEqual(Guid.Empty, _lastSceneFromRequest, "Invalid state.");
- // Bind events
- Level.SceneLoaded += OnSceneEvent;
- Level.SceneLoadError += OnSceneEvent;
- Level.SceneUnloaded += OnSceneEvent;
+ // Bind events, only bind loading event and error if re-loading the same scene to avoid issues.
+ if (_scenesToUnload.Count == 1 && _scenesToLoad.Count == 1)
+ {
+ if (_scenesToLoad[0] == _scenesToUnload[0].ID)
+ {
+ Level.SceneLoaded += OnSceneEvent;
+ Level.SceneLoadError += OnSceneEvent;
+ _sameSceneReload = true;
+ }
+ }
+ if (!_sameSceneReload)
+ {
+ Level.SceneLoaded += OnSceneEvent;
+ Level.SceneLoadError += OnSceneEvent;
+ Level.SceneUnloaded += OnSceneEvent;
+ }
// Push scenes changing requests
for (int i = 0; i < _scenesToUnload.Count; i++)
@@ -210,9 +223,18 @@ namespace FlaxEditor.States
}
// Unbind events
- Level.SceneLoaded -= OnSceneEvent;
- Level.SceneLoadError -= OnSceneEvent;
- Level.SceneUnloaded -= OnSceneEvent;
+ if (_sameSceneReload)
+ {
+ Level.SceneLoaded -= OnSceneEvent;
+ Level.SceneLoadError -= OnSceneEvent;
+ _sameSceneReload = false;
+ }
+ else
+ {
+ Level.SceneLoaded -= OnSceneEvent;
+ Level.SceneLoadError -= OnSceneEvent;
+ Level.SceneUnloaded -= OnSceneEvent;
+ }
}
private void OnSceneEvent(Scene scene, Guid sceneId)
diff --git a/Source/Editor/Surface/SurfaceNode.cs b/Source/Editor/Surface/SurfaceNode.cs
index 5dedd604f..97ecab1d0 100644
--- a/Source/Editor/Surface/SurfaceNode.cs
+++ b/Source/Editor/Surface/SurfaceNode.cs
@@ -40,6 +40,11 @@ namespace FlaxEditor.Surface
[HideInEditor]
public class SurfaceNode : SurfaceControl
{
+ ///
+ /// The box to draw a highlight around. Drawing will be skipped if null.
+ ///
+ internal Box highlightBox;
+
///
/// Flag used to discard node values setting during event sending for node UI flushing.
///
@@ -1102,6 +1107,9 @@ namespace FlaxEditor.Surface
Render2D.DrawSprite(icon, new Rectangle(-7, -7, 16, 16), new Color(0.9f, 0.9f, 0.9f));
Render2D.DrawSprite(icon, new Rectangle(-6, -6, 14, 14), new Color(0.894117647f, 0.0784313725f, 0.0f));
}
+
+ if (highlightBox != null)
+ Render2D.DrawRectangle(highlightBox.Bounds, style.BorderHighlighted, 2f);
}
///
diff --git a/Source/Editor/Surface/VisjectSurface.ContextMenu.cs b/Source/Editor/Surface/VisjectSurface.ContextMenu.cs
index 84055aaf0..b1af9589b 100644
--- a/Source/Editor/Surface/VisjectSurface.ContextMenu.cs
+++ b/Source/Editor/Surface/VisjectSurface.ContextMenu.cs
@@ -427,7 +427,7 @@ namespace FlaxEditor.Surface
_cmDistributeNodesHorizontallyButton = _cmFormatNodesMenu.ContextMenu.AddButton("Distribute horizontally", Editor.Instance.Options.Options.Input.NodesDistributeHorizontal, () => { DistributeNodes(SelectedNodes, false); });
_cmDistributeNodesVerticallyButton = _cmFormatNodesMenu.ContextMenu.AddButton("Distribute vertically", Editor.Instance.Options.Options.Input.NodesDistributeVertical, () => { DistributeNodes(SelectedNodes, true); });
- _cmRemoveNodeConnectionsButton = menu.AddButton("Remove all connections to that node(s)", () =>
+ _cmRemoveNodeConnectionsButton = menu.AddButton("Remove all connections", () =>
{
var nodes = ((List)menu.Tag);
@@ -453,8 +453,10 @@ namespace FlaxEditor.Surface
MarkAsEdited();
});
- _cmRemoveNodeConnectionsButton.Enabled = CanEdit;
- _cmRemoveBoxConnectionsButton = menu.AddButton("Remove all connections to that box", () =>
+ bool anyConnection = SelectedNodes.Any(n => n.GetBoxes().Any(b => b.HasAnyConnection));
+ _cmRemoveNodeConnectionsButton.Enabled = CanEdit && anyConnection;
+
+ _cmRemoveBoxConnectionsButton = menu.AddButton("Remove all socket connections", () =>
{
var boxUnderMouse = (Box)_cmRemoveBoxConnectionsButton.Tag;
if (Undo != null)
@@ -475,6 +477,16 @@ namespace FlaxEditor.Surface
var boxUnderMouse = GetChildAtRecursive(location) as Box;
_cmRemoveBoxConnectionsButton.Enabled = boxUnderMouse != null && boxUnderMouse.HasAnyConnection;
_cmRemoveBoxConnectionsButton.Tag = boxUnderMouse;
+
+ if (boxUnderMouse != null)
+ {
+ boxUnderMouse.ParentNode.highlightBox = boxUnderMouse;
+ menu.VisibleChanged += (c) =>
+ {
+ if (!c.Visible)
+ boxUnderMouse.ParentNode.highlightBox = null;
+ };
+ }
}
controlUnderMouse?.OnShowSecondaryContextMenu(menu, controlUnderMouse.PointFromParent(location));
diff --git a/Source/Editor/Surface/VisjectSurface.Draw.cs b/Source/Editor/Surface/VisjectSurface.Draw.cs
index 01277d0d2..f60c19d21 100644
--- a/Source/Editor/Surface/VisjectSurface.Draw.cs
+++ b/Source/Editor/Surface/VisjectSurface.Draw.cs
@@ -225,6 +225,10 @@ namespace FlaxEditor.Surface
_rootControl.DrawComments();
+ // Reset input flags here because this is the closest to Update we have
+ WasBoxSelecting = IsBoxSelecting;
+ WasMovingSelection = IsMovingSelection;
+
if (IsBoxSelecting)
{
DrawSelection();
diff --git a/Source/Editor/Surface/VisjectSurface.Input.cs b/Source/Editor/Surface/VisjectSurface.Input.cs
index 63dfa063d..09df195eb 100644
--- a/Source/Editor/Surface/VisjectSurface.Input.cs
+++ b/Source/Editor/Surface/VisjectSurface.Input.cs
@@ -590,9 +590,6 @@ namespace FlaxEditor.Surface
// Cache flags and state
if (_leftMouseDown && button == MouseButton.Left)
{
- WasBoxSelecting = IsBoxSelecting;
- WasMovingSelection = _isMovingSelection;
-
_leftMouseDown = false;
EndMouseCapture();
Cursor = CursorType.Default;
diff --git a/Source/Editor/Windows/DebugLogWindow.cs b/Source/Editor/Windows/DebugLogWindow.cs
index b5d71f6a0..ed133d4e8 100644
--- a/Source/Editor/Windows/DebugLogWindow.cs
+++ b/Source/Editor/Windows/DebugLogWindow.cs
@@ -447,6 +447,10 @@ namespace FlaxEditor.Windows
///
public void Clear()
{
+ lock (_locker)
+ {
+ _pendingEntries.Clear();
+ }
if (_entriesPanel == null)
return;
RemoveEntries();
@@ -735,10 +739,10 @@ namespace FlaxEditor.Windows
}
///
- public override void OnPlayBegin()
+ public override void OnPlayBeginning()
{
// Clear on Play
- if (_clearOnPlayButton.Checked)
+ if (Editor.Options.Options.Interface.DebugLogClearOnPlay)
{
Clear();
}
diff --git a/Source/Editor/Windows/SceneTreeWindow.cs b/Source/Editor/Windows/SceneTreeWindow.cs
index 4ae975cfe..afbbf6c92 100644
--- a/Source/Editor/Windows/SceneTreeWindow.cs
+++ b/Source/Editor/Windows/SceneTreeWindow.cs
@@ -26,6 +26,7 @@ namespace FlaxEditor.Windows
private Tree _tree;
private Panel _sceneTreePanel;
private bool _isUpdatingSelection;
+ private bool _blockSceneTreeScroll = false;
private DragAssets _dragAssets;
private DragActorType _dragActorType;
@@ -110,6 +111,34 @@ namespace FlaxEditor.Windows
InputActions.Add(options => options.LockFocusSelection, () => Editor.Windows.EditWin.Viewport.LockFocusSelection());
InputActions.Add(options => options.Rename, RenameSelection);
}
+
+ ///
+ public override void OnPlayBeginning()
+ {
+ base.OnPlayBeginning();
+ _blockSceneTreeScroll = true;
+ }
+
+ ///
+ public override void OnPlayBegin()
+ {
+ base.OnPlayBegin();
+ _blockSceneTreeScroll = false;
+ }
+
+ ///
+ public override void OnPlayEnding()
+ {
+ base.OnPlayEnding();
+ _blockSceneTreeScroll = true;
+ }
+
+ ///
+ public override void OnPlayEnd()
+ {
+ base.OnPlayEnd();
+ _blockSceneTreeScroll = true;
+ }
///
/// Enables or disables vertical and horizontal scrolling on the scene tree panel.
@@ -269,7 +298,7 @@ namespace FlaxEditor.Windows
_tree.Select(nodes);
// For single node selected scroll view so user can see it
- if (nodes.Count == 1)
+ if (nodes.Count == 1 && !_blockSceneTreeScroll)
{
nodes[0].ExpandAllParents(true);
_sceneTreePanel.ScrollViewTo(nodes[0]);
@@ -279,6 +308,12 @@ namespace FlaxEditor.Windows
_isUpdatingSelection = false;
}
+ ///
+ public override void OnEditorStateChanged()
+ {
+ _blockSceneTreeScroll = Editor.StateMachine.ReloadingScriptsState.IsActive;
+ }
+
private bool ValidateDragAsset(AssetItem assetItem)
{
if (assetItem.IsOfType())
diff --git a/Source/Editor/Windows/Search/SearchItem.cs b/Source/Editor/Windows/Search/SearchItem.cs
index 11bc79991..63263cc58 100644
--- a/Source/Editor/Windows/Search/SearchItem.cs
+++ b/Source/Editor/Windows/Search/SearchItem.cs
@@ -20,6 +20,11 @@ namespace FlaxEditor.Windows.Search
///
protected Image _icon;
+ ///
+ /// The color of the accent strip.
+ ///
+ protected Color _accentColor;
+
///
/// The item name.
///
@@ -56,7 +61,7 @@ namespace FlaxEditor.Windows.Search
var icon = new Image
{
Size = new Float2(logoSize),
- Location = new Float2(5, (height - logoSize) / 2)
+ Location = new Float2(7, (height - logoSize) / 2)
};
_icon = icon;
@@ -74,6 +79,20 @@ namespace FlaxEditor.Windows.Search
typeLabel.TextColor = Style.Current.ForegroundGrey;
}
+ ///
+ public override bool OnMouseDown(Float2 location, MouseButton button)
+ {
+ // Select and focus the item on right click to prevent the search from being cleared
+ if (button == MouseButton.Right)
+ {
+ _finder.SelectedItem = this;
+ _finder.Hand = true;
+ Focus();
+ return true;
+ }
+ return base.OnMouseUp(location, button);
+ }
+
///
public override bool OnMouseUp(Float2 location, MouseButton button)
{
@@ -86,6 +105,15 @@ namespace FlaxEditor.Windows.Search
return base.OnMouseUp(location, button);
}
+ ///
+ public override void Draw()
+ {
+ if (IsMouseOver)
+ Render2D.FillRectangle(new Rectangle(Float2.Zero, Size), Style.Current.BackgroundHighlighted);
+
+ base.Draw();
+ }
+
///
public override void OnMouseEnter(Float2 location)
{
@@ -93,12 +121,7 @@ namespace FlaxEditor.Windows.Search
var root = RootWindow;
if (root != null)
- {
root.Cursor = CursorType.Hand;
- }
-
- _finder.SelectedItem = this;
- _finder.Hand = true;
}
///
@@ -128,6 +151,7 @@ namespace FlaxEditor.Windows.Search
{
_asset = item;
_asset.AddReference(this);
+ _accentColor = Editor.Instance.ContentDatabase.GetProxy(item).AccentColor;
}
///
@@ -176,9 +200,7 @@ namespace FlaxEditor.Windows.Search
{
string importLocation = System.IO.Path.GetDirectoryName(importPath);
if (!string.IsNullOrEmpty(importLocation) && System.IO.Directory.Exists(importLocation))
- {
cm.AddButton("Show import location", () => FileSystem.ShowFileExplorer(importLocation));
- }
}
}
cm.AddSeparator();
@@ -212,6 +234,10 @@ namespace FlaxEditor.Windows.Search
// Draw icon
var iconRect = _icon.Bounds;
_asset.DrawThumbnail(ref iconRect);
+
+ // Draw color strip
+ var rect = iconRect with { Width = 2, Height = Height, Location = new Float2(2, 0) };
+ Render2D.FillRectangle(rect, _accentColor);
}
///
diff --git a/Source/Engine/Core/Config/GraphicsSettings.h b/Source/Engine/Core/Config/GraphicsSettings.h
index 831605596..d8b35533a 100644
--- a/Source/Engine/Core/Config/GraphicsSettings.h
+++ b/Source/Engine/Core/Config/GraphicsSettings.h
@@ -84,7 +84,7 @@ public:
bool EnableGlobalSDF = false;
///
- /// Draw distance of the Global SDF. Actual value can be large when using DDGI.
+ /// Draw distance of the Global SDF. Actual value can be larger when using DDGI.
///
API_FIELD(Attributes="EditorOrder(2001), EditorDisplay(\"Global SDF\"), Limit(1000), ValueCategory(Utils.ValueCategory.Distance)")
float GlobalSDFDistance = 15000.0f;
diff --git a/Source/Engine/Foliage/Foliage.cpp b/Source/Engine/Foliage/Foliage.cpp
index a1cd046ae..c0e0b0b0e 100644
--- a/Source/Engine/Foliage/Foliage.cpp
+++ b/Source/Engine/Foliage/Foliage.cpp
@@ -993,6 +993,12 @@ void Foliage::RemoveAllInstances()
RebuildClusters();
}
+void Foliage::RemoveLightmap()
+{
+ for (auto& e : Instances)
+ e.RemoveLightmap();
+}
+
static float GlobalDensityScale = 1.0f;
float Foliage::GetGlobalDensityScale()
diff --git a/Source/Engine/Foliage/Foliage.h b/Source/Engine/Foliage/Foliage.h
index f9055f377..1855e9914 100644
--- a/Source/Engine/Foliage/Foliage.h
+++ b/Source/Engine/Foliage/Foliage.h
@@ -139,6 +139,11 @@ public:
///
API_FUNCTION() void RemoveAllInstances();
+ ///
+ /// Removes the lightmap data from the foliage instances.
+ ///
+ API_FUNCTION() void RemoveLightmap();
+
public:
///
/// Gets the global density scale for all foliage instances. The default value is 1. Use values from range 0-1. Lower values decrease amount of foliage instances in-game. Use it to tweak game performance for slower devices.
diff --git a/Source/Engine/Level/Actors/ExponentialHeightFog.cpp b/Source/Engine/Level/Actors/ExponentialHeightFog.cpp
index d62aecac4..efb5351e7 100644
--- a/Source/Engine/Level/Actors/ExponentialHeightFog.cpp
+++ b/Source/Engine/Level/Actors/ExponentialHeightFog.cpp
@@ -41,11 +41,10 @@ void ExponentialHeightFog::Draw(RenderContext& renderContext)
&& _shader->IsLoaded()
&& renderContext.View.IsPerspectiveProjection())
{
- // Prepare
if (_psFog.States[0] == nullptr)
- {
- // Create pipeline states
_psFog.CreatePipelineStates();
+ if (!_psFog.States[0]->IsValid())
+ {
GPUPipelineState::Description psDesc = GPUPipelineState::Description::DefaultFullscreenTriangle;
psDesc.DepthWriteEnable = false;
psDesc.BlendMode.BlendEnable = true;
@@ -59,6 +58,7 @@ void ExponentialHeightFog::Draw(RenderContext& renderContext)
if (_psFog.Create(psDesc, _shader->GetShader(), "PS_Fog"))
{
LOG(Warning, "Cannot create graphics pipeline state object for '{0}'.", ToString());
+ return;
}
}
@@ -160,7 +160,7 @@ void ExponentialHeightFog::GetExponentialHeightFogData(const RenderView& view, S
result.FogAtViewPosition = density * Math::Pow(2.0f, Math::Clamp(-heightFalloff * (viewHeight - height), -125.f, 126.f));
result.StartDistance = StartDistance;
result.FogMinOpacity = 1.0f - FogMaxOpacity;
- result.FogCutoffDistance = FogCutoffDistance;
+ result.FogCutoffDistance = FogCutoffDistance >= 0 ? FogCutoffDistance : view.Far + FogCutoffDistance;
if (useDirectionalLightInscattering)
{
result.InscatteringLightDirection = -DirectionalInscatteringLight->GetDirection();
diff --git a/Source/Engine/Level/Actors/ExponentialHeightFog.h b/Source/Engine/Level/Actors/ExponentialHeightFog.h
index 0b442ba9f..c0e5407d2 100644
--- a/Source/Engine/Level/Actors/ExponentialHeightFog.h
+++ b/Source/Engine/Level/Actors/ExponentialHeightFog.h
@@ -55,9 +55,9 @@ public:
float StartDistance = 0.0f;
///
- /// Scene elements past this distance will not have fog applied. This is useful for excluding skyboxes which already have fog baked in. Setting this value to 0 disables it.
+ /// Scene elements past this distance will not have fog applied. This is useful for excluding skyboxes which already have fog baked in. Setting this value to 0 disables it. Negative value sets the cutoff distance relative to the far plane of the camera.
///
- API_FIELD(Attributes="EditorOrder(60), DefaultValue(0.0f), Limit(0), EditorDisplay(\"Exponential Height Fog\")")
+ API_FIELD(Attributes="EditorOrder(60), DefaultValue(0.0f), EditorDisplay(\"Exponential Height Fog\")")
float FogCutoffDistance = 0.0f;
public:
diff --git a/Source/Engine/Level/Scene/Scene.cpp b/Source/Engine/Level/Scene/Scene.cpp
index 215153122..f60aa8d2f 100644
--- a/Source/Engine/Level/Scene/Scene.cpp
+++ b/Source/Engine/Level/Scene/Scene.cpp
@@ -7,6 +7,7 @@
#include "Engine/Content/Content.h"
#include "Engine/Content/Deprecated.h"
#include "Engine/Content/Factories/JsonAssetFactory.h"
+#include "Engine/Foliage/Foliage.h"
#include "Engine/Physics/Colliders/MeshCollider.h"
#include "Engine/Level/Actors/StaticModel.h"
#include "Engine/Level/ActorsCache.h"
@@ -15,6 +16,7 @@
#include "Engine/Navigation/NavMesh.h"
#include "Engine/Profiler/ProfilerCPU.h"
#include "Engine/Serialization/Serialization.h"
+#include "Engine/Terrain/Terrain.h"
#if USE_EDITOR
#include "Engine/Engine/Globals.h"
#endif
@@ -98,6 +100,19 @@ void Scene::SetLightmapSettings(const LightmapSettings& value)
void Scene::ClearLightmaps()
{
LightmapsData.ClearLightmaps();
+
+ // Unlink any actors from lightmap
+ Function function = [this](Actor* actor)
+ {
+ if (auto* staticModel = Cast(actor))
+ staticModel->RemoveLightmap();
+ else if (auto* terrain = Cast(actor))
+ terrain->RemoveLightmap();
+ else if (auto* foliage = Cast(actor))
+ foliage->RemoveLightmap();
+ return true;
+ };
+ TreeExecute(function);
}
void Scene::BuildCSG(float timeoutMs)
diff --git a/Source/Engine/Tools/ModelTool/ModelTool.OpenFBX.cpp b/Source/Engine/Tools/ModelTool/ModelTool.OpenFBX.cpp
index 2cc2823af..81ce46d6c 100644
--- a/Source/Engine/Tools/ModelTool/ModelTool.OpenFBX.cpp
+++ b/Source/Engine/Tools/ModelTool/ModelTool.OpenFBX.cpp
@@ -692,8 +692,12 @@ int Triangulate(OpenFbxImporterData& data, const ofbx::GeometryData& geom, const
triangulatedIndices[i] = polygon.from_vertex + (earIndices[i] % polygon.vertex_count);
// Ensure that we've written enough ears
- ASSERT(earIndices.Count() == 3 * (polygon.vertex_count - 2));
- return earIndices.Count();
+ const int32 indexCount = 3 * (polygon.vertex_count - 2);
+ if (indexCount != earIndices.Count())
+ {
+ LOG(Error, "Invalid amount of vertices after triangulation. Expected {} but got {}. Use proper mesh triangulation when exporting source asset to the engine.", earIndices.Count(), indexCount);
+ }
+ return indexCount;
}
bool ProcessMesh(ModelData& result, OpenFbxImporterData& data, const ofbx::Mesh* aMesh, MeshData& mesh, String& errorMsg, int partitionIndex)
@@ -729,7 +733,7 @@ bool ProcessMesh(ModelData& result, OpenFbxImporterData& data, const ofbx::Mesh*
mesh.Positions.Get()[j] = ToFloat3(positions.get(triangulatedIndices[j]));
numIndicesTotal += numIndices;
}
- ASSERT(numIndicesTotal == vertexCount);
+ ASSERT_LOW_LAYER(numIndicesTotal == vertexCount);
}
// Indices (dummy index buffer)
diff --git a/Source/Shaders/ExponentialHeightFog.hlsl b/Source/Shaders/ExponentialHeightFog.hlsl
index 2e34936eb..f6fb918f5 100644
--- a/Source/Shaders/ExponentialHeightFog.hlsl
+++ b/Source/Shaders/ExponentialHeightFog.hlsl
@@ -29,7 +29,7 @@ struct ExponentialHeightFogData
float StartDistance;
};
-float4 GetExponentialHeightFog(ExponentialHeightFogData exponentialHeightFog, float3 posWS, float3 camWS, float skipDistance)
+float4 GetExponentialHeightFog(ExponentialHeightFogData exponentialHeightFog, float3 posWS, float3 camWS, float skipDistance, float sceneDistance)
{
float3 cameraToPos = posWS - camWS;
float cameraToPosSqr = dot(cameraToPos, cameraToPos);
@@ -78,7 +78,7 @@ float4 GetExponentialHeightFog(ExponentialHeightFogData exponentialHeightFog, fl
// Disable fog after a certain distance
FLATTEN
- if (exponentialHeightFog.FogCutoffDistance > 0 && cameraToPosLen > exponentialHeightFog.FogCutoffDistance)
+ if (exponentialHeightFog.FogCutoffDistance > 0 && sceneDistance > exponentialHeightFog.FogCutoffDistance)
{
expFogFactor = 1;
directionalInscattering = 0;
@@ -87,4 +87,9 @@ float4 GetExponentialHeightFog(ExponentialHeightFogData exponentialHeightFog, fl
return float4(inscatteringColor * (1.0f - expFogFactor) + directionalInscattering, expFogFactor);
}
+float4 GetExponentialHeightFog(ExponentialHeightFogData exponentialHeightFog, float3 posWS, float3 camWS, float skipDistance)
+{
+ return GetExponentialHeightFog(exponentialHeightFog, posWS, camWS, skipDistance, distance(posWS, camWS));
+}
+
#endif
diff --git a/Source/Shaders/Fog.shader b/Source/Shaders/Fog.shader
index 7dcc679ec..dfea921cc 100644
--- a/Source/Shaders/Fog.shader
+++ b/Source/Shaders/Fog.shader
@@ -24,41 +24,17 @@ Texture2D Depth : register(t0);
Texture3D IntegratedLightScattering : register(t1);
#endif
-// Get world space position at given pixel coordinate
-float3 GetWorldPos(float2 uv)
-{
- float depth = SAMPLE_RT(Depth, uv).r;
- GBufferData gBufferData = GetGBufferData();
- float3 viewPos = GetViewPos(gBufferData, uv, depth);
- return mul(float4(viewPos, 1), gBufferData.InvViewMatrix).xyz;
-}
-
-float4 CalculateCombinedFog(float3 posWS, float sceneDepth, float3 volumeUV)
-{
- float skipDistance = 0;
-
-#if VOLUMETRIC_FOG
- skipDistance = max(ExponentialHeightFog.VolumetricFogMaxDistance - 100, 0);
-#endif
-
- float4 fog = GetExponentialHeightFog(ExponentialHeightFog, posWS, GBuffer.ViewPos, skipDistance);
-
-#if VOLUMETRIC_FOG
- float4 volumetricFog = IntegratedLightScattering.SampleLevel(SamplerLinearClamp, volumeUV, 0);
- fog = float4(volumetricFog.rgb + fog.rgb * volumetricFog.a, volumetricFog.a * fog.a);
-#endif
-
- return fog;
-}
-
META_PS(true, FEATURE_LEVEL_ES2)
META_PERMUTATION_1(VOLUMETRIC_FOG=0)
META_PERMUTATION_1(VOLUMETRIC_FOG=1)
float4 PS_Fog(Quad_VS2PS input) : SV_Target0
{
- // Calculate pixel world space position
- float3 posWS = GetWorldPos(input.TexCoord);
- float3 viewVector = posWS - GBuffer.ViewPos;
+ // Get world space position at given pixel coordinate
+ float rawDepth = SAMPLE_RT(Depth, input.TexCoord).r;
+ GBufferData gBufferData = GetGBufferData();
+ float3 viewPos = GetViewPos(gBufferData, input.TexCoord, rawDepth);
+ float3 worldPos = mul(float4(viewPos, 1), gBufferData.InvViewMatrix).xyz;
+ float3 viewVector = worldPos - GBuffer.ViewPos;
float sceneDepth = length(viewVector);
// Calculate volumetric fog coordinates
@@ -67,17 +43,28 @@ float4 PS_Fog(Quad_VS2PS input) : SV_Target0
// Debug code
#if VOLUMETRIC_FOG && 0
- volumeUV = posWS / 1000;
+ volumeUV = worldPos / 1000;
if (!all(volumeUV >= 0 && volumeUV <= 1))
return 0;
return float4(IntegratedLightScattering.SampleLevel(SamplerLinearClamp, volumeUV, 0).rgb, 1);
//return float4(volumeUV, 1);
- //return float4(posWS / 100, 1);
+ //return float4(worldPos / 100, 1);
#endif
- // Calculate fog color
- float4 fog = CalculateCombinedFog(posWS, sceneDepth, volumeUV);
+ float skipDistance = 0;
+#if VOLUMETRIC_FOG
+ skipDistance = max(ExponentialHeightFog.VolumetricFogMaxDistance - 100, 0);
+#endif
+
+ // Calculate exponential fog color
+ float4 fog = GetExponentialHeightFog(ExponentialHeightFog, worldPos, GBuffer.ViewPos, skipDistance, viewPos.z);
+
+#if VOLUMETRIC_FOG
+ // Sample volumetric fog and mix it in
+ float4 volumetricFog = IntegratedLightScattering.SampleLevel(SamplerLinearClamp, volumeUV, 0);
+ fog = float4(volumetricFog.rgb + fog.rgb * volumetricFog.a, volumetricFog.a * fog.a);
+#endif
return fog;
}