Merge remote-tracking branch 'origin/master' into 1.5

This commit is contained in:
Wojciech Figat
2022-09-03 12:54:45 +02:00
18 changed files with 242 additions and 27 deletions

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 341 KiB

After

Width:  |  Height:  |  Size: 263 KiB

View File

@@ -3,7 +3,7 @@
"Version": {
"Major": 1,
"Minor": 4,
"Build": 6333
"Build": 6334
},
"Company": "Flax",
"Copyright": "Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.",

View File

@@ -18,9 +18,9 @@ This repository contains full source code of the Flax Engine (excluding NDA-prot
# Screenshots
![pbr-rendering](Development/Images/flax-pic-2.jpg "PBR Rendering and Global Illumination")
![rendering](Development/Images/flax-pic-1.jpg "Rendering")
![performance](Development/Images/flax-pic-3.jpg "High Performance")
![pbr-rendering](Development/Images/flax-pic-2.jpg "PBR Rendering")
# Getting started

View File

@@ -572,7 +572,13 @@ namespace FlaxEditor
// Deinitialize Editor Plugins
foreach (var plugin in PluginManager.EditorPlugins)
((EditorPlugin)plugin).DeinitializeEditor();
{
if (plugin is EditorPlugin editorPlugin && editorPlugin._isEditorInitialized)
{
editorPlugin._isEditorInitialized = false;
editorPlugin.DeinitializeEditor();
}
}
// Start exit
StateMachine.GoToState<ClosingState>();

View File

@@ -5,15 +5,10 @@ using FlaxEngine;
namespace FlaxEditor
{
/// <summary>
/// Base class for all plugins used in Editor.
/// </summary>
/// <remarks>
/// Plugins should have a public and parameter-less constructor.
/// </remarks>
/// <seealso cref="FlaxEngine.Plugin" />
public abstract class EditorPlugin : Plugin
partial class EditorPlugin
{
internal bool _isEditorInitialized;
/// <summary>
/// Gets the type of the <see cref="GamePlugin"/> that is related to this plugin. Some plugins may be used only in editor while others want to gave a runtime representation. Use this property to link the related game plugin.
/// </summary>
@@ -24,14 +19,12 @@ namespace FlaxEditor
/// </summary>
public Editor Editor { get; private set; }
/// <inheritdoc />
public override void Initialize()
internal void Initialize_Internal()
{
base.Initialize();
Editor = Editor.Instance;
if (Editor.IsInitialized)
{
_isEditorInitialized = true;
InitializeEditor();
}
else
@@ -40,9 +33,21 @@ namespace FlaxEditor
}
}
internal void Deinitialize_Internal()
{
if (_isEditorInitialized)
{
_isEditorInitialized = false;
DeinitializeEditor();
}
}
private void OnEditorInitializationEnd()
{
Editor.InitializationEnd -= OnEditorInitializationEnd;
if (_isEditorInitialized)
return;
_isEditorInitialized = true;
InitializeEditor();
}

View File

@@ -385,6 +385,26 @@ namespace FlaxEditor.Surface.Archetypes
NodeElementArchetype.Factory.Input(0, "World Position", true, typeof(Float3), 1),
}
},
new NodeArchetype
{
TypeID = 16,
Title = "World Triplanar Texture",
Description = "Projects a texture using world-space coordinates instead of UVs.",
Flags = NodeFlags.MaterialGraph,
Size = new Float2(240, 60),
DefaultValues = new object[]
{
1.0f,
1.0f
},
Elements = new[]
{
NodeElementArchetype.Factory.Input(0, "Texture", true, typeof(FlaxEngine.Object), 0),
NodeElementArchetype.Factory.Input(1, "Scale", true, typeof(float), 1, 0),
NodeElementArchetype.Factory.Input(2, "Blend", true, typeof(float), 2, 1),
NodeElementArchetype.Factory.Output(0, "Color", typeof(Float3), 3)
}
},
};
}
}

View File

@@ -520,9 +520,19 @@ void StaticModel::OnTransformChanged()
void StaticModel::OnEnable()
{
if (_scene && _sceneRenderingKey == -1 && !_residencyChangedModel && Model && Model->IsLoaded() && Model->GetLoadedLODs() != 0)
// If model is set and loaded but we still don't have residency registered do it here (eg. model is streaming LODs right now)
if (_scene && _sceneRenderingKey == -1 && !_residencyChangedModel && Model && Model->IsLoaded())
{
GetSceneRendering()->AddActor(this, _sceneRenderingKey);
// Register for rendering but once the model has any LOD loaded
if (Model->GetLoadedLODs() == 0)
{
_residencyChangedModel = Model;
_residencyChangedModel->ResidencyChanged.Bind<StaticModel, &StaticModel::OnModelResidencyChanged>(this);
}
else
{
GetSceneRendering()->AddActor(this, _sceneRenderingKey);
}
}
// Skip ModelInstanceActor (add to SceneRendering manually)

View File

@@ -56,7 +56,7 @@ bool DepthOfFieldPass::Init()
// (in future we should support it or faster solution using pixel shaders)
auto& limits = GPUDevice::Instance->Limits;
_platformSupportsDoF = limits.HasCompute;
_platformSupportsBokeh = false && _platformSupportsDoF && limits.HasGeometryShaders && limits.HasDrawIndirect && limits.HasAppendConsumeBuffers;
_platformSupportsBokeh = _platformSupportsDoF && limits.HasGeometryShaders && limits.HasDrawIndirect && limits.HasAppendConsumeBuffers;
// Create pipeline states
if (_platformSupportsDoF)

View File

@@ -0,0 +1,24 @@
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
#pragma once
#include "Plugin.h"
#if USE_EDITOR
/// <summary>
/// Base class for all plugins used in Editor.
/// </summary>
/// <remarks>
/// Plugins should have a public and parameter-less constructor.
/// </remarks>
/// <seealso cref="FlaxEngine.Plugin" />
API_CLASS(Abstract, Namespace="FlaxEditor") class FLAXENGINE_API EditorPlugin : public Plugin
{
DECLARE_SCRIPTING_TYPE(EditorPlugin);
public:
void Initialize() override;
void Deinitialize() override;
};
#endif

View File

@@ -27,6 +27,45 @@ GamePlugin::GamePlugin(const SpawnParams& params)
{
}
#if USE_EDITOR
#include "EditorPlugin.h"
#include "Engine/Scripting/MException.h"
#include "Engine/Scripting/ManagedCLR/MMethod.h"
EditorPlugin::EditorPlugin(const SpawnParams& params)
: Plugin(params)
{
}
void EditorPlugin::Initialize()
{
Plugin::Initialize();
MObject* exception = nullptr;
TypeInitializer.GetType().ManagedClass->GetMethod("Initialize_Internal")->Invoke(GetOrCreateManagedInstance(), nullptr, &exception);
if (exception)
{
MException ex(exception);
ex.Log(LogType::Error,TEXT("EditorPlugin"));
}
}
void EditorPlugin::Deinitialize()
{
MObject* exception = nullptr;
TypeInitializer.GetType().ManagedClass->GetMethod("Deinitialize_Internal")->Invoke(GetOrCreateManagedInstance(), nullptr, &exception);
if (exception)
{
MException ex(exception);
ex.Log(LogType::Error,TEXT("EditorPlugin"));
}
Plugin::Deinitialize();
}
#endif
Delegate<Plugin*> PluginManager::PluginLoading;
Delegate<Plugin*> PluginManager::PluginLoaded;
Delegate<Plugin*> PluginManager::PluginUnloading;
@@ -42,6 +81,7 @@ namespace PluginManagerImpl
void OnAssemblyLoaded(MAssembly* assembly);
void OnAssemblyUnloading(MAssembly* assembly);
void OnBinaryModuleLoaded(BinaryModule* module);
void OnScriptsReloading();
}
using namespace PluginManagerImpl;
@@ -211,6 +251,32 @@ void PluginManagerImpl::OnBinaryModuleLoaded(BinaryModule* module)
managedModule->Assembly->Unloading.Bind(OnAssemblyUnloading);
}
void PluginManagerImpl::OnScriptsReloading()
{
// When scripting is reloading (eg. for hot-reload in Editor) we have to deinitialize plugins (Scripting service destroys C# objects later on)
bool changed = false;
for (int32 i = EditorPlugins.Count() - 1; i >= 0 && EditorPlugins.Count() > 0; i--)
{
auto plugin = EditorPlugins[i];
{
PluginManagerService::InvokeDeinitialize(plugin);
EditorPlugins.RemoveAtKeepOrder(i);
changed = true;
}
}
for (int32 i = GamePlugins.Count() - 1; i >= 0 && GamePlugins.Count() > 0; i--)
{
auto plugin = GamePlugins[i];
{
PluginManagerService::InvokeDeinitialize(plugin);
GamePlugins.RemoveAtKeepOrder(i);
changed = true;
}
}
if (changed)
PluginManager::PluginsChanged();
}
bool PluginManagerService::Init()
{
// Process already loaded modules
@@ -221,6 +287,7 @@ bool PluginManagerService::Init()
// Register for new binary modules load actions
Scripting::BinaryModuleLoaded.Bind(&OnBinaryModuleLoaded);
Scripting::ScriptsReloading.Bind(&OnScriptsReloading);
return false;
}
@@ -228,6 +295,7 @@ bool PluginManagerService::Init()
void PluginManagerService::Dispose()
{
Scripting::BinaryModuleLoaded.Unbind(&OnBinaryModuleLoaded);
Scripting::ScriptsReloading.Unbind(&OnScriptsReloading);
// Cleanup all plugins
PROFILE_CPU_NAMED("Dispose Plugins");

View File

@@ -444,6 +444,55 @@ void MaterialGenerator::ProcessGroupTextures(Box* box, Node* node, Value& value)
value = box == gradientBox ? gradient : distance;
break;
}
// World Triplanar Texture
case 16:
{
// Get input boxes
auto textureBox = node->GetBox(0);
auto scaleBox = node->GetBox(1);
auto blendBox = node->GetBox(2);
if (!textureBox->HasConnection())
{
// No texture to sample
value = Value::Zero;
break;
}
if (!CanUseSample(_treeType))
{
// Must sample texture in pixel shader
value = Value::Zero;
break;
}
const auto texture = eatBox(textureBox->GetParent<Node>(), textureBox->FirstConnection());
const auto scale = tryGetValue(scaleBox, node->Values[0]).AsFloat();
const auto blend = tryGetValue(blendBox, node->Values[1]).AsFloat();
auto result = writeLocal(Value::InitForZero(ValueType::Float4), node);
const String triplanarTexture = String::Format(TEXT(
" {{\n"
" float3 worldPos = input.WorldPosition.xyz * ({1} * 0.001f);\n"
" float3 normal = abs(input.TBN[2]);\n"
" normal = pow(normal, {2});\n"
" normal = normal / (normal.x + normal.y + normal.z);\n"
" {3} += {0}.Sample(SamplerLinearWrap, worldPos.yz) * normal.x;\n"
" {3} += {0}.Sample(SamplerLinearWrap, worldPos.xz) * normal.y;\n"
" {3} += {0}.Sample(SamplerLinearWrap, worldPos.xy) * normal.z;\n"
" }}\n"
),
texture.Value, // {0}
scale.Value, // {1}
blend.Value, // {2}
result.Value // {3}
);
_writer.Write(*triplanarTexture);
value = result;
}
default:
break;
}

View File

@@ -13,5 +13,5 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: Guid("b8442186-4a70-7c85-704a-857cc7990797")]
[assembly: AssemblyVersion("1.4.6333")]
[assembly: AssemblyFileVersion("1.4.6333")]
[assembly: AssemblyVersion("1.4.6334")]
[assembly: AssemblyFileVersion("1.4.6334")]

View File

@@ -3,11 +3,11 @@
#pragma once
#define FLAXENGINE_NAME "FlaxEngine"
#define FLAXENGINE_VERSION Version(1, 4, 6333)
#define FLAXENGINE_VERSION_TEXT "1.4.6333"
#define FLAXENGINE_VERSION Version(1, 4, 6334)
#define FLAXENGINE_VERSION_TEXT "1.4.6334"
#define FLAXENGINE_VERSION_MAJOR 1
#define FLAXENGINE_VERSION_MINOR 4
#define FLAXENGINE_VERSION_BUILD 6333
#define FLAXENGINE_VERSION_BUILD 6334
#define FLAXENGINE_COMPANY "Flax"
#define FLAXENGINE_COPYRIGHT "Copyright (c) 2012-2022 Wojciech Figat. All rights reserved."

View File

@@ -3,6 +3,10 @@
#include "./Flax/Common.hlsl"
#include "./Flax/Collisions.hlsl"
#if CAN_USE_GATHER
#define CAN_USE_GLOBAL_SURFACE_ATLAS 1
#endif
// This must match C++
#define GLOBAL_SURFACE_ATLAS_CHUNKS_RESOLUTION 40 // Amount of chunks (in each direction) to split atlas draw distance for objects culling
#define GLOBAL_SURFACE_ATLAS_CHUNKS_GROUP_SIZE 4

View File

@@ -70,4 +70,30 @@ float4 TextureGatherRed(Texture2D<float> tex, SamplerState sam, float2 uv, int2
#endif
}
float4 TextureGatherGreen(Texture2D tex, SamplerState sam, float2 uv)
{
#if CAN_USE_GATHER
return tex.GatherGreen(sam, uv);
#else
float x = tex.Sample(sam, uv, int2(0, 1)).g;
float y = tex.Sample(sam, uv, int2(1, 1)).g;
float z = tex.Sample(sam, uv, int2(1, 0)).g;
float w = tex.Sample(sam, uv, int2(0, 0)).g;
return float4(x, y, z, w);
#endif
}
float4 TextureGatherBlue(Texture2D tex, SamplerState sam, float2 uv)
{
#if CAN_USE_GATHER
return tex.GatherBlue(sam, uv);
#else
float x = tex.Sample(sam, uv, int2(0, 1)).b;
float y = tex.Sample(sam, uv, int2(1, 1)).b;
float z = tex.Sample(sam, uv, int2(1, 0)).b;
float w = tex.Sample(sam, uv, int2(0, 0)).b;
return float4(x, y, z, w);
#endif
}
#endif

View File

@@ -134,7 +134,7 @@ float4 PS_RayTracePass(Quad_VS2PS input) : SV_Target0
float3 reflectWS = ScreenSpaceReflectionDirection(input.TexCoord, gBuffer, gBufferData.ViewPos, TemporalEffect, TemporalTime, BRDFBias);
// Fallback to Global SDF and Global Surface Atlas tracing
#if USE_GLOBAL_SURFACE_ATLAS
#if USE_GLOBAL_SURFACE_ATLAS && CAN_USE_GLOBAL_SURFACE_ATLAS
GlobalSDFTrace sdfTrace;
float maxDistance = 100000;
float selfOcclusionBias = GlobalSDF.CascadeVoxelSize[0];

View File

@@ -1569,7 +1569,10 @@ namespace Flax.Build.Bindings
}
contents.Append(')').AppendLine();
contents.Append(" {").AppendLine();
contents.Append(" static MMethod* mmethod = nullptr;").AppendLine();
if (buildData.Target.IsEditor)
contents.Append(" MMethod* mmethod = nullptr;").AppendLine(); // TODO: find a better way to cache event method in editor and handle C# hot-reload
else
contents.Append(" static MMethod* mmethod = nullptr;").AppendLine();
contents.Append(" if (!mmethod)").AppendLine();
contents.AppendFormat(" mmethod = {1}::TypeInitializer.GetType().ManagedClass->GetMethod(\"Internal_{0}_Invoke\", {2});", eventInfo.Name, classTypeNameNative, paramsCount).AppendLine();
contents.Append(" CHECK(mmethod);").AppendLine();