Merge remote-tracking branch 'origin/master' into 1.11
This commit is contained in:
@@ -149,7 +149,7 @@ 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, gBuffer.ViewPos.z);
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "./Flax/Common.hlsl"
|
||||
#include "./Flax/MaterialCommon.hlsl"
|
||||
#include "./Flax/GBufferCommon.hlsl"
|
||||
#include "./Flax/TerrainCommon.hlsl"
|
||||
@7
|
||||
// Primary constant buffer (with additional material parameters)
|
||||
META_CB_BEGIN(0, Data)
|
||||
@@ -334,7 +335,7 @@ VertexOutput VS(TerrainVertexInput input)
|
||||
float lodValue = CurrentLOD;
|
||||
float morphAlpha = lodCalculated - CurrentLOD;
|
||||
|
||||
// Sample heightmap
|
||||
// Sample heightmap and splatmaps
|
||||
float2 heightmapUVs = input.TexCoord * HeightmapUVScaleBias.xy + HeightmapUVScaleBias.zw;
|
||||
#if USE_SMOOTH_LOD_TRANSITION
|
||||
float4 heightmapValueThisLOD = Heightmap.SampleLevel(SamplerPointClamp, heightmapUVs, lodValue);
|
||||
@@ -342,7 +343,6 @@ VertexOutput VS(TerrainVertexInput input)
|
||||
float2 heightmapUVsNextLOD = nextLODPos * HeightmapUVScaleBias.xy + HeightmapUVScaleBias.zw;
|
||||
float4 heightmapValueNextLOD = Heightmap.SampleLevel(SamplerPointClamp, heightmapUVsNextLOD, lodValue + 1);
|
||||
float4 heightmapValue = lerp(heightmapValueThisLOD, heightmapValueNextLOD, morphAlpha);
|
||||
bool isHole = max(heightmapValueThisLOD.b + heightmapValueThisLOD.a, heightmapValueNextLOD.b + heightmapValueNextLOD.a) >= 1.9f;
|
||||
#if USE_TERRAIN_LAYERS
|
||||
float4 splatmapValueThisLOD = Splatmap0.SampleLevel(SamplerPointClamp, heightmapUVs, lodValue);
|
||||
float4 splatmapValueNextLOD = Splatmap0.SampleLevel(SamplerPointClamp, heightmapUVsNextLOD, lodValue + 1);
|
||||
@@ -355,7 +355,6 @@ VertexOutput VS(TerrainVertexInput input)
|
||||
#endif
|
||||
#else
|
||||
float4 heightmapValue = Heightmap.SampleLevel(SamplerPointClamp, heightmapUVs, lodValue);
|
||||
bool isHole = (heightmapValue.b + heightmapValue.a) >= 1.9f;
|
||||
#if USE_TERRAIN_LAYERS
|
||||
float4 splatmap0Value = Splatmap0.SampleLevel(SamplerPointClamp, heightmapUVs, lodValue);
|
||||
#if TERRAIN_LAYERS_DATA_SIZE > 1
|
||||
@@ -363,12 +362,11 @@ VertexOutput VS(TerrainVertexInput input)
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
float height = (float)((int)(heightmapValue.x * 255.0) + ((int)(heightmapValue.y * 255) << 8)) / 65535.0;
|
||||
float height = DecodeHeightmapHeight(heightmapValue);
|
||||
|
||||
// Extract normal and the holes mask
|
||||
float2 normalTemp = float2(heightmapValue.b, heightmapValue.a) * 2.0f - 1.0f;
|
||||
float3 normal = float3(normalTemp.x, sqrt(1.0 - saturate(dot(normalTemp, normalTemp))), normalTemp.y);
|
||||
normal = normalize(normal);
|
||||
bool isHole;
|
||||
float3 normal = DecodeHeightmapNormal(heightmapValue, isHole);
|
||||
output.Geometry.HolesMask = isHole ? 0 : 1;
|
||||
if (isHole)
|
||||
{
|
||||
|
||||
@@ -267,6 +267,7 @@
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=comperand/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=coord/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=cubemap/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=DDGI/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Deformer/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=deformers/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=defragmentation/@EntryIndexedValue">True</s:Boolean>
|
||||
|
||||
@@ -604,6 +604,9 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
root.SortChildrenRecursive();
|
||||
root.Expand(true);
|
||||
|
||||
if (Input.GetKey(KeyboardKeys.Shift))
|
||||
root.ExpandAll(true);
|
||||
|
||||
return menu;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Item> GetVisibleItems()
|
||||
private List<Item> GetVisibleItems(bool ignoreFoldedCategories)
|
||||
{
|
||||
var result = new List<Item>();
|
||||
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);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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]);
|
||||
|
||||
@@ -76,9 +76,13 @@ namespace FlaxEditor.SceneGraph.Actors
|
||||
// Skip removing this terrain file sif it's still referenced
|
||||
var sceneReferences = Editor.GetAssetReferences(e.SceneId);
|
||||
if (sceneReferences != null && sceneReferences.Contains(e.TerrainId))
|
||||
{
|
||||
Debug.Log($"Skip removing files used by terrain {e.TerrainId} on scene {e.SceneId} as it's still in use");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Delete files
|
||||
Debug.Log($"Removing files used by removed terrain {e.TerrainId} on scene {e.SceneId}");
|
||||
foreach (var file in e.Files)
|
||||
{
|
||||
if (file != null && File.Exists(file))
|
||||
|
||||
@@ -19,6 +19,7 @@ namespace FlaxEditor.States
|
||||
private readonly List<Guid> _scenesToLoad = new List<Guid>();
|
||||
private readonly List<Scene> _scenesToUnload = new List<Scene>();
|
||||
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)
|
||||
|
||||
@@ -40,6 +40,11 @@ namespace FlaxEditor.Surface
|
||||
[HideInEditor]
|
||||
public class SurfaceNode : SurfaceControl
|
||||
{
|
||||
/// <summary>
|
||||
/// The box to draw a highlight around. Drawing will be skipped if null.
|
||||
/// </summary>
|
||||
internal Box highlightBox;
|
||||
|
||||
/// <summary>
|
||||
/// Flag used to discard node values setting during event sending for node UI flushing.
|
||||
/// </summary>
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -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<SurfaceNode>)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));
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -447,6 +447,10 @@ namespace FlaxEditor.Windows
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
lock (_locker)
|
||||
{
|
||||
_pendingEntries.Clear();
|
||||
}
|
||||
if (_entriesPanel == null)
|
||||
return;
|
||||
RemoveEntries();
|
||||
@@ -735,10 +739,10 @@ namespace FlaxEditor.Windows
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnPlayBegin()
|
||||
public override void OnPlayBeginning()
|
||||
{
|
||||
// Clear on Play
|
||||
if (_clearOnPlayButton.Checked)
|
||||
if (Editor.Options.Options.Interface.DebugLogClearOnPlay)
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ namespace FlaxEditor.Windows
|
||||
private Panel _sceneTreePanel;
|
||||
private bool _isUpdatingSelection;
|
||||
private bool _isMouseDown;
|
||||
private bool _blockSceneTreeScroll = false;
|
||||
|
||||
private DragAssets _dragAssets;
|
||||
private DragActorType _dragActorType;
|
||||
@@ -111,6 +112,34 @@ namespace FlaxEditor.Windows
|
||||
InputActions.Add(options => options.LockFocusSelection, () => Editor.Windows.EditWin.Viewport.LockFocusSelection());
|
||||
InputActions.Add(options => options.Rename, RenameSelection);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnPlayBeginning()
|
||||
{
|
||||
base.OnPlayBeginning();
|
||||
_blockSceneTreeScroll = true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnPlayBegin()
|
||||
{
|
||||
base.OnPlayBegin();
|
||||
_blockSceneTreeScroll = false;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnPlayEnding()
|
||||
{
|
||||
base.OnPlayEnding();
|
||||
_blockSceneTreeScroll = true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnPlayEnd()
|
||||
{
|
||||
base.OnPlayEnd();
|
||||
_blockSceneTreeScroll = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enables or disables vertical and horizontal scrolling on the scene tree panel.
|
||||
@@ -270,7 +299,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]);
|
||||
@@ -280,6 +309,12 @@ namespace FlaxEditor.Windows
|
||||
_isUpdatingSelection = false;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnEditorStateChanged()
|
||||
{
|
||||
_blockSceneTreeScroll = Editor.StateMachine.ReloadingScriptsState.IsActive;
|
||||
}
|
||||
|
||||
private bool ValidateDragAsset(AssetItem assetItem)
|
||||
{
|
||||
if (assetItem.IsOfType<SceneAsset>())
|
||||
|
||||
@@ -20,6 +20,11 @@ namespace FlaxEditor.Windows.Search
|
||||
/// </summary>
|
||||
protected Image _icon;
|
||||
|
||||
/// <summary>
|
||||
/// The color of the accent strip.
|
||||
/// </summary>
|
||||
protected Color _accentColor;
|
||||
|
||||
/// <summary>
|
||||
/// The item name.
|
||||
/// </summary>
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseUp(Float2 location, MouseButton button)
|
||||
{
|
||||
@@ -86,6 +105,15 @@ namespace FlaxEditor.Windows.Search
|
||||
return base.OnMouseUp(location, button);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Draw()
|
||||
{
|
||||
if (IsMouseOver)
|
||||
Render2D.FillRectangle(new Rectangle(Float2.Zero, Size), Style.Current.BackgroundHighlighted);
|
||||
|
||||
base.Draw();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -128,6 +151,7 @@ namespace FlaxEditor.Windows.Search
|
||||
{
|
||||
_asset = item;
|
||||
_asset.AddReference(this);
|
||||
_accentColor = Editor.Instance.ContentDatabase.GetProxy(item).AccentColor;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -84,7 +84,7 @@ public:
|
||||
bool EnableGlobalSDF = false;
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="EditorOrder(2001), EditorDisplay(\"Global SDF\"), Limit(1000), ValueCategory(Utils.ValueCategory.Distance)")
|
||||
float GlobalSDFDistance = 15000.0f;
|
||||
|
||||
@@ -154,7 +154,7 @@ void ObjectsRemoval::Dispose()
|
||||
|
||||
Object::~Object()
|
||||
{
|
||||
#if BUILD_DEBUG
|
||||
#if BUILD_DEBUG && 0
|
||||
// Prevent removing object that is still reverenced by the removal service
|
||||
//ASSERT(!ObjectsRemovalService::IsInPool(this));
|
||||
#endif
|
||||
|
||||
@@ -998,6 +998,12 @@ void Foliage::RemoveAllInstances()
|
||||
RebuildClusters();
|
||||
}
|
||||
|
||||
void Foliage::RemoveLightmap()
|
||||
{
|
||||
for (auto& e : Instances)
|
||||
e.RemoveLightmap();
|
||||
}
|
||||
|
||||
static float GlobalDensityScale = 1.0f;
|
||||
|
||||
float Foliage::GetGlobalDensityScale()
|
||||
|
||||
@@ -139,6 +139,11 @@ public:
|
||||
/// </summary>
|
||||
API_FUNCTION() void RemoveAllInstances();
|
||||
|
||||
/// <summary>
|
||||
/// Removes the lightmap data from the foliage instances.
|
||||
/// </summary>
|
||||
API_FUNCTION() void RemoveLightmap();
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
/// 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.
|
||||
|
||||
@@ -605,10 +605,11 @@ int32 MaterialParams::GetVersionHash() const
|
||||
void MaterialParams::Bind(MaterialParamsLink* link, MaterialParameter::BindMeta& meta)
|
||||
{
|
||||
ASSERT(link && link->This);
|
||||
for (int32 i = 0; i < link->This->Count(); i++)
|
||||
const int32 count = link->This->Count();
|
||||
for (int32 i = 0; i < count; i++)
|
||||
{
|
||||
MaterialParamsLink* l = link;
|
||||
while (l->Down && !l->This->At(i).IsOverride())
|
||||
while (l->Down && !l->This->At(i).IsOverride() && l->Down->This->Count() == count)
|
||||
{
|
||||
l = l->Down;
|
||||
}
|
||||
|
||||
@@ -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<bool(Actor*)> function = [this](Actor* actor)
|
||||
{
|
||||
if (auto* staticModel = Cast<StaticModel>(actor))
|
||||
staticModel->RemoveLightmap();
|
||||
else if (auto* terrain = Cast<Terrain>(actor))
|
||||
terrain->RemoveLightmap();
|
||||
else if (auto* foliage = Cast<Foliage>(actor))
|
||||
foliage->RemoveLightmap();
|
||||
return true;
|
||||
};
|
||||
TreeExecute(function);
|
||||
}
|
||||
|
||||
void Scene::BuildCSG(float timeoutMs)
|
||||
|
||||
@@ -433,8 +433,6 @@ void UpdateNormalsAndHoles(const TerrainDataUpdateInfo& info, const float* heigh
|
||||
GET_VERTEX(1, 1);
|
||||
#undef GET_VERTEX
|
||||
|
||||
// TODO: use SIMD for those calculations
|
||||
|
||||
// Calculate normals for quad two vertices
|
||||
Float3 n0 = Float3::Normalize((v00 - v01) ^ (v01 - v10));
|
||||
Float3 n1 = Float3::Normalize((v11 - v10) ^ (v10 - v01));
|
||||
@@ -448,6 +446,7 @@ void UpdateNormalsAndHoles(const TerrainDataUpdateInfo& info, const float* heigh
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
// Smooth normals
|
||||
for (int32 z = 1; z < normalsSize.Y - 1; z++)
|
||||
{
|
||||
@@ -468,8 +467,6 @@ void UpdateNormalsAndHoles(const TerrainDataUpdateInfo& info, const float* heigh
|
||||
GET_NORMAL(2, 2);
|
||||
#undef GET_VERTEX
|
||||
|
||||
// TODO: use SIMD for those calculations
|
||||
|
||||
/*
|
||||
* The current vertex is (11). Calculate average for the nearby vertices.
|
||||
* 00 01 02
|
||||
@@ -483,6 +480,7 @@ void UpdateNormalsAndHoles(const TerrainDataUpdateInfo& info, const float* heigh
|
||||
normalsPerVertex[i11] = Float3::Lerp(n11, avg, 0.6f);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Write back to the data container
|
||||
const auto ptr = (Color32*)data;
|
||||
@@ -527,10 +525,9 @@ void UpdateNormalsAndHoles(const TerrainDataUpdateInfo& info, const float* heigh
|
||||
const int32 textureIndex = tz + tx;
|
||||
const int32 heightmapIndex = hz + hx;
|
||||
const int32 normalIndex = sz + sx;
|
||||
#if BUILD_DEBUG
|
||||
ASSERT(normalIndex >= 0 && normalIndex < normalsLength);
|
||||
#endif
|
||||
Float3 normal = Float3::NormalizeFast(normalsPerVertex[normalIndex]) * 0.5f + 0.5f;
|
||||
ASSERT_LOW_LAYER(normalIndex >= 0 && normalIndex < normalsLength);
|
||||
Float3 normal = Float3::NormalizeFast(normalsPerVertex[normalIndex]);
|
||||
normal = normal * 0.5f + 0.5f;
|
||||
|
||||
if (holesMask && !holesMask[heightmapIndex])
|
||||
normal = Float3::One;
|
||||
@@ -1252,6 +1249,11 @@ void TerrainPatch::ClearCache()
|
||||
|
||||
void TerrainPatch::CacheHeightData()
|
||||
{
|
||||
if (Heightmap == nullptr)
|
||||
{
|
||||
LOG(Error, "Missing heightmap.");
|
||||
return;
|
||||
}
|
||||
PROFILE_CPU_NAMED("Terrain.CacheHeightData");
|
||||
PROFILE_MEM(LevelTerrain);
|
||||
const TerrainDataUpdateInfo info(this);
|
||||
@@ -1756,7 +1758,7 @@ bool TerrainPatch::UpdateHeightData(TerrainDataUpdateInfo& info, const Int2& mod
|
||||
// Prepare data for the uploading to GPU
|
||||
ASSERT(Heightmap);
|
||||
auto texture = Heightmap->GetTexture();
|
||||
ASSERT(texture->ResidentMipLevels() > 0);
|
||||
ASSERT(texture->IsAllocated());
|
||||
const int32 textureSize = texture->Width();
|
||||
const PixelFormat pixelFormat = texture->Format();
|
||||
const int32 pixelStride = PixelFormatExtensions::SizeInBytes(pixelFormat);
|
||||
|
||||
@@ -10,6 +10,10 @@ void MaterialGenerator::ProcessGroupMaterial(Box* box, Node* node, Value& value)
|
||||
{
|
||||
switch (node->TypeID)
|
||||
{
|
||||
// Material
|
||||
case 1:
|
||||
value = tryGetValue(box, Value::Zero);
|
||||
break;
|
||||
// World Position
|
||||
case 2:
|
||||
value = Value(VariantType::Float3, TEXT("input.WorldPosition.xyz"));
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -286,7 +286,7 @@ void ShaderGenerator::ProcessGroupMath(Box* box, Node* node, Value& value)
|
||||
case 29:
|
||||
{
|
||||
Value inXY = tryGetValue(node->GetBox(0), Value::Zero).AsFloat2();
|
||||
value = writeLocal(ValueType::Float3, String::Format(TEXT("float3({0}, sqrt(saturate(1.0 - dot({0}.xy, {0}.xy))))"), inXY.Value), node);
|
||||
value = writeLocal(ValueType::Float3, String::Format(TEXT("float3({0}, sqrt(saturate(1.0 - dot({0}, {0}))))"), inXY.Value), node);
|
||||
break;
|
||||
}
|
||||
// Mad
|
||||
|
||||
@@ -5,28 +5,30 @@
|
||||
|
||||
#include "./Flax/Common.hlsl"
|
||||
|
||||
float DecodeHeightmapHeight(float4 value)
|
||||
{
|
||||
return (float)((int)(value.x * 255.0) + ((int)(value.y * 255) << 8)) / 65535.0;
|
||||
}
|
||||
|
||||
float3 DecodeHeightmapNormal(float4 value, out bool isHole)
|
||||
{
|
||||
isHole = (value.b + value.a) >= 1.9f;
|
||||
float2 normalTemp = float2(value.b, value.a) * 2.0f - 1.0f;
|
||||
float3 normal = float3(normalTemp.x, sqrt(1.0 - saturate(dot(normalTemp, normalTemp))), normalTemp.y);
|
||||
return normalize(normal);
|
||||
}
|
||||
|
||||
float SampleHeightmap(Texture2D<float4> heightmap, float2 uv, float mipOffset = 0.0f)
|
||||
{
|
||||
// Sample heightmap
|
||||
float4 value = heightmap.SampleLevel(SamplerPointClamp, uv, mipOffset);
|
||||
|
||||
// Decode heightmap
|
||||
float height = (float)((int)(value.x * 255.0) + ((int)(value.y * 255) << 8)) / 65535.0;
|
||||
return height;
|
||||
return DecodeHeightmapHeight(value);
|
||||
}
|
||||
|
||||
float SampleHeightmap(Texture2D<float4> heightmap, float2 uv, out float3 normal, out bool isHole, float mipOffset = 0.0f)
|
||||
{
|
||||
// Sample heightmap
|
||||
float4 value = heightmap.SampleLevel(SamplerPointClamp, uv, mipOffset);
|
||||
|
||||
// Decode heightmap
|
||||
float height = (float)((int)(value.x * 255.0) + ((int)(value.y * 255) << 8)) / 65535.0;
|
||||
float2 normalTemp = float2(value.b, value.a) * 2.0f - 1.0f;
|
||||
normal = float3(normalTemp.x, sqrt(1.0 - saturate(dot(normalTemp, normalTemp))), normalTemp.y);
|
||||
isHole = (value.b + value.a) >= 1.9f;
|
||||
normal = normalize(normal);
|
||||
return height;
|
||||
normal = DecodeHeightmapNormal(value, isHole);
|
||||
return DecodeHeightmapHeight(value);
|
||||
}
|
||||
|
||||
float3 SampleHeightmap(Texture2D<float4> heightmap, float3 localPosition, float4 localToUV, out float3 normal, out bool isHole, float mipOffset = 0.0f)
|
||||
@@ -36,12 +38,9 @@ float3 SampleHeightmap(Texture2D<float4> heightmap, float3 localPosition, float4
|
||||
float4 value = heightmap.SampleLevel(SamplerPointClamp, uv, mipOffset);
|
||||
|
||||
// Decode heightmap
|
||||
isHole = (value.b + value.a) >= 1.9f;
|
||||
float height = (float)((int)(value.x * 255.0) + ((int)(value.y * 255) << 8)) / 65535.0;
|
||||
normal = DecodeHeightmapNormal(value, isHole);
|
||||
float height = DecodeHeightmapHeight(value);;
|
||||
float3 position = float3(localPosition.x, height, localPosition.z);
|
||||
float2 normalTemp = float2(value.b, value.a) * 2.0f - 1.0f;
|
||||
normal = float3(normalTemp.x, sqrt(1.0 - saturate(dot(normalTemp, normalTemp))), normalTemp.y);
|
||||
normal = normalize(normal);
|
||||
|
||||
// UVs outside the heightmap are empty
|
||||
isHole = isHole || any(uv < 0.0f) || any(uv > 1.0f);
|
||||
|
||||
Reference in New Issue
Block a user