diff --git a/Content/Shaders/SSR.flax b/Content/Shaders/SSR.flax index 36d193f28..09d4db9d7 100644 --- a/Content/Shaders/SSR.flax +++ b/Content/Shaders/SSR.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9403835414767ee73082d543b0e0f0827e2dfaf7e108ccb06145acb5f8576c03 -size 11173 +oid sha256:51826aca596ee714a557d74adcee138e674d30197cffebe454e20474713f3b37 +size 10916 diff --git a/Development/Images/flax-pic-2.jpg b/Development/Images/flax-pic-2.jpg index fbf3517fd..044c6302e 100644 Binary files a/Development/Images/flax-pic-2.jpg and b/Development/Images/flax-pic-2.jpg differ diff --git a/Flax.flaxproj b/Flax.flaxproj index ae03ab860..8712154f5 100644 --- a/Flax.flaxproj +++ b/Flax.flaxproj @@ -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.", diff --git a/README.md b/README.md index 317dc8c4a..f37a11d19 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/Source/Editor/Editor.cs b/Source/Editor/Editor.cs index 946894ab9..0219e1769 100644 --- a/Source/Editor/Editor.cs +++ b/Source/Editor/Editor.cs @@ -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(); diff --git a/Source/Editor/Plugins/EditorPlugin.cs b/Source/Editor/Plugins/EditorPlugin.cs index cf22ff7af..bfc4e037a 100644 --- a/Source/Editor/Plugins/EditorPlugin.cs +++ b/Source/Editor/Plugins/EditorPlugin.cs @@ -5,15 +5,10 @@ using FlaxEngine; namespace FlaxEditor { - /// - /// Base class for all plugins used in Editor. - /// - /// - /// Plugins should have a public and parameter-less constructor. - /// - /// - public abstract class EditorPlugin : Plugin + partial class EditorPlugin { + internal bool _isEditorInitialized; + /// /// Gets the type of the 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. /// @@ -24,14 +19,12 @@ namespace FlaxEditor /// public Editor Editor { get; private set; } - /// - 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(); } diff --git a/Source/Editor/Surface/Archetypes/Textures.cs b/Source/Editor/Surface/Archetypes/Textures.cs index a7180f78e..2b566b0bd 100644 --- a/Source/Editor/Surface/Archetypes/Textures.cs +++ b/Source/Editor/Surface/Archetypes/Textures.cs @@ -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) + } + }, }; } } diff --git a/Source/Engine/Level/Actors/StaticModel.cpp b/Source/Engine/Level/Actors/StaticModel.cpp index f5d9b68c2..26eb1fc44 100644 --- a/Source/Engine/Level/Actors/StaticModel.cpp +++ b/Source/Engine/Level/Actors/StaticModel.cpp @@ -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(this); + } + else + { + GetSceneRendering()->AddActor(this, _sceneRenderingKey); + } } // Skip ModelInstanceActor (add to SceneRendering manually) diff --git a/Source/Engine/Renderer/DepthOfFieldPass.cpp b/Source/Engine/Renderer/DepthOfFieldPass.cpp index 8ed51d696..f80441d00 100644 --- a/Source/Engine/Renderer/DepthOfFieldPass.cpp +++ b/Source/Engine/Renderer/DepthOfFieldPass.cpp @@ -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) diff --git a/Source/Engine/Scripting/Plugins/EditorPlugin.h b/Source/Engine/Scripting/Plugins/EditorPlugin.h new file mode 100644 index 000000000..7a519ee0d --- /dev/null +++ b/Source/Engine/Scripting/Plugins/EditorPlugin.h @@ -0,0 +1,24 @@ +// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved. + +#pragma once + +#include "Plugin.h" + +#if USE_EDITOR + +/// +/// Base class for all plugins used in Editor. +/// +/// +/// Plugins should have a public and parameter-less constructor. +/// +/// +API_CLASS(Abstract, Namespace="FlaxEditor") class FLAXENGINE_API EditorPlugin : public Plugin +{ + DECLARE_SCRIPTING_TYPE(EditorPlugin); +public: + void Initialize() override; + void Deinitialize() override; +}; + +#endif diff --git a/Source/Engine/Scripting/Plugins/PluginManager.cpp b/Source/Engine/Scripting/Plugins/PluginManager.cpp index 0d0fdcb12..0347fc6b2 100644 --- a/Source/Engine/Scripting/Plugins/PluginManager.cpp +++ b/Source/Engine/Scripting/Plugins/PluginManager.cpp @@ -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 PluginManager::PluginLoading; Delegate PluginManager::PluginLoaded; Delegate 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"); diff --git a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Textures.cpp b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Textures.cpp index 5d19f46d2..a29b3d0d9 100644 --- a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Textures.cpp +++ b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Textures.cpp @@ -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(), 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; } diff --git a/Source/FlaxEngine.Gen.cs b/Source/FlaxEngine.Gen.cs index 63340690e..d1695ed23 100644 --- a/Source/FlaxEngine.Gen.cs +++ b/Source/FlaxEngine.Gen.cs @@ -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")] diff --git a/Source/FlaxEngine.Gen.h b/Source/FlaxEngine.Gen.h index e565bc61c..c0f57118d 100644 --- a/Source/FlaxEngine.Gen.h +++ b/Source/FlaxEngine.Gen.h @@ -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." diff --git a/Source/Shaders/GI/GlobalSurfaceAtlas.hlsl b/Source/Shaders/GI/GlobalSurfaceAtlas.hlsl index 30bab5742..93633dbec 100644 --- a/Source/Shaders/GI/GlobalSurfaceAtlas.hlsl +++ b/Source/Shaders/GI/GlobalSurfaceAtlas.hlsl @@ -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 diff --git a/Source/Shaders/Gather.hlsl b/Source/Shaders/Gather.hlsl index f6540fe86..76950bd66 100644 --- a/Source/Shaders/Gather.hlsl +++ b/Source/Shaders/Gather.hlsl @@ -70,4 +70,30 @@ float4 TextureGatherRed(Texture2D 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 diff --git a/Source/Shaders/SSR.shader b/Source/Shaders/SSR.shader index e6c57e943..765952cfb 100644 --- a/Source/Shaders/SSR.shader +++ b/Source/Shaders/SSR.shader @@ -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]; diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs index 9d0e22401..dc5190f36 100644 --- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs @@ -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();