From c99793d2a445e86dcc0786dc690d937796c5e345 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 11 Apr 2022 18:32:28 +0200 Subject: [PATCH 01/19] Fix typo --- Source/Engine/Utilities/MeshDataCache.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Engine/Utilities/MeshDataCache.cs b/Source/Engine/Utilities/MeshDataCache.cs index 9d4e78e90..e7a0d8436 100644 --- a/Source/Engine/Utilities/MeshDataCache.cs +++ b/Source/Engine/Utilities/MeshDataCache.cs @@ -47,7 +47,7 @@ namespace FlaxEngine.Utilities /// Requests the mesh data. /// /// The model to get it's data. - /// True if ahs valid data to access, otherwise false if it's during downloading. + /// True if has valid data to access, otherwise false if it's during downloading. public bool RequestMeshData(Model model) { if (model == null) From e32ad93020567868415e7a37f3f186290ba24f51 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 12 Apr 2022 21:48:52 +0200 Subject: [PATCH 02/19] Add support for sampling Scene Color in transparent materials (forward pass) --- .../Graphics/Materials/ForwardMaterialShader.cpp | 2 +- .../Engine/Graphics/Materials/MaterialParams.cpp | 4 +++- Source/Engine/Renderer/ForwardPass.cpp | 7 ++----- Source/Engine/Renderer/RenderList.cpp | 3 ++- Source/Engine/Renderer/RenderList.h | 8 +++++--- Source/Engine/Renderer/Renderer.cpp | 14 ++++---------- 6 files changed, 17 insertions(+), 21 deletions(-) diff --git a/Source/Engine/Graphics/Materials/ForwardMaterialShader.cpp b/Source/Engine/Graphics/Materials/ForwardMaterialShader.cpp index 5f9c385d4..a62ab9014 100644 --- a/Source/Engine/Graphics/Materials/ForwardMaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/ForwardMaterialShader.cpp @@ -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; diff --git a/Source/Engine/Graphics/Materials/MaterialParams.cpp b/Source/Engine/Graphics/Materials/MaterialParams.cpp index 7386343b5..c99d358e3 100644 --- a/Source/Engine/Graphics/Materials/MaterialParams.cpp +++ b/Source/Engine/Graphics/Materials/MaterialParams.cpp @@ -400,11 +400,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: diff --git a/Source/Engine/Renderer/ForwardPass.cpp b/Source/Engine/Renderer/ForwardPass.cpp index bf607ea6b..b853b71c4 100644 --- a/Source/Engine/Renderer/ForwardPass.cpp +++ b/Source/Engine/Renderer/ForwardPass.cpp @@ -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()); } } diff --git a/Source/Engine/Renderer/RenderList.cpp b/Source/Engine/Renderer/RenderList.cpp index 09e6bc6b2..5df281aae 100644 --- a/Source/Engine/Renderer/RenderList.cpp +++ b/Source/Engine/Renderer/RenderList.cpp @@ -553,7 +553,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; @@ -625,6 +625,7 @@ DRAW: // Execute draw calls MaterialBase::BindParameters bindParams(context, renderContext); + bindParams.Input = input; if (useInstancing) { int32 instanceBufferOffset = 0; diff --git a/Source/Engine/Renderer/RenderList.h b/Source/Engine/Renderer/RenderList.h index 1b514f824..7ff47014b 100644 --- a/Source/Engine/Renderer/RenderList.h +++ b/Source/Engine/Renderer/RenderList.h @@ -564,9 +564,10 @@ public: /// /// The rendering context. /// The collected draw calls list type. - API_FUNCTION() FORCE_INLINE void ExecuteDrawCalls(API_PARAM(Ref) const RenderContext& renderContext, DrawCallsListType listType) + /// The input scene color. It's optional and used in forward/postFx rendering. + 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); } /// @@ -574,7 +575,8 @@ public: /// /// The rendering context. /// The collected draw calls list. - void ExecuteDrawCalls(const RenderContext& renderContext, DrawCallsList& list); + /// The input scene color. It's optional and used in forward/postFx rendering. + void ExecuteDrawCalls(const RenderContext& renderContext, DrawCallsList& list, GPUTextureView* input = nullptr); }; /// diff --git a/Source/Engine/Renderer/Renderer.cpp b/Source/Engine/Renderer/Renderer.cpp index d529447d9..7758e824e 100644 --- a/Source/Engine/Renderer/Renderer.cpp +++ b/Source/Engine/Renderer/Renderer.cpp @@ -45,7 +45,6 @@ Array PassList(64); class RendererService : public EngineService { public: - RendererService() : EngineService(TEXT("Renderer"), 20) { @@ -429,8 +428,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(); @@ -443,16 +443,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); From 58491e6d23a7f73223f81a1d81b6b75eff73c1e1 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 12 Apr 2022 22:16:06 +0200 Subject: [PATCH 03/19] Add **Screen Space Reflections for transparent materials** --- .../Features/ForwardShading.hlsl | 28 +++- .../Editor/Windows/Assets/MaterialWindow.cs | 7 + Source/Engine/Content/Assets/Material.cpp | 2 + .../Engine/Graphics/Materials/MaterialInfo.h | 5 + .../Graphics/Materials/MaterialShader.h | 2 +- .../MaterialGenerator/MaterialGenerator.cpp | 9 + Source/Shaders/ReflectionsCommon.hlsl | 11 +- Source/Shaders/SSR.hlsl | 154 ++++++++++++++++++ 8 files changed, 207 insertions(+), 11 deletions(-) create mode 100644 Source/Shaders/SSR.hlsl diff --git a/Content/Editor/MaterialTemplates/Features/ForwardShading.hlsl b/Content/Editor/MaterialTemplates/Features/ForwardShading.hlsl index c21fe37d2..34376caf3 100644 --- a/Content/Editor/MaterialTemplates/Features/ForwardShading.hlsl +++ b/Content/Editor/MaterialTemplates/Features/ForwardShading.hlsl @@ -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) diff --git a/Source/Editor/Windows/Assets/MaterialWindow.cs b/Source/Editor/Windows/Assets/MaterialWindow.cs index 69ad94630..2c3f05ab9 100644 --- a/Source/Editor/Windows/Assets/MaterialWindow.cs +++ b/Source/Editor/Windows/Assets/MaterialWindow.cs @@ -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) diff --git a/Source/Engine/Content/Assets/Material.cpp b/Source/Engine/Content/Assets/Material.cpp index c70794e45..2b715da0c 100644 --- a/Source/Engine/Content/Assets/Material.cpp +++ b/Source/Engine/Content/Assets/Material.cpp @@ -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] }); diff --git a/Source/Engine/Graphics/Materials/MaterialInfo.h b/Source/Engine/Graphics/Materials/MaterialInfo.h index 77f3d8c77..98f9bad74 100644 --- a/Source/Engine/Graphics/Materials/MaterialInfo.h +++ b/Source/Engine/Graphics/Materials/MaterialInfo.h @@ -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. /// PixelNormalOffsetRefraction = 1 << 9, + + /// + /// 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. + /// + ScreenSpaceReflections = 1 << 10, }; DECLARE_ENUM_OPERATORS(MaterialFeaturesFlags); diff --git a/Source/Engine/Graphics/Materials/MaterialShader.h b/Source/Engine/Graphics/Materials/MaterialShader.h index 29074ec37..4c789b2ea 100644 --- a/Source/Engine/Graphics/Materials/MaterialShader.h +++ b/Source/Engine/Graphics/Materials/MaterialShader.h @@ -10,7 +10,7 @@ /// /// Current materials shader version. /// -#define MATERIAL_GRAPH_VERSION 150 +#define MATERIAL_GRAPH_VERSION 151 class Material; class GPUShader; diff --git a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.cpp b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.cpp index d9e24935d..6e6ab486f 100644 --- a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.cpp +++ b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.cpp @@ -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; diff --git a/Source/Shaders/ReflectionsCommon.hlsl b/Source/Shaders/ReflectionsCommon.hlsl index cb33274eb..cd4695095 100644 --- a/Source/Shaders/ReflectionsCommon.hlsl +++ b/Source/Shaders/ReflectionsCommon.hlsl @@ -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 diff --git a/Source/Shaders/SSR.hlsl b/Source/Shaders/SSR.hlsl new file mode 100644 index 000000000..838cf9482 --- /dev/null +++ b/Source/Shaders/SSR.hlsl @@ -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 = true, 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); +} From 96ed1708715c3970cca35db78e0c0b45cf6858cf Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 12 Apr 2022 22:16:45 +0200 Subject: [PATCH 04/19] Use `TraceSceenSpaceReflection` in SSR shader for opaque --- Content/Shaders/SSR.flax | 4 +- .../Renderer/ScreenSpaceReflectionsPass.cpp | 10 +- Source/Shaders/SSR.hlsl | 2 +- Source/Shaders/SSR.shader | 161 +----------------- 4 files changed, 13 insertions(+), 164 deletions(-) diff --git a/Content/Shaders/SSR.flax b/Content/Shaders/SSR.flax index 116d1415b..7e249afb5 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:f8047ea5ef2604e1111db1c559def9a63700bbd88a0f6f32264f7490a14c8c86 -size 13442 +oid sha256:fd2d0c05638d8e4c6c307d70d57a29f2475c9c0d8dfb43f8b8ff09189e4a62bb +size 9341 diff --git a/Source/Engine/Renderer/ScreenSpaceReflectionsPass.cpp b/Source/Engine/Renderer/ScreenSpaceReflectionsPass.cpp index 2b226af85..10b9636c8 100644 --- a/Source/Engine/Renderer/ScreenSpaceReflectionsPass.cpp +++ b/Source/Engine/Renderer/ScreenSpaceReflectionsPass.cpp @@ -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(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(); diff --git a/Source/Shaders/SSR.hlsl b/Source/Shaders/SSR.hlsl index 838cf9482..86d8c5f6b 100644 --- a/Source/Shaders/SSR.hlsl +++ b/Source/Shaders/SSR.hlsl @@ -52,7 +52,7 @@ float RayAttenBorder(float2 pos, float 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 = true, float temporalTime = 0.0f, float worldAntiSelfOcclusionBias = 0.1f, float brdfBias = 0.82f, float drawDistance = 5000.0f, float roughnessThreshold = 0.4f, float edgeFade = 0.1f) +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) diff --git a/Source/Shaders/SSR.shader b/Source/Shaders/SSR.shader index 659290afe..5893a6ad1 100644 --- a/Source/Shaders/SSR.shader +++ b/Source/Shaders/SSR.shader @@ -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 From 738e7d2516bbdcb3cfd67095320e41b56abb9760 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 12 Apr 2022 22:17:01 +0200 Subject: [PATCH 05/19] Update engine materials --- Content/Editor/Camera/M_Camera.flax | 2 +- Content/Editor/CubeTexturePreviewMaterial.flax | 2 +- Content/Editor/DebugMaterials/SingleColor/Decal.flax | 2 +- Content/Editor/DebugMaterials/SingleColor/Particle.flax | 4 ++-- Content/Editor/DebugMaterials/SingleColor/Surface.flax | 2 +- .../Editor/DebugMaterials/SingleColor/SurfaceAdditive.flax | 4 ++-- Content/Editor/DebugMaterials/SingleColor/Terrain.flax | 2 +- Content/Editor/DefaultFontMaterial.flax | 2 +- Content/Editor/Gizmo/FoliageBrushMaterial.flax | 4 ++-- Content/Editor/Gizmo/Material.flax | 4 ++-- Content/Editor/Gizmo/MaterialWire.flax | 4 ++-- Content/Editor/Gizmo/SelectionOutlineMaterial.flax | 2 +- Content/Editor/Gizmo/VertexColorsPreviewMaterial.flax | 2 +- Content/Editor/Highlight Material.flax | 4 ++-- Content/Editor/Icons/IconsMaterial.flax | 4 ++-- Content/Editor/IesProfilePreviewMaterial.flax | 2 +- Content/Editor/Particles/Particle Material Color.flax | 4 ++-- Content/Editor/Particles/Smoke Material.flax | 4 ++-- Content/Editor/SpriteMaterial.flax | 2 +- Content/Editor/Terrain/Circle Brush Material.flax | 2 +- Content/Editor/Terrain/Highlight Terrain Material.flax | 2 +- Content/Editor/TexturePreviewMaterial.flax | 2 +- Content/Editor/Wires Debug Material.flax | 4 ++-- Content/Engine/DefaultDeformableMaterial.flax | 2 +- Content/Engine/DefaultMaterial.flax | 2 +- Content/Engine/DefaultTerrainMaterial.flax | 2 +- Content/Engine/SingleColorMaterial.flax | 2 +- Content/Engine/SkyboxMaterial.flax | 2 +- 28 files changed, 38 insertions(+), 38 deletions(-) diff --git a/Content/Editor/Camera/M_Camera.flax b/Content/Editor/Camera/M_Camera.flax index 7012a6765..b11c1331e 100644 --- a/Content/Editor/Camera/M_Camera.flax +++ b/Content/Editor/Camera/M_Camera.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d39623bd7b4e79992f6d2647be985a84ad0ce9ec78052905a5f36a9988ccb746 +oid sha256:38a03c2e201ff0901b27bd48186fbe1331e445218a605346f914630bb0a2bd78 size 30340 diff --git a/Content/Editor/CubeTexturePreviewMaterial.flax b/Content/Editor/CubeTexturePreviewMaterial.flax index a9de80284..1238c595e 100644 --- a/Content/Editor/CubeTexturePreviewMaterial.flax +++ b/Content/Editor/CubeTexturePreviewMaterial.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1570cc9fb648f891b2b188a278200a41f9eaca4862ea2d216647ee75fd904ba0 +oid sha256:2ff38f4c346be7229cc8151fd49013c1f0f5845880e29933a410f9ff7e66e1be size 31893 diff --git a/Content/Editor/DebugMaterials/SingleColor/Decal.flax b/Content/Editor/DebugMaterials/SingleColor/Decal.flax index 66ca0adce..87f5f944a 100644 --- a/Content/Editor/DebugMaterials/SingleColor/Decal.flax +++ b/Content/Editor/DebugMaterials/SingleColor/Decal.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4d053e866b52cba2d292e3537916196eab425e7e52cf5fe1298420acfeff203d +oid sha256:0d86213b34b35238366a621a56a95dfa5736509fd2ec93eac96eeb19d933497a size 7822 diff --git a/Content/Editor/DebugMaterials/SingleColor/Particle.flax b/Content/Editor/DebugMaterials/SingleColor/Particle.flax index 63743e039..0e3002020 100644 --- a/Content/Editor/DebugMaterials/SingleColor/Particle.flax +++ b/Content/Editor/DebugMaterials/SingleColor/Particle.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3629fc8250d82ada838e6da8fa284911325e15e666cb699b3afb7444c2319d0c -size 31365 +oid sha256:97372e302cad8f94fe9d0edd256756c7b483c2d87f94c90b18bb83a5d1466085 +size 32561 diff --git a/Content/Editor/DebugMaterials/SingleColor/Surface.flax b/Content/Editor/DebugMaterials/SingleColor/Surface.flax index dd879c95e..9f1460ca1 100644 --- a/Content/Editor/DebugMaterials/SingleColor/Surface.flax +++ b/Content/Editor/DebugMaterials/SingleColor/Surface.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0ae12ffa79130352df1c42067ab6b7d6f032541d68ad74efd28843a317ef2759 +oid sha256:089813b532167491f17f8074125c06c35810194edf4bd791a6446638590804e3 size 30236 diff --git a/Content/Editor/DebugMaterials/SingleColor/SurfaceAdditive.flax b/Content/Editor/DebugMaterials/SingleColor/SurfaceAdditive.flax index f814262a2..869953e5c 100644 --- a/Content/Editor/DebugMaterials/SingleColor/SurfaceAdditive.flax +++ b/Content/Editor/DebugMaterials/SingleColor/SurfaceAdditive.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4f78ac31e666257c1b6d5e60e63229d44b6611099218a17f1a0f85cc43fa96f3 -size 30836 +oid sha256:30655a6b7eb49e2dd9ee15bdc898905938172dc8eebeda6f1fe162557e74b875 +size 32032 diff --git a/Content/Editor/DebugMaterials/SingleColor/Terrain.flax b/Content/Editor/DebugMaterials/SingleColor/Terrain.flax index 1c46175b9..b5e7fe2c1 100644 --- a/Content/Editor/DebugMaterials/SingleColor/Terrain.flax +++ b/Content/Editor/DebugMaterials/SingleColor/Terrain.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ded2a4675aeced74c9b33722cd3668500c0333e2af37b85e175a57734ed3fbac +oid sha256:f36b4072904c5127daaeac2c0edde438122f5bec3ad51a1594ba1bb9d7031107 size 21481 diff --git a/Content/Editor/DefaultFontMaterial.flax b/Content/Editor/DefaultFontMaterial.flax index 9445e16a5..451084abd 100644 --- a/Content/Editor/DefaultFontMaterial.flax +++ b/Content/Editor/DefaultFontMaterial.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6f30a84a089effbd8638dda642d738c8d0db7cd0da4d036098a728e2abb0b371 +oid sha256:424176ef59b8ef62099fe79ee89eb5db70b6fe937342da171a6081e76105e9ba size 30415 diff --git a/Content/Editor/Gizmo/FoliageBrushMaterial.flax b/Content/Editor/Gizmo/FoliageBrushMaterial.flax index d1eda425c..15d63b305 100644 --- a/Content/Editor/Gizmo/FoliageBrushMaterial.flax +++ b/Content/Editor/Gizmo/FoliageBrushMaterial.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fe51d4eca6b28e25bb72c94bdc44488d12d274f87c40994f5839871b880f5f41 -size 34854 +oid sha256:0b32dc99aad29946091ed9991fb0952d538eb7b8e2c648377d71fcc9270980e8 +size 36050 diff --git a/Content/Editor/Gizmo/Material.flax b/Content/Editor/Gizmo/Material.flax index ac76d440d..7a5a8ce24 100644 --- a/Content/Editor/Gizmo/Material.flax +++ b/Content/Editor/Gizmo/Material.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0fd85bde2ee395078b32cdf68a623689d821e6367c4d667688b1b0cf20db04b9 -size 31374 +oid sha256:ba37d5537a22ea1483bf13c27a4ccb218517cffe7b6960d41d992272acd49032 +size 32570 diff --git a/Content/Editor/Gizmo/MaterialWire.flax b/Content/Editor/Gizmo/MaterialWire.flax index 9d7601bea..648e5cb25 100644 --- a/Content/Editor/Gizmo/MaterialWire.flax +++ b/Content/Editor/Gizmo/MaterialWire.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:187f04bd8bd6feaff1a33672dee0cd61203351a995e6680c0cc280d1f9486570 -size 30587 +oid sha256:a76497c67dbaa7a6aa6c96147f7fc772c7e67b2c9f7d55cf1d79f79dcc149a00 +size 31783 diff --git a/Content/Editor/Gizmo/SelectionOutlineMaterial.flax b/Content/Editor/Gizmo/SelectionOutlineMaterial.flax index ffd994f19..3eeab310f 100644 --- a/Content/Editor/Gizmo/SelectionOutlineMaterial.flax +++ b/Content/Editor/Gizmo/SelectionOutlineMaterial.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d4ac71ac110eb2357f7a9a08f05116de03f5ee3642edd6063a1289756d61a7b7 +oid sha256:20415adad14b5a5a12a0287df8cad073ea9880f37cc8b8c0c0c1488d3fbacf02 size 15899 diff --git a/Content/Editor/Gizmo/VertexColorsPreviewMaterial.flax b/Content/Editor/Gizmo/VertexColorsPreviewMaterial.flax index 53f0975de..8f9c3dcbd 100644 --- a/Content/Editor/Gizmo/VertexColorsPreviewMaterial.flax +++ b/Content/Editor/Gizmo/VertexColorsPreviewMaterial.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c4c736662bd5aed811daf176db722eae0a0e398646c1a303de8f4b94a031e722 +oid sha256:793d85a1da716994070241f65655a705e303998ff9795109e05b9a58d719b7e9 size 31349 diff --git a/Content/Editor/Highlight Material.flax b/Content/Editor/Highlight Material.flax index d50acc463..02d9afe95 100644 --- a/Content/Editor/Highlight Material.flax +++ b/Content/Editor/Highlight Material.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:320a2810f6d52b90379ee04368b5b36d76d5b73b2e7587870f1476f028396b5c -size 29186 +oid sha256:b64eff61a0c30e2954d43f1afab9ac98b2e584ac772a00cb9f8179e11650827e +size 30382 diff --git a/Content/Editor/Icons/IconsMaterial.flax b/Content/Editor/Icons/IconsMaterial.flax index 61e58c7ec..abfd14d21 100644 --- a/Content/Editor/Icons/IconsMaterial.flax +++ b/Content/Editor/Icons/IconsMaterial.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c2148bde9a0344321adcf7ee68db9aef3605b07f7c80aee6f31796d3ec73f3e3 -size 29114 +oid sha256:3a75aba2502ccad291ba5a3d4d65595140ee897909e4db11b6bf96a0889b5b34 +size 30310 diff --git a/Content/Editor/IesProfilePreviewMaterial.flax b/Content/Editor/IesProfilePreviewMaterial.flax index c74afca82..835eac7f0 100644 --- a/Content/Editor/IesProfilePreviewMaterial.flax +++ b/Content/Editor/IesProfilePreviewMaterial.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b1f24e17557532287dec583eecd8aae2fe485ca4b0301a6fadb18cd9c594014f +oid sha256:848245bbfbfd8cd7f38f6f84ff42f4310fd0aa6a47a66c6106de46a11635d7bc size 18459 diff --git a/Content/Editor/Particles/Particle Material Color.flax b/Content/Editor/Particles/Particle Material Color.flax index 60cf02ae9..4ebc4703f 100644 --- a/Content/Editor/Particles/Particle Material Color.flax +++ b/Content/Editor/Particles/Particle Material Color.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:871f60baac3be29c6c7a070d8e69fa1de12747bb0042bab661e29f260709a1c9 -size 29557 +oid sha256:bceb91f3bf329b2c0ba673ea43cd636a572734b44217437faf5c3a8086bd5905 +size 30753 diff --git a/Content/Editor/Particles/Smoke Material.flax b/Content/Editor/Particles/Smoke Material.flax index da5ffaa1a..22cd545f4 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:0d484730a17fa0f560c244793f7c59e7a348f7536f9e64830e1f08906e7fecca -size 35668 +oid sha256:060b26beeb9266dbb1e6887f7aa27d2b08354cc7a7d82af20ec57793e411248b +size 36864 diff --git a/Content/Editor/SpriteMaterial.flax b/Content/Editor/SpriteMaterial.flax index fba4fa0e9..d6c0efb30 100644 --- a/Content/Editor/SpriteMaterial.flax +++ b/Content/Editor/SpriteMaterial.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:15b759f0d6d33bddf6107b87f9d423c042a8f6c8d7667e24fca8621489ba0d2f +oid sha256:e92f22c4f401af0d2f10e79f2cd1a10729ed927c63bd54c7c39cc2603ae4347e size 31428 diff --git a/Content/Editor/Terrain/Circle Brush Material.flax b/Content/Editor/Terrain/Circle Brush Material.flax index 4a7ef848f..2cad2873c 100644 --- a/Content/Editor/Terrain/Circle Brush Material.flax +++ b/Content/Editor/Terrain/Circle Brush Material.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cece02494deb12155bace72e2d795564b0d19a012ac1b930678ae17834a70cdd +oid sha256:da332ee2be6aac66e6ef23702e446d937f781c95cc4c5221c95c643924c2560f size 27862 diff --git a/Content/Editor/Terrain/Highlight Terrain Material.flax b/Content/Editor/Terrain/Highlight Terrain Material.flax index e58f205c9..b95162dbe 100644 --- a/Content/Editor/Terrain/Highlight Terrain Material.flax +++ b/Content/Editor/Terrain/Highlight Terrain Material.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8d63374ad0463242a5af5c7865306e56369c0279d56aabd357508b435424a61a +oid sha256:349a75d005145ad36c0acebdd04cb5da9a2cbe4ab913dcbc6756b7e1b4cf4a2d size 21534 diff --git a/Content/Editor/TexturePreviewMaterial.flax b/Content/Editor/TexturePreviewMaterial.flax index 2b7d758c7..f62dbebcf 100644 --- a/Content/Editor/TexturePreviewMaterial.flax +++ b/Content/Editor/TexturePreviewMaterial.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f46e195fb74337ab1b39583a342be4dc68b1ddb9afe5631627a8d756d9f7742d +oid sha256:055baf0848477f0a12aca0686868cf998659c01db6ffba6707456895559c92d0 size 10655 diff --git a/Content/Editor/Wires Debug Material.flax b/Content/Editor/Wires Debug Material.flax index d6a700957..9ddc1c50a 100644 --- a/Content/Editor/Wires Debug Material.flax +++ b/Content/Editor/Wires Debug Material.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fbb87e216eb2525588965cd4f6762f80cf62cc1a04ed3e861a74c19522651c4e -size 29186 +oid sha256:81a6d6920c961255be654beb648f809e52e6acaa51ee95452ef31fb0c6da019d +size 30382 diff --git a/Content/Engine/DefaultDeformableMaterial.flax b/Content/Engine/DefaultDeformableMaterial.flax index 7f6adb948..ebcc13b03 100644 --- a/Content/Engine/DefaultDeformableMaterial.flax +++ b/Content/Engine/DefaultDeformableMaterial.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8247aaf570f66f48f38a7f4f0b713a0baf6c4b2b2ebe4a58cc0196790c66bdde +oid sha256:0275e7ac6c6dfc7b4cdaa1a6c4bfc59f2cc6f51711cc7a2374a68a47cc89dd1e size 19131 diff --git a/Content/Engine/DefaultMaterial.flax b/Content/Engine/DefaultMaterial.flax index ee86a8b04..a2e4278eb 100644 --- a/Content/Engine/DefaultMaterial.flax +++ b/Content/Engine/DefaultMaterial.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5e5f38372d149583cfd99e4322f9f7b793f65572c48d425f31de43f53e4d9a1d +oid sha256:ba558d6a9aa4d15b8fbee093d93f3c5f02b985f2e5ee0c3a0a078cb8ae96cc96 size 32119 diff --git a/Content/Engine/DefaultTerrainMaterial.flax b/Content/Engine/DefaultTerrainMaterial.flax index 1a4075124..fa556a1be 100644 --- a/Content/Engine/DefaultTerrainMaterial.flax +++ b/Content/Engine/DefaultTerrainMaterial.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:be5cfad3e38b9800a756285b4078acb760f4ec36fe776a62251962998fecc3df +oid sha256:0cbced27fa189bd7db1e18a467424d665837d8cfbcaad6f1dbe4046c7c98c5e3 size 23624 diff --git a/Content/Engine/SingleColorMaterial.flax b/Content/Engine/SingleColorMaterial.flax index fe7f4519e..819344ec4 100644 --- a/Content/Engine/SingleColorMaterial.flax +++ b/Content/Engine/SingleColorMaterial.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a3b841f6a888a0fec34e57de08762edb3a9ca28c5d5130634899c23388cb4d84 +oid sha256:130b9e13a68376279b81de1ab323998e365e010301fb99b9553d65aafa04483c size 30437 diff --git a/Content/Engine/SkyboxMaterial.flax b/Content/Engine/SkyboxMaterial.flax index 82e64d2fd..a2039ac86 100644 --- a/Content/Engine/SkyboxMaterial.flax +++ b/Content/Engine/SkyboxMaterial.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4611ba39d116ba65578a95240b3e84beff8a54d7d1e9b2b334cda1489922a63c +oid sha256:d0e54ecc01e5556dcc0ccd8564956b2e0ad59a843cde250be4b6bebb4a5a64fe size 31635 From 017492dbfa75d3f9ff6c066ead1916d943bc756f Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 13 Apr 2022 19:48:39 +0200 Subject: [PATCH 06/19] Optimize C# types searching with typename --- Source/Editor/Scripting/TypeUtils.cs | 29 +++----------------- Source/Engine/Content/JsonAsset.cs | 40 ++++++++++------------------ 2 files changed, 18 insertions(+), 51 deletions(-) diff --git a/Source/Editor/Scripting/TypeUtils.cs b/Source/Editor/Scripting/TypeUtils.cs index b2b71d370..cc763b9b8 100644 --- a/Source/Editor/Scripting/TypeUtils.cs +++ b/Source/Editor/Scripting/TypeUtils.cs @@ -233,18 +233,7 @@ namespace FlaxEditor.Scripting { if (string.IsNullOrEmpty(typeName)) return null; - var assemblies = AppDomain.CurrentDomain.GetAssemblies(); - for (int i = 0; i < assemblies.Length; i++) - { - var assembly = assemblies[i]; - if (assembly != null) - { - var type = assembly.GetType(typeName); - if (type != null) - return type; - } - } - return null; + return Type.GetType(typeName); } /// @@ -258,18 +247,10 @@ namespace FlaxEditor.Scripting return ScriptType.Null; // C#/C++ types - var assemblies = AppDomain.CurrentDomain.GetAssemblies(); - for (int i = 0; i < assemblies.Length; i++) { - var assembly = assemblies[i]; - if (assembly != null) - { - var type = assembly.GetType(typeName); - if (type != null) - { - return new ScriptType(type); - } - } + var type = Type.GetType(typeName); + if (type != null) + return new ScriptType(type); } // Custom types @@ -277,9 +258,7 @@ namespace FlaxEditor.Scripting { var type = customTypesInfo.GetType(typeName); if (type) - { return type; - } } return ScriptType.Null; diff --git a/Source/Engine/Content/JsonAsset.cs b/Source/Engine/Content/JsonAsset.cs index 60e01d472..9b9441435 100644 --- a/Source/Engine/Content/JsonAsset.cs +++ b/Source/Engine/Content/JsonAsset.cs @@ -25,38 +25,26 @@ namespace FlaxEngine if (WaitForLoaded()) return null; - var assemblies = AppDomain.CurrentDomain.GetAssemblies(); + object obj = null; var dataTypeName = DataTypeName; - - for (int i = 0; i < assemblies.Length; i++) + var type = Type.GetType(dataTypeName); + if (type != null) { - var assembly = assemblies[i]; - if (assembly != null) + try { - var type = assembly.GetType(dataTypeName); - if (type != null) - { - object obj = null; - try - { - // Create instance - obj = Activator.CreateInstance(type); + // Create instance + obj = Activator.CreateInstance(type); - // Deserialize object - var data = Data; - JsonSerializer.Deserialize(obj, data); - } - catch (Exception ex) - { - Debug.LogException(ex); - } - - return obj; - } + // Deserialize object + var data = Data; + JsonSerializer.Deserialize(obj, data); + } + catch (Exception ex) + { + Debug.LogException(ex); } } - - return null; + return obj; } } } From 9fb4624b03f7e1eb97f31344bff5f41d5ec069db Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 13 Apr 2022 21:18:35 +0200 Subject: [PATCH 07/19] Add `JsonAsset.Instance` for C# asset object --- Source/Engine/Content/JsonAsset.cpp | 28 ++++++++++++++++------------ Source/Engine/Content/JsonAsset.cs | 24 +++++++++++++++++++----- 2 files changed, 35 insertions(+), 17 deletions(-) diff --git a/Source/Engine/Content/JsonAsset.cpp b/Source/Engine/Content/JsonAsset.cpp index 2332181b9..0fc5df599 100644 --- a/Source/Engine/Content/JsonAsset.cpp +++ b/Source/Engine/Content/JsonAsset.cpp @@ -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(this); - Level::ScriptsReloaded.Bind(this); - } + // Reload instance when module with this type gets reloaded + Level::ScriptsReloadStart.Bind(this); + Level::ScriptsReloaded.Bind(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(this); - Level::ScriptsReloaded.Unbind(this); + Level::ScriptsReloadStart.Unbind(this); + Level::ScriptsReloaded.Unbind(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); diff --git a/Source/Engine/Content/JsonAsset.cs b/Source/Engine/Content/JsonAsset.cs index 9b9441435..13c53f532 100644 --- a/Source/Engine/Content/JsonAsset.cs +++ b/Source/Engine/Content/JsonAsset.cs @@ -7,19 +7,28 @@ namespace FlaxEngine { partial class JsonAsset { + private object _instance; + /// - /// Creates the serialized object instance from the json asset data. + /// Gets the instance of the serialized object from the json asset data. Cached internally. /// - /// The created object or null. + public object Instance => _instance ?? (_instance = CreateInstance()); + + /// + /// Creates a new instance of the serialized object from the json asset data. + /// + /// Use to get cached object. + /// The new object or null if failed. public T CreateInstance() { return (T)CreateInstance(); } /// - /// Creates the serialized object instance from the json asset data. + /// Creates a new instance of the serialized object from the json asset data. /// - /// The created object or null. + /// Use to get cached object. + /// The new object or null if failed. public object CreateInstance() { if (WaitForLoaded()) @@ -41,9 +50,14 @@ namespace FlaxEngine } catch (Exception ex) { - Debug.LogException(ex); + Debug.LogException(ex, this); } } + else + { + Debug.LogError(string.Format("Missing type '{0}' to create Json Asset instance.", dataTypeName), this); + } + return obj; } } From a27d69f8529e726a46dc3ffd90912cc879f9f729 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 13 Apr 2022 21:19:10 +0200 Subject: [PATCH 08/19] Improve Json Asset development workflow --- .../CustomEditors/CustomEditorPresenter.cs | 26 +++++++++++--- .../Editor/Windows/Assets/JsonAssetWindow.cs | 36 +++++++++++++++++-- Source/Engine/Core/Config/GameSettings.cs | 8 ++--- 3 files changed, 60 insertions(+), 10 deletions(-) diff --git a/Source/Editor/CustomEditors/CustomEditorPresenter.cs b/Source/Editor/CustomEditors/CustomEditorPresenter.cs index 62ce2df77..48371a936 100644 --- a/Source/Editor/CustomEditors/CustomEditorPresenter.cs +++ b/Source/Editor/CustomEditors/CustomEditorPresenter.cs @@ -29,7 +29,7 @@ namespace FlaxEditor.CustomEditors /// Enables using prefab-related features of the properties editor (eg. revert to prefab option). /// UsePrefab = 1 << 1, - + /// /// Enables using default-value-related features of the properties editor (eg. revert to default option). /// @@ -88,7 +88,6 @@ namespace FlaxEditor.CustomEditors /// protected class RootEditor : SyncPointEditor { - private readonly string _noSelectionText; private CustomEditor _overrideEditor; /// @@ -109,13 +108,18 @@ namespace FlaxEditor.CustomEditors } } + /// + /// The text to show when no object is selected. + /// + public string NoSelectionText; + /// /// Initializes a new instance of the class. /// /// The text to show when no item is selected. public RootEditor(string noSelectionText) { - _noSelectionText = noSelectionText ?? "No selection"; + NoSelectionText = noSelectionText ?? "No selection"; } /// @@ -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 /// public object Owner; + /// + /// Gets or sets the text to show when no object is selected. + /// + public string NoSelectionText + { + get => Editor.NoSelectionText; + set + { + Editor.NoSelectionText = value; + if (SelectionCount == 0) + BuildLayoutOnUpdate(); + } + } + private bool _buildOnUpdate; /// diff --git a/Source/Editor/Windows/Assets/JsonAssetWindow.cs b/Source/Editor/Windows/Assets/JsonAssetWindow.cs index 5abddea32..1cb1cbdd0 100644 --- a/Source/Editor/Windows/Assets/JsonAssetWindow.cs +++ b/Source/Editor/Windows/Assets/JsonAssetWindow.cs @@ -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 /// 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(); } + /// + protected override void OnAssetLoadFailed() + { + _presenter.NoSelectionText = "Failed to load the asset."; + + base.OnAssetLoadFailed(); + } + /// public override void OnItemReimported(ContentItem item) { diff --git a/Source/Engine/Core/Config/GameSettings.cs b/Source/Engine/Core/Config/GameSettings.cs index e721da61d..a8519fe4c 100644 --- a/Source/Engine/Core/Config/GameSettings.cs +++ b/Source/Engine/Core/Config/GameSettings.cs @@ -202,7 +202,7 @@ namespace FlaxEditor.Content.Settings var asset = FlaxEngine.Content.LoadAsync(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; } From 3d76b2c10f21627090ba96cd6cf269549e869c1c Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 13 Apr 2022 21:25:11 +0200 Subject: [PATCH 09/19] Add `Array Add Unique` node to Visual Scripting --- .../Editor/Surface/Archetypes/Collections.cs | 18 ++++++++++++++++++ Source/Engine/Visject/VisjectGraph.cpp | 7 +++++++ 2 files changed, 25 insertions(+) diff --git a/Source/Editor/Surface/Archetypes/Collections.cs b/Source/Editor/Surface/Archetypes/Collections.cs index 72f76825c..d09b02a69 100644 --- a/Source/Editor/Surface/Archetypes/Collections.cs +++ b/Source/Editor/Surface/Archetypes/Collections.cs @@ -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 }; } diff --git a/Source/Engine/Visject/VisjectGraph.cpp b/Source/Engine/Visject/VisjectGraph.cpp index df5d56fec..3f6fd60c4 100644 --- a/Source/Engine/Visject/VisjectGraph.cpp +++ b/Source/Engine/Visject/VisjectGraph.cpp @@ -1344,6 +1344,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(), b->FirstConnection())); + value = MoveTemp(v); + break; } } } From e554b7f531b5822aa04af94b9cbd1f0c67d3bb30 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 13 Apr 2022 21:34:13 +0200 Subject: [PATCH 10/19] Move `Actor.DestroyChildren` to C++ --- Source/Engine/Level/Actor.cpp | 11 +++++++++++ Source/Engine/Level/Actor.cs | 17 ----------------- Source/Engine/Level/Actor.h | 6 ++++++ 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Source/Engine/Level/Actor.cpp b/Source/Engine/Level/Actor.cpp index f58dfd587..5ca9e957a 100644 --- a/Source/Engine/Level/Actor.cpp +++ b/Source/Engine/Level/Actor.cpp @@ -418,6 +418,17 @@ Array Actor::GetChildren(const MClass* type) const return result; } +void Actor::DestroyChildren(float timeLeft) +{ + Array 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]; diff --git a/Source/Engine/Level/Actor.cs b/Source/Engine/Level/Actor.cs index 077ec346e..91f56798d 100644 --- a/Source/Engine/Level/Actor.cs +++ b/Source/Engine/Level/Actor.cs @@ -296,23 +296,6 @@ namespace FlaxEngine return output; } - /// - /// Destroys the children. Calls Object.Destroy on every child actor and unlink them for the parent. - /// - /// The time left to destroy object (in seconds). - [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); - } - } - /// /// Gets the matrix that transforms a point from the world space to local space of the actor. /// diff --git a/Source/Engine/Level/Actor.h b/Source/Engine/Level/Actor.h index b31654c72..85dccfe13 100644 --- a/Source/Engine/Level/Actor.h +++ b/Source/Engine/Level/Actor.h @@ -242,6 +242,12 @@ public: return result; } + /// + /// Destroys the children. Calls Object.Destroy on every child actor and unlinks them for this actor. + /// + /// The time left to destroy object (in seconds). + API_FUNCTION(Attributes="NoAnimate") void DestroyChildren(float timeLeft = 0.0f); + public: /// From 47cc49a962f125269942576830fa66ccb1f547e7 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 14 Apr 2022 22:17:40 +0200 Subject: [PATCH 11/19] Add `Delegate::BindUnique` --- Source/Engine/Core/Delegate.h | 53 +++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/Source/Engine/Core/Delegate.h b/Source/Engine/Core/Delegate.h index bd448165f..57d685031 100644 --- a/Source/Engine/Core/Delegate.h +++ b/Source/Engine/Core/Delegate.h @@ -405,6 +405,59 @@ public: } } + /// + /// Binds a static function (if not binded yet). + /// + template + void BindUnique() + { + FunctionType f; + f.template Bind(); + BindUnique(f); + } + + /// + /// Binds a member function (if not binded yet). + /// + /// The object instance. + template + void BindUnique(T* callee) + { + FunctionType f; + f.template Bind(callee); + BindUnique(f); + } + + /// + /// Binds a function (if not binded yet). + /// + /// The method. + void BindUnique(Signature method) + { + FunctionType f(method); + BindUnique(f); + } + + /// + /// Binds a function (if not binded yet). + /// + /// The function to bind. + 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); + } + /// /// Unbinds a static function. /// From 4ac9406b902152a385b098306f81146850a4c0cc Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 14 Apr 2022 23:10:01 +0200 Subject: [PATCH 12/19] Revert 017492dbfa75d3f9ff6c066ead1916d943bc756f --- Source/Editor/Scripting/TypeUtils.cs | 29 ++++++++++++++++--- Source/Engine/Content/JsonAsset.cs | 42 ++++++++++++++++------------ 2 files changed, 49 insertions(+), 22 deletions(-) diff --git a/Source/Editor/Scripting/TypeUtils.cs b/Source/Editor/Scripting/TypeUtils.cs index cc763b9b8..b2b71d370 100644 --- a/Source/Editor/Scripting/TypeUtils.cs +++ b/Source/Editor/Scripting/TypeUtils.cs @@ -233,7 +233,18 @@ namespace FlaxEditor.Scripting { if (string.IsNullOrEmpty(typeName)) return null; - return Type.GetType(typeName); + var assemblies = AppDomain.CurrentDomain.GetAssemblies(); + for (int i = 0; i < assemblies.Length; i++) + { + var assembly = assemblies[i]; + if (assembly != null) + { + var type = assembly.GetType(typeName); + if (type != null) + return type; + } + } + return null; } /// @@ -247,10 +258,18 @@ namespace FlaxEditor.Scripting return ScriptType.Null; // C#/C++ types + var assemblies = AppDomain.CurrentDomain.GetAssemblies(); + for (int i = 0; i < assemblies.Length; i++) { - var type = Type.GetType(typeName); - if (type != null) - return new ScriptType(type); + var assembly = assemblies[i]; + if (assembly != null) + { + var type = assembly.GetType(typeName); + if (type != null) + { + return new ScriptType(type); + } + } } // Custom types @@ -258,7 +277,9 @@ namespace FlaxEditor.Scripting { var type = customTypesInfo.GetType(typeName); if (type) + { return type; + } } return ScriptType.Null; diff --git a/Source/Engine/Content/JsonAsset.cs b/Source/Engine/Content/JsonAsset.cs index 13c53f532..dda7bd879 100644 --- a/Source/Engine/Content/JsonAsset.cs +++ b/Source/Engine/Content/JsonAsset.cs @@ -34,31 +34,37 @@ namespace FlaxEngine if (WaitForLoaded()) return null; - object obj = null; var dataTypeName = DataTypeName; - var type = Type.GetType(dataTypeName); - if (type != null) + var assemblies = AppDomain.CurrentDomain.GetAssemblies(); + for (int i = 0; i < assemblies.Length; i++) { - try + var assembly = assemblies[i]; + if (assembly != null) { - // Create instance - obj = Activator.CreateInstance(type); + var type = assembly.GetType(dataTypeName); + if (type != null) + { + object obj = null; + try + { + // Create instance + obj = Activator.CreateInstance(type); - // Deserialize object - var data = Data; - JsonSerializer.Deserialize(obj, data); - } - catch (Exception ex) - { - Debug.LogException(ex, this); + // Deserialize object + var data = Data; + JsonSerializer.Deserialize(obj, data); + } + catch (Exception ex) + { + Debug.LogException(ex, this); + } + return obj; + } } } - else - { - Debug.LogError(string.Format("Missing type '{0}' to create Json Asset instance.", dataTypeName), this); - } - return obj; + Debug.LogError(string.Format("Missing type '{0}' to create Json Asset instance.", dataTypeName), this); + return null; } } } From 03524caebf59510b8db770a42fa7b7cba446a558 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 14 Apr 2022 23:14:49 +0200 Subject: [PATCH 13/19] Fix function name --- Source/Editor/CustomEditors/Dedicated/ScriptsEditor.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Editor/CustomEditors/Dedicated/ScriptsEditor.cs b/Source/Editor/CustomEditors/Dedicated/ScriptsEditor.cs index d101d2ff2..9c3a3f645 100644 --- a/Source/Editor/CustomEditors/Dedicated/ScriptsEditor.cs +++ b/Source/Editor/CustomEditors/Dedicated/ScriptsEditor.cs @@ -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) From 991abb1cf87edd41eba78cd507c788597ca9f418 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 14 Apr 2022 23:18:37 +0200 Subject: [PATCH 14/19] Add `loopCount` to `PlaySlotAnimation` for looping slot animation --- .../Animations/Graph/AnimGraph.Base.cpp | 2 ++ Source/Engine/Animations/Graph/AnimGraph.h | 3 +++ .../Animations/Graph/AnimGroup.Animation.cpp | 27 +++++++++++++------ Source/Engine/Level/Actors/AnimatedModel.cpp | 4 ++- Source/Engine/Level/Actors/AnimatedModel.h | 3 ++- 5 files changed, 29 insertions(+), 10 deletions(-) diff --git a/Source/Engine/Animations/Graph/AnimGraph.Base.cpp b/Source/Engine/Animations/Graph/AnimGraph.Base.cpp index 86efbb70c..725265359 100644 --- a/Source/Engine/Animations/Graph/AnimGraph.Base.cpp +++ b/Source/Engine/Animations/Graph/AnimGraph.Base.cpp @@ -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) diff --git a/Source/Engine/Animations/Graph/AnimGraph.h b/Source/Engine/Animations/Graph/AnimGraph.h index dde47b8b6..70c3d9696 100644 --- a/Source/Engine/Animations/Graph/AnimGraph.h +++ b/Source/Engine/Animations/Graph/AnimGraph.h @@ -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; }; /// diff --git a/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp b/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp index e34450a17..0f4a206e5 100644 --- a/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp +++ b/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp @@ -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); diff --git a/Source/Engine/Level/Actors/AnimatedModel.cpp b/Source/Engine/Level/Actors/AnimatedModel.cpp index 87226ac9c..44b50ac3a 100644 --- a/Source/Engine/Level/Actors/AnimatedModel.cpp +++ b/Source/Engine/Level/Actors/AnimatedModel.cpp @@ -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() diff --git a/Source/Engine/Level/Actors/AnimatedModel.h b/Source/Engine/Level/Actors/AnimatedModel.h index 556a1d1cf..d8491e78a 100644 --- a/Source/Engine/Level/Actors/AnimatedModel.h +++ b/Source/Engine/Level/Actors/AnimatedModel.h @@ -313,7 +313,8 @@ public: /// The playback speed. /// The animation blending in time (in seconds). Cam be used to smooth the slot animation playback with the input pose when starting the animation. /// The animation blending out time (in seconds). Cam be used to smooth the slot animation playback with the input pose when ending animation. - API_FUNCTION() void PlaySlotAnimation(const StringView& slotName, Animation* anim, float speed = 1.0f, float blendInTime = 0.2f, float blendOutTime = 0.2f); + /// The amount of loops to play the animation: 0 to play once, -1 to play infinite, 1 or higher to loop once or more. + API_FUNCTION() void PlaySlotAnimation(const StringView& slotName, Animation* anim, float speed = 1.0f, float blendInTime = 0.2f, float blendOutTime = 0.2f, int32 loopCount = 0); /// /// Stops all the animations playback on the all slots in Anim Graph. From 493787d4d6ab2972c4f3fbd2f686a09baee06460 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 15 Apr 2022 17:04:28 +0200 Subject: [PATCH 15/19] Add `Custom Global Code` node to materials for injecting custom code, includes or constants --- Source/Editor/Surface/Archetypes/Material.cs | 23 +++++++++++++++++-- .../ContentImporters/CreateMaterial.cpp | 2 +- .../MaterialGenerator.Texture.cpp | 2 +- .../MaterialGenerator/MaterialGenerator.cpp | 17 +++++++++++++- .../Tools/MaterialGenerator/MaterialLayer.cpp | 6 ++--- .../Tools/MaterialGenerator/MaterialLayer.h | 2 +- Source/Engine/Tools/MaterialGenerator/Types.h | 4 ---- 7 files changed, 43 insertions(+), 13 deletions(-) diff --git a/Source/Editor/Surface/Archetypes/Material.cs b/Source/Editor/Surface/Archetypes/Material.cs index 63cc3db9b..424511cce 100644 --- a/Source/Editor/Surface/Archetypes/Material.cs +++ b/Source/Editor/Surface/Archetypes/Material.cs @@ -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), + } + }, }; } } diff --git a/Source/Engine/ContentImporters/CreateMaterial.cpp b/Source/Engine/ContentImporters/CreateMaterial.cpp index 30cd163ba..36caacb23 100644 --- a/Source/Engine/ContentImporters/CreateMaterial.cpp +++ b/Source/Engine/ContentImporters/CreateMaterial.cpp @@ -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; diff --git a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Texture.cpp b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Texture.cpp index 356cedc81..c6fa11e94 100644 --- a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Texture.cpp +++ b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Texture.cpp @@ -9,7 +9,7 @@ MaterialValue* MaterialGenerator::sampleTextureRaw(Node* caller, Value& value, B ASSERT(texture && box); // Cache data - const auto parent = box->GetParent(); + const auto parent = box->GetParent>(); const bool isCubemap = texture->Type == MaterialParameterType::CubeTexture; const bool isArray = texture->Type == MaterialParameterType::GPUTextureArray; const bool isVolume = texture->Type == MaterialParameterType::GPUTextureVolume; diff --git a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.cpp b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.cpp index 6e6ab486f..f1d5b5840 100644 --- a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.cpp +++ b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.cpp @@ -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); @@ -492,6 +492,21 @@ bool MaterialGenerator::Generate(WriteStream& source, MaterialInfo& materialInfo // Utilities { WRITE_FEATURES(Utilities); + Array> 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(); } diff --git a/Source/Engine/Tools/MaterialGenerator/MaterialLayer.cpp b/Source/Engine/Tools/MaterialGenerator/MaterialLayer.cpp index 6ae076555..8ed2a9d10 100644 --- a/Source/Engine/Tools/MaterialGenerator/MaterialLayer.cpp +++ b/Source/Engine/Tools/MaterialGenerator/MaterialLayer.cpp @@ -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 diff --git a/Source/Engine/Tools/MaterialGenerator/MaterialLayer.h b/Source/Engine/Tools/MaterialGenerator/MaterialLayer.h index f40674f6a..f6aa118b8 100644 --- a/Source/Engine/Tools/MaterialGenerator/MaterialLayer.h +++ b/Source/Engine/Tools/MaterialGenerator/MaterialLayer.h @@ -50,7 +50,7 @@ public: /// /// Root node /// - MaterialGraphNode* Root; + MaterialGraph::Node* Root; /// /// Material structure variable name (different for every layer sampling with different UVs, default UVs are a first index) diff --git a/Source/Engine/Tools/MaterialGenerator/Types.h b/Source/Engine/Tools/MaterialGenerator/Types.h index 0807a396f..04c35b81d 100644 --- a/Source/Engine/Tools/MaterialGenerator/Types.h +++ b/Source/Engine/Tools/MaterialGenerator/Types.h @@ -7,10 +7,6 @@ #include "Engine/Core/Enums.h" #include "Engine/Visject/ShaderGraph.h" -class MaterialGraphNode : public ShaderGraphNode<> -{ -}; - class MaterialGraph : public ShaderGraph<> { }; From 8a01a31e8dcb600b1f2df73e111bcaaf5eed7c82 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 15 Apr 2022 17:12:50 +0200 Subject: [PATCH 16/19] Add keyboard key navigation to Content View based on items name first character --- Source/Editor/Content/GUI/ContentView.cs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/Source/Editor/Content/GUI/ContentView.cs b/Source/Editor/Content/GUI/ContentView.cs index 79e4cd0c0..5d6041af0 100644 --- a/Source/Editor/Content/GUI/ContentView.cs +++ b/Source/Editor/Content/GUI/ContentView.cs @@ -689,6 +689,30 @@ namespace FlaxEditor.Content.GUI return base.OnKeyDown(key); } + /// + 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; + } + /// protected override void PerformLayoutBeforeChildren() { From 75b61f2bef43495b1c827fdecd878bc964f99e60 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 15 Apr 2022 19:16:14 +0200 Subject: [PATCH 17/19] Fix typos --- Source/Engine/Render2D/FontReference.cs | 2 +- Source/Engine/Scripting/Attributes/Editor/VisibleIfAttribute.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Engine/Render2D/FontReference.cs b/Source/Engine/Render2D/FontReference.cs index 41095190e..b92415d4d 100644 --- a/Source/Engine/Render2D/FontReference.cs +++ b/Source/Engine/Render2D/FontReference.cs @@ -96,7 +96,7 @@ namespace FlaxEngine /// /// Gets the font object described by the structure. /// - /// Th font or null if descriptor is invalid. + /// The font or null if descriptor is invalid. public Font GetFont() { if (_cachedFont) diff --git a/Source/Engine/Scripting/Attributes/Editor/VisibleIfAttribute.cs b/Source/Engine/Scripting/Attributes/Editor/VisibleIfAttribute.cs index 6eb418cad..5f4177a6c 100644 --- a/Source/Engine/Scripting/Attributes/Editor/VisibleIfAttribute.cs +++ b/Source/Engine/Scripting/Attributes/Editor/VisibleIfAttribute.cs @@ -27,7 +27,7 @@ namespace FlaxEngine } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The name of the field or property of the object. Must be a bool type. /// True if invert member value when computing the visibility value. From ddb9b327d45da735498c469a469653c773369a17 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 15 Apr 2022 19:16:30 +0200 Subject: [PATCH 18/19] Add `Color.FromRGBA` --- Source/Engine/Core/Math/Color.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Source/Engine/Core/Math/Color.cs b/Source/Engine/Core/Math/Color.cs index a8a89ef60..aa3f5f0a5 100644 --- a/Source/Engine/Core/Math/Color.cs +++ b/Source/Engine/Core/Math/Color.cs @@ -230,6 +230,20 @@ namespace FlaxEngine a); } + /// + /// Creates from the RGBA value. + /// + /// The packed RGBA value. + /// The color. + 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); + } + /// /// Gets the color value as the hexadecimal string. /// From 3c841b1be1fe0178cea908153ea0c12732275798 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 15 Apr 2022 19:16:50 +0200 Subject: [PATCH 19/19] Add support for font size and color in `Header` attribute --- .../CustomEditors/Editors/GenericEditor.cs | 2 +- .../CustomEditors/LayoutElementsContainer.cs | 10 ++++++++++ Source/Editor/Surface/SurfaceUtils.cs | 2 +- Source/Editor/Surface/VisjectSurfaceWindow.cs | 2 +- .../Attributes/Editor/HeaderAttribute.cs | 16 +++++++++++++++- 5 files changed, 28 insertions(+), 4 deletions(-) diff --git a/Source/Editor/CustomEditors/Editors/GenericEditor.cs b/Source/Editor/CustomEditors/Editors/GenericEditor.cs index 4ca761634..a7ea235f2 100644 --- a/Source/Editor/CustomEditors/Editors/GenericEditor.cs +++ b/Source/Editor/CustomEditors/Editors/GenericEditor.cs @@ -715,7 +715,7 @@ namespace FlaxEditor.CustomEditors.Editors // Header if (item.Header != null) - itemLayout.Header(item.Header.Text); + itemLayout.Header(item.Header); try { diff --git a/Source/Editor/CustomEditors/LayoutElementsContainer.cs b/Source/Editor/CustomEditors/LayoutElementsContainer.cs index 0c9b01942..29d7cf359 100644 --- a/Source/Editor/CustomEditors/LayoutElementsContainer.cs +++ b/Source/Editor/CustomEditors/LayoutElementsContainer.cs @@ -274,6 +274,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; + } + /// /// Adds new text box element. /// diff --git a/Source/Editor/Surface/SurfaceUtils.cs b/Source/Editor/Surface/SurfaceUtils.cs index 014459694..d53049b16 100644 --- a/Source/Editor/Surface/SurfaceUtils.cs +++ b/Source/Editor/Surface/SurfaceUtils.cs @@ -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); diff --git a/Source/Editor/Surface/VisjectSurfaceWindow.cs b/Source/Editor/Surface/VisjectSurfaceWindow.cs index 6ae949000..733cd2682 100644 --- a/Source/Editor/Surface/VisjectSurfaceWindow.cs +++ b/Source/Editor/Surface/VisjectSurfaceWindow.cs @@ -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 ( diff --git a/Source/Engine/Scripting/Attributes/Editor/HeaderAttribute.cs b/Source/Engine/Scripting/Attributes/Editor/HeaderAttribute.cs index e994fe26a..3f0ce57d0 100644 --- a/Source/Engine/Scripting/Attributes/Editor/HeaderAttribute.cs +++ b/Source/Engine/Scripting/Attributes/Editor/HeaderAttribute.cs @@ -17,6 +17,16 @@ namespace FlaxEngine /// public string Text; + /// + /// The custom header font size. + /// + public int FontSize; + + /// + /// The custom header color (as 32-bit uint). + /// + public uint Color; + private HeaderAttribute() { } @@ -25,9 +35,13 @@ namespace FlaxEngine /// Initializes a new instance of the class. /// /// The header text. - public HeaderAttribute(string text) + /// The header text font size (-1 to use default which is 14). + /// The header color (as 32-bit uint, 0 to use default). + public HeaderAttribute(string text, int fontSize = -1, uint color = 0) { Text = text; + FontSize = fontSize; + Color = color; } } }