diff --git a/Content/Editor/Camera/M_Camera.flax b/Content/Editor/Camera/M_Camera.flax index 768ed42d6..26ba67429 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:ec25eba344fed990157e902029f7b113e4fda7ed5630a6b3b693d5c07351a178 -size 30138 +oid sha256:966db15e769106e448eedaaf8bff4d5724f63e813fc7f81c9da2962b37c9b57e +size 30094 diff --git a/Content/Editor/CubeTexturePreviewMaterial.flax b/Content/Editor/CubeTexturePreviewMaterial.flax index fd3d482bf..28860d3cc 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:2cf6beb5cefcfd91c758b7940b7ed26f435c5e5144233d88c5daf274e8b05c1e -size 31691 +oid sha256:c04e226f6f8aa0de1049694ed813b0bd75864da76be2df43fb9db08162daadaa +size 31647 diff --git a/Content/Editor/DebugMaterials/DDGIDebugProbes.flax b/Content/Editor/DebugMaterials/DDGIDebugProbes.flax index 68f46f7d4..8e810f7d4 100644 --- a/Content/Editor/DebugMaterials/DDGIDebugProbes.flax +++ b/Content/Editor/DebugMaterials/DDGIDebugProbes.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a34e48c787818a3a22072142c6a51aa8dd37ae03a1f96526f6021302c6f6508a -size 41832 +oid sha256:57066ba805fd3f21a1d48048c7d3a0ec4e4c66c5cdd1ca97553605987f43b460 +size 41028 diff --git a/Content/Editor/DebugMaterials/SingleColor/Decal.flax b/Content/Editor/DebugMaterials/SingleColor/Decal.flax index 0c3b3b6c0..f5ed08a03 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:e47d5133f12b96d0ce9cde651032b9ede2eec0a099d3702d02bf26a31c9ec051 -size 7696 +oid sha256:6854135456c47f2c693ebd875d83812f29a6c93b6cddad9e267de2db261a6133 +size 7489 diff --git a/Content/Editor/DebugMaterials/SingleColor/Particle.flax b/Content/Editor/DebugMaterials/SingleColor/Particle.flax index 30db32463..72e956e7a 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:7a509d2985b590d20d892189684d31ffcf71e0306637ddb93948d8a9649168c5 -size 31753 +oid sha256:e737c911cffc1e1ad5cad3d7d4e13e24cdba7d08da4b488bf7bb41f098cb1638 +size 31713 diff --git a/Content/Editor/DebugMaterials/SingleColor/Surface.flax b/Content/Editor/DebugMaterials/SingleColor/Surface.flax index f60f7c4cf..95bab955f 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:b091889f827c292b2656aa64af9b9101a1eb465b7c9818e6358b2928d9f69c29 -size 30034 +oid sha256:129afa8e75f4e83307e3171993f6e3ae52a205456a629beae4a58ed84e435292 +size 29990 diff --git a/Content/Editor/DebugMaterials/SingleColor/SurfaceAdditive.flax b/Content/Editor/DebugMaterials/SingleColor/SurfaceAdditive.flax index 0bbf43c36..2fffdd0eb 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:8e7af2e0901a62301e6cfbb7df915e04486073dbeee0904adea99774ee9d93d5 -size 31919 +oid sha256:7933e14f937b148d6b0c4a7fff10aa9b931f01e1bfe42ce3e5ff4575fbeeb463 +size 31873 diff --git a/Content/Editor/DebugMaterials/SingleColor/Terrain.flax b/Content/Editor/DebugMaterials/SingleColor/Terrain.flax index 20220b081..6e85901e7 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:07d8e970f92010b4fdb3a058415a758d87d2117bf7668b1fa4471a13fc623177 -size 21238 +oid sha256:e21ef2afb59c22647d644502c6c0b6316f3e1b75be0b4ac95e4cde0701969d45 +size 20769 diff --git a/Content/Editor/DefaultFontMaterial.flax b/Content/Editor/DefaultFontMaterial.flax index d93a64e18..87e8f541c 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:25f8315d4bfdc65c101a6b8b423b999d058321f158ad4fc98bffe74678b8b2d3 -size 30213 +oid sha256:a7838428fc9afa03649b25168f2458f7c06fc99c6a50f17579daa19ccc93916e +size 30169 diff --git a/Content/Editor/Gizmo/FoliageBrushMaterial.flax b/Content/Editor/Gizmo/FoliageBrushMaterial.flax index 8a3cdb2df..8eb64e89d 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:485cedb18db31cb18c7991dbda99dcc3440b48b0f49b219b563731e5304504c5 -size 38691 +oid sha256:67e5aba4c1eeb15231aef4001c7b0bb25db4243b871b1493774b1d1348310b22 +size 37868 diff --git a/Content/Editor/Gizmo/Material.flax b/Content/Editor/Gizmo/Material.flax index 66f72fd47..d44e7590a 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:a1a0beaec89af72a7622512963b3a431c61fad77d289794e2fde2e256f7b3f37 -size 32457 +oid sha256:8b8d0157ba0eb18a8ab9613b4429343b4f52fdeb14d1adc73c0682a75b6a7466 +size 32411 diff --git a/Content/Editor/Gizmo/MaterialWire.flax b/Content/Editor/Gizmo/MaterialWire.flax index 532a49b86..db5910a4f 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:3938bb1381efc2842f73f514dcb3289f29fda2504c2550a25e807080dc8150b0 -size 31670 +oid sha256:4dcae1147c6a225a8e5e0613d15950b77c05f3f90f60acdfa3943063ccc582a5 +size 31624 diff --git a/Content/Editor/Gizmo/SelectionOutlineMaterial.flax b/Content/Editor/Gizmo/SelectionOutlineMaterial.flax index 20cb250ad..1deecbcd9 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:c68d577cc0d761c5ba02992b666f2ceb85c6178a5b2639b14bbcabdc449a1c03 +oid sha256:811b50ce2d2672bf7ce12dc161f6dc2038c5cfe8792012632ed89fb951c4058f size 16202 diff --git a/Content/Editor/Gizmo/VertexColorsPreviewMaterial.flax b/Content/Editor/Gizmo/VertexColorsPreviewMaterial.flax index 539fa76ad..f9f1b97c7 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:145a977ccd4fc5f0ef8dc7411331a414e473c13cc3a7fde8b9fa9cb02f3156a1 -size 31147 +oid sha256:30bcf9eb156bafe9b5536c040994877eab6cb0fe942fc31d744e5bff1bb02838 +size 31103 diff --git a/Content/Editor/Highlight Material.flax b/Content/Editor/Highlight Material.flax index 78fd05c06..c13a1c0d4 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:53f86e6b1f6d1f9c31845a86a028a67937f79b90b878783601b752b1c82f67e2 -size 30269 +oid sha256:eb2d2b798b5fe819a0c137603b1c1bb598530ef01efb681690e5ce0901a550a9 +size 30271 diff --git a/Content/Editor/Icons/IconsMaterial.flax b/Content/Editor/Icons/IconsMaterial.flax index 9b6e5e1e6..7966e8335 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:4751716e158f8390e4f451e4eb64df71472a4b1f822247995be4417a81169880 -size 30197 +oid sha256:2d4413df45e276c0cf6b0ede54ecf8dbf1a6f16ee12db3df9b409db2a632adc7 +size 30199 diff --git a/Content/Editor/IesProfilePreviewMaterial.flax b/Content/Editor/IesProfilePreviewMaterial.flax index 097ca7846..ba6d02979 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:cddc591a3af95c1c49983ee0e220ec39ad93e9af4a113d20cb2d5ded9f3230f4 +oid sha256:4d3c6d38944ae59d48c60c7e937c43b03d4659398ac05ac863fd4da16156529f size 18217 diff --git a/Content/Editor/MaterialTemplates/Features/DeferredShading.hlsl b/Content/Editor/MaterialTemplates/Features/DeferredShading.hlsl index 556cc99a1..fd0023a91 100644 --- a/Content/Editor/MaterialTemplates/Features/DeferredShading.hlsl +++ b/Content/Editor/MaterialTemplates/Features/DeferredShading.hlsl @@ -40,7 +40,7 @@ void PS_GBuffer( #if MATERIAL_MASKED clip(material.Mask - MATERIAL_MASK_THRESHOLD); #endif - + #if USE_LIGHTMAP float3 diffuseColor = GetDiffuseColor(material.Color, material.Metalness); float3 specularColor = GetSpecularColor(material.Color, material.Specular, material.Metalness); diff --git a/Content/Editor/MaterialTemplates/Features/ForwardShading.hlsl b/Content/Editor/MaterialTemplates/Features/ForwardShading.hlsl index d395a8bd1..cf596bb30 100644 --- a/Content/Editor/MaterialTemplates/Features/ForwardShading.hlsl +++ b/Content/Editor/MaterialTemplates/Features/ForwardShading.hlsl @@ -33,9 +33,12 @@ DECLARE_LIGHTSHADOWDATA_ACCESS(DirectionalLightShadow); // Pixel Shader function for Forward Pass META_PS(USE_FORWARD, FEATURE_LEVEL_ES2) -float4 PS_Forward(PixelInput input) : SV_Target0 +void PS_Forward( + in PixelInput input + ,out float4 output : SV_Target0 + ) { - float4 output = 0; + output = 0; #if USE_DITHERED_LOD_TRANSITION // LOD masking @@ -148,6 +151,4 @@ float4 PS_Forward(PixelInput input) : SV_Target0 #endif #endif - - return output; } diff --git a/Content/Editor/MaterialTemplates/Particle.shader b/Content/Editor/MaterialTemplates/Particle.shader index 18a270cc0..3f6b03a58 100644 --- a/Content/Editor/MaterialTemplates/Particle.shader +++ b/Content/Editor/MaterialTemplates/Particle.shader @@ -4,8 +4,6 @@ #define MATERIAL 1 #define USE_PER_VIEW_CONSTANTS 1 @3 -// Ribbons don't use sorted indices so overlap the segment distances buffer on the slot -#define HAS_SORTED_INDICES (!defined(_VS_Ribbon)) #include "./Flax/Common.hlsl" #include "./Flax/MaterialCommon.hlsl" @@ -18,6 +16,14 @@ struct SpriteInput float2 TexCoord : TEXCOORD; }; +struct RibbonInput +{ + uint Order : TEXCOORD0; + uint ParticleIndex : TEXCOORD1; + uint PrevParticleIndex : TEXCOORD2; + float Distance : TEXCOORD3; +}; + // Primary constant buffer (with additional material parameters) META_CB_BEGIN(0, Data) float4x4 WorldMatrix; @@ -45,13 +51,8 @@ float4x4 WorldMatrixInverseTransposed; // Particles attributes buffer ByteAddressBuffer ParticlesData : register(t0); -#if HAS_SORTED_INDICES // Sorted particles indices Buffer SortedIndices : register(t1); -#else -// Ribbon particles segments distances buffer -Buffer SegmentDistances : register(t1); -#endif // Shader resources @2 @@ -320,13 +321,11 @@ VertexOutput VS_Sprite(SpriteInput input, uint particleIndex : SV_InstanceID) { VertexOutput output; -#if HAS_SORTED_INDICES // Sorted particles mapping if (SortedIndicesOffset != 0xFFFFFFFF) { particleIndex = SortedIndices[SortedIndicesOffset + particleIndex]; } -#endif // Read particle data float3 particlePosition = GetParticleVec3(particleIndex, PositionOffset); @@ -457,13 +456,11 @@ VertexOutput VS_Model(ModelInput input, uint particleIndex : SV_InstanceID) { VertexOutput output; -#if HAS_SORTED_INDICES // Sorted particles mapping if (SortedIndicesOffset != 0xFFFFFFFF) { particleIndex = SortedIndices[SortedIndicesOffset + particleIndex]; } -#endif // Read particle data float3 particlePosition = GetParticleVec3(particleIndex, PositionOffset); @@ -566,12 +563,16 @@ VertexOutput VS_Model(ModelInput input, uint particleIndex : SV_InstanceID) // Vertex Shader function for Ribbon Rendering META_VS(true, FEATURE_LEVEL_ES2) -VertexOutput VS_Ribbon(uint vertexIndex : SV_VertexID) +META_VS_IN_ELEMENT(TEXCOORD, 0, R32_UINT, 0, 0, PER_VERTEX, 0, true) +META_VS_IN_ELEMENT(TEXCOORD, 1, R32_UINT, 0, ALIGN, PER_VERTEX, 0, true) +META_VS_IN_ELEMENT(TEXCOORD, 2, R32_UINT, 0, ALIGN, PER_VERTEX, 0, true) +META_VS_IN_ELEMENT(TEXCOORD, 3, R32_FLOAT, 0, ALIGN, PER_VERTEX, 0, true) +VertexOutput VS_Ribbon(RibbonInput input, uint vertexIndex : SV_VertexID) { VertexOutput output; // Get particle data - uint particleIndex = vertexIndex / 2; + uint particleIndex = input.ParticleIndex; int vertexSign = (((int)vertexIndex & 0x1) * 2) - 1; float3 position = GetParticlePosition(particleIndex); float ribbonWidth = RibbonWidthOffset != -1 ? GetParticleFloat(particleIndex, RibbonWidthOffset) : 20.0f; @@ -579,15 +580,13 @@ VertexOutput VS_Ribbon(uint vertexIndex : SV_VertexID) // Calculate ribbon direction float3 direction; - if (particleIndex == 0) + if (input.Order == 0) { - float3 nextParticlePos = GetParticlePosition(particleIndex + 1); - direction = nextParticlePos - position; + direction = GetParticlePosition(input.PrevParticleIndex) - position; } else { - float3 previousParticlePos = GetParticlePosition(particleIndex - 1); - direction = position - previousParticlePos; + direction = position - GetParticlePosition(input.PrevParticleIndex); } // Calculate particle orientation (tangent vectors) @@ -604,19 +603,16 @@ VertexOutput VS_Ribbon(uint vertexIndex : SV_VertexID) } // Calculate texture coordinates - float texCoordU; -#ifdef _VS_Ribbon if (RibbonUVTilingDistance != 0.0f) { - texCoordU = SegmentDistances[particleIndex] / RibbonUVTilingDistance; + output.TexCoord.x = input.Distance / RibbonUVTilingDistance; } else -#endif { - texCoordU = (float)particleIndex / RibbonSegmentCount; + output.TexCoord.x = (float)input.Order / (float)RibbonSegmentCount; } - float texCoordV = (vertexIndex + 1) & 0x1; - output.TexCoord = float2(texCoordU, texCoordV) * RibbonUVScale + RibbonUVOffset; + output.TexCoord.y = (vertexIndex + 1) & 0x1; + output.TexCoord = output.TexCoord * RibbonUVScale + RibbonUVOffset; // Compute world space vertex position output.WorldPosition = position + tangentRight * vertexSign * (ribbonWidth.xxx * 0.5f); diff --git a/Content/Editor/MaterialTemplates/Surface.shader b/Content/Editor/MaterialTemplates/Surface.shader index 0e7c948a1..1e8589ff2 100644 --- a/Content/Editor/MaterialTemplates/Surface.shader +++ b/Content/Editor/MaterialTemplates/Surface.shader @@ -594,7 +594,7 @@ void PS_Depth(PixelInput input) ClipLODTransition(input); #endif -#if MATERIAL_MASKED || MATERIAL_BLEND != MATERIAL_BLEND_OPAQUE +#if MATERIAL_MASKED || MATERIAL_BLEND != MATERIAL_BLEND_OPAQUE // Get material parameters MaterialInput materialInput = GetMaterialInput(input); Material material = GetMaterialPS(materialInput); diff --git a/Content/Editor/Particles/Particle Material Color.flax b/Content/Editor/Particles/Particle Material Color.flax index 2847afa57..3fbacc935 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:357608bdb965c0bc4391cccb8c2ffacdc7eda4542e3bf09e81f9d899626e06b5 -size 29945 +oid sha256:3217b2dc041d3c41e77522a0766d99de0af26fd3ec28142cb9bb505b0fbc7723 +size 29953 diff --git a/Content/Editor/Particles/Smoke Material.flax b/Content/Editor/Particles/Smoke Material.flax index a3c824681..d12139eff 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:6fa22067784d57637da65339a71a722360a441ecb4c266242e65212dbe2db1be -size 37133 +oid sha256:8657cb23bdf2423f4535cb67da0487be72864a12d53e9521fdc99bce752ff518 +size 37141 diff --git a/Content/Editor/SpriteMaterial.flax b/Content/Editor/SpriteMaterial.flax index 8cfcdb81b..75f4d1f89 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:7dc760c37c70008e1d8e71f392138d54d4a6308df768381864994027474f94e3 -size 31226 +oid sha256:eae8e6b9147611dcf98b181339d3b581128a877b55c8b52b586b7d3fe43d01b2 +size 31182 diff --git a/Content/Editor/Terrain/Circle Brush Material.flax b/Content/Editor/Terrain/Circle Brush Material.flax index 730130f85..b014ffb1f 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:131dac4676de0b4ac8257cd450b7538307383143d352265b062f6689d5215374 -size 27619 +oid sha256:1e73a50fe4296e58eff5942855dd655ba4c2c776ee3acc0451844645dda14247 +size 27150 diff --git a/Content/Editor/Terrain/Highlight Terrain Material.flax b/Content/Editor/Terrain/Highlight Terrain Material.flax index 3ee054ccf..00560e1cb 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:adf85e5679b8a0a4f78663d0a119e1819641a0460100595654fe31649b798c1d -size 21291 +oid sha256:f48c4f43dcf7e05255b41d763e1ca9b21d629df43d35b59b8574ae955d392fc4 +size 20822 diff --git a/Content/Editor/TexturePreviewMaterial.flax b/Content/Editor/TexturePreviewMaterial.flax index 90235d453..d4ff0c0cd 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:26ff727713fd57c857f9a21e369f3a91ae3188e95cb9d762cac523d8c663262a +oid sha256:2970eb5c0000661663a3cadffb1b8e67215f4425da24d5313e1d07fc44f0594d size 10413 diff --git a/Content/Editor/Wires Debug Material.flax b/Content/Editor/Wires Debug Material.flax index f58128c37..caa177eac 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:f1ab66e68b7d4e237232e4abac2be1763b4149109a619901b00862a3a86639e5 -size 30269 +oid sha256:6f8018999baf4b415d400b0b6150de27fbed48e2c93afbd16d074efc39b9c206 +size 30271 diff --git a/Content/Engine/DefaultDeformableMaterial.flax b/Content/Engine/DefaultDeformableMaterial.flax index 1b90f7fc3..052d5946e 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:c58b87b135659215bbea0094368511c1b925fc82df35d2e6403ccbbcd34e9322 -size 18914 +oid sha256:a70603cf2ace948b588924b39a1d31e309238782581f26b3388b8d9d3b44d4d7 +size 18530 diff --git a/Content/Engine/DefaultMaterial.flax b/Content/Engine/DefaultMaterial.flax index 8c54ba2c8..588f85571 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:2fb9906c87a1e11261ca8a12fde8a5e808827599d3f423ebfd2437bd5c26d375 -size 32065 +oid sha256:de63950e622426ed8905d19097a5f9d189da4a6300ae9a77577f0e7fab59a1bb +size 32021 diff --git a/Content/Engine/DefaultTerrainMaterial.flax b/Content/Engine/DefaultTerrainMaterial.flax index 8787991a0..e9af0516e 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:e7676a6523be037dbfa10e2957c2175f650978e7850af443f4c859f687f5f89f -size 23381 +oid sha256:7c206df1af51d206c805449d5e6a4ce3fcaf70ac0c5310cf77dc0921a56e8552 +size 22912 diff --git a/Content/Engine/SingleColorMaterial.flax b/Content/Engine/SingleColorMaterial.flax index ede999b2c..31af3b1c8 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:26fe92bc72d726fde4811aee6056f3b8ed0797a433d5a76b07c24dd20bc42199 -size 30235 +oid sha256:c87f422816ea68b3d6524b4f727d007ac4d5d2484931cf7a61cfe722b9c111d7 +size 30191 diff --git a/Content/Engine/SkyboxMaterial.flax b/Content/Engine/SkyboxMaterial.flax index 97875e653..df2859f7b 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:46f557106d4b4b7768cdeb0db8da1d1ae40637495afef2fe71b3591d82063f55 -size 31433 +oid sha256:0e8a62e94c4e265902ed2e95ea059dcc0aca50f79f7a6986ff5a6d99f034f3d3 +size 31389 diff --git a/Content/Shaders/GI/DDGI.flax b/Content/Shaders/GI/DDGI.flax index c8f8eee9d..6b387f70b 100644 --- a/Content/Shaders/GI/DDGI.flax +++ b/Content/Shaders/GI/DDGI.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6b00a1519c9fe2303a05c10ae4061649c4073a3f65a3bd8c2af848cdc7bf5e53 -size 23702 +oid sha256:d851e919211c073ac83ba5e9e2c75529164c588ea1ace8eca858995643f5744a +size 23686 diff --git a/Content/Shaders/GI/GlobalSurfaceAtlas.flax b/Content/Shaders/GI/GlobalSurfaceAtlas.flax index f74572140..fc09f8b77 100644 --- a/Content/Shaders/GI/GlobalSurfaceAtlas.flax +++ b/Content/Shaders/GI/GlobalSurfaceAtlas.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8b69d6b93baa29702789073f911dbe784dc65ccd66a43cef837a217959d24d13 -size 12612 +oid sha256:de6aea50d923fb5ca9fec7a9eb2186e643a3edad21772a12ee27e703050aee77 +size 12616 diff --git a/Content/Shaders/GUI.flax b/Content/Shaders/GUI.flax index fc197f16a..e46a9abf3 100644 --- a/Content/Shaders/GUI.flax +++ b/Content/Shaders/GUI.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b0560421c43d81b73bc970ea77ff5d72661ef3817bbbf38cb91297596fb4c583 -size 5111 +oid sha256:9f30f532a71194bb7a2d3b538b18cff80862407c9950516c4751767df8290d63 +size 4951 diff --git a/Content/Shaders/GlobalSignDistanceField.flax b/Content/Shaders/GlobalSignDistanceField.flax index 8014efcd5..e013618f3 100644 --- a/Content/Shaders/GlobalSignDistanceField.flax +++ b/Content/Shaders/GlobalSignDistanceField.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0a96e3dec992385e4e4e7073fdd990baf1351d027648c7e52808c3eaceb55348 -size 11787 +oid sha256:3e12440d4fcc78a0d7e07da6584efcc95750046db500d0aff2dc9a41360aac36 +size 11798 diff --git a/Content/Shaders/ProbesFilter.flax b/Content/Shaders/ProbesFilter.flax index 219e309e4..4df12098a 100644 --- a/Content/Shaders/ProbesFilter.flax +++ b/Content/Shaders/ProbesFilter.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c86511466b35459fd56d56bbb967eeba2a62f81ff3bbb5350caa4053f582424c -size 2108 +oid sha256:7f61b3517bafb1f02771a39b9fff037495b893525de272d89e2c211985cfb30f +size 2032 diff --git a/Content/Shaders/SSR.flax b/Content/Shaders/SSR.flax index 9e63ae962..a422ce5c0 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:c400f07912ab73b91d4707ebbb94127b835265365ac37a6264e54e9dbba92f9f -size 11205 +oid sha256:0317fb2ca888fee6d32c7754d6f83e2f1e58924725a8221c5131e974501168ac +size 10912 diff --git a/Content/Shaders/TAA.flax b/Content/Shaders/TAA.flax index e9575793e..03d9d6617 100644 --- a/Content/Shaders/TAA.flax +++ b/Content/Shaders/TAA.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:26cf20668dc0d93fdffa3ea715130b618e9c491e73dc8be779c1d182e73b255b -size 3257 +oid sha256:9c528dc72d727f847b89da70b827b629e7eec8dc7205cf50b212152e62a0786c +size 3265 diff --git a/Source/Editor/Cooker/Steps/CookAssetsStep.cpp b/Source/Editor/Cooker/Steps/CookAssetsStep.cpp index 1b6d13fa6..92ebf39f6 100644 --- a/Source/Editor/Cooker/Steps/CookAssetsStep.cpp +++ b/Source/Editor/Cooker/Steps/CookAssetsStep.cpp @@ -354,7 +354,7 @@ bool CookAssetsStep::Process(CookingData& data, CacheData& cache, Asset* asset) if (asset->WaitForLoaded()) { LOG(Error, "Failed to load asset \'{0}\'", asset->ToString()); - return false; + return true; } // Switch based on an asset type @@ -1132,7 +1132,10 @@ bool CookAssetsStep::Perform(CookingData& data) // Cook asset if (Process(data, cache, assetRef.Get())) + { + cache.Save(); return true; + } data.Stats.CookedAssets++; // Auto save build cache after every few cooked assets (reduces next build time if cooking fails later) diff --git a/Source/Editor/CustomEditors/Editors/TagEditor.cs b/Source/Editor/CustomEditors/Editors/TagEditor.cs index e9bcd97a9..8a4333a9b 100644 --- a/Source/Editor/CustomEditors/Editors/TagEditor.cs +++ b/Source/Editor/CustomEditors/Editors/TagEditor.cs @@ -322,7 +322,7 @@ namespace FlaxEditor.CustomEditors.Editors internal static ContextMenuBase CreatePicker(Tag value, Tag[] values, PickerData pickerData) { // Initialize search popup - var menu = Utilities.Utils.CreateSearchPopup(out var searchBox, out var tree, 40.0f); + var menu = Utilities.Utils.CreateSearchPopup(out var searchBox, out var tree, 42.0f); // Add tag drop panel var addTagDropPanel = new DropPanel @@ -333,6 +333,7 @@ namespace FlaxEditor.CustomEditors.Editors ArrowImageClosed = new SpriteBrush(FlaxEngine.GUI.Style.Current.ArrowRight), Parent = menu, HeaderTextMargin = new Margin(2.0f), + HeaderHeight = 18.0f, AnchorPreset = AnchorPresets.TopLeft, Bounds = new Rectangle(2, 2, menu.Width - 4, 30), IsClosed = true, @@ -408,7 +409,7 @@ namespace FlaxEditor.CustomEditors.Editors var buttonAddTag = new Button { Parent = addButtonPanel, - Size = new Float2(100, 20), + Size = new Float2(100, 18), Text = "Add Tag", AnchorPreset = AnchorPresets.MiddleCenter, }; diff --git a/Source/Editor/CustomEditors/Values/ValueContainer.cs b/Source/Editor/CustomEditors/Values/ValueContainer.cs index 92c44fbb5..dfec33f49 100644 --- a/Source/Editor/CustomEditors/Values/ValueContainer.cs +++ b/Source/Editor/CustomEditors/Values/ValueContainer.cs @@ -275,12 +275,16 @@ namespace FlaxEditor.CustomEditors // Workaround for DefaultValueAttribute that doesn't support certain value types storage if (Type.Type == typeof(sbyte)) _defaultValue = Convert.ToSByte(_defaultValue); + else if (Type.Type == typeof(short)) + _defaultValue = Convert.ToInt16(_defaultValue); else if (Type.Type == typeof(ushort)) _defaultValue = Convert.ToUInt16(_defaultValue); else if (Type.Type == typeof(uint)) _defaultValue = Convert.ToUInt32(_defaultValue); else if (Type.Type == typeof(ulong)) _defaultValue = Convert.ToUInt64(_defaultValue); + else if (Type.Type == typeof(long)) + _defaultValue = Convert.ToInt64(_defaultValue); } } } diff --git a/Source/Editor/Editor.cs b/Source/Editor/Editor.cs index 04c498915..878888a73 100644 --- a/Source/Editor/Editor.cs +++ b/Source/Editor/Editor.cs @@ -50,7 +50,8 @@ namespace FlaxEditor private bool _isAfterInit, _areModulesInited, _areModulesAfterInitEnd, _isHeadlessMode; private string _projectToOpen; private float _lastAutoSaveTimer; - private AutoSavePopup _autoSavePopup; + private Button _saveNowButton; + private Button _cancelSaveButton; private bool _autoSaveNow; private Guid _startupSceneCmdLine; @@ -498,28 +499,6 @@ namespace FlaxEditor { var timeSinceLastSave = Time.UnscaledGameTime - _lastAutoSaveTimer; var timeToNextSave = options.AutoSaveFrequency * 60.0f - timeSinceLastSave; - var countDownDuration = 4.0f; - - // Show auto save popup - if (timeToNextSave <= options.AutoSaveReminderTime && timeToNextSave >= 0) - { - if (_autoSavePopup == null) - { - _autoSavePopup = AutoSavePopup.Show(Instance.Windows.MainWindow.GUI, timeToNextSave); - _autoSavePopup.SaveNowButton.Clicked += () => _autoSaveNow = true; - _autoSavePopup.CancelSaveButton.Clicked += () => - { - Log("Auto save canceled"); - _autoSavePopup.HidePopup(); - _lastAutoSaveTimer = Time.UnscaledGameTime; // Reset timer - }; - } - else if (!_autoSavePopup.Visible && !_autoSavePopup.UserClosed) - _autoSavePopup.ShowPopup(); - - if (_autoSavePopup.Visible) - _autoSavePopup.UpdateTime(timeToNextSave); - } if (timeToNextSave <= 0.0f || _autoSaveNow) { @@ -530,14 +509,76 @@ namespace FlaxEditor if (options.AutoSaveContent) SaveContent(); - // Hide auto save popup and reset user closed - _autoSavePopup.HidePopup(); - _autoSavePopup.UserClosed = false; _autoSaveNow = false; + + // Hide save now and cancel save buttons + if (_saveNowButton != null && _cancelSaveButton != null) + { + _saveNowButton.Visible = false; + _cancelSaveButton.Visible = false; + } } - else if (timeToNextSave < countDownDuration) + else if (timeToNextSave <= options.AutoSaveReminderTime) { msg = string.Format("Auto save in {0}s...", Mathf.CeilToInt(timeToNextSave)); + + // Create save now and cancel save buttons if needed + if (_saveNowButton == null) + { + _saveNowButton = new Button + { + Parent = UI.StatusBar, + Height = 14, + Width = 60, + AnchorPreset = AnchorPresets.MiddleLeft, + BackgroundColor = Color.Transparent, + BorderColor = Color.Transparent, + BackgroundColorHighlighted = Color.Transparent, + BackgroundColorSelected = Color.Transparent, + BorderColorHighlighted = Color.Transparent, + Text = "Save Now", + TooltipText = "Saves now and restarts the auto save timer." + }; + _saveNowButton.LocalX += 120; + _saveNowButton.Clicked += () => _autoSaveNow = true; + _saveNowButton.HoverBegin += () => _saveNowButton.TextColor = Style.Current.BackgroundHighlighted; + _saveNowButton.HoverEnd += () => _saveNowButton.TextColor = UI.StatusBar.TextColor; + } + + if (_cancelSaveButton == null) + { + _cancelSaveButton = new Button + { + Parent = UI.StatusBar, + Height = 14, + Width = 70, + AnchorPreset = AnchorPresets.MiddleLeft, + BackgroundColor = Color.Transparent, + BorderColor = Color.Transparent, + BackgroundColorHighlighted = Color.Transparent, + BackgroundColorSelected = Color.Transparent, + BorderColorHighlighted = Color.Transparent, + Text = "Cancel", + TooltipText = "Cancels this auto save." + }; + _cancelSaveButton.LocalX += 180; + _cancelSaveButton.Clicked += () => + { + Log("Auto save canceled"); + _saveNowButton.Visible = false; + _cancelSaveButton.Visible = false; + _lastAutoSaveTimer = Time.UnscaledGameTime; // Reset timer + }; + _cancelSaveButton.HoverBegin += () => _cancelSaveButton.TextColor = Style.Current.BackgroundHighlighted; + _cancelSaveButton.HoverEnd += () => _cancelSaveButton.TextColor = UI.StatusBar.TextColor; + } + + // Show save now and cancel save buttons + if (!_saveNowButton.Visible || !_cancelSaveButton.Visible) + { + _saveNowButton.Visible = true; + _cancelSaveButton.Visible = true; + } } } if (StateMachine.EditingSceneState.AutoSaveStatus != msg) @@ -545,6 +586,14 @@ namespace FlaxEditor StateMachine.EditingSceneState.AutoSaveStatus = msg; UI.UpdateStatusBar(); } + + if (UI?.StatusBar?.Text != null && !UI.StatusBar.Text.Contains("Auto") && + _saveNowButton != null && _cancelSaveButton != null && + (_saveNowButton.Visible || _cancelSaveButton.Visible)) + { + _saveNowButton.Visible = false; + _cancelSaveButton.Visible = false; + } } private void InitProject() diff --git a/Source/Editor/GUI/Popups/AutoSavePopup.cs b/Source/Editor/GUI/Popups/AutoSavePopup.cs deleted file mode 100644 index 0992def3e..000000000 --- a/Source/Editor/GUI/Popups/AutoSavePopup.cs +++ /dev/null @@ -1,169 +0,0 @@ -using FlaxEngine; -using FlaxEngine.GUI; - -namespace FlaxEditor.GUI -{ - /// - /// Popup menu for reminding of an upcoming auto save. - /// - public class AutoSavePopup : ContainerControl - { - /// - /// Gets or sets the value for if the user has manually closed this popup. - /// - public bool UserClosed { get; set; } - - /// - /// The save now button. Used to skip the last remaining auto save time. - /// - public Button SaveNowButton => _saveNowButton; - - /// - /// Button that should be used to cancel the auto save. - /// - public Button CancelSaveButton => _cancelSaveButton; - - private int _timeRemaining; - private Panel _backgroundPanel; - private Label _timeLabel; - private Button _saveNowButton; - private Button _cancelSaveButton; - private Color _defaultTextColor; - private bool _isMoved = false; - - /// - /// Initialize the AutoSavePopup. - /// - /// The initial time to set the time label to. - public AutoSavePopup(float initialTime) - { - UpdateTime(initialTime); - - _backgroundPanel = new Panel(ScrollBars.None) - { - Parent = this, - AnchorPreset = AnchorPresets.StretchAll, - BackgroundColor = Color.Transparent, - }; - - _timeLabel = new Label(0, 0, 25, 10) - { - Parent = _backgroundPanel, - Text = _timeRemaining.ToString(), - HorizontalAlignment = TextAlignment.Near, - VerticalAlignment = TextAlignment.Near, - AutoWidth = true, - Height = 14, - AnchorPreset = AnchorPresets.MiddleLeft, - }; - - _saveNowButton = new Button - { - Parent = _backgroundPanel, - Height = 14, - Width = 60, - AnchorPreset = AnchorPresets.MiddleRight, - BackgroundColor = Color.Transparent, - BorderColor = Color.Transparent, - BackgroundColorHighlighted = Color.Transparent, - BackgroundColorSelected = Color.Transparent, - BorderColorHighlighted = Color.Transparent, - Text = "Save Now", - TooltipText = "Saves now and restarts the auto save timer." - }; - _saveNowButton.LocalX -= 85; - - _cancelSaveButton = new Button - { - Parent = _backgroundPanel, - Height = 14, - Width = 70, - AnchorPreset = AnchorPresets.MiddleRight, - BackgroundColor = Color.Transparent, - BorderColor = Color.Transparent, - BackgroundColorHighlighted = Color.Transparent, - BackgroundColorSelected = Color.Transparent, - BorderColorHighlighted = Color.Transparent, - Text = "Cancel Save", - TooltipText = "Cancels this auto save." - }; - _cancelSaveButton.LocalX -= 5; - - _defaultTextColor = _saveNowButton.TextColor; - } - - /// - /// Updates the time label - /// - /// The time to change the label to. - public void UpdateTime(float time) - { - _timeRemaining = Mathf.CeilToInt(time); - if (_timeLabel != null) - _timeLabel.Text = "Auto Save in: " + _timeRemaining; - } - - /// - public override void Update(float deltaTime) - { - if (IsMouseOver) - { - _saveNowButton.TextColor = _saveNowButton.IsMouseOver ? Style.Current.BackgroundHighlighted : _defaultTextColor; - _cancelSaveButton.TextColor = _cancelSaveButton.IsMouseOver ? Style.Current.BackgroundHighlighted : _defaultTextColor; - } - - // Move if the progress bar is visible - if (Editor.Instance.UI.ProgressVisible && !_isMoved) - { - _isMoved = true; - LocalX -= 280; - } - else if (!Editor.Instance.UI.ProgressVisible && _isMoved) - { - LocalX += 280; - _isMoved = false; - } - base.Update(deltaTime); - } - - /// - /// Creates and shows the AutoSavePopup - /// - /// The parent control. - /// The time to start at. - /// - public static AutoSavePopup Show(ContainerControl parentControl, float initialTime) - { - var popup = new AutoSavePopup(initialTime) - { - Parent = parentControl, - Height = Editor.Instance.UI.StatusBar.Height, - Width = 250, - AnchorPreset = AnchorPresets.BottomRight, - }; - popup.ShowPopup(); - return popup; - } - - /// - /// Shows the popup by changing its visibility - /// - public void ShowPopup() - { - Visible = true; - UserClosed = false; - _saveNowButton.TextColor = _defaultTextColor; - _cancelSaveButton.TextColor = _defaultTextColor; - } - - /// - /// Hides the popup by changing its visibility - /// - public void HidePopup() - { - Visible = false; - if (_containsFocus) - Defocus(); - } - } -} diff --git a/Source/Editor/Utilities/ViewportIconsRenderer.cpp b/Source/Editor/Utilities/ViewportIconsRenderer.cpp index 657117c11..9b7f4979b 100644 --- a/Source/Editor/Utilities/ViewportIconsRenderer.cpp +++ b/Source/Editor/Utilities/ViewportIconsRenderer.cpp @@ -78,6 +78,7 @@ void ViewportIconsRenderer::DrawIcons(RenderContext& renderContext, Actor* actor draw.PerInstanceRandom = 0; draw.LODBias = 0; draw.ForcedLOD = -1; + draw.SortOrder = 0; draw.VertexColors = nullptr; if (const auto scene = SceneObject::Cast(actor)) diff --git a/Source/Editor/Viewport/EditorViewport.cs b/Source/Editor/Viewport/EditorViewport.cs index aa9e3638f..f56370352 100644 --- a/Source/Editor/Viewport/EditorViewport.cs +++ b/Source/Editor/Viewport/EditorViewport.cs @@ -1521,6 +1521,7 @@ namespace FlaxEditor.Viewport new ViewFlagOptions(ViewFlags.PointLights, "Point Lights"), new ViewFlagOptions(ViewFlags.SpotLights, "Spot Lights"), new ViewFlagOptions(ViewFlags.SkyLights, "Sky Lights"), + new ViewFlagOptions(ViewFlags.Sky, "Sky"), new ViewFlagOptions(ViewFlags.Fog, "Fog"), new ViewFlagOptions(ViewFlags.SpecularLight, "Specular Light"), new ViewFlagOptions(ViewFlags.Decals, "Decals"), diff --git a/Source/Editor/Viewport/Previews/AnimatedModelPreview.cs b/Source/Editor/Viewport/Previews/AnimatedModelPreview.cs index b9f27f77b..268295405 100644 --- a/Source/Editor/Viewport/Previews/AnimatedModelPreview.cs +++ b/Source/Editor/Viewport/Previews/AnimatedModelPreview.cs @@ -428,8 +428,12 @@ namespace FlaxEditor.Viewport.Previews case KeyboardKeys.F: // Pay respect.. ViewportCamera.SetArcBallView(_previewModel.Box); - break; + return true; + case KeyboardKeys.Spacebar: + PlayAnimation = !PlayAnimation; + return true; } + return base.OnKeyDown(key); } diff --git a/Source/Editor/Viewport/Previews/ParticleSystemPreview.cs b/Source/Editor/Viewport/Previews/ParticleSystemPreview.cs index e845ae62c..1e0c89528 100644 --- a/Source/Editor/Viewport/Previews/ParticleSystemPreview.cs +++ b/Source/Editor/Viewport/Previews/ParticleSystemPreview.cs @@ -2,8 +2,10 @@ using FlaxEditor.GUI.ContextMenu; using FlaxEditor.Viewport.Cameras; +using FlaxEditor.Viewport.Widgets; using FlaxEngine; using FlaxEngine.GUI; +using System; using Object = FlaxEngine.Object; namespace FlaxEditor.Viewport.Previews @@ -14,10 +16,12 @@ namespace FlaxEditor.Viewport.Previews /// public class ParticleSystemPreview : AssetPreview { + private bool _playSimulation = false; private ParticleEffect _previewEffect; private ContextMenuButton _showBoundsButton; private ContextMenuButton _showOriginButton; private ContextMenuButton _showParticleCounterButton; + private ViewportWidgetButton _playPauseButton; private StaticModel _boundsModel; private StaticModel _originModel; private bool _showParticlesCounter; @@ -39,7 +43,25 @@ namespace FlaxEditor.Viewport.Previews /// /// Gets or sets a value indicating whether to play the particles simulation in editor. /// - public bool PlaySimulation { get; set; } = false; + public bool PlaySimulation + { + get => _playSimulation; + set + { + if (_playSimulation == value) + return; + _playSimulation = value; + PlaySimulationChanged?.Invoke(); + + if (_playPauseButton != null) + _playPauseButton.Icon = value ? Editor.Instance.Icons.Pause64 : Editor.Instance.Icons.Play64; + } + } + + /// + /// Occurs when particles simulation playback state gets changed. + /// + public event Action PlaySimulationChanged; /// /// Gets or sets a value indicating whether to show particle effect bounding box. @@ -161,11 +183,22 @@ namespace FlaxEditor.Viewport.Previews // Link actors for rendering Task.AddCustomActor(_previewEffect); - if (useWidgets) + if (!useWidgets) + return; + _showBoundsButton = ViewWidgetShowMenu.AddButton("Bounds", () => ShowBounds = !ShowBounds); + _showOriginButton = ViewWidgetShowMenu.AddButton("Origin", () => ShowOrigin = !ShowOrigin); + _showParticleCounterButton = ViewWidgetShowMenu.AddButton("Particles Counter", () => ShowParticlesCounter = !ShowParticlesCounter); + + // Play/Pause widget { - _showBoundsButton = ViewWidgetShowMenu.AddButton("Bounds", () => ShowBounds = !ShowBounds); - _showOriginButton = ViewWidgetShowMenu.AddButton("Origin", () => ShowOrigin = !ShowOrigin); - _showParticleCounterButton = ViewWidgetShowMenu.AddButton("Particles Counter", () => ShowParticlesCounter = !ShowParticlesCounter); + var playPauseWidget = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight); + _playPauseButton = new ViewportWidgetButton(null, Editor.Instance.Icons.Pause64) + { + TooltipText = "Simulation playback play (F5) or pause (F6)", + Parent = playPauseWidget, + }; + _playPauseButton.Clicked += button => PlaySimulation = !PlaySimulation; + playPauseWidget.Parent = this; } } @@ -200,7 +233,7 @@ namespace FlaxEditor.Viewport.Previews // Manually update simulation if (PlaySimulation) { - _previewEffect.UpdateSimulation(); + _previewEffect.UpdateSimulation(true); } // Keep bounds matching the model @@ -228,6 +261,34 @@ namespace FlaxEditor.Viewport.Previews } } + /// + public override bool OnKeyDown(KeyboardKeys key) + { + switch (key) + { + case KeyboardKeys.F: + ViewportCamera.SetArcBallView(_previewEffect.Box); + return true; + case KeyboardKeys.Spacebar: + PlaySimulation = !PlaySimulation; + return true; + } + + var inputOptions = Editor.Instance.Options.Options.Input; + if (inputOptions.Play.Process(this, key)) + { + PlaySimulation = true; + return true; + } + if (inputOptions.Pause.Process(this, key)) + { + PlaySimulation = false; + return true; + } + + return base.OnKeyDown(key); + } + /// public override void OnDestroy() { @@ -239,6 +300,7 @@ namespace FlaxEditor.Viewport.Previews _showBoundsButton = null; _showOriginButton = null; _showParticleCounterButton = null; + _playPauseButton = null; base.OnDestroy(); } diff --git a/Source/Editor/Windows/EditGameWindow.cs b/Source/Editor/Windows/EditGameWindow.cs index 9335cd00b..698972b64 100644 --- a/Source/Editor/Windows/EditGameWindow.cs +++ b/Source/Editor/Windows/EditGameWindow.cs @@ -430,7 +430,7 @@ namespace FlaxEditor.Windows writer.WriteAttributeString("MovementSpeed", Viewport.MovementSpeed.ToString()); writer.WriteAttributeString("OrthographicScale", Viewport.OrthographicScale.ToString()); writer.WriteAttributeString("UseOrthographicProjection", Viewport.UseOrthographicProjection.ToString()); - writer.WriteAttributeString("ViewFlags", ((long)Viewport.Task.View.Flags).ToString()); + writer.WriteAttributeString("ViewFlags", ((ulong)Viewport.Task.View.Flags).ToString()); } /// @@ -463,7 +463,7 @@ namespace FlaxEditor.Windows if (bool.TryParse(node.GetAttribute("UseOrthographicProjection"), out value1)) Viewport.UseOrthographicProjection = value1; - if (long.TryParse(node.GetAttribute("ViewFlags"), out long value3)) + if (ulong.TryParse(node.GetAttribute("ViewFlags"), out ulong value3)) Viewport.Task.ViewFlags = (ViewFlags)value3; // Reset view flags if opening with different engine version (ViewFlags enum could be modified) diff --git a/Source/Engine/Audio/Audio.cpp b/Source/Engine/Audio/Audio.cpp index 450625a48..377a4595d 100644 --- a/Source/Engine/Audio/Audio.cpp +++ b/Source/Engine/Audio/Audio.cpp @@ -91,6 +91,10 @@ namespace void AudioSettings::Apply() { ::MuteOnFocusLoss = MuteOnFocusLoss; + if (AudioBackend::Instance != nullptr) + { + Audio::SetDopplerFactor(DopplerFactor); + } } AudioDevice* Audio::GetActiveDevice() diff --git a/Source/Engine/Content/Assets/Model.cpp b/Source/Engine/Content/Assets/Model.cpp index d54bc1ae8..9319f2667 100644 --- a/Source/Engine/Content/Assets/Model.cpp +++ b/Source/Engine/Content/Assets/Model.cpp @@ -187,7 +187,7 @@ BoundingBox Model::GetBox(int32 lodIndex) const return LODs[lodIndex].GetBox(); } -void Model::Draw(const RenderContext& renderContext, MaterialBase* material, const Matrix& world, StaticFlags flags, bool receiveDecals) const +void Model::Draw(const RenderContext& renderContext, MaterialBase* material, const Matrix& world, StaticFlags flags, bool receiveDecals, int16 sortOrder) const { if (!CanBeRendered()) return; @@ -203,7 +203,7 @@ void Model::Draw(const RenderContext& renderContext, MaterialBase* material, con lodIndex = ClampLODIndex(lodIndex); // Draw - LODs[lodIndex].Draw(renderContext, material, world, flags, receiveDecals); + LODs[lodIndex].Draw(renderContext, material, world, flags, receiveDecals, DrawPass::Default, 0, sortOrder); } template diff --git a/Source/Engine/Content/Assets/Model.h b/Source/Engine/Content/Assets/Model.h index ffc14d5da..d0ddee758 100644 --- a/Source/Engine/Content/Assets/Model.h +++ b/Source/Engine/Content/Assets/Model.h @@ -181,7 +181,8 @@ public: /// The world transformation of the model. /// The object static flags. /// True if rendered geometry can receive decals, otherwise false. - API_FUNCTION() void Draw(API_PARAM(Ref) const RenderContext& renderContext, MaterialBase* material, API_PARAM(Ref) const Matrix& world, StaticFlags flags = StaticFlags::None, bool receiveDecals = true) const; + /// Object sorting key. + API_FUNCTION() void Draw(API_PARAM(Ref) const RenderContext& renderContext, MaterialBase* material, API_PARAM(Ref) const Matrix& world, StaticFlags flags = StaticFlags::None, bool receiveDecals = true, int16 sortOrder = 0) const; /// /// Draws the model. diff --git a/Source/Engine/Core/Math/Float2.cs b/Source/Engine/Core/Math/Float2.cs index 276c0c713..15f412d6e 100644 --- a/Source/Engine/Core/Math/Float2.cs +++ b/Source/Engine/Core/Math/Float2.cs @@ -267,6 +267,19 @@ namespace FlaxEngine /// This method may be preferred to when only a relative length is needed and speed is of the essence. public float LengthSquared => X * X + Y * Y; + /// + /// Gets the normalized vector. Returned vector has length equal 1. + /// + public Float2 Normalized + { + get + { + Float2 result = this; + result.Normalize(); + return result; + } + } + /// /// Converts the vector into a unit vector. /// diff --git a/Source/Engine/Core/Math/Vector2.cs b/Source/Engine/Core/Math/Vector2.cs index 25c25ca21..cd1849383 100644 --- a/Source/Engine/Core/Math/Vector2.cs +++ b/Source/Engine/Core/Math/Vector2.cs @@ -301,6 +301,19 @@ namespace FlaxEngine } } + /// + /// Gets the normalized vector. Returned vector has length equal 1. + /// + public Vector2 Normalized + { + get + { + Vector2 result = this; + result.Normalize(); + return result; + } + } + /// /// Creates an array containing the elements of the vector. /// diff --git a/Source/Engine/Core/Math/Vector2.h b/Source/Engine/Core/Math/Vector2.h index 2b8c80293..2f7a143c4 100644 --- a/Source/Engine/Core/Math/Vector2.h +++ b/Source/Engine/Core/Math/Vector2.h @@ -223,6 +223,15 @@ public: return Vector2Base(-X, -Y); } + /// + /// Calculates a normalized vector that has length equal to 1. + /// + Vector2Base GetNormalized() const + { + const T rcp = 1.0f / Length(); + return Vector2Base(X * rcp, Y * rcp); + } + public: /// /// Performs vector normalization (scales vector up to unit length). diff --git a/Source/Engine/Core/Math/Viewport.cs b/Source/Engine/Core/Math/Viewport.cs index cf100dc9c..b375e416c 100644 --- a/Source/Engine/Core/Math/Viewport.cs +++ b/Source/Engine/Core/Math/Viewport.cs @@ -161,6 +161,11 @@ namespace FlaxEngine } } + /// + /// Gets the aspect ratio used by the viewport. + /// + public float AspectRatio => !Mathf.IsZero(Height) ? Width / Height : 0f; + /// /// Determines whether the specified is equal to this instance. /// @@ -326,21 +331,5 @@ namespace FlaxEngine vector /= w; } } - - /// - /// Gets the aspect ratio used by the viewport. - /// - /// The aspect ratio. - public float AspectRatio - { - get - { - if (!Mathf.IsZero(Height)) - { - return Width / Height; - } - return 0f; - } - } } } diff --git a/Source/Engine/Core/Types/BaseTypes.h b/Source/Engine/Core/Types/BaseTypes.h index 9db3020e1..b766d42ec 100644 --- a/Source/Engine/Core/Types/BaseTypes.h +++ b/Source/Engine/Core/Types/BaseTypes.h @@ -164,5 +164,12 @@ constexpr bool EnumHasAllFlags(T value, T flags) return ((__underlying_type(T))value & (__underlying_type(T))flags) == (__underlying_type(T))flags; } +// Returns true if given enum value has none of enum flags set +template +constexpr bool EnumHasNoneFlags(T value, T flags) +{ + return ((__underlying_type(T))value & (__underlying_type(T))flags) == 0; +} + // Returns byte offset from the object pointer in vtable to the begin of the given inherited type implementation #define VTABLE_OFFSET(type, baseType) (((intptr)static_cast((type*)1))-1) diff --git a/Source/Engine/Debug/DebugDraw.cpp b/Source/Engine/Debug/DebugDraw.cpp index 0b58172ab..a1dfa0b61 100644 --- a/Source/Engine/Debug/DebugDraw.cpp +++ b/Source/Engine/Debug/DebugDraw.cpp @@ -140,13 +140,13 @@ struct PsData bool Create(GPUPipelineState::Description& desc) { - desc.DepthTestEnable = true; + desc.DepthEnable = true; desc.DepthWriteEnable = false; Depth = GPUDevice::Instance->CreatePipelineState(); if (Depth->Init(desc)) return true; - desc.DepthTestEnable = false; + desc.DepthEnable = false; NoDepthTest = GPUDevice::Instance->CreatePipelineState(); if (NoDepthTest->Init(desc)) return false; @@ -156,7 +156,7 @@ struct PsData NoDepthTestDepthWrite = GPUDevice::Instance->CreatePipelineState(); if (NoDepthTestDepthWrite->Init(desc)) return false; - desc.DepthTestEnable = true; + desc.DepthEnable = true; DepthWrite = GPUDevice::Instance->CreatePipelineState(); return DepthWrite->Init(desc); } diff --git a/Source/Engine/Foliage/Foliage.cpp b/Source/Engine/Foliage/Foliage.cpp index 97688e196..23a31ad89 100644 --- a/Source/Engine/Foliage/Foliage.cpp +++ b/Source/Engine/Foliage/Foliage.cpp @@ -1173,6 +1173,7 @@ void Foliage::Draw(RenderContext& renderContext) draw.Flags = GetStaticFlags(); draw.LODBias = 0; draw.ForcedLOD = -1; + draw.SortOrder = 0; draw.VertexColors = nullptr; draw.Lightmap = _scene->LightmapsData.GetReadyLightmap(instance.Lightmap.TextureIndex); draw.LightmapUVs = &instance.Lightmap.UVsArea; diff --git a/Source/Engine/Graphics/Enums.h b/Source/Engine/Graphics/Enums.h index 2bbef6085..7d9b5ceb3 100644 --- a/Source/Engine/Graphics/Enums.h +++ b/Source/Engine/Graphics/Enums.h @@ -514,7 +514,7 @@ public: API_FIELD(ReadOnly) static BlendingMode Additive; /// - /// Gets the alpha blending. + /// Gets the alpha blending. Source alpha controls the output color (0 - use destination color, 1 - use source color). /// API_FIELD(ReadOnly) static BlendingMode AlphaBlend; @@ -591,22 +591,22 @@ API_ENUM() enum class Quality : byte API_ENUM() enum class MaterialPostFxLocation : byte { /// - /// The after post processing pass using LDR input frame. + /// The 'after' post processing pass using LDR input frame. /// AfterPostProcessingPass = 0, /// - /// The before post processing pass using HDR input frame. + /// The 'before' post processing pass using HDR input frame. /// BeforePostProcessingPass = 1, /// - /// The before forward pass but after GBuffer with HDR input frame. + /// The 'before' forward pass but after GBuffer with HDR input frame. /// BeforeForwardPass = 2, /// - /// The after custom post effects. + /// The 'after' custom post effects. /// AfterCustomPostEffects = 3, @@ -620,6 +620,11 @@ API_ENUM() enum class MaterialPostFxLocation : byte /// AfterAntiAliasingPass = 5, + /// + /// The 'after' forward pass but before any post processing. + /// + AfterForwardPass = 6, + API_ENUM(Attributes="HideInEditor") MAX, }; @@ -635,7 +640,7 @@ API_ENUM() enum class PostProcessEffectLocation Default = 0, /// - ///The 'before' in-build PostFx pass (bloom, color grading, etc.). After Forward Pass (transparency) and fog effects. + /// The 'before' in-build PostFx pass (bloom, color grading, etc.). After Forward Pass (transparency) and fog effects. /// BeforePostProcessingPass = 1, @@ -659,6 +664,16 @@ API_ENUM() enum class PostProcessEffectLocation /// CustomUpscale = 5, + /// + /// The 'after' GBuffer rendering pass. Can be used to render custom geometry into GBuffer. Output is light buffer, single-target only (no output). + /// + AfterGBufferPass = 6, + + /// + /// The 'after' forward pass but before any post processing. + /// + AfterForwardPass = 7, + API_ENUM(Attributes="HideInEditor") MAX, }; @@ -874,7 +889,7 @@ API_ENUM() enum class ViewMode /// /// Frame rendering flags used to switch between graphics features. /// -API_ENUM(Attributes="Flags") enum class ViewFlags : int64 +API_ENUM(Attributes="Flags") enum class ViewFlags : uint64 { /// /// Nothing. @@ -1011,20 +1026,25 @@ API_ENUM(Attributes="Flags") enum class ViewFlags : int64 /// GlobalSDF = 1 << 25, + /// + /// Shows/hides the Sky/Skybox rendering. + /// + Sky = 1 << 26, + /// /// Default flags for Game. /// - DefaultGame = Reflections | DepthOfField | Fog | Decals | MotionBlur | SSR | AO | GI | DirectionalLights | PointLights | SpotLights | SkyLights | Shadows | SpecularLight | AntiAliasing | CustomPostProcess | Bloom | ToneMapping | EyeAdaptation | CameraArtifacts | LensFlares | ContactShadows | GlobalSDF, + DefaultGame = Reflections | DepthOfField | Fog | Decals | MotionBlur | SSR | AO | GI | DirectionalLights | PointLights | SpotLights | SkyLights | Shadows | SpecularLight | AntiAliasing | CustomPostProcess | Bloom | ToneMapping | EyeAdaptation | CameraArtifacts | LensFlares | ContactShadows | GlobalSDF | Sky, /// /// Default flags for Editor. /// - DefaultEditor = Reflections | Fog | Decals | DebugDraw | SSR | AO | GI | DirectionalLights | PointLights | SpotLights | SkyLights | Shadows | SpecularLight | AntiAliasing | CustomPostProcess | Bloom | ToneMapping | EyeAdaptation | CameraArtifacts | LensFlares | EditorSprites | ContactShadows | GlobalSDF, + DefaultEditor = Reflections | Fog | Decals | DebugDraw | SSR | AO | GI | DirectionalLights | PointLights | SpotLights | SkyLights | Shadows | SpecularLight | AntiAliasing | CustomPostProcess | Bloom | ToneMapping | EyeAdaptation | CameraArtifacts | LensFlares | EditorSprites | ContactShadows | GlobalSDF | Sky, /// /// Default flags for materials/models previews generating. /// - DefaultAssetPreview = Reflections | Decals | DirectionalLights | PointLights | SpotLights | SkyLights | SpecularLight | AntiAliasing | Bloom | ToneMapping | EyeAdaptation | CameraArtifacts | LensFlares | ContactShadows, + DefaultAssetPreview = Reflections | Decals | DirectionalLights | PointLights | SpotLights | SkyLights | SpecularLight | AntiAliasing | Bloom | ToneMapping | EyeAdaptation | CameraArtifacts | LensFlares | ContactShadows | Sky, }; DECLARE_ENUM_OPERATORS(ViewFlags); diff --git a/Source/Engine/Graphics/GPUContext.h b/Source/Engine/Graphics/GPUContext.h index 593282555..99a226193 100644 --- a/Source/Engine/Graphics/GPUContext.h +++ b/Source/Engine/Graphics/GPUContext.h @@ -315,6 +315,12 @@ public: /// The array with render targets to bind. API_FUNCTION() virtual void SetRenderTarget(GPUTextureView* depthBuffer, const Span& rts) = 0; + /// + /// Sets the blend factor that modulate values for a pixel shader, render target, or both. + /// + /// Blend factors, one for each RGBA component. + API_FUNCTION() virtual void SetBlendFactor(const Float4& value) = 0; + public: /// /// Unbinds all shader resource slots and flushes the change with the driver (used to prevent driver detection of resource hazards, eg. when down-scaling the texture). diff --git a/Source/Engine/Graphics/GPUDevice.cpp b/Source/Engine/Graphics/GPUDevice.cpp index 1c3ade229..fe7c59e3a 100644 --- a/Source/Engine/Graphics/GPUDevice.cpp +++ b/Source/Engine/Graphics/GPUDevice.cpp @@ -76,7 +76,7 @@ bool GPUPipelineState::Init(const Description& desc) Complexity += tessCost; if (desc.DepthWriteEnable) Complexity += 5; - if (desc.DepthTestEnable) + if (desc.DepthEnable) Complexity += 5; if (desc.BlendMode.BlendEnable) Complexity += 20; diff --git a/Source/Engine/Graphics/GPUDevice.h b/Source/Engine/Graphics/GPUDevice.h index 37fc8cb87..4dbcf6d06 100644 --- a/Source/Engine/Graphics/GPUDevice.h +++ b/Source/Engine/Graphics/GPUDevice.h @@ -134,7 +134,7 @@ public: /// /// Quad rendering shader /// - GPUShader* QuadShader; + API_FIELD(ReadOnly) GPUShader* QuadShader; /// /// The current task being executed. diff --git a/Source/Engine/Graphics/GPUPipelineState.h b/Source/Engine/Graphics/GPUPipelineState.h index a8f9c449b..647d8da04 100644 --- a/Source/Engine/Graphics/GPUPipelineState.h +++ b/Source/Engine/Graphics/GPUPipelineState.h @@ -24,16 +24,16 @@ public: { DECLARE_SCRIPTING_TYPE_NO_SPAWN(Description); + /// + /// Enable/disable depth (DepthFunc and DepthWriteEnable) + /// + API_FIELD() bool DepthEnable; + /// /// Enable/disable depth write /// API_FIELD() bool DepthWriteEnable; - /// - /// Enable/disable depth test - /// - API_FIELD() bool DepthTestEnable; - /// /// Enable/disable depth clipping /// diff --git a/Source/Engine/Graphics/Materials/DeferredMaterialShader.cpp b/Source/Engine/Graphics/Materials/DeferredMaterialShader.cpp index 9e5f43957..52a0bd551 100644 --- a/Source/Engine/Graphics/Materials/DeferredMaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/DeferredMaterialShader.cpp @@ -137,8 +137,13 @@ void DeferredMaterialShader::Unload() bool DeferredMaterialShader::Load() { auto psDesc = GPUPipelineState::Description::Default; - psDesc.DepthTestEnable = (_info.FeaturesFlags & MaterialFeaturesFlags::DisableDepthTest) == MaterialFeaturesFlags::None; psDesc.DepthWriteEnable = (_info.FeaturesFlags & MaterialFeaturesFlags::DisableDepthWrite) == MaterialFeaturesFlags::None; + if (EnumHasAnyFlags(_info.FeaturesFlags, MaterialFeaturesFlags::DisableDepthTest)) + { + psDesc.DepthFunc = ComparisonFunc::Always; + if (!psDesc.DepthWriteEnable) + psDesc.DepthEnable = false; + } // Check if use tessellation (both material and runtime supports it) const bool useTess = _info.TessellationMode != TessellationMethod::None && GPUDevice::Instance->Limits.HasTessellation; @@ -183,7 +188,7 @@ bool DeferredMaterialShader::Load() // Motion Vectors pass psDesc.DepthWriteEnable = false; - psDesc.DepthTestEnable = true; + psDesc.DepthEnable = true; psDesc.DepthFunc = ComparisonFunc::LessEqual; psDesc.VS = _shader->GetVS("VS"); psDesc.PS = _shader->GetPS("PS_MotionVectors"); @@ -201,7 +206,7 @@ bool DeferredMaterialShader::Load() psDesc.CullMode = CullMode::TwoSided; psDesc.DepthClipEnable = false; psDesc.DepthWriteEnable = true; - psDesc.DepthTestEnable = true; + psDesc.DepthEnable = true; psDesc.DepthFunc = ComparisonFunc::Less; psDesc.HS = nullptr; psDesc.DS = nullptr; diff --git a/Source/Engine/Graphics/Materials/DeformableMaterialShader.cpp b/Source/Engine/Graphics/Materials/DeformableMaterialShader.cpp index 83bfc457b..24775241b 100644 --- a/Source/Engine/Graphics/Materials/DeformableMaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/DeformableMaterialShader.cpp @@ -112,7 +112,7 @@ bool DeformableMaterialShader::Load() { _drawModes = DrawPass::Depth | DrawPass::QuadOverdraw; auto psDesc = GPUPipelineState::Description::Default; - psDesc.DepthTestEnable = (_info.FeaturesFlags & MaterialFeaturesFlags::DisableDepthTest) == MaterialFeaturesFlags::None; + psDesc.DepthEnable = (_info.FeaturesFlags & MaterialFeaturesFlags::DisableDepthTest) == MaterialFeaturesFlags::None; psDesc.DepthWriteEnable = (_info.FeaturesFlags & MaterialFeaturesFlags::DisableDepthWrite) == MaterialFeaturesFlags::None; // Check if use tessellation (both material and runtime supports it) @@ -170,7 +170,7 @@ bool DeformableMaterialShader::Load() psDesc.CullMode = CullMode::TwoSided; psDesc.DepthClipEnable = false; psDesc.DepthWriteEnable = true; - psDesc.DepthTestEnable = true; + psDesc.DepthEnable = true; psDesc.DepthFunc = ComparisonFunc::Less; psDesc.HS = nullptr; psDesc.DS = nullptr; diff --git a/Source/Engine/Graphics/Materials/ForwardMaterialShader.cpp b/Source/Engine/Graphics/Materials/ForwardMaterialShader.cpp index a1646a154..d391f3295 100644 --- a/Source/Engine/Graphics/Materials/ForwardMaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/ForwardMaterialShader.cpp @@ -130,7 +130,7 @@ bool ForwardMaterialShader::Load() _drawModes = DrawPass::Depth | DrawPass::Forward | DrawPass::QuadOverdraw; auto psDesc = GPUPipelineState::Description::Default; - psDesc.DepthTestEnable = (_info.FeaturesFlags & MaterialFeaturesFlags::DisableDepthTest) == MaterialFeaturesFlags::None; + psDesc.DepthEnable = (_info.FeaturesFlags & MaterialFeaturesFlags::DisableDepthTest) == MaterialFeaturesFlags::None; psDesc.DepthWriteEnable = (_info.FeaturesFlags & MaterialFeaturesFlags::DisableDepthWrite) == MaterialFeaturesFlags::None; // Check if use tessellation (both material and runtime supports it) @@ -200,7 +200,7 @@ bool ForwardMaterialShader::Load() psDesc.CullMode = CullMode::TwoSided; psDesc.DepthClipEnable = false; psDesc.DepthWriteEnable = true; - psDesc.DepthTestEnable = true; + psDesc.DepthEnable = true; psDesc.DepthFunc = ComparisonFunc::Less; psDesc.HS = nullptr; psDesc.DS = nullptr; diff --git a/Source/Engine/Graphics/Materials/GUIMaterialShader.cpp b/Source/Engine/Graphics/Materials/GUIMaterialShader.cpp index 795d16311..17be156bb 100644 --- a/Source/Engine/Graphics/Materials/GUIMaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/GUIMaterialShader.cpp @@ -89,13 +89,13 @@ bool GUIMaterialShader::Load() psDesc0.PS = _shader->GetPS("PS_GUI"); psDesc0.BlendMode = BlendingMode::AlphaBlend; - psDesc0.DepthTestEnable = psDesc0.DepthWriteEnable = true; + psDesc0.DepthEnable = psDesc0.DepthWriteEnable = true; _cache.Depth = GPUDevice::Instance->CreatePipelineState(); _cache.NoDepth = GPUDevice::Instance->CreatePipelineState(); bool failed = _cache.Depth->Init(psDesc0); - psDesc0.DepthTestEnable = psDesc0.DepthWriteEnable = false; + psDesc0.DepthEnable = psDesc0.DepthWriteEnable = false; failed |= _cache.NoDepth->Init(psDesc0); if (failed) diff --git a/Source/Engine/Graphics/Materials/MaterialShader.h b/Source/Engine/Graphics/Materials/MaterialShader.h index 007afee67..be6a58741 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 159 +#define MATERIAL_GRAPH_VERSION 161 class Material; class GPUShader; diff --git a/Source/Engine/Graphics/Materials/ParticleMaterialShader.cpp b/Source/Engine/Graphics/Materials/ParticleMaterialShader.cpp index 43dd9d447..8cf8299e9 100644 --- a/Source/Engine/Graphics/Materials/ParticleMaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/ParticleMaterialShader.cpp @@ -154,9 +154,6 @@ void ParticleMaterialShader::Bind(BindParameters& params) materialData->RibbonUVOffset.Y = drawCall.Particle.Ribbon.UVOffsetY; materialData->RibbonSegmentCount = drawCall.Particle.Ribbon.SegmentCount; - if (drawCall.Particle.Ribbon.SegmentDistances) - context->BindSR(1, drawCall.Particle.Ribbon.SegmentDistances->View()); - break; } } @@ -189,7 +186,7 @@ bool ParticleMaterialShader::Load() { _drawModes = DrawPass::Depth | DrawPass::Forward | DrawPass::QuadOverdraw; GPUPipelineState::Description psDesc = GPUPipelineState::Description::Default; - psDesc.DepthTestEnable = (_info.FeaturesFlags & MaterialFeaturesFlags::DisableDepthTest) == MaterialFeaturesFlags::None; + psDesc.DepthEnable = (_info.FeaturesFlags & MaterialFeaturesFlags::DisableDepthTest) == MaterialFeaturesFlags::None; psDesc.DepthWriteEnable = (_info.FeaturesFlags & MaterialFeaturesFlags::DisableDepthWrite) == MaterialFeaturesFlags::None; auto vsSprite = _shader->GetVS("VS_Sprite"); diff --git a/Source/Engine/Graphics/Materials/TerrainMaterialShader.cpp b/Source/Engine/Graphics/Materials/TerrainMaterialShader.cpp index 7c25a12fc..575f71b34 100644 --- a/Source/Engine/Graphics/Materials/TerrainMaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/TerrainMaterialShader.cpp @@ -133,7 +133,7 @@ void TerrainMaterialShader::Unload() bool TerrainMaterialShader::Load() { GPUPipelineState::Description psDesc = GPUPipelineState::Description::Default; - psDesc.DepthTestEnable = (_info.FeaturesFlags & MaterialFeaturesFlags::DisableDepthTest) == MaterialFeaturesFlags::None; + psDesc.DepthEnable = (_info.FeaturesFlags & MaterialFeaturesFlags::DisableDepthTest) == MaterialFeaturesFlags::None; psDesc.DepthWriteEnable = (_info.FeaturesFlags & MaterialFeaturesFlags::DisableDepthWrite) == MaterialFeaturesFlags::None; // Check if use tessellation (both material and runtime supports it) @@ -182,7 +182,7 @@ bool TerrainMaterialShader::Load() psDesc.BlendMode = BlendingMode::Opaque; psDesc.DepthClipEnable = false; psDesc.DepthWriteEnable = true; - psDesc.DepthTestEnable = true; + psDesc.DepthEnable = true; psDesc.DepthFunc = ComparisonFunc::Less; psDesc.HS = nullptr; psDesc.DS = nullptr; diff --git a/Source/Engine/Graphics/Models/Mesh.cpp b/Source/Engine/Graphics/Models/Mesh.cpp index 9dfcd72e8..7b0130874 100644 --- a/Source/Engine/Graphics/Models/Mesh.cpp +++ b/Source/Engine/Graphics/Models/Mesh.cpp @@ -408,7 +408,7 @@ void Mesh::Render(GPUContext* context) const context->DrawIndexedInstanced(_triangles * 3, 1, 0, 0, 0); } -void Mesh::Draw(const RenderContext& renderContext, MaterialBase* material, const Matrix& world, StaticFlags flags, bool receiveDecals, DrawPass drawModes, float perInstanceRandom) const +void Mesh::Draw(const RenderContext& renderContext, MaterialBase* material, const Matrix& world, StaticFlags flags, bool receiveDecals, DrawPass drawModes, float perInstanceRandom, int16 sortOrder) const { if (!material || !material->IsSurface() || !IsInitialized()) return; @@ -446,7 +446,7 @@ void Mesh::Draw(const RenderContext& renderContext, MaterialBase* material, cons #endif // Push draw call to the render list - renderContext.List->AddDrawCall(renderContext, drawModes, flags, drawCall, receiveDecals); + renderContext.List->AddDrawCall(renderContext, drawModes, flags, drawCall, receiveDecals, sortOrder); } void Mesh::Draw(const RenderContext& renderContext, const DrawInfo& info, float lodDitherFactor) const @@ -512,7 +512,7 @@ void Mesh::Draw(const RenderContext& renderContext, const DrawInfo& info, float #endif // Push draw call to the render list - renderContext.List->AddDrawCall(renderContext, drawModes, info.Flags, drawCall, entry.ReceiveDecals); + renderContext.List->AddDrawCall(renderContext, drawModes, info.Flags, drawCall, entry.ReceiveDecals, info.SortOrder); } void Mesh::Draw(const RenderContextBatch& renderContextBatch, const DrawInfo& info, float lodDitherFactor) const @@ -575,7 +575,7 @@ void Mesh::Draw(const RenderContextBatch& renderContextBatch, const DrawInfo& in const auto shadowsMode = entry.ShadowsMode & slot.ShadowsMode; const auto drawModes = info.DrawModes & material->GetDrawModes(); if (drawModes != DrawPass::None) - renderContextBatch.GetMainContext().List->AddDrawCall(renderContextBatch, drawModes, info.Flags, shadowsMode, info.Bounds, drawCall, entry.ReceiveDecals); + renderContextBatch.GetMainContext().List->AddDrawCall(renderContextBatch, drawModes, info.Flags, shadowsMode, info.Bounds, drawCall, entry.ReceiveDecals, info.SortOrder); } bool Mesh::DownloadDataGPU(MeshBufferType type, BytesContainer& result) const diff --git a/Source/Engine/Graphics/Models/Mesh.h b/Source/Engine/Graphics/Models/Mesh.h index cc112bbe8..ee16c16e3 100644 --- a/Source/Engine/Graphics/Models/Mesh.h +++ b/Source/Engine/Graphics/Models/Mesh.h @@ -6,14 +6,11 @@ #include "ModelInstanceEntry.h" #include "Config.h" #include "Types.h" -#include "Engine/Level/Types.h" #if USE_PRECISE_MESH_INTERSECTS #include "CollisionProxy.h" #endif -struct GeometryDrawStateData; class Lightmap; -class GPUBuffer; /// /// Represents part of the model that is made of vertices and can be rendered using custom material and transformation. @@ -275,72 +272,6 @@ public: /// The draw call. void GetDrawCallGeometry(DrawCall& drawCall) const; - /// - /// Model instance drawing packed data. - /// - struct DrawInfo - { - /// - /// The instance buffer to use during model rendering. - /// - ModelInstanceEntries* Buffer; - - /// - /// The world transformation of the model. - /// - Matrix* World; - - /// - /// The instance drawing state data container. Used for LOD transition handling and previous world transformation matrix updating. - /// - GeometryDrawStateData* DrawState; - - /// - /// The lightmap. - /// - const Lightmap* Lightmap; - - /// - /// The lightmap UVs. - /// - const Rectangle* LightmapUVs; - - /// - /// The model instance vertex colors buffers (per-lod all meshes packed in a single allocation, array length equal to model lods count). - /// - GPUBuffer** VertexColors; - - /// - /// The object static flags. - /// - StaticFlags Flags; - - /// - /// The object draw modes. - /// - DrawPass DrawModes; - - /// - /// The bounds of the model (used to select a proper LOD during rendering). - /// - BoundingSphere Bounds; - - /// - /// The per-instance random value. - /// - float PerInstanceRandom; - - /// - /// The LOD bias value. - /// - char LODBias; - - /// - /// The forced LOD to use. Value -1 disables this feature. - /// - char ForcedLOD; - }; - /// /// Draws the mesh. Binds vertex and index buffers and invokes the draw call. /// @@ -357,7 +288,8 @@ public: /// True if rendered geometry can receive decals, otherwise false. /// The draw passes to use for rendering this object. /// The random per-instance value (normalized to range 0-1). - API_FUNCTION() void Draw(API_PARAM(Ref) const RenderContext& renderContext, MaterialBase* material, API_PARAM(Ref) const Matrix& world, StaticFlags flags = StaticFlags::None, bool receiveDecals = true, DrawPass drawModes = DrawPass::Default, float perInstanceRandom = 0.0f) const; + /// Object sorting key. + API_FUNCTION() void Draw(API_PARAM(Ref) const RenderContext& renderContext, MaterialBase* material, API_PARAM(Ref) const Matrix& world, StaticFlags flags = StaticFlags::None, bool receiveDecals = true, DrawPass drawModes = DrawPass::Default, float perInstanceRandom = 0.0f, int16 sortOrder = 0) const; /// /// Draws the mesh. diff --git a/Source/Engine/Graphics/Models/MeshBase.h b/Source/Engine/Graphics/Models/MeshBase.h index 8f2c80e20..0d07ec4ec 100644 --- a/Source/Engine/Graphics/Models/MeshBase.h +++ b/Source/Engine/Graphics/Models/MeshBase.h @@ -5,12 +5,20 @@ #include "Engine/Core/Math/BoundingBox.h" #include "Engine/Core/Math/BoundingSphere.h" #include "Engine/Core/Types/DataContainer.h" +#include "Engine/Graphics/Enums.h" #include "Engine/Graphics/Models/Types.h" +#include "Engine/Level/Types.h" #include "Engine/Scripting/ScriptingObject.h" +struct GeometryDrawStateData; +struct RenderContext; +struct RenderContextBatch; class Task; class ModelBase; -struct RenderContextBatch; +class Lightmap; +class GPUBuffer; +class SkinnedMeshDrawData; +class BlendShapesInstance; /// /// Base class for model resources meshes. @@ -143,4 +151,95 @@ public: /// The amount of items inside the result buffer. /// True if failed, otherwise false virtual bool DownloadDataCPU(MeshBufferType type, BytesContainer& result, int32& count) const = 0; + +public: + /// + /// Model instance drawing packed data. + /// + struct DrawInfo + { + /// + /// The instance buffer to use during model rendering + /// + ModelInstanceEntries* Buffer; + + /// + /// The world transformation of the model. + /// + Matrix* World; + + /// + /// The instance drawing state data container. Used for LOD transition handling and previous world transformation matrix updating. + /// + GeometryDrawStateData* DrawState; + + union + { + struct + { + /// + /// The skinning. + /// + SkinnedMeshDrawData* Skinning; + + /// + /// The blend shapes. + /// + BlendShapesInstance* BlendShapes; + }; + + struct + { + /// + /// The lightmap. + /// + const Lightmap* Lightmap; + + /// + /// The lightmap UVs. + /// + const Rectangle* LightmapUVs; + }; + }; + + /// + /// The model instance vertex colors buffers (per-lod all meshes packed in a single allocation, array length equal to model lods count). + /// + GPUBuffer** VertexColors; + + /// + /// The object static flags. + /// + StaticFlags Flags; + + /// + /// The object draw modes. + /// + DrawPass DrawModes; + + /// + /// The bounds of the model (used to select a proper LOD during rendering). + /// + BoundingSphere Bounds; + + /// + /// The per-instance random value. + /// + float PerInstanceRandom; + + /// + /// The LOD bias value. + /// + char LODBias; + + /// + /// The forced LOD to use. Value -1 disables this feature. + /// + char ForcedLOD; + + /// + /// The object sorting key. + /// + int16 SortOrder; + }; }; diff --git a/Source/Engine/Graphics/Models/ModelLOD.h b/Source/Engine/Graphics/Models/ModelLOD.h index 4a452129d..c6cd33976 100644 --- a/Source/Engine/Graphics/Models/ModelLOD.h +++ b/Source/Engine/Graphics/Models/ModelLOD.h @@ -124,9 +124,7 @@ public: FORCE_INLINE void Render(GPUContext* context) { for (int32 i = 0; i < Meshes.Count(); i++) - { Meshes.Get()[i].Render(context); - } } /// @@ -139,12 +137,11 @@ public: /// True if rendered geometry can receive decals, otherwise false. /// The draw passes to use for rendering this object. /// The random per-instance value (normalized to range 0-1). - API_FUNCTION() void Draw(API_PARAM(Ref) const RenderContext& renderContext, MaterialBase* material, API_PARAM(Ref) const Matrix& world, StaticFlags flags = StaticFlags::None, bool receiveDecals = true, DrawPass drawModes = DrawPass::Default, float perInstanceRandom = 0.0f) const + /// Object sorting key. + API_FUNCTION() void Draw(API_PARAM(Ref) const RenderContext& renderContext, MaterialBase* material, API_PARAM(Ref) const Matrix& world, StaticFlags flags = StaticFlags::None, bool receiveDecals = true, DrawPass drawModes = DrawPass::Default, float perInstanceRandom = 0.0f, int16 sortOrder = 0) const { for (int32 i = 0; i < Meshes.Count(); i++) - { - Meshes.Get()[i].Draw(renderContext, material, world, flags, receiveDecals, drawModes, perInstanceRandom); - } + Meshes.Get()[i].Draw(renderContext, material, world, flags, receiveDecals, drawModes, perInstanceRandom, sortOrder); } /// @@ -156,9 +153,7 @@ public: FORCE_INLINE void Draw(const RenderContext& renderContext, const Mesh::DrawInfo& info, float lodDitherFactor) const { for (int32 i = 0; i < Meshes.Count(); i++) - { Meshes.Get()[i].Draw(renderContext, info, lodDitherFactor); - } } /// @@ -170,8 +165,6 @@ public: FORCE_INLINE void Draw(const RenderContextBatch& renderContextBatch, const Mesh::DrawInfo& info, float lodDitherFactor) const { for (int32 i = 0; i < Meshes.Count(); i++) - { Meshes.Get()[i].Draw(renderContextBatch, info, lodDitherFactor); - } } }; diff --git a/Source/Engine/Graphics/Models/SkinnedMesh.cpp b/Source/Engine/Graphics/Models/SkinnedMesh.cpp index 979d9e250..89db8ff8b 100644 --- a/Source/Engine/Graphics/Models/SkinnedMesh.cpp +++ b/Source/Engine/Graphics/Models/SkinnedMesh.cpp @@ -119,28 +119,22 @@ bool SkinnedMesh::UpdateMesh(uint32 vertexCount, uint32 triangleCount, VB0Skinne bool SkinnedMesh::Intersects(const Ray& ray, const Matrix& world, Real& distance, Vector3& normal) const { // Transform points - Vector3 min, max; - Vector3::Transform(_box.Minimum, world, min); - Vector3::Transform(_box.Maximum, world, max); + BoundingBox transformedBox; + Vector3::Transform(_box.Minimum, world, transformedBox.Minimum); + Vector3::Transform(_box.Maximum, world, transformedBox.Maximum); - // Get transformed box - BoundingBox transformedBox(min, max); - - // Test ray on a box + // Test ray on a transformed box return transformedBox.Intersects(ray, distance, normal); } bool SkinnedMesh::Intersects(const Ray& ray, const Transform& transform, Real& distance, Vector3& normal) const { // Transform points - Vector3 min, max; - transform.LocalToWorld(_box.Minimum, min); - transform.LocalToWorld(_box.Maximum, max); + BoundingBox transformedBox; + transform.LocalToWorld(_box.Minimum, transformedBox.Minimum); + transform.LocalToWorld(_box.Maximum, transformedBox.Maximum); - // Get transformed box - BoundingBox transformedBox(min, max); - - // Test ray on a box + // Test ray on a transformed box return transformedBox.Intersects(ray, distance, normal); } @@ -216,7 +210,7 @@ void SkinnedMesh::Draw(const RenderContext& renderContext, const DrawInfo& info, drawCall.PerInstanceRandom = info.PerInstanceRandom; // Push draw call to the render list - renderContext.List->AddDrawCall(renderContext, drawModes, StaticFlags::None, drawCall, entry.ReceiveDecals); + renderContext.List->AddDrawCall(renderContext, drawModes, StaticFlags::None, drawCall, entry.ReceiveDecals, info.SortOrder); } void SkinnedMesh::Draw(const RenderContextBatch& renderContextBatch, const DrawInfo& info, float lodDitherFactor) const @@ -279,7 +273,7 @@ void SkinnedMesh::Draw(const RenderContextBatch& renderContextBatch, const DrawI const auto shadowsMode = entry.ShadowsMode & slot.ShadowsMode; const auto drawModes = info.DrawModes & material->GetDrawModes(); if (drawModes != DrawPass::None) - renderContextBatch.GetMainContext().List->AddDrawCall(renderContextBatch, drawModes, StaticFlags::None, shadowsMode, info.Bounds, drawCall, entry.ReceiveDecals); + renderContextBatch.GetMainContext().List->AddDrawCall(renderContextBatch, drawModes, StaticFlags::None, shadowsMode, info.Bounds, drawCall, entry.ReceiveDecals, info.SortOrder); } bool SkinnedMesh::DownloadDataGPU(MeshBufferType type, BytesContainer& result) const diff --git a/Source/Engine/Graphics/Models/SkinnedMesh.h b/Source/Engine/Graphics/Models/SkinnedMesh.h index c4893c8ac..8bf957554 100644 --- a/Source/Engine/Graphics/Models/SkinnedMesh.h +++ b/Source/Engine/Graphics/Models/SkinnedMesh.h @@ -6,11 +6,6 @@ #include "Types.h" #include "BlendShape.h" -struct GeometryDrawStateData; -struct RenderContext; -class GPUBuffer; -class SkinnedMeshDrawData; - /// /// Represents part of the skinned model that is made of vertices and can be rendered using custom material, transformation and skeleton bones hierarchy. /// @@ -170,62 +165,6 @@ public: } public: - /// - /// Model instance drawing packed data. - /// - struct DrawInfo - { - /// - /// The instance buffer to use during model rendering - /// - ModelInstanceEntries* Buffer; - - /// - /// The skinning. - /// - SkinnedMeshDrawData* Skinning; - - /// - /// The blend shapes. - /// - BlendShapesInstance* BlendShapes; - - /// - /// The world transformation of the model. - /// - Matrix* World; - - /// - /// The instance drawing state data container. Used for LOD transition handling and previous world transformation matrix updating. - /// - GeometryDrawStateData* DrawState; - - /// - /// The object draw modes. - /// - DrawPass DrawModes; - - /// - /// The bounds of the model (used to select a proper LOD during rendering). - /// - BoundingSphere Bounds; - - /// - /// The per-instance random value. - /// - float PerInstanceRandom; - - /// - /// The LOD bias value. - /// - char LODBias; - - /// - /// The forced LOD to use. Value -1 disables this feature. - /// - char ForcedLOD; - }; - /// /// Draws the mesh. Binds vertex and index buffers and invokes the draw call. /// diff --git a/Source/Engine/Graphics/RenderBuffers.cpp b/Source/Engine/Graphics/RenderBuffers.cpp index 32d0d1848..e0f4869ad 100644 --- a/Source/Engine/Graphics/RenderBuffers.cpp +++ b/Source/Engine/Graphics/RenderBuffers.cpp @@ -128,6 +128,8 @@ void RenderBuffers::SetUseAlpha(bool value) const RenderBuffers::CustomBuffer* RenderBuffers::FindCustomBuffer(const StringView& name) const { + if (LinkedCustomBuffers) + return LinkedCustomBuffers->FindCustomBuffer(name); for (const CustomBuffer* e : CustomBuffers) { if (e->Name == name) @@ -196,6 +198,7 @@ bool RenderBuffers::Init(int32 width, int32 height) void RenderBuffers::Release() { LastEyeAdaptationTime = 0; + LinkedCustomBuffers = nullptr; for (int32 i = 0; i < _resources.Count(); i++) _resources[i]->ReleaseGPU(); diff --git a/Source/Engine/Graphics/RenderBuffers.h b/Source/Engine/Graphics/RenderBuffers.h index 86a621afc..4010760c9 100644 --- a/Source/Engine/Graphics/RenderBuffers.h +++ b/Source/Engine/Graphics/RenderBuffers.h @@ -45,10 +45,14 @@ public: { struct { - GPUTexture* GBuffer0; - GPUTexture* GBuffer1; - GPUTexture* GBuffer2; - GPUTexture* GBuffer3; + /// Gets the GBuffer texture 0. RGB: Color, A: AO + API_FIELD(ReadOnly) GPUTexture* GBuffer0; + /// Gets the GBuffer texture 1. RGB: Normal, A: ShadingModel + API_FIELD(ReadOnly) GPUTexture* GBuffer1; + /// Gets the GBuffer texture 2. R: Roughness, G: Metalness, B:Specular + API_FIELD(ReadOnly) GPUTexture* GBuffer2; + /// Gets the GBuffer texture 3. RGBA: Custom Data + API_FIELD(ReadOnly) GPUTexture* GBuffer3; }; GPUTexture* GBuffer[4]; @@ -174,6 +178,8 @@ public: template T* GetCustomBuffer(const StringView& name) { + if (LinkedCustomBuffers) + return LinkedCustomBuffers->GetCustomBuffer(name); CustomBuffer* result = (CustomBuffer*)FindCustomBuffer(name); if (!result) { @@ -202,6 +208,11 @@ public: /// API_FIELD(ReadOnly) GPUTexture* MotionVectors; + /// + /// External Render Buffers used to redirect FindCustomBuffer/GetCustomBuffer calls. Can be linked to other rendering task (eg. main game viewport) to reuse graphics effect state from it (eg. use GI from main game view in in-game camera renderer). + /// + API_FIELD() RenderBuffers* LinkedCustomBuffers = nullptr; + public: /// /// Allocates the buffers. diff --git a/Source/Engine/Graphics/RenderTask.cpp b/Source/Engine/Graphics/RenderTask.cpp index 59b29e893..e10f4b6f5 100644 --- a/Source/Engine/Graphics/RenderTask.cpp +++ b/Source/Engine/Graphics/RenderTask.cpp @@ -154,7 +154,7 @@ void SceneRenderTask::CameraCut() void SceneRenderTask::AddCustomActor(Actor* actor) { - CustomActors.Add(actor); + CustomActors.AddUnique(actor); } void SceneRenderTask::RemoveCustomActor(Actor* actor) @@ -169,7 +169,7 @@ void SceneRenderTask::ClearCustomActors() void SceneRenderTask::AddCustomPostFx(PostProcessEffect* fx) { - CustomPostFx.Add(fx); + CustomPostFx.AddUnique(fx); } void SceneRenderTask::RemoveCustomPostFx(PostProcessEffect* fx) @@ -179,7 +179,7 @@ void SceneRenderTask::RemoveCustomPostFx(PostProcessEffect* fx) void SceneRenderTask::AddGlobalCustomPostFx(PostProcessEffect* fx) { - GlobalCustomPostFx.Add(fx); + GlobalCustomPostFx.AddUnique(fx); } void SceneRenderTask::RemoveGlobalCustomPostFx(PostProcessEffect* fx) diff --git a/Source/Engine/Graphics/RenderTools.cpp b/Source/Engine/Graphics/RenderTools.cpp index 67cbce85b..8389e5d3c 100644 --- a/Source/Engine/Graphics/RenderTools.cpp +++ b/Source/Engine/Graphics/RenderTools.cpp @@ -181,116 +181,75 @@ uint32 GetHash(const BlendingMode& key) return hash; } +// @formatter:off + BlendingMode BlendingMode::Opaque = { - false, - // AlphaToCoverageEnable - false, - // BlendEnable - Blend::One, - // SrcBlend - Blend::Zero, - // DestBlend - Operation::Add, - // BlendOp - Blend::One, - // SrcBlendAlpha - Blend::Zero, - // DestBlendAlpha - Operation::Add, - // BlendOpAlpha - ColorWrite::All, - // RenderTargetWriteMask + false, // AlphaToCoverageEnable + false, // BlendEnable + Blend::One, // SrcBlend + Blend::Zero, // DestBlend + Operation::Add, // BlendOp + Blend::One, // SrcBlendAlpha + Blend::Zero, // DestBlendAlpha + Operation::Add, // BlendOpAlpha + ColorWrite::All, // RenderTargetWriteMask }; BlendingMode BlendingMode::Additive = { - false, - // AlphaToCoverageEnable - true, - // BlendEnable - Blend::SrcAlpha, - // SrcBlend - Blend::One, - // DestBlend - Operation::Add, - // BlendOp - Blend::SrcAlpha, - // SrcBlendAlpha - Blend::One, - // DestBlendAlpha - Operation::Add, - // BlendOpAlpha - ColorWrite::All, - // RenderTargetWriteMask + false, // AlphaToCoverageEnable + true, // BlendEnable + Blend::SrcAlpha, // SrcBlend + Blend::One, // DestBlend + Operation::Add, // BlendOp + Blend::SrcAlpha, // SrcBlendAlpha + Blend::One, // DestBlendAlpha + Operation::Add, // BlendOpAlpha + ColorWrite::All, // RenderTargetWriteMask }; BlendingMode BlendingMode::AlphaBlend = { - false, - // AlphaToCoverageEnable - true, - // BlendEnable - Blend::SrcAlpha, - // SrcBlend - Blend::InvSrcAlpha, - // DestBlend - Operation::Add, - // BlendOp - Blend::One, - // SrcBlendAlpha - Blend::InvSrcAlpha, - // DestBlendAlpha - Operation::Add, - // BlendOpAlpha - ColorWrite::All, - // RenderTargetWriteMask + false, // AlphaToCoverageEnable + true, // BlendEnable + Blend::SrcAlpha, // SrcBlend + Blend::InvSrcAlpha, // DestBlend + Operation::Add, // BlendOp + Blend::One, // SrcBlendAlpha + Blend::InvSrcAlpha, // DestBlendAlpha + Operation::Add, // BlendOpAlpha + ColorWrite::All, // RenderTargetWriteMask }; BlendingMode BlendingMode::Add = { - false, - // AlphaToCoverageEnable - true, - // BlendEnable - Blend::One, - // SrcBlend - Blend::One, - // DestBlend - Operation::Add, - // BlendOp - Blend::One, - // SrcBlendAlpha - Blend::One, - // DestBlendAlpha - Operation::Add, - // BlendOpAlpha - ColorWrite::All, - // RenderTargetWriteMask + false, // AlphaToCoverageEnable + true, // BlendEnable + Blend::One, // SrcBlend + Blend::One, // DestBlend + Operation::Add, // BlendOp + Blend::One, // SrcBlendAlpha + Blend::One, // DestBlendAlpha + Operation::Add, // BlendOpAlpha + ColorWrite::All, // RenderTargetWriteMask }; BlendingMode BlendingMode::Multiply = { - false, - // AlphaToCoverageEnable - true, - // BlendEnable - Blend::Zero, - // SrcBlend - Blend::SrcColor, - // DestBlend - Operation::Add, - // BlendOp - Blend::Zero, - // SrcBlendAlpha - Blend::SrcAlpha, - // DestBlendAlpha - Operation::Add, - // BlendOpAlpha - ColorWrite::All, - // RenderTargetWriteMask + false, // AlphaToCoverageEnable + true, // BlendEnable + Blend::Zero, // SrcBlend + Blend::SrcColor, // DestBlend + Operation::Add, // BlendOp + Blend::Zero, // SrcBlendAlpha + Blend::SrcAlpha, // DestBlendAlpha + Operation::Add, // BlendOpAlpha + ColorWrite::All, // RenderTargetWriteMask }; +// @formatter:on + FeatureLevel RenderTools::GetFeatureLevel(ShaderProfile profile) { switch (profile) diff --git a/Source/Engine/Graphics/RenderView.cpp b/Source/Engine/Graphics/RenderView.cpp index 736609e0c..baa5d5058 100644 --- a/Source/Engine/Graphics/RenderView.cpp +++ b/Source/Engine/Graphics/RenderView.cpp @@ -84,6 +84,14 @@ void RenderView::PrepareCache(const RenderContext& renderContext, float width, f MainScreenSize = mainView->ScreenSize; } +void RenderView::SetUp(const Matrix& viewProjection) +{ + // Copy data + Matrix::Invert(viewProjection, IVP); + Frustum.SetMatrix(viewProjection); + CullingFrustum = Frustum; +} + void RenderView::SetUp(const Matrix& view, const Matrix& projection) { // Copy data diff --git a/Source/Engine/Graphics/RenderView.h b/Source/Engine/Graphics/RenderView.h index d64e05d4b..52e317a51 100644 --- a/Source/Engine/Graphics/RenderView.h +++ b/Source/Engine/Graphics/RenderView.h @@ -255,13 +255,7 @@ public: public: // Set up view with custom params // @param viewProjection View * Projection matrix - void SetUp(const Matrix& viewProjection) - { - // Copy data - Matrix::Invert(viewProjection, IVP); - Frustum.SetMatrix(viewProjection); - CullingFrustum = Frustum; - } + void SetUp(const Matrix& viewProjection); // Set up view with custom params // @param view View matrix diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUContextDX11.cpp b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUContextDX11.cpp index 06f666e12..10d85c179 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUContextDX11.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUContextDX11.cpp @@ -103,6 +103,7 @@ void GPUContextDX11::FrameBegin() CurrentPS = nullptr; CurrentCS = nullptr; CurrentPrimitiveTopology = D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED; + CurrentBlendFactor = Float4::One; // Bind static samplers ID3D11SamplerState* samplers[] = @@ -267,6 +268,13 @@ void GPUContextDX11::SetRenderTarget(GPUTextureView* depthBuffer, const SpanOMSetBlendState(CurrentBlendState, CurrentBlendFactor.Raw, D3D11_DEFAULT_SAMPLE_MASK); +} + void GPUContextDX11::ResetSR() { _srDirtyFlag = false; @@ -420,6 +428,7 @@ void GPUContextDX11::Dispatch(GPUShaderProgramCS* shader, uint32 threadGroupCoun void GPUContextDX11::DispatchIndirect(GPUShaderProgramCS* shader, GPUBuffer* bufferForArgs, uint32 offsetForArgs) { + ASSERT(bufferForArgs && EnumHasAnyFlags(bufferForArgs->GetFlags(), GPUBufferFlags::Argument)); CurrentCS = (GPUShaderProgramCSDX11*)shader; auto bufferForArgsDX11 = (GPUBufferDX11*)bufferForArgs; @@ -560,8 +569,7 @@ void GPUContextDX11::SetState(GPUPipelineState* state) if (CurrentBlendState != blendState) { CurrentBlendState = blendState; - FLOAT blendFactor[4] = { 1, 1, 1, 1 }; - _context->OMSetBlendState(blendState, blendFactor, D3D11_DEFAULT_SAMPLE_MASK); + _context->OMSetBlendState(blendState, CurrentBlendFactor.Raw, D3D11_DEFAULT_SAMPLE_MASK); } if (CurrentVS != vs) { diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUContextDX11.h b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUContextDX11.h index 209968fda..b623cba3b 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUContextDX11.h +++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUContextDX11.h @@ -61,6 +61,7 @@ private: GPUShaderProgramPSDX11* CurrentPS; GPUShaderProgramCSDX11* CurrentCS; D3D11_PRIMITIVE_TOPOLOGY CurrentPrimitiveTopology; + Float4 CurrentBlendFactor; public: @@ -115,6 +116,7 @@ public: void SetRenderTarget(GPUTextureView* rt) override; void SetRenderTarget(GPUTextureView* depthBuffer, GPUTextureView* rt) override; void SetRenderTarget(GPUTextureView* depthBuffer, const Span& rts) override; + void SetBlendFactor(const Float4& value) override; void ResetSR() override; void ResetUA() override; void ResetCB() override; diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUPipelineStateDX11.cpp b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUPipelineStateDX11.cpp index 97c1281a3..e3458fcae 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUPipelineStateDX11.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUPipelineStateDX11.cpp @@ -48,7 +48,7 @@ bool GPUPipelineStateDX11::Init(const Description& desc) PrimitiveTopology = (D3D11_PRIMITIVE_TOPOLOGY)((int32)D3D11_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST + (HS->GetControlPointsCount() - 1)); // States - DepthStencilStateIndex = static_cast(desc.DepthFunc) + (desc.DepthTestEnable ? 0 : 9) + (desc.DepthWriteEnable ? 0 : 18); + DepthStencilStateIndex = static_cast(desc.DepthFunc) + (desc.DepthEnable ? 0 : 9) + (desc.DepthWriteEnable ? 0 : 18); RasterizerStateIndex = static_cast(desc.CullMode) + (desc.Wireframe ? 0 : 3) + (desc.DepthClipEnable ? 0 : 6); BlendState = _device->GetBlendState(desc.BlendMode); diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUBufferDX12.cpp b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUBufferDX12.cpp index 0f389a9c3..5d2d97f0b 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUBufferDX12.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUBufferDX12.cpp @@ -111,7 +111,7 @@ bool GPUBufferDX12::OnInit() if (useUAV) resourceDesc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; #if PLATFORM_XBOX_SCARLETT || PLATFORM_XBOX_ONE - if (_desc.Flags & GPUBufferFlags::Argument) + if (EnumHasAnyFlags(_desc.Flags, GPUBufferFlags::Argument)) resourceDesc.Flags |= D3D12XBOX_RESOURCE_FLAG_ALLOW_INDIRECT_BUFFER; #endif diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUContextDX12.cpp b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUContextDX12.cpp index b8af1178b..54f1a4290 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUContextDX12.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUContextDX12.cpp @@ -845,6 +845,11 @@ void GPUContextDX12::SetRenderTarget(GPUTextureView* depthBuffer, const SpanOMSetBlendFactor(value.Raw); +} + void GPUContextDX12::ResetSR() { for (int32 slot = 0; slot < GPU_MAX_SR_BINDED; slot++) diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUContextDX12.h b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUContextDX12.h index 4ab6c9155..c870cf71e 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUContextDX12.h +++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUContextDX12.h @@ -166,6 +166,7 @@ public: void SetRenderTarget(GPUTextureView* rt) override; void SetRenderTarget(GPUTextureView* depthBuffer, GPUTextureView* rt) override; void SetRenderTarget(GPUTextureView* depthBuffer, const Span& rts) override; + void SetBlendFactor(const Float4& value) override; void ResetSR() override; void ResetUA() override; void ResetCB() override; diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUPipelineStateDX12.cpp b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUPipelineStateDX12.cpp index 982a27661..3bfe09401 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUPipelineStateDX12.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUPipelineStateDX12.cpp @@ -172,7 +172,7 @@ bool GPUPipelineStateDX12::Init(const Description& desc) } // Depth State - psDesc.DepthStencilState.DepthEnable = !!desc.DepthTestEnable; + psDesc.DepthStencilState.DepthEnable = !!desc.DepthEnable; psDesc.DepthStencilState.DepthWriteMask = desc.DepthWriteEnable ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO; psDesc.DepthStencilState.DepthFunc = static_cast(desc.DepthFunc); psDesc.DepthStencilState.StencilEnable = FALSE; diff --git a/Source/Engine/GraphicsDevice/Null/GPUContextNull.h b/Source/Engine/GraphicsDevice/Null/GPUContextNull.h index a1ffc290a..7568bb60c 100644 --- a/Source/Engine/GraphicsDevice/Null/GPUContextNull.h +++ b/Source/Engine/GraphicsDevice/Null/GPUContextNull.h @@ -84,6 +84,10 @@ public: { } + void SetBlendFactor(const Float4& value) override + { + } + void ResetSR() override { } diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.cpp index 5c13dd896..d52b446e3 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.cpp @@ -966,6 +966,12 @@ void GPUContextVulkan::SetRenderTarget(GPUTextureView* depthBuffer, const SpanGetCmdBuffer(); + vkCmdSetBlendConstants(cmdBuffer->GetHandle(), value.Raw); +} + void GPUContextVulkan::ResetSR() { Platform::MemoryClear(_srHandles, sizeof(_srHandles)); diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.h b/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.h index 2b8d9f122..63224b2d0 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.h +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.h @@ -184,6 +184,7 @@ public: void SetRenderTarget(GPUTextureView* rt) override; void SetRenderTarget(GPUTextureView* depthBuffer, GPUTextureView* rt) override; void SetRenderTarget(GPUTextureView* depthBuffer, const Span& rts) override; + void SetBlendFactor(const Float4& value) override; void ResetSR() override; void ResetUA() override; void ResetCB() override; diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUPipelineStateVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUPipelineStateVulkan.cpp index 236a8c7ce..935f37873 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUPipelineStateVulkan.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUPipelineStateVulkan.cpp @@ -286,7 +286,7 @@ bool GPUPipelineStateVulkan::Init(const Description& desc) // Depth Stencil RenderToolsVulkan::ZeroStruct(_descDepthStencil, VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO); - _descDepthStencil.depthTestEnable = desc.DepthTestEnable; + _descDepthStencil.depthTestEnable = desc.DepthEnable; _descDepthStencil.depthWriteEnable = desc.DepthWriteEnable; _descDepthStencil.depthCompareOp = RenderToolsVulkan::ToVulkanCompareOp(desc.DepthFunc); _desc.pDepthStencilState = &_descDepthStencil; diff --git a/Source/Engine/Input/Gamepad.cpp b/Source/Engine/Input/Gamepad.cpp index 7835e7724..278dc5961 100644 --- a/Source/Engine/Input/Gamepad.cpp +++ b/Source/Engine/Input/Gamepad.cpp @@ -31,6 +31,15 @@ void Gamepad::ResetState() _mappedPrevState.Clear(); } +bool Gamepad::IsAnyButtonDown() const +{ + // TODO: optimize with SIMD + bool result = false; + for (auto e : _state.Buttons) + result |= e; + return result; +} + bool Gamepad::Update(EventQueue& queue) { // Copy state diff --git a/Source/Engine/Input/Gamepad.h b/Source/Engine/Input/Gamepad.h index 63decde7c..27a53a716 100644 --- a/Source/Engine/Input/Gamepad.h +++ b/Source/Engine/Input/Gamepad.h @@ -164,6 +164,11 @@ public: return _mappedState.Buttons[static_cast(button)] && !_mappedPrevState.Buttons[static_cast(button)]; } + /// + /// Checks if any gamepad button is currently pressed. + /// + API_PROPERTY() bool IsAnyButtonDown() const; + /// /// Gets the gamepad button up state (true if was released during the current frame). /// diff --git a/Source/Engine/Input/Input.cpp b/Source/Engine/Input/Input.cpp index b7c202512..7a4547c62 100644 --- a/Source/Engine/Input/Input.cpp +++ b/Source/Engine/Input/Input.cpp @@ -183,6 +183,15 @@ void Mouse::OnMouseDown(const Float2& position, const MouseButton button, Window e.MouseData.Position = position; } +bool Mouse::IsAnyButtonDown() const +{ + // TODO: optimize with SIMD + bool result = false; + for (auto e : Mouse::_state.MouseButtons) + result |= e; + return result; +} + void Mouse::OnMouseUp(const Float2& position, const MouseButton button, Window* target) { Event& e = _queue.AddOne(); diff --git a/Source/Engine/Input/Mouse.h b/Source/Engine/Input/Mouse.h index ebf25ebb1..7fc2be75a 100644 --- a/Source/Engine/Input/Mouse.h +++ b/Source/Engine/Input/Mouse.h @@ -64,6 +64,11 @@ public: return _state.MousePosition; } + /// + /// Checks if any mouse button is currently pressed. + /// + API_PROPERTY() bool IsAnyButtonDown() const; + /// /// Gets the delta position of the mouse in the screen-space coordinates. /// diff --git a/Source/Engine/Level/Actors/AnimatedModel.cpp b/Source/Engine/Level/Actors/AnimatedModel.cpp index ecaed39cb..9605119a3 100644 --- a/Source/Engine/Level/Actors/AnimatedModel.cpp +++ b/Source/Engine/Level/Actors/AnimatedModel.cpp @@ -737,6 +737,7 @@ void AnimatedModel::Draw(RenderContext& renderContext) draw.PerInstanceRandom = GetPerInstanceRandom(); draw.LODBias = LODBias; draw.ForcedLOD = ForcedLOD; + draw.SortOrder = SortOrder; SkinnedModel->Draw(renderContext, draw); } @@ -777,6 +778,7 @@ void AnimatedModel::Draw(RenderContextBatch& renderContextBatch) draw.PerInstanceRandom = GetPerInstanceRandom(); draw.LODBias = LODBias; draw.ForcedLOD = ForcedLOD; + draw.SortOrder = SortOrder; PRAGMA_DISABLE_DEPRECATION_WARNINGS if (ShadowsMode != ShadowsCastingMode::All) @@ -851,6 +853,7 @@ void AnimatedModel::Serialize(SerializeStream& stream, const void* otherObj) SERIALIZE(CustomBounds); SERIALIZE(LODBias); SERIALIZE(ForcedLOD); + SERIALIZE(SortOrder); SERIALIZE(DrawModes); PRAGMA_DISABLE_DEPRECATION_WARNINGS SERIALIZE(ShadowsMode); @@ -877,6 +880,7 @@ void AnimatedModel::Deserialize(DeserializeStream& stream, ISerializeModifier* m DESERIALIZE(CustomBounds); DESERIALIZE(LODBias); DESERIALIZE(ForcedLOD); + DESERIALIZE(SortOrder); DESERIALIZE(DrawModes); PRAGMA_DISABLE_DEPRECATION_WARNINGS DESERIALIZE(ShadowsMode); diff --git a/Source/Engine/Level/Actors/AnimatedModel.h b/Source/Engine/Level/Actors/AnimatedModel.h index f8cb18907..3c578d244 100644 --- a/Source/Engine/Level/Actors/AnimatedModel.h +++ b/Source/Engine/Level/Actors/AnimatedModel.h @@ -138,6 +138,12 @@ public: API_FIELD(Attributes="EditorOrder(100), DefaultValue(DrawPass.Default), EditorDisplay(\"Skinned Model\")") DrawPass DrawModes = DrawPass::Default; + /// + /// The object sort order key used when sorting drawable objects during rendering. Use lower values to draw object before others, higher values are rendered later (on top). Can be use to control transparency drawing. + /// + API_FIELD(Attributes="EditorDisplay(\"Skinned Model\"), EditorOrder(110), DefaultValue(0)") + int16 SortOrder = 0; + /// /// The shadows casting mode. /// [Deprecated on 26.10.2022, expires on 26.10.2024] diff --git a/Source/Engine/Level/Actors/Camera.cpp b/Source/Engine/Level/Actors/Camera.cpp index 064d6344a..ea161c38a 100644 --- a/Source/Engine/Level/Actors/Camera.cpp +++ b/Source/Engine/Level/Actors/Camera.cpp @@ -297,6 +297,7 @@ void Camera::Draw(RenderContext& renderContext) draw.PerInstanceRandom = GetPerInstanceRandom(); draw.LODBias = 0; draw.ForcedLOD = -1; + draw.SortOrder = 0; draw.VertexColors = nullptr; if (draw.DrawModes != DrawPass::None) { diff --git a/Source/Engine/Level/Actors/Sky.cpp b/Source/Engine/Level/Actors/Sky.cpp index f0ccf84b4..dcb2bb77e 100644 --- a/Source/Engine/Level/Actors/Sky.cpp +++ b/Source/Engine/Level/Actors/Sky.cpp @@ -81,7 +81,7 @@ void Sky::InitConfig(AtmosphericFogData& config) const void Sky::Draw(RenderContext& renderContext) { - if (HasContentLoaded()) + if (HasContentLoaded() && EnumHasAnyFlags(renderContext.View.Flags, ViewFlags::Sky)) { // Ensure to have pipeline state cache created if (_psSky == nullptr || _psFog == nullptr) diff --git a/Source/Engine/Level/Actors/Skybox.cpp b/Source/Engine/Level/Actors/Skybox.cpp index 8606b179e..7d35a2776 100644 --- a/Source/Engine/Level/Actors/Skybox.cpp +++ b/Source/Engine/Level/Actors/Skybox.cpp @@ -40,7 +40,7 @@ void Skybox::Draw(RenderContext& renderContext) setupProxy(); isReady = _proxyMaterial && _proxyMaterial->IsReady(); } - if (isReady) + if (isReady && EnumHasAnyFlags(renderContext.View.Flags, ViewFlags::Sky)) { renderContext.List->Sky = this; } diff --git a/Source/Engine/Level/Actors/StaticModel.cpp b/Source/Engine/Level/Actors/StaticModel.cpp index ef6446874..17c99a40a 100644 --- a/Source/Engine/Level/Actors/StaticModel.cpp +++ b/Source/Engine/Level/Actors/StaticModel.cpp @@ -25,6 +25,7 @@ StaticModel::StaticModel(const SpawnParams& params) , _forcedLod(-1) , _vertexColorsDirty(false) , _vertexColorsCount(0) + , _sortOrder(0) { _drawCategory = SceneRendering::SceneDrawAsync; Model.Changed.Bind(this); @@ -37,11 +38,21 @@ StaticModel::~StaticModel() SAFE_DELETE_GPU_RESOURCE(_vertexColorsBuffer[lodIndex]); } +float StaticModel::GetScaleInLightmap() const +{ + return _scaleInLightmap; +} + void StaticModel::SetScaleInLightmap(float value) { _scaleInLightmap = value; } +float StaticModel::GetBoundsScale() const +{ + return _boundsScale; +} + void StaticModel::SetBoundsScale(float value) { if (Math::NearEqual(_boundsScale, value)) @@ -51,6 +62,46 @@ void StaticModel::SetBoundsScale(float value) UpdateBounds(); } +int32 StaticModel::GetLODBias() const +{ + return _lodBias; +} + +void StaticModel::SetLODBias(int32 value) +{ + _lodBias = static_cast(Math::Clamp(value, -100, 100)); +} + +int32 StaticModel::GetForcedLOD() const +{ + return _forcedLod; +} + +void StaticModel::SetForcedLOD(int32 value) +{ + _forcedLod = static_cast(Math::Clamp(value, -1, 100)); +} + +int32 StaticModel::GetSortOrder() const +{ + return _sortOrder; +} + +void StaticModel::SetSortOrder(int32 value) +{ + _sortOrder = (int16)Math::Clamp(value, MIN_int16, MAX_int16); +} + +bool StaticModel::HasLightmap() const +{ + return Lightmap.TextureIndex != INVALID_INDEX; +} + +void StaticModel::RemoveLightmap() +{ + Lightmap.TextureIndex = INVALID_INDEX; +} + MaterialBase* StaticModel::GetMaterial(int32 meshIndex, int32 lodIndex) const { auto model = Model.Get(); @@ -153,6 +204,11 @@ void StaticModel::SetVertexColor(int32 lodIndex, int32 meshIndex, int32 vertexIn LOG(Warning, "Specified model mesh index was out of range. LOD{0} mesh {1}.", lodIndex, meshIndex); } +bool StaticModel::HasVertexColors() const +{ + return _vertexColorsCount != 0; +} + void StaticModel::RemoveVertexColors() { for (int32 lodIndex = 0; lodIndex < _vertexColorsCount; lodIndex++) @@ -292,6 +348,7 @@ void StaticModel::Draw(RenderContext& renderContext) draw.PerInstanceRandom = GetPerInstanceRandom(); draw.LODBias = _lodBias; draw.ForcedLOD = _forcedLod; + draw.SortOrder = _sortOrder; draw.VertexColors = _vertexColorsCount ? _vertexColorsBuffer : nullptr; Model->Draw(renderContext, draw); @@ -324,6 +381,7 @@ void StaticModel::Draw(RenderContextBatch& renderContextBatch) draw.PerInstanceRandom = GetPerInstanceRandom(); draw.LODBias = _lodBias; draw.ForcedLOD = _forcedLod; + draw.SortOrder = _sortOrder; draw.VertexColors = _vertexColorsCount ? _vertexColorsBuffer : nullptr; Model->Draw(renderContextBatch, draw); @@ -356,6 +414,7 @@ void StaticModel::Serialize(SerializeStream& stream, const void* otherObj) SERIALIZE(Model); SERIALIZE_MEMBER(LODBias, _lodBias); SERIALIZE_MEMBER(ForcedLOD, _forcedLod); + SERIALIZE_MEMBER(SortOrder, _sortOrder); SERIALIZE(DrawModes); if (HasLightmap() @@ -405,22 +464,9 @@ void StaticModel::Deserialize(DeserializeStream& stream, ISerializeModifier* mod DESERIALIZE_MEMBER(ScaleInLightmap, _scaleInLightmap); DESERIALIZE_MEMBER(BoundsScale, _boundsScale); DESERIALIZE(Model); - - { - const auto member = stream.FindMember("LODBias"); - if (member != stream.MemberEnd() && member->value.IsInt()) - { - SetLODBias(member->value.GetInt()); - } - } - { - const auto member = stream.FindMember("ForcedLOD"); - if (member != stream.MemberEnd() && member->value.IsInt()) - { - SetForcedLOD(member->value.GetInt()); - } - } - + DESERIALIZE_MEMBER(LODBias, _lodBias); + DESERIALIZE_MEMBER(ForcedLOD, _forcedLod); + DESERIALIZE_MEMBER(SortOrder, _sortOrder); DESERIALIZE(DrawModes); DESERIALIZE_MEMBER(LightmapIndex, Lightmap.TextureIndex); DESERIALIZE_MEMBER(LightmapArea, Lightmap.UVsArea); diff --git a/Source/Engine/Level/Actors/StaticModel.h b/Source/Engine/Level/Actors/StaticModel.h index 4b4356218..af3aa53c0 100644 --- a/Source/Engine/Level/Actors/StaticModel.h +++ b/Source/Engine/Level/Actors/StaticModel.h @@ -21,6 +21,7 @@ private: char _forcedLod; bool _vertexColorsDirty; byte _vertexColorsCount; + int16 _sortOrder; Array _vertexColorsData[MODEL_MAX_LODS]; GPUBuffer* _vertexColorsBuffer[MODEL_MAX_LODS]; Model* _residencyChangedModel = nullptr; @@ -53,10 +54,7 @@ public: /// Gets the model scale in lightmap (applied to all the meshes). /// API_PROPERTY(Attributes="EditorOrder(10), DefaultValue(1.0f), EditorDisplay(\"Model\", \"Scale In Lightmap\"), Limit(0, 1000.0f, 0.1f)") - FORCE_INLINE float GetScaleInLightmap() const - { - return _scaleInLightmap; - } + float GetScaleInLightmap() const; /// /// Sets the model scale in lightmap (applied to all the meshes). @@ -67,10 +65,7 @@ public: /// Gets the model bounds scale. It is useful when using Position Offset to animate the vertices of the object outside of its bounds. Increasing the bounds of an object will reduce performance. /// API_PROPERTY(Attributes="EditorOrder(12), DefaultValue(1.0f), EditorDisplay(\"Model\"), Limit(0, 10.0f, 0.1f)") - FORCE_INLINE float GetBoundsScale() const - { - return _boundsScale; - } + float GetBoundsScale() const; /// /// Sets the model bounds scale. It is useful when using Position Offset to animate the vertices of the object outside of its bounds. @@ -81,51 +76,44 @@ public: /// Gets the model Level Of Detail bias value. Allows to increase or decrease rendered model quality. /// API_PROPERTY(Attributes="EditorOrder(40), DefaultValue(0), Limit(-100, 100, 0.1f), EditorDisplay(\"Model\", \"LOD Bias\")") - FORCE_INLINE int32 GetLODBias() const - { - return static_cast(_lodBias); - } + int32 GetLODBias() const; /// /// Sets the model Level Of Detail bias value. Allows to increase or decrease rendered model quality. /// - API_PROPERTY() void SetLODBias(int32 value) - { - _lodBias = static_cast(Math::Clamp(value, -100, 100)); - } + API_PROPERTY() void SetLODBias(int32 value); /// /// Gets the model forced Level Of Detail index. Allows to bind the given model LOD to show. Value -1 disables this feature. /// API_PROPERTY(Attributes="EditorOrder(50), DefaultValue(-1), Limit(-1, 100, 0.1f), EditorDisplay(\"Model\", \"Forced LOD\")") - FORCE_INLINE int32 GetForcedLOD() const - { - return static_cast(_forcedLod); - } + int32 GetForcedLOD() const; /// /// Sets the model forced Level Of Detail index. Allows to bind the given model LOD to show. Value -1 disables this feature. /// - API_PROPERTY() void SetForcedLOD(int32 value) - { - _forcedLod = static_cast(Math::Clamp(value, -1, 100)); - } + API_PROPERTY() void SetForcedLOD(int32 value); + + /// + /// Gets the model sort order key used when sorting drawable objects during rendering. Use lower values to draw object before others, higher values are rendered later (on top). Can be use to control transparency drawing. + /// + API_PROPERTY(Attributes="EditorOrder(60), DefaultValue(0), EditorDisplay(\"Model\")") + int32 GetSortOrder() const; + + /// + /// Sets the model sort order key used when sorting drawable objects during rendering. Use lower values to draw object before others, higher values are rendered later (on top). Can be use to control transparency drawing. + /// + API_PROPERTY() void SetSortOrder(int32 value); /// /// Determines whether this model has valid lightmap data. /// - API_PROPERTY() FORCE_INLINE bool HasLightmap() const - { - return Lightmap.TextureIndex != INVALID_INDEX; - } + API_PROPERTY() bool HasLightmap() const; /// /// Removes the lightmap data from the model. /// - API_FUNCTION() FORCE_INLINE void RemoveLightmap() - { - Lightmap.TextureIndex = INVALID_INDEX; - } + API_FUNCTION() void RemoveLightmap(); /// /// Gets the material used to render mesh at given index (overriden by model instance buffer or model default). @@ -156,10 +144,7 @@ public: /// /// Returns true if model instance is using custom painted vertex colors buffer, otherwise it will use vertex colors from the original asset. /// - API_PROPERTY() bool HasVertexColors() const - { - return _vertexColorsCount != 0; - } + API_PROPERTY() bool HasVertexColors() const; /// /// Removes the vertex colors buffer from this instance. diff --git a/Source/Engine/Level/Scene/SceneRendering.cpp b/Source/Engine/Level/Scene/SceneRendering.cpp index 7f3d32ecc..b75cd6851 100644 --- a/Source/Engine/Level/Scene/SceneRendering.cpp +++ b/Source/Engine/Level/Scene/SceneRendering.cpp @@ -152,7 +152,7 @@ void SceneRendering::AddActor(Actor* a, int32& key) listener->OnSceneRenderingAddActor(a); } -void SceneRendering::UpdateActor(Actor* a, int32 key) +void SceneRendering::UpdateActor(Actor* a, int32& key) { const int32 category = a->_drawCategory; ScopeLock lock(Locker); diff --git a/Source/Engine/Level/Scene/SceneRendering.h b/Source/Engine/Level/Scene/SceneRendering.h index 1fa3bc725..ef9fc6c3c 100644 --- a/Source/Engine/Level/Scene/SceneRendering.h +++ b/Source/Engine/Level/Scene/SceneRendering.h @@ -123,7 +123,7 @@ public: public: void AddActor(Actor* a, int32& key); - void UpdateActor(Actor* a, int32 key); + void UpdateActor(Actor* a, int32& key); void RemoveActor(Actor* a, int32& key); FORCE_INLINE void AddPostFxProvider(IPostFxSettingsProvider* obj) diff --git a/Source/Engine/Particles/Graph/ParticleEmitterGraph.h b/Source/Engine/Particles/Graph/ParticleEmitterGraph.h index e5801827e..7b0b53eb7 100644 --- a/Source/Engine/Particles/Graph/ParticleEmitterGraph.h +++ b/Source/Engine/Particles/Graph/ParticleEmitterGraph.h @@ -556,7 +556,7 @@ public: // Compute particle data layout and initialize used nodes (for only used nodes, start depth searching rom the modules) Layout.AddAttribute(TEXT("Position"), ParticleAttribute::ValueTypes::Float3); -#define PROCESS_MODULES(modules) for (int32 i = 0; i < modules.Count(); i++) { InitializeNode(modules[i]); } +#define PROCESS_MODULES(modules) for (int32 i = 0; i < modules.Count(); i++) { modules[i]->Used = false; InitializeNode(modules[i]); } PROCESS_MODULES(SpawnModules); PROCESS_MODULES(InitModules); PROCESS_MODULES(UpdateModules); diff --git a/Source/Engine/Particles/ParticleEffect.cpp b/Source/Engine/Particles/ParticleEffect.cpp index 43531589a..4b7923439 100644 --- a/Source/Engine/Particles/ParticleEffect.cpp +++ b/Source/Engine/Particles/ParticleEffect.cpp @@ -258,7 +258,7 @@ void ParticleEffect::ResetSimulation() Instance.ClearState(); } -void ParticleEffect::UpdateSimulation() +void ParticleEffect::UpdateSimulation(bool singleFrame) { // Skip if need to if (!IsActiveInHierarchy() @@ -270,6 +270,8 @@ void ParticleEffect::UpdateSimulation() // Request update _lastUpdateFrame = Engine::FrameCount; _lastMinDstSqr = MAX_Real; + if (singleFrame) + Instance.LastUpdateTime = (UseTimeScale ? Time::Update.Time : Time::Update.UnscaledTime).GetTotalSeconds(); Particles::UpdateEffect(this); } @@ -576,6 +578,7 @@ void ParticleEffect::Serialize(SerializeStream& stream, const void* otherObj) SERIALIZE(IsLooping); SERIALIZE(UpdateWhenOffscreen); SERIALIZE(DrawModes); + SERIALIZE(SortOrder); } void ParticleEffect::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) @@ -674,6 +677,7 @@ void ParticleEffect::Deserialize(DeserializeStream& stream, ISerializeModifier* DESERIALIZE(IsLooping); DESERIALIZE(UpdateWhenOffscreen); DESERIALIZE(DrawModes); + DESERIALIZE(SortOrder); if (_parameters.HasItems()) { diff --git a/Source/Engine/Particles/ParticleEffect.h b/Source/Engine/Particles/ParticleEffect.h index 789738bc0..3487a35f4 100644 --- a/Source/Engine/Particles/ParticleEffect.h +++ b/Source/Engine/Particles/ParticleEffect.h @@ -246,6 +246,12 @@ public: API_FIELD(Attributes="EditorDisplay(\"Particle Effect\"), EditorOrder(75), DefaultValue(DrawPass.Default)") DrawPass DrawModes = DrawPass::Default; + /// + /// The object sort order key used when sorting drawable objects during rendering. Use lower values to draw object before others, higher values are rendered later (on top). Can be use to control transparency drawing. + /// + API_FIELD(Attributes="EditorDisplay(\"Particle Effect\"), EditorOrder(80), DefaultValue(0)") + int16 SortOrder = 0; + public: /// /// Gets the effect parameters collection. Those parameters are instanced from the that contains a linear list of emitters and every emitter has a list of own parameters. @@ -328,7 +334,8 @@ public: /// /// Performs the full particles simulation update (postponed for the next particle manager update). /// - API_FUNCTION() void UpdateSimulation(); + /// True if update animation by a single frame only (time time since last engine update), otherwise will update simulation with delta time since last update. + API_FUNCTION() void UpdateSimulation(bool singleFrame = false); /// /// Updates the actor bounds. diff --git a/Source/Engine/Particles/Particles.cpp b/Source/Engine/Particles/Particles.cpp index 8e3756a19..873c4bd52 100644 --- a/Source/Engine/Particles/Particles.cpp +++ b/Source/Engine/Particles/Particles.cpp @@ -28,13 +28,13 @@ #include "Editor/Editor.h" #endif -struct SpriteParticleVertex -{ +PACK_STRUCT(struct SpriteParticleVertex + { float X; float Y; float U; float V; -}; + }); class SpriteParticleRenderer { @@ -82,6 +82,14 @@ public: } }; +PACK_STRUCT(struct RibbonParticleVertex { + uint32 Order; + uint32 ParticleIndex; + uint32 PrevParticleIndex; + float Distance; + // TODO: pack into half/uint16 data + }); + struct EmitterCache { double LastTimeUsed; @@ -113,7 +121,6 @@ namespace ParticlesDrawCPU Array SortingKeys[2]; Array SortingIndices; Array SortedIndices; - Array RibbonTotalDistances; } class ParticleManagerService : public EngineService @@ -154,7 +161,7 @@ void Particles::OnEffectDestroy(ParticleEffect* effect) typedef Array> RenderModulesIndices; -void DrawEmitterCPU(RenderContext& renderContext, ParticleBuffer* buffer, DrawCall& drawCall, DrawPass drawModes, StaticFlags staticFlags, ParticleEmitterInstance& emitterData, const RenderModulesIndices& renderModulesIndices) +void DrawEmitterCPU(RenderContext& renderContext, ParticleBuffer* buffer, DrawCall& drawCall, DrawPass drawModes, StaticFlags staticFlags, ParticleEmitterInstance& emitterData, const RenderModulesIndices& renderModulesIndices, int16 sortOrder) { // Skip if CPU buffer is empty if (buffer->CPU.Count == 0) @@ -289,14 +296,17 @@ void DrawEmitterCPU(RenderContext& renderContext, ParticleBuffer* buffer, DrawCa { // Prepare ribbon data if (!buffer->GPU.RibbonIndexBufferDynamic) - { buffer->GPU.RibbonIndexBufferDynamic = New(0, (uint32)sizeof(uint16), TEXT("RibbonIndexBufferDynamic")); - } - buffer->GPU.RibbonIndexBufferDynamic->Clear(); + else + buffer->GPU.RibbonIndexBufferDynamic->Clear(); + if (!buffer->GPU.RibbonVertexBufferDynamic) + buffer->GPU.RibbonVertexBufferDynamic = New(0, (uint32)sizeof(RibbonParticleVertex), TEXT("RibbonVertexBufferDynamic")); + else + buffer->GPU.RibbonVertexBufferDynamic->Clear(); + auto& indexBuffer = buffer->GPU.RibbonIndexBufferDynamic->Data; + auto& vertexBuffer = buffer->GPU.RibbonVertexBufferDynamic->Data; // Setup all ribbon modules - auto& totalDistances = ParticlesDrawCPU::RibbonTotalDistances; - totalDistances.Clear(); for (int32 index = 0; index < renderModulesIndices.Count(); index++) { const int32 moduleIndex = renderModulesIndices[index]; @@ -310,77 +320,91 @@ void DrawEmitterCPU(RenderContext& renderContext, ParticleBuffer* buffer, DrawCa auto positionOffset = emitter->Graph.GetPositionAttributeOffset(); if (positionOffset == -1 || buffer->CPU.Count < 2 || buffer->CPU.RibbonOrder.IsEmpty()) break; - int32 count = buffer->CPU.Count; + uint32 count = buffer->CPU.Count; ASSERT(buffer->CPU.RibbonOrder.Count() == emitter->Graph.RibbonRenderingModules.Count() * buffer->Capacity); int32* ribbonOrderData = buffer->CPU.RibbonOrder.Get() + module->RibbonOrderOffset; - ParticleBufferCPUDataAccessor positionData(buffer, emitter->Graph.Layout.GetAttributeOffset(module->Attributes[0])); - int32 indices = 0; - + // Write ribbon indices/vertices + int32 indices = 0, segmentCount = 0; float totalDistance = 0.0f; - uint32 lastParticleIdx = ribbonOrderData[0]; - for (int32 i = 0; i < count; i++) + int32 firstVertexIndex = vertexBuffer.Count(); + uint32 idxPrev = ribbonOrderData[0], vertexPrev = 0; { - bool isNotLast = i != count - 1; - uint32 idx0 = ribbonOrderData[i]; - uint32 idx1 = 0; - Float3 direction; - if (isNotLast) + uint32 idxThis = ribbonOrderData[0]; + + // 2 vertices { - idx1 = ribbonOrderData[i + 1]; - direction = positionData[idx1] - positionData[lastParticleIdx]; - } - else - { - idx1 = ribbonOrderData[i - 1]; - direction = positionData[lastParticleIdx] - positionData[idx1]; + vertexBuffer.AddUninitialized(2 * sizeof(RibbonParticleVertex)); + auto ptr = (RibbonParticleVertex*)(vertexBuffer.Get() + firstVertexIndex); + + RibbonParticleVertex v = { 0, idxThis, idxThis, totalDistance }; + + *ptr++ = v; + *ptr++ = v; } - if (direction.LengthSquared() > 0.002f || !isNotLast) + idxPrev = idxThis; + } + for (uint32 i = 1; i < count; i++) + { + uint32 idxThis = ribbonOrderData[i]; + Float3 direction = positionData[idxThis] - positionData[idxPrev]; + const float distance = direction.Length(); + if (distance > 0.002f) { - totalDistances.Add(totalDistance); - lastParticleIdx = idx1; + totalDistance += distance; - if (isNotLast) + // 2 vertices { - auto idx = buffer->GPU.RibbonIndexBufferDynamic->Data.Count(); - buffer->GPU.RibbonIndexBufferDynamic->Data.AddDefault(6 * sizeof(uint16)); - auto ptr = (uint16*)(buffer->GPU.RibbonIndexBufferDynamic->Data.Get() + idx); + auto idx = vertexBuffer.Count(); + vertexBuffer.AddUninitialized(2 * sizeof(RibbonParticleVertex)); + auto ptr = (RibbonParticleVertex*)(vertexBuffer.Get() + idx); - idx0 *= 2; - idx1 *= 2; + // TODO: this could be optimized by manually fetching per-particle data in vertex shader (2x less data to send and fetch) + RibbonParticleVertex v = { i, idxThis, idxPrev, totalDistance }; - *ptr++ = idx0 + 1; - *ptr++ = idx1; - *ptr++ = idx0; + *ptr++ = v; + *ptr++ = v; + } - *ptr++ = idx0 + 1; - *ptr++ = idx1 + 1; - *ptr++ = idx1; + // 2 triangles + { + auto idx = indexBuffer.Count(); + indexBuffer.AddUninitialized(6 * sizeof(uint16)); + auto ptr = (uint16*)(indexBuffer.Get() + idx); + + uint32 i0 = vertexPrev; + uint32 i1 = vertexPrev + 2; + + *ptr++ = i0; + *ptr++ = i0 + 1; + *ptr++ = i1; + + *ptr++ = i0 + 1; + *ptr++ = i1 + 1; + *ptr++ = i1; indices += 6; } - } - totalDistance += direction.Length(); + idxPrev = idxThis; + segmentCount++; + vertexPrev += 2; + } + } + if (segmentCount == 0) + continue; + { + // Fix first particle vertex data to have proper direction + auto ptr0 = (RibbonParticleVertex*)(vertexBuffer.Get() + firstVertexIndex); + auto ptr1 = ptr0 + 1; + auto ptr2 = ptr1 + 1; + ptr0->PrevParticleIndex = ptr1->PrevParticleIndex = ptr2->ParticleIndex; } - if (indices == 0) - break; // Setup ribbon data - ribbonModulesSegmentCount[ribbonModuleIndex] = totalDistances.Count(); - if (totalDistances.HasItems()) - { - auto& ribbonSegmentDistancesBuffer = buffer->GPU.RibbonSegmentDistances[index]; - if (!ribbonSegmentDistancesBuffer) - { - ribbonSegmentDistancesBuffer = GPUDevice::Instance->CreateBuffer(TEXT("RibbonSegmentDistances")); - ribbonSegmentDistancesBuffer->Init(GPUBufferDescription::Typed(buffer->Capacity, PixelFormat::R32_Float, false, GPUResourceUsage::Dynamic)); - } - context->UpdateBuffer(ribbonSegmentDistancesBuffer, totalDistances.Get(), totalDistances.Count() * sizeof(float)); - } - + ribbonModulesSegmentCount[ribbonModuleIndex] = segmentCount; ribbonModulesDrawIndicesCount[index] = indices; ribbonModulesDrawIndicesPos += indices; @@ -391,6 +415,7 @@ void DrawEmitterCPU(RenderContext& renderContext, ParticleBuffer* buffer, DrawCa { // Upload data to the GPU buffer buffer->GPU.RibbonIndexBufferDynamic->Flush(context); + buffer->GPU.RibbonVertexBufferDynamic->Flush(context); } } @@ -417,7 +442,7 @@ void DrawEmitterCPU(RenderContext& renderContext, ParticleBuffer* buffer, DrawCa // Submit draw call SpriteRenderer.SetupDrawCall(drawCall); drawCall.InstanceCount = buffer->CPU.Count; - renderContext.List->AddDrawCall(renderContext, dp, staticFlags, drawCall, false); + renderContext.List->AddDrawCall(renderContext, dp, staticFlags, drawCall, false, sortOrder); break; } @@ -445,7 +470,7 @@ void DrawEmitterCPU(RenderContext& renderContext, ParticleBuffer* buffer, DrawCa // Submit draw call mesh.GetDrawCallGeometry(drawCall); drawCall.InstanceCount = buffer->CPU.Count; - renderContext.List->AddDrawCall(renderContext, dp, staticFlags, drawCall, false); + renderContext.List->AddDrawCall(renderContext, dp, staticFlags, drawCall, false, sortOrder); } break; @@ -490,13 +515,12 @@ void DrawEmitterCPU(RenderContext& renderContext, ParticleBuffer* buffer, DrawCa ribbon.UVScaleX *= sortUScale; ribbon.UVOffsetX += sortUOffset * uvScale.X; } - ribbon.SegmentDistances = ribbon.SegmentCount != 0 ? buffer->GPU.RibbonSegmentDistances[index] : nullptr; // TODO: invert particles rendering order if camera is closer to the ribbon end than start // Submit draw call drawCall.Geometry.IndexBuffer = buffer->GPU.RibbonIndexBufferDynamic->GetBuffer(); - drawCall.Geometry.VertexBuffers[0] = nullptr; + drawCall.Geometry.VertexBuffers[0] = buffer->GPU.RibbonVertexBufferDynamic->GetBuffer(); drawCall.Geometry.VertexBuffers[1] = nullptr; drawCall.Geometry.VertexBuffers[2] = nullptr; drawCall.Geometry.VertexBuffersOffsets[0] = 0; @@ -505,7 +529,7 @@ void DrawEmitterCPU(RenderContext& renderContext, ParticleBuffer* buffer, DrawCa drawCall.Draw.StartIndex = ribbonModulesDrawIndicesStart[ribbonModuleIndex]; drawCall.Draw.IndicesCount = ribbonModulesDrawIndicesCount[ribbonModuleIndex]; drawCall.InstanceCount = 1; - renderContext.List->AddDrawCall(renderContext, dp, staticFlags, drawCall, false); + renderContext.List->AddDrawCall(renderContext, dp, staticFlags, drawCall, false, sortOrder); ribbonModuleIndex++; @@ -574,7 +598,7 @@ void CleanupGPUParticlesSorting() GPUParticlesSorting = nullptr; } -void DrawEmitterGPU(RenderContext& renderContext, ParticleBuffer* buffer, DrawCall& drawCall, DrawPass drawModes, StaticFlags staticFlags, ParticleEmitterInstance& emitterData, const RenderModulesIndices& renderModulesIndices) +void DrawEmitterGPU(RenderContext& renderContext, ParticleBuffer* buffer, DrawCall& drawCall, DrawPass drawModes, StaticFlags staticFlags, ParticleEmitterInstance& emitterData, const RenderModulesIndices& renderModulesIndices, int16 sortOrder) { const auto context = GPUDevice::Instance->GetMainContext(); auto emitter = buffer->Emitter; @@ -829,7 +853,7 @@ void DrawEmitterGPU(RenderContext& renderContext, ParticleBuffer* buffer, DrawCa drawCall.Draw.IndirectArgsBuffer = buffer->GPU.IndirectDrawArgsBuffer; drawCall.Draw.IndirectArgsOffset = indirectDrawCallIndex * sizeof(GPUDrawIndexedIndirectArgs); if (dp != DrawPass::None) - renderContext.List->AddDrawCall(renderContext, dp, staticFlags, drawCall, false); + renderContext.List->AddDrawCall(renderContext, dp, staticFlags, drawCall, false, sortOrder); indirectDrawCallIndex++; break; @@ -859,7 +883,7 @@ void DrawEmitterGPU(RenderContext& renderContext, ParticleBuffer* buffer, DrawCa drawCall.Draw.IndirectArgsBuffer = buffer->GPU.IndirectDrawArgsBuffer; drawCall.Draw.IndirectArgsOffset = indirectDrawCallIndex * sizeof(GPUDrawIndexedIndirectArgs); if (dp != DrawPass::None) - renderContext.List->AddDrawCall(renderContext, dp, staticFlags, drawCall, false); + renderContext.List->AddDrawCall(renderContext, dp, staticFlags, drawCall, false, sortOrder); indirectDrawCallIndex++; } @@ -887,13 +911,17 @@ void Particles::DrawParticles(RenderContext& renderContext, ParticleEffect* effe { // Setup auto& view = renderContext.View; - const auto drawModes = view.Pass & effect->DrawModes; + const DrawPass drawModes = view.Pass & effect->DrawModes; if (drawModes == DrawPass::None || SpriteRenderer.Init()) return; Matrix worlds[2]; Matrix::Translation(-renderContext.View.Origin, worlds[0]); // World renderContext.View.GetWorldMatrix(effect->GetTransform(), worlds[1]); // Local - const auto staticFlags = effect->GetStaticFlags(); + float worldDeterminantSigns[2]; + worldDeterminantSigns[0] = Math::FloatSelect(worlds[0].RotDeterminant(), 1, -1); + worldDeterminantSigns[1] = Math::FloatSelect(worlds[1].RotDeterminant(), 1, -1); + const StaticFlags staticFlags = effect->GetStaticFlags(); + const int16 sortOrder = effect->SortOrder; // Draw lights for (int32 emitterIndex = 0; emitterIndex < effect->Instance.Emitters.Count(); emitterIndex++) @@ -922,7 +950,7 @@ void Particles::DrawParticles(RenderContext& renderContext, ParticleEffect* effe auto emitter = buffer->Emitter; drawCall.World = worlds[(int32)emitter->SimulationSpace]; - drawCall.WorldDeterminantSign = Math::FloatSelect(drawCall.World.RotDeterminant(), 1, -1); + drawCall.WorldDeterminantSign = worldDeterminantSigns[(int32)emitter->SimulationSpace]; drawCall.Particle.Particles = buffer; // Check if need to render any module @@ -1002,11 +1030,11 @@ void Particles::DrawParticles(RenderContext& renderContext, ParticleEffect* effe switch (buffer->Mode) { case ParticlesSimulationMode::CPU: - DrawEmitterCPU(renderContext, buffer, drawCall, drawModes, staticFlags, emitterData, renderModulesIndices); + DrawEmitterCPU(renderContext, buffer, drawCall, drawModes, staticFlags, emitterData, renderModulesIndices, sortOrder); break; #if COMPILE_WITH_GPU_PARTICLES case ParticlesSimulationMode::GPU: - DrawEmitterGPU(renderContext, buffer, drawCall, drawModes, staticFlags, emitterData, renderModulesIndices); + DrawEmitterGPU(renderContext, buffer, drawCall, drawModes, staticFlags, emitterData, renderModulesIndices, sortOrder); break; #endif } @@ -1183,7 +1211,6 @@ void ParticleManagerService::Dispose() ParticlesDrawCPU::SortingKeys[1].SetCapacity(0); ParticlesDrawCPU::SortingIndices.SetCapacity(0); ParticlesDrawCPU::SortedIndices.SetCapacity(0); - ParticlesDrawCPU::RibbonTotalDistances.SetCapacity(0); PoolLocker.Lock(); for (auto i = Pool.Begin(); i.IsNotEnd(); ++i) diff --git a/Source/Engine/Particles/ParticlesData.cpp b/Source/Engine/Particles/ParticlesData.cpp index 986e4cc9c..eace8d1e3 100644 --- a/Source/Engine/Particles/ParticlesData.cpp +++ b/Source/Engine/Particles/ParticlesData.cpp @@ -18,8 +18,7 @@ ParticleBuffer::~ParticleBuffer() SAFE_DELETE_GPU_RESOURCE(GPU.SortingKeysBuffer); SAFE_DELETE_GPU_RESOURCE(GPU.SortedIndices); SAFE_DELETE(GPU.RibbonIndexBufferDynamic); - for (auto& e : GPU.RibbonSegmentDistances) - SAFE_DELETE_GPU_RESOURCE(e); + SAFE_DELETE(GPU.RibbonVertexBufferDynamic); } bool ParticleBuffer::Init(ParticleEmitter* emitter) diff --git a/Source/Engine/Particles/ParticlesData.h b/Source/Engine/Particles/ParticlesData.h index 45cc455db..5f8dd6332 100644 --- a/Source/Engine/Particles/ParticlesData.h +++ b/Source/Engine/Particles/ParticlesData.h @@ -17,6 +17,7 @@ class ParticleEmitter; class Particles; class GPUBuffer; class DynamicIndexBuffer; +class DynamicVertexBuffer; /// /// The particle attribute that defines a single particle layout component. @@ -302,9 +303,9 @@ public: DynamicIndexBuffer* RibbonIndexBufferDynamic = nullptr; /// - /// The ribbon particles rendering segment distances buffer. Stored one per ribbon module. + /// The ribbon particles rendering vertex buffer (dynamic GPU access). /// - GPUBuffer* RibbonSegmentDistances[PARTICLE_EMITTER_MAX_RIBBONS] = {}; + DynamicVertexBuffer* RibbonVertexBufferDynamic = nullptr; /// /// The flag used to indicate that GPU buffers data should be cleared before next simulation. @@ -422,19 +423,16 @@ public: return Get(index); } - T Get(int32 index) const + FORCE_INLINE T Get(int32 index) const { - ASSERT(IsValid()); - ASSERT(index >= 0 && index < _buffer->CPU.Count); + ASSERT(IsValid() && index >= 0 && index < _buffer->CPU.Count); return *(T*)(_buffer->CPU.Buffer.Get() + _offset + index * _buffer->Stride); } FORCE_INLINE T Get(int32 index, const T& defaultValue) const { if (IsValid()) - { return Get(index); - } return defaultValue; } }; diff --git a/Source/Engine/Render2D/Render2D.cpp b/Source/Engine/Render2D/Render2D.cpp index 1fd384d44..b56c3e1a2 100644 --- a/Source/Engine/Render2D/Render2D.cpp +++ b/Source/Engine/Render2D/Render2D.cpp @@ -481,7 +481,7 @@ bool CachedPSO::Init(GPUShader* shader, bool useDepth) // Create pipeline states GPUPipelineState::Description desc = GPUPipelineState::Description::DefaultFullscreenTriangle; - desc.DepthTestEnable = desc.DepthWriteEnable = useDepth; + desc.DepthEnable = desc.DepthWriteEnable = useDepth; desc.DepthWriteEnable = false; desc.DepthClipEnable = false; desc.VS = shader->GetVS("VS"); diff --git a/Source/Engine/Renderer/ColorGradingPass.cpp b/Source/Engine/Renderer/ColorGradingPass.cpp index fbfa4eae6..fa8e7facc 100644 --- a/Source/Engine/Renderer/ColorGradingPass.cpp +++ b/Source/Engine/Renderer/ColorGradingPass.cpp @@ -62,7 +62,7 @@ bool ColorGradingPass::Init() formatSupportFlags |= FormatSupport::Texture3D; else formatSupportFlags |= FormatSupport::Texture2D; - if (!EnumHasAllFlags(formatSupport, formatSupportFlags)) + if (EnumHasNoneFlags(formatSupport, formatSupportFlags)) { // Fallback to format that is supported on every washing machine _lutFormat = PixelFormat::R8G8B8A8_UNorm; diff --git a/Source/Engine/Renderer/Config.h b/Source/Engine/Renderer/Config.h index ac3fcbd6e..659369a71 100644 --- a/Source/Engine/Renderer/Config.h +++ b/Source/Engine/Renderer/Config.h @@ -117,6 +117,3 @@ PACK_STRUCT(struct ProbeData { // Default format for the shadow map textures #define SHADOW_MAPS_FORMAT PixelFormat::D16_UNorm - -// Material distortion offsets output pass (material uses PS_Distortion, ForwardPass resolves the offsets) -#define Distortion_Pass_Output_Format PixelFormat::R8G8B8A8_UNorm diff --git a/Source/Engine/Renderer/DrawCall.h b/Source/Engine/Renderer/DrawCall.h index f0c075285..9fd6c13b5 100644 --- a/Source/Engine/Renderer/DrawCall.h +++ b/Source/Engine/Renderer/DrawCall.h @@ -221,7 +221,6 @@ struct DrawCall float UVOffsetX; float UVOffsetY; uint32 SegmentCount; - GPUBuffer* SegmentDistances; } Ribbon; struct diff --git a/Source/Engine/Renderer/ForwardPass.cpp b/Source/Engine/Renderer/ForwardPass.cpp index 0eb637eea..53c9b74bd 100644 --- a/Source/Engine/Renderer/ForwardPass.cpp +++ b/Source/Engine/Renderer/ForwardPass.cpp @@ -107,7 +107,7 @@ void ForwardPass::Render(RenderContext& renderContext, GPUTexture* input, GPUTex const int32 height = renderContext.Buffers->GetHeight(); const int32 distortionWidth = width; const int32 distortionHeight = height; - const auto tempDesc = GPUTextureDescription::New2D(distortionWidth, distortionHeight, Distortion_Pass_Output_Format); + const auto tempDesc = GPUTextureDescription::New2D(distortionWidth, distortionHeight, PixelFormat::R8G8B8A8_UNorm); auto distortionRT = RenderTargetPool::Get(tempDesc); RENDER_TARGET_POOL_SET_NAME(distortionRT, "Forward.Distortion"); @@ -119,15 +119,13 @@ void ForwardPass::Render(RenderContext& renderContext, GPUTexture* input, GPUTex // Render distortion pass view.Pass = DrawPass::Distortion; mainCache->ExecuteDrawCalls(renderContext, distortionList); + + // Copy combined frame with distortion from transparent materials context->SetViewportAndScissors((float)width, (float)height); context->ResetRenderTarget(); context->ResetSR(); - - // Bind inputs context->BindSR(0, input); context->BindSR(1, distortionRT); - - // Copy combined frame with distortion from transparent materials context->SetRenderTarget(output->View()); context->SetState(_psApplyDistortion); context->DrawFullscreenTriangle(); diff --git a/Source/Engine/Renderer/GBufferPass.cpp b/Source/Engine/Renderer/GBufferPass.cpp index 87ddf1bf2..0e5e8508a 100644 --- a/Source/Engine/Renderer/GBufferPass.cpp +++ b/Source/Engine/Renderer/GBufferPass.cpp @@ -146,7 +146,7 @@ void DebugOverrideDrawCallsMaterial(const RenderContext& renderContext, IMateria #endif -void GBufferPass::Fill(RenderContext& renderContext, GPUTextureView* lightBuffer) +void GBufferPass::Fill(RenderContext& renderContext, GPUTexture* lightBuffer) { PROFILE_GPU_CPU("GBuffer"); @@ -155,7 +155,7 @@ void GBufferPass::Fill(RenderContext& renderContext, GPUTextureView* lightBuffer auto context = device->GetMainContext(); GPUTextureView* targetBuffers[5] = { - lightBuffer, + lightBuffer->View(), renderContext.Buffers->GBuffer0->View(), renderContext.Buffers->GBuffer1->View(), renderContext.Buffers->GBuffer2->View(), @@ -168,7 +168,7 @@ void GBufferPass::Fill(RenderContext& renderContext, GPUTextureView* lightBuffer PROFILE_GPU_CPU_NAMED("Clear"); context->ClearDepth(*renderContext.Buffers->DepthBuffer); - context->Clear(lightBuffer, Color::Transparent); + context->Clear(lightBuffer->View(), Color::Transparent); context->Clear(renderContext.Buffers->GBuffer0->View(), Color::Transparent); context->Clear(renderContext.Buffers->GBuffer1->View(), Color::Transparent); context->Clear(renderContext.Buffers->GBuffer2->View(), Color(1, 0, 0, 0)); @@ -192,7 +192,7 @@ void GBufferPass::Fill(RenderContext& renderContext, GPUTextureView* lightBuffer renderContext.List->Sky->ApplySky(context, renderContext, Matrix::Identity); GPUPipelineState* materialPs = context->GetState(); const float complexity = (float)Math::Min(materialPs->Complexity, MATERIAL_COMPLEXITY_LIMIT) / MATERIAL_COMPLEXITY_LIMIT; - context->Clear(lightBuffer, Color(complexity, complexity, complexity, 1.0f)); + context->Clear(lightBuffer->View(), Color(complexity, complexity, complexity, 1.0f)); renderContext.List->Sky = nullptr; } } @@ -208,16 +208,20 @@ void GBufferPass::Fill(RenderContext& renderContext, GPUTextureView* lightBuffer renderContext.List->ExecuteDrawCalls(renderContext, DrawCallsListType::GBuffer); // Draw decals - DrawDecals(renderContext, lightBuffer); + DrawDecals(renderContext, lightBuffer->View()); // Draw objects that cannot get decals context->SetRenderTarget(*renderContext.Buffers->DepthBuffer, ToSpan(targetBuffers, ARRAY_COUNT(targetBuffers))); renderContext.List->ExecuteDrawCalls(renderContext, DrawCallsListType::GBufferNoDecals); + GPUTexture* nullTexture = nullptr; + renderContext.List->RunCustomPostFxPass(context, renderContext, PostProcessEffectLocation::AfterGBufferPass, lightBuffer, nullTexture); + // Draw sky - if (renderContext.List->Sky && _skyModel && _skyModel->CanBeRendered()) + if (renderContext.List->Sky && _skyModel && _skyModel->CanBeRendered() && EnumHasAnyFlags(renderContext.View.Flags, ViewFlags::Sky)) { PROFILE_GPU_CPU_NAMED("Sky"); + context->SetRenderTarget(*renderContext.Buffers->DepthBuffer, ToSpan(targetBuffers, ARRAY_COUNT(targetBuffers))); DrawSky(renderContext, context); } @@ -279,7 +283,7 @@ public: GPUTextureView* GBufferPass::RenderSkybox(RenderContext& renderContext, GPUContext* context) { GPUTextureView* result = nullptr; - if (renderContext.List->Sky && _skyModel && _skyModel->CanBeRendered()) + if (renderContext.List->Sky && _skyModel && _skyModel->CanBeRendered() && EnumHasAnyFlags(renderContext.View.Flags, ViewFlags::Sky)) { // Initialize skybox texture auto& skyboxData = *renderContext.Buffers->GetCustomBuffer(TEXT("Skybox")); @@ -426,7 +430,7 @@ void GBufferPass::DrawDecals(RenderContext& renderContext, GPUTextureView* light { // Skip if no decals to render auto& decals = renderContext.List->Decals; - if (decals.IsEmpty() || _boxModel == nullptr || !_boxModel->CanBeRendered()) + if (decals.IsEmpty() || _boxModel == nullptr || !_boxModel->CanBeRendered() || EnumHasNoneFlags(renderContext.View.Flags, ViewFlags::Decals)) return; PROFILE_GPU_CPU("Decals"); diff --git a/Source/Engine/Renderer/GBufferPass.h b/Source/Engine/Renderer/GBufferPass.h index d33d92b22..6ff59d1d9 100644 --- a/Source/Engine/Renderer/GBufferPass.h +++ b/Source/Engine/Renderer/GBufferPass.h @@ -32,7 +32,7 @@ public: /// /// The rendering context. /// Light buffer to output material emissive light and precomputed indirect lighting - void Fill(RenderContext& renderContext, GPUTextureView* lightBuffer); + void Fill(RenderContext& renderContext, GPUTexture* lightBuffer); /// /// Render debug view diff --git a/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp b/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp index d4ac81f98..2ca702d4f 100644 --- a/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp +++ b/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp @@ -284,7 +284,7 @@ bool GlobalSurfaceAtlasPass::setupResources() if (!_psClear) { _psClear = device->CreatePipelineState(); - psDesc.DepthTestEnable = true; + psDesc.DepthEnable = true; psDesc.DepthWriteEnable = true; psDesc.DepthFunc = ComparisonFunc::Always; psDesc.VS = shader->GetVS("VS_Atlas"); @@ -292,7 +292,7 @@ bool GlobalSurfaceAtlasPass::setupResources() if (_psClear->Init(psDesc)) return true; } - psDesc.DepthTestEnable = false; + psDesc.DepthEnable = false; psDesc.DepthWriteEnable = false; psDesc.DepthFunc = ComparisonFunc::Never; if (!_psClearLighting) diff --git a/Source/Engine/Renderer/GlobalSignDistanceFieldPass.cpp b/Source/Engine/Renderer/GlobalSignDistanceFieldPass.cpp index fb3b9ee39..993b0c4b7 100644 --- a/Source/Engine/Renderer/GlobalSignDistanceFieldPass.cpp +++ b/Source/Engine/Renderer/GlobalSignDistanceFieldPass.cpp @@ -64,7 +64,7 @@ PACK_STRUCT(struct ModelsRasterizeData Int3 ChunkCoord; float MaxDistance; Float3 CascadeCoordToPosMul; - int32 ObjectsCount; + uint32 ObjectsCount; Float3 CascadeCoordToPosAdd; int32 CascadeResolution; int32 CascadeIndex; diff --git a/Source/Engine/Renderer/LightPass.cpp b/Source/Engine/Renderer/LightPass.cpp index 0b98067d7..30b0b78bb 100644 --- a/Source/Engine/Renderer/LightPass.cpp +++ b/Source/Engine/Renderer/LightPass.cpp @@ -50,7 +50,7 @@ bool LightPass::Init() #endif auto format = PixelFormat::R8G8_UNorm; - if (!EnumHasAllFlags(GPUDevice::Instance->GetFormatFeatures(format).Support, (FormatSupport::RenderTarget | FormatSupport::ShaderSample | FormatSupport::Texture2D))) + if (EnumHasNoneFlags(GPUDevice::Instance->GetFormatFeatures(format).Support, (FormatSupport::RenderTarget | FormatSupport::ShaderSample | FormatSupport::Texture2D))) { format = PixelFormat::B8G8R8A8_UNorm; } @@ -98,7 +98,7 @@ bool LightPass::setupResources() if (_psLightPointInverted.Create(psDesc, shader, "PS_Point")) return true; psDesc.CullMode = CullMode::Normal; - psDesc.DepthTestEnable = true; + psDesc.DepthEnable = true; if (_psLightPointNormal.Create(psDesc, shader, "PS_Point")) return true; } @@ -112,7 +112,7 @@ bool LightPass::setupResources() if (_psLightSpotInverted.Create(psDesc, shader, "PS_Spot")) return true; psDesc.CullMode = CullMode::Normal; - psDesc.DepthTestEnable = true; + psDesc.DepthEnable = true; if (_psLightSpotNormal.Create(psDesc, shader, "PS_Spot")) return true; } diff --git a/Source/Engine/Renderer/MotionBlurPass.cpp b/Source/Engine/Renderer/MotionBlurPass.cpp index e5f622fc5..d425df80f 100644 --- a/Source/Engine/Renderer/MotionBlurPass.cpp +++ b/Source/Engine/Renderer/MotionBlurPass.cpp @@ -62,11 +62,11 @@ bool MotionBlurPass::Init() // Prepare formats for the buffers auto format = PixelFormat::R16G16_Float; - if (!EnumHasAllFlags(GPUDevice::Instance->GetFormatFeatures(format).Support, FormatSupport::RenderTarget | FormatSupport::ShaderSample | FormatSupport::Texture2D)) + if (EnumHasNoneFlags(GPUDevice::Instance->GetFormatFeatures(format).Support, FormatSupport::RenderTarget | FormatSupport::ShaderSample | FormatSupport::Texture2D)) { - if (!EnumHasAllFlags(GPUDevice::Instance->GetFormatFeatures(PixelFormat::R32G32_Float).Support, FormatSupport::RenderTarget | FormatSupport::ShaderSample | FormatSupport::Texture2D)) + if (EnumHasNoneFlags(GPUDevice::Instance->GetFormatFeatures(PixelFormat::R32G32_Float).Support, FormatSupport::RenderTarget | FormatSupport::ShaderSample | FormatSupport::Texture2D)) format = PixelFormat::R32G32_Float; - else if (!EnumHasAllFlags(GPUDevice::Instance->GetFormatFeatures(PixelFormat::R16G16B16A16_Float).Support, FormatSupport::RenderTarget | FormatSupport::ShaderSample | FormatSupport::Texture2D)) + else if (EnumHasNoneFlags(GPUDevice::Instance->GetFormatFeatures(PixelFormat::R16G16B16A16_Float).Support, FormatSupport::RenderTarget | FormatSupport::ShaderSample | FormatSupport::Texture2D)) format = PixelFormat::R16G16B16A16_Float; else format = PixelFormat::R32G32B32A32_Float; diff --git a/Source/Engine/Renderer/PostProcessingPass.cpp b/Source/Engine/Renderer/PostProcessingPass.cpp index 058ceabab..760b12ea0 100644 --- a/Source/Engine/Renderer/PostProcessingPass.cpp +++ b/Source/Engine/Renderer/PostProcessingPass.cpp @@ -181,24 +181,13 @@ void PostProcessingPass::Dispose() void PostProcessingPass::Render(RenderContext& renderContext, GPUTexture* input, GPUTexture* output, GPUTexture* colorGradingLUT) { + PROFILE_GPU_CPU("Post Processing"); auto device = GPUDevice::Instance; auto context = device->GetMainContext(); auto& view = renderContext.View; - - PROFILE_GPU_CPU("Post Processing"); - + context->ResetRenderTarget(); - // Ensure to have valid data - if (checkIfSkipPass()) - { - // Resources are missing. Do not perform rendering. Just copy raw frame - context->SetRenderTarget(*output); - context->Draw(input); - return; - } - - // Cache data PostProcessSettings& settings = renderContext.List->Settings; bool useBloom = EnumHasAnyFlags(view.Flags, ViewFlags::Bloom) && settings.Bloom.Enabled && settings.Bloom.Intensity > 0.0f; bool useToneMapping = EnumHasAnyFlags(view.Flags, ViewFlags::ToneMapping); @@ -206,9 +195,10 @@ void PostProcessingPass::Render(RenderContext& renderContext, GPUTexture* input, bool useLensFlares = EnumHasAnyFlags(view.Flags, ViewFlags::LensFlares) && settings.LensFlares.Intensity > 0.0f && useBloom; // Ensure to have valid data and if at least one effect should be applied - if (!(useBloom || useToneMapping || useCameraArtifacts)) + if (checkIfSkipPass() || !(useBloom || useToneMapping || useCameraArtifacts)) { // Resources are missing. Do not perform rendering. Just copy raw frame + context->SetViewportAndScissors((float)output->Width(), (float)output->Height()); context->SetRenderTarget(*output); context->Draw(input); return; diff --git a/Source/Engine/Renderer/ProbesRenderer.cpp b/Source/Engine/Renderer/ProbesRenderer.cpp index 376c8632d..e24022b07 100644 --- a/Source/Engine/Renderer/ProbesRenderer.cpp +++ b/Source/Engine/Renderer/ProbesRenderer.cpp @@ -73,7 +73,7 @@ PACK_STRUCT(struct Data { Float2 Dummy0; int32 CubeFace; - int32 SourceMipIndex; + float SourceMipIndex; }); namespace ProbesRendererImpl @@ -268,6 +268,7 @@ bool ProbesRenderer::Init() ViewFlags::SkyLights | ViewFlags::Decals | ViewFlags::Shadows | + ViewFlags::Sky | ViewFlags::Fog; view.Mode = ViewMode::NoPostFx; view.IsOfflinePass = true; @@ -514,8 +515,8 @@ void ProbesRenderer::OnRender(RenderTask* task, GPUContext* context) auto cb = shader->GetCB(0); for (int32 mipIndex = 1; mipIndex < mipLevels; mipIndex++) { - int32 mipSize = 1 << (mipLevels - mipIndex - 1); - data.SourceMipIndex = mipIndex - 1; + const int32 mipSize = 1 << (mipLevels - mipIndex - 1); + data.SourceMipIndex = (float)mipIndex - 1.0f; context->SetViewportAndScissors((float)mipSize, (float)mipSize); for (int32 faceIndex = 0; faceIndex < 6; faceIndex++) { diff --git a/Source/Engine/Renderer/RenderList.cpp b/Source/Engine/Renderer/RenderList.cpp index 2f8fba76f..1a4cc0205 100644 --- a/Source/Engine/Renderer/RenderList.cpp +++ b/Source/Engine/Renderer/RenderList.cpp @@ -265,7 +265,7 @@ void RenderList::RunPostFxPass(GPUContext* context, RenderContext& renderContext { if (fx->Location == locationB) { - if (fx->UseSingleTarget) + if (fx->UseSingleTarget || output == nullptr) { fx->Render(context, renderContext, input, nullptr); } @@ -298,9 +298,9 @@ void RenderList::RunMaterialPostFxPass(GPUContext* context, RenderContext& rende bindParams.Input = *input; material->Bind(bindParams); context->DrawFullscreenTriangle(); - context->ResetRenderTarget(); Swap(output, input); } + context->ResetRenderTarget(); } } @@ -312,7 +312,7 @@ void RenderList::RunCustomPostFxPass(GPUContext* context, RenderContext& renderC { if (fx->Location == location) { - if (fx->UseSingleTarget) + if (fx->UseSingleTarget || output == nullptr) { fx->Render(context, renderContext, input, nullptr); } @@ -412,12 +412,28 @@ void RenderList::Clear() _instanceBuffer.Clear(); } -FORCE_INLINE void CalculateSortKey(const RenderContext& renderContext, DrawCall& drawCall) +struct PackedSortKey +{ + union + { + uint64 Data; + + struct + { + uint32 DistanceKey; + uint16 BatchKey; + uint16 SortKey; + }; + }; +}; + +FORCE_INLINE void CalculateSortKey(const RenderContext& renderContext, DrawCall& drawCall, int16 sortOrder) { const Float3 planeNormal = renderContext.View.Direction; const float planePoint = -Float3::Dot(planeNormal, renderContext.View.Position); const float distance = Float3::Dot(planeNormal, drawCall.ObjectPosition) - planePoint; - const uint32 sortKey = RenderTools::ComputeDistanceSortKey(distance); + PackedSortKey key; + key.DistanceKey = RenderTools::ComputeDistanceSortKey(distance); uint32 batchKey = GetHash(drawCall.Geometry.IndexBuffer); batchKey = (batchKey * 397) ^ GetHash(drawCall.Geometry.VertexBuffers[0]); batchKey = (batchKey * 397) ^ GetHash(drawCall.Geometry.VertexBuffers[1]); @@ -427,10 +443,12 @@ FORCE_INLINE void CalculateSortKey(const RenderContext& renderContext, DrawCall& if (drawCall.Material->CanUseInstancing(handler)) handler.GetHash(drawCall, batchKey); batchKey += (int32)(471 * drawCall.WorldDeterminantSign); - drawCall.SortKey = (uint64)batchKey << 32 | (uint64)sortKey; + key.SortKey = (uint16)(sortOrder - MIN_int16); + key.BatchKey = (uint16)batchKey; + drawCall.SortKey = key.Data; } -void RenderList::AddDrawCall(const RenderContext& renderContext, DrawPass drawModes, StaticFlags staticFlags, DrawCall& drawCall, bool receivesDecals) +void RenderList::AddDrawCall(const RenderContext& renderContext, DrawPass drawModes, StaticFlags staticFlags, DrawCall& drawCall, bool receivesDecals, int16 sortOrder) { #if ENABLE_ASSERTION_LOW_LAYERS // Ensure that draw modes are non-empty and in conjunction with material draw modes @@ -439,7 +457,7 @@ void RenderList::AddDrawCall(const RenderContext& renderContext, DrawPass drawMo #endif // Append draw call data - CalculateSortKey(renderContext, drawCall); + CalculateSortKey(renderContext, drawCall, sortOrder); const int32 index = DrawCalls.Add(drawCall); // Add draw call to proper draw lists @@ -468,7 +486,7 @@ void RenderList::AddDrawCall(const RenderContext& renderContext, DrawPass drawMo } } -void RenderList::AddDrawCall(const RenderContextBatch& renderContextBatch, DrawPass drawModes, StaticFlags staticFlags, ShadowsCastingMode shadowsMode, const BoundingSphere& bounds, DrawCall& drawCall, bool receivesDecals) +void RenderList::AddDrawCall(const RenderContextBatch& renderContextBatch, DrawPass drawModes, StaticFlags staticFlags, ShadowsCastingMode shadowsMode, const BoundingSphere& bounds, DrawCall& drawCall, bool receivesDecals, int16 sortOrder) { #if ENABLE_ASSERTION_LOW_LAYERS // Ensure that draw modes are non-empty and in conjunction with material draw modes @@ -478,7 +496,7 @@ void RenderList::AddDrawCall(const RenderContextBatch& renderContextBatch, DrawP const RenderContext& mainRenderContext = renderContextBatch.Contexts.Get()[0]; // Append draw call data - CalculateSortKey(mainRenderContext, drawCall); + CalculateSortKey(mainRenderContext, drawCall, sortOrder); const int32 index = DrawCalls.Add(drawCall); // Add draw call to proper draw lists @@ -514,7 +532,7 @@ void RenderList::AddDrawCall(const RenderContextBatch& renderContextBatch, DrawP { const RenderContext& renderContext = renderContextBatch.Contexts.Get()[i]; ASSERT_LOW_LAYER(renderContext.View.Pass == DrawPass::Depth); - drawModes = (DrawPass)(modes & renderContext.View.Pass); + drawModes = modes & renderContext.View.Pass; if (drawModes != DrawPass::None && renderContext.View.CullingFrustum.Intersects(bounds)) { renderContext.List->ShadowDepthDrawCallsList.Indices.Add(index); @@ -558,16 +576,17 @@ void RenderList::SortDrawCalls(const RenderContext& renderContext, bool reverseD #undef PREPARE_CACHE uint64* sortedKeys = SortingKeys[0].Get(); - // Generate sort keys (by depth) and batch keys (higher bits) + // Setup sort keys if (reverseDistance) { - const uint32 sortKeyXor = reverseDistance ? MAX_uint32 : 0; for (int32 i = 0; i < listSize; i++) { const DrawCall& drawCall = drawCallsData[listData[i]]; - const uint32 sortKey = (uint32)drawCall.SortKey ^ sortKeyXor; - const uint32 batchKey = (uint32)(drawCall.SortKey >> 32); - sortedKeys[i] = (uint64)batchKey << 32 | (uint64)sortKey; + PackedSortKey key; + key.Data = drawCall.SortKey; + key.DistanceKey ^= MAX_uint32; // Reverse depth + key.SortKey ^= MAX_uint16; // Reverse sort order + sortedKeys[i] = key.Data; } } else @@ -605,7 +624,7 @@ void RenderList::SortDrawCalls(const RenderContext& renderContext, bool reverseD } DrawBatch batch; - batch.SortKey = sortedKeys[i] & MAX_uint32; + batch.SortKey = sortedKeys[i]; batch.StartIndex = i; batch.BatchSize = batchSize; batch.InstanceCount = instanceCount; @@ -618,7 +637,7 @@ void RenderList::SortDrawCalls(const RenderContext& renderContext, bool reverseD Sorting::QuickSort(list.Batches.Get(), list.Batches.Count()); } -bool CanUseInstancing(DrawPass pass) +FORCE_INLINE bool CanUseInstancing(DrawPass pass) { return pass == DrawPass::GBuffer || pass == DrawPass::Depth; } diff --git a/Source/Engine/Renderer/RenderList.h b/Source/Engine/Renderer/RenderList.h index 44eabcdc1..493f80101 100644 --- a/Source/Engine/Renderer/RenderList.h +++ b/Source/Engine/Renderer/RenderList.h @@ -201,7 +201,7 @@ struct DrawBatch /// /// Draw calls sorting key (shared by the all draw calls withing a patch). /// - uint32 SortKey; + uint64 SortKey; /// /// The first draw call index. @@ -489,7 +489,8 @@ public: /// The object static flags. /// The draw call data. /// True if the rendered mesh can receive decals. - void AddDrawCall(const RenderContext& renderContext, DrawPass drawModes, StaticFlags staticFlags, DrawCall& drawCall, bool receivesDecals); + /// Object sorting key. + void AddDrawCall(const RenderContext& renderContext, DrawPass drawModes, StaticFlags staticFlags, DrawCall& drawCall, bool receivesDecals = true, int16 sortOrder = 0); /// /// Adds the draw call to the draw lists and references it in other render contexts. Performs additional per-context frustum culling. @@ -501,7 +502,8 @@ public: /// The object bounds. /// The draw call data. /// True if the rendered mesh can receive decals. - void AddDrawCall(const RenderContextBatch& renderContextBatch, DrawPass drawModes, StaticFlags staticFlags, ShadowsCastingMode shadowsMode, const BoundingSphere& bounds, DrawCall& drawCall, bool receivesDecals); + /// Object sorting key. + void AddDrawCall(const RenderContextBatch& renderContextBatch, DrawPass drawModes, StaticFlags staticFlags, ShadowsCastingMode shadowsMode, const BoundingSphere& bounds, DrawCall& drawCall, bool receivesDecals = true, int16 sortOrder = 0); /// /// Sorts the collected draw calls list. diff --git a/Source/Engine/Renderer/Renderer.cpp b/Source/Engine/Renderer/Renderer.cpp index 295a2ea77..584ab6b45 100644 --- a/Source/Engine/Renderer/Renderer.cpp +++ b/Source/Engine/Renderer/Renderer.cpp @@ -236,24 +236,7 @@ void Renderer::DrawSceneDepth(GPUContext* context, SceneRenderTask* task, GPUTex renderContext.View.Prepare(renderContext); // Call drawing (will collect draw calls) - if (customActors.HasItems()) - { - // Draw custom actors - for (auto actor : customActors) - { - if (actor && actor->GetIsActive()) - actor->Draw(renderContext); - } - } - else - { - // Draw scene actors - RenderContextBatch renderContextBatch(renderContext); - Level::DrawActors(renderContextBatch); - for (const int64 label : renderContextBatch.WaitLabels) - JobSystem::Wait(label); - renderContextBatch.WaitLabels.Clear(); - } + DrawActors(renderContext, customActors); // Sort draw calls renderContext.List->SortDrawCalls(renderContext, false, DrawCallsListType::Depth); @@ -287,6 +270,31 @@ void Renderer::DrawPostFxMaterial(GPUContext* context, const RenderContext& rend context->ResetRenderTarget(); } +void Renderer::DrawActors(RenderContext& renderContext, const Array& customActors) +{ + if (customActors.HasItems()) + { + // Draw custom actors + for (Actor* actor : customActors) + { + if (actor && actor->GetIsActive()) + actor->Draw(renderContext); + } + } + else + { + // Draw scene actors + RenderContextBatch renderContextBatch(renderContext); + JobSystem::SetJobStartingOnDispatch(false); + Level::DrawActors(renderContextBatch, SceneRendering::DrawCategory::SceneDraw); + Level::DrawActors(renderContextBatch, SceneRendering::DrawCategory::SceneDrawAsync); + JobSystem::SetJobStartingOnDispatch(true); + for (const int64 label : renderContextBatch.WaitLabels) + JobSystem::Wait(label); + renderContextBatch.WaitLabels.Clear(); + } +} + void RenderInner(SceneRenderTask* task, RenderContext& renderContext, RenderContextBatch& renderContextBatch) { auto context = GPUDevice::Instance->GetMainContext(); @@ -304,6 +312,7 @@ void RenderInner(SceneRenderTask* task, RenderContext& renderContext, RenderCont // Initialize setup RenderSetup& setup = renderContext.List->Setup; + const bool isGBufferDebug = GBufferPass::IsDebugView(renderContext.View.Mode); { PROFILE_CPU_NAMED("Setup"); if (renderContext.View.Origin != renderContext.View.PrevOrigin) @@ -311,7 +320,7 @@ void RenderInner(SceneRenderTask* task, RenderContext& renderContext, RenderCont const int32 screenWidth = renderContext.Buffers->GetWidth(); const int32 screenHeight = renderContext.Buffers->GetHeight(); setup.UpscaleLocation = renderContext.Task->UpscaleLocation; - if (screenWidth < 16 || screenHeight < 16 || renderContext.Task->IsCameraCut) + if (screenWidth < 16 || screenHeight < 16 || renderContext.Task->IsCameraCut || isGBufferDebug || renderContext.View.Mode == ViewMode::NoPostFx) setup.UseMotionVectors = false; else { @@ -336,7 +345,6 @@ void RenderInner(SceneRenderTask* task, RenderContext& renderContext, RenderCont renderContext.Buffers->Prepare(); // Build batch of render contexts (main view and shadow projections) - const bool isGBufferDebug = GBufferPass::IsDebugView(renderContext.View.Mode); { PROFILE_CPU_NAMED("Collect Draw Calls"); @@ -423,7 +431,7 @@ void RenderInner(SceneRenderTask* task, RenderContext& renderContext, RenderCont } // Fill GBuffer - GBufferPass::Instance()->Fill(renderContext, lightBuffer->View()); + GBufferPass::Instance()->Fill(renderContext, lightBuffer); // Debug drawing if (renderContext.View.Mode == ViewMode::GlobalSDF) @@ -537,6 +545,10 @@ void RenderInner(SceneRenderTask* task, RenderContext& renderContext, RenderCont RENDER_TARGET_POOL_SET_NAME(frameBuffer, "FrameBuffer"); ForwardPass::Instance()->Render(renderContext, lightBuffer, frameBuffer); + // Material and Custom PostFx + renderContext.List->RunMaterialPostFxPass(context, renderContext, MaterialPostFxLocation::AfterForwardPass, frameBuffer, lightBuffer); + renderContext.List->RunCustomPostFxPass(context, renderContext, PostProcessEffectLocation::AfterForwardPass, frameBuffer, lightBuffer); + // Cleanup context->ResetRenderTarget(); context->ResetSR(); diff --git a/Source/Engine/Renderer/Renderer.cs b/Source/Engine/Renderer/Renderer.cs index a58a5eb21..bfb81a84c 100644 --- a/Source/Engine/Renderer/Renderer.cs +++ b/Source/Engine/Renderer/Renderer.cs @@ -14,6 +14,7 @@ namespace FlaxEngine /// Render task to use it's view description and the render buffers. /// The output texture. Must be valid and created. /// The custom set of actors to render. If empty, the loaded scenes will be rendered. + [Unmanaged] public static void DrawSceneDepth(GPUContext context, SceneRenderTask task, GPUTexture output, List customActors) { if (customActors.Count == 0) @@ -22,5 +23,16 @@ namespace FlaxEngine var tempCount = temp.Length; Internal_DrawSceneDepth(FlaxEngine.Object.GetUnmanagedPtr(context), FlaxEngine.Object.GetUnmanagedPtr(task), FlaxEngine.Object.GetUnmanagedPtr(output), temp, ref tempCount); } + + /// + /// Invoked drawing of the scene objects (collects draw calls into RenderList for a given RenderContext). + /// + /// The rendering context. + /// The custom set of actors to render. If empty, the loaded scenes will be rendered. + [Unmanaged] + public static void DrawActors(ref RenderContext renderContext, List customActors) + { + DrawActors(ref renderContext, Utils.ExtractArrayFromList(customActors)); + } } } diff --git a/Source/Engine/Renderer/Renderer.h b/Source/Engine/Renderer/Renderer.h index 654dde929..885b8ca43 100644 --- a/Source/Engine/Renderer/Renderer.h +++ b/Source/Engine/Renderer/Renderer.h @@ -18,22 +18,18 @@ class Actor; /// API_CLASS(Static) class FLAXENGINE_API Renderer { -DECLARE_SCRIPTING_TYPE_NO_SPAWN(Renderer); + DECLARE_SCRIPTING_TYPE_NO_SPAWN(Renderer); public: - /// /// Determines whether the scene rendering system is ready (all shaders are loaded and helper resources are ready). /// - /// true if this rendering service is ready for scene rendering; otherwise, false. static bool IsReady(); /// /// Performs rendering for the input task. /// /// The scene rendering task. - static void Render(SceneRenderTask* task); - -public: + API_FUNCTION() static void Render(SceneRenderTask* task); /// /// Draws scene objects depth (to the output Z buffer). The output must be depth texture to write hardware depth to it. @@ -53,4 +49,11 @@ public: /// The output texture. Must be valid and created. /// The input texture. It's optional. API_FUNCTION() static void DrawPostFxMaterial(GPUContext* context, API_PARAM(Ref) const RenderContext& renderContext, MaterialBase* material, GPUTexture* output, GPUTextureView* input); + + /// + /// Invoked drawing of the scene objects (collects draw calls into RenderList for a given RenderContext). + /// + /// The rendering context. + /// The custom set of actors to render. If empty, the loaded scenes will be rendered. + API_FUNCTION() static void DrawActors(API_PARAM(Ref) RenderContext& renderContext, API_PARAM(DefaultValue=null) const Array& customActors); }; diff --git a/Source/Engine/Renderer/Utils/MultiScaler.cpp b/Source/Engine/Renderer/Utils/MultiScaler.cpp index ce0b4ac3a..036c586a6 100644 --- a/Source/Engine/Renderer/Utils/MultiScaler.cpp +++ b/Source/Engine/Renderer/Utils/MultiScaler.cpp @@ -76,7 +76,7 @@ bool MultiScaler::setupResources() { psDesc.PS = shader->GetPS("PS_HalfDepth"); psDesc.DepthWriteEnable = true; - psDesc.DepthTestEnable = true; + psDesc.DepthEnable = true; psDesc.DepthFunc = ComparisonFunc::Always; if (_psHalfDepth->Init(psDesc)) return true; diff --git a/Source/Engine/Scripting/BinaryModule.cpp b/Source/Engine/Scripting/BinaryModule.cpp index 08eaf41ae..a1e2fb134 100644 --- a/Source/Engine/Scripting/BinaryModule.cpp +++ b/Source/Engine/Scripting/BinaryModule.cpp @@ -882,9 +882,7 @@ ScriptingTypeHandle ManagedBinaryModule::FindType(MonoClass* klass) { int32 typeIndex; if (typeModule->ClassToTypeIndex.TryGet(klass, typeIndex)) - { return ScriptingTypeHandle(typeModule, typeIndex); - } } return ScriptingTypeHandle(); } diff --git a/Source/Engine/ShadowsOfMordor/Builder.cpp b/Source/Engine/ShadowsOfMordor/Builder.cpp index 426925c43..ccf956d47 100644 --- a/Source/Engine/ShadowsOfMordor/Builder.cpp +++ b/Source/Engine/ShadowsOfMordor/Builder.cpp @@ -448,6 +448,7 @@ bool ShadowsOfMordor::Builder::initResources() ViewFlags::DirectionalLights | ViewFlags::PointLights | ViewFlags::SpotLights | + ViewFlags::Sky | ViewFlags::Shadows | ViewFlags::Decals | ViewFlags::SkyLights | diff --git a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Layer.cpp b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Layer.cpp index b7af16cb2..61a487074 100644 --- a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Layer.cpp +++ b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Layer.cpp @@ -31,6 +31,7 @@ MaterialGenerator::MaterialGraphBoxesMapping MaterialGenerator::MaterialGraphBox const MaterialGenerator::MaterialGraphBoxesMapping& MaterialGenerator::GetMaterialRootNodeBox(MaterialGraphBoxes box) { + static_assert(ARRAY_COUNT(MaterialGenerator::MaterialGraphBoxesMappings) == 15, "Invalid amount of boxes added for root node. Please update the code above"); return MaterialGraphBoxesMappings[static_cast(box)]; } diff --git a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Layers.cpp b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Layers.cpp index 63718b329..8db8a0d0d 100644 --- a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Layers.cpp +++ b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Layers.cpp @@ -252,6 +252,7 @@ void MaterialGenerator::ProcessGroupLayers(Box* box, Node* node, Value& value) CHECK_MATERIAL_FEATURE(Emissive, UseEmissive); CHECK_MATERIAL_FEATURE(Normal, UseNormal); CHECK_MATERIAL_FEATURE(Mask, UseMask); + CHECK_MATERIAL_FEATURE(Refraction, UseRefraction); break; } diff --git a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.h b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.h index 92f238508..f93a2204d 100644 --- a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.h +++ b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.h @@ -6,7 +6,6 @@ #include "Engine/Graphics/Materials/MaterialInfo.h" #include "Engine/Graphics/Materials/MaterialParams.h" -#include "Engine/Content/AssetsContainer.h" #include "MaterialLayer.h" #include "Types.h" diff --git a/Source/Engine/Tools/MaterialGenerator/MaterialLayer.cpp b/Source/Engine/Tools/MaterialGenerator/MaterialLayer.cpp index 33b3dfed3..c09a24e35 100644 --- a/Source/Engine/Tools/MaterialGenerator/MaterialLayer.cpp +++ b/Source/Engine/Tools/MaterialGenerator/MaterialLayer.cpp @@ -170,11 +170,11 @@ MaterialLayer* MaterialLayer::Load(const Guid& id, ReadStream* graphData, const LOG(Warning, "Missing root node in '{0}'.", caller); layer->createRootNode(); } - // Ensure to have valid root node - else if (layer->Root->Boxes.Count() != static_cast(MaterialGraphBoxes::MAX)) + // Ensure to have valid root node + else if (layer->Root->Boxes.Count() < static_cast(MaterialGraphBoxes::MAX)) { #define ADD_BOX(type, valueType) \ - if(layer->Root->Boxes.Count() <= static_cast(MaterialGraphBoxes::type)) \ + if (layer->Root->Boxes.Count() <= static_cast(MaterialGraphBoxes::type)) \ layer->Root->Boxes.Add(MaterialGraphBox(layer->Root, static_cast(MaterialGraphBoxes::type), VariantType::valueType)) ADD_BOX(TessellationMultiplier, Float); ADD_BOX(WorldDisplacement, Float3); diff --git a/Source/Engine/UI/GUI/Common/TextBoxBase.cs b/Source/Engine/UI/GUI/Common/TextBoxBase.cs index 24657b62f..12760c176 100644 --- a/Source/Engine/UI/GUI/Common/TextBoxBase.cs +++ b/Source/Engine/UI/GUI/Common/TextBoxBase.cs @@ -1128,6 +1128,24 @@ namespace FlaxEngine.GUI base.OnSubmit(); } + /// + public override void OnMouseEnter(Float2 location) + { + if (_isEditing) + Cursor = CursorType.IBeam; + + base.OnMouseEnter(location); + } + + /// + public override void OnMouseLeave() + { + if (Cursor == CursorType.IBeam) + Cursor = CursorType.Default; + + base.OnMouseLeave(); + } + /// public override void OnMouseMove(Float2 location) { @@ -1141,6 +1159,9 @@ namespace FlaxEngine.GUI // Modify selection end SetSelection(_selectionStart, currentIndex); } + + if (Cursor == CursorType.Default && _isEditing) + Cursor = CursorType.IBeam; } /// @@ -1169,6 +1190,9 @@ namespace FlaxEngine.GUI { SetSelection(hitPos); } + + if (Cursor == CursorType.Default) + Cursor = CursorType.IBeam; return true; } diff --git a/Source/Engine/UI/SpriteRender.cpp b/Source/Engine/UI/SpriteRender.cpp index 0ff23d52b..fb4f54e7f 100644 --- a/Source/Engine/UI/SpriteRender.cpp +++ b/Source/Engine/UI/SpriteRender.cpp @@ -130,7 +130,7 @@ void SpriteRender::Draw(RenderContext& renderContext) view.GetWorldMatrix(_transform, m2); Matrix::Multiply(m1, m2, world); } - model->LODs[0].Draw(renderContext, _materialInstance, world, GetStaticFlags(), false, DrawModes, GetPerInstanceRandom()); + model->LODs[0].Draw(renderContext, _materialInstance, world, GetStaticFlags(), false, DrawModes, GetPerInstanceRandom(), SortOrder); } void SpriteRender::Serialize(SerializeStream& stream, const void* otherObj) @@ -147,6 +147,7 @@ void SpriteRender::Serialize(SerializeStream& stream, const void* otherObj) SERIALIZE(Material); SERIALIZE(FaceCamera); SERIALIZE(DrawModes); + SERIALIZE(SortOrder); } void SpriteRender::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) @@ -161,6 +162,7 @@ void SpriteRender::Deserialize(DeserializeStream& stream, ISerializeModifier* mo DESERIALIZE(Material); DESERIALIZE(FaceCamera); DESERIALIZE(DrawModes); + DESERIALIZE(SortOrder); SetImage(); if (_paramColor) diff --git a/Source/Engine/UI/SpriteRender.h b/Source/Engine/UI/SpriteRender.h index 2405c5c67..8027fab8d 100644 --- a/Source/Engine/UI/SpriteRender.h +++ b/Source/Engine/UI/SpriteRender.h @@ -84,6 +84,12 @@ public: API_FIELD(Attributes="EditorOrder(50), DefaultValue(DrawPass.Default), EditorDisplay(\"Sprite\")") DrawPass DrawModes = DrawPass::Default; + /// + /// Gets the object sort order key used when sorting drawable objects during rendering. Use lower values to draw object before others, higher values are rendered later (on top). Can be use to control transparency drawing. + /// + API_FIELD(Attributes="EditorOrder(60), DefaultValue(0), EditorDisplay(\"Sprite\")") + int16 SortOrder = 0; + private: void OnMaterialLoaded(); void SetImage(); diff --git a/Source/Engine/UI/TextRender.cpp b/Source/Engine/UI/TextRender.cpp index c1d173870..d4db794eb 100644 --- a/Source/Engine/UI/TextRender.cpp +++ b/Source/Engine/UI/TextRender.cpp @@ -392,7 +392,7 @@ void TextRender::Draw(RenderContext& renderContext) drawCall.Draw.IndicesCount = e.IndicesCount; drawCall.Draw.StartIndex = e.StartIndex; drawCall.Material = e.Material; - renderContext.List->AddDrawCall(renderContext, chunkDrawModes, GetStaticFlags(), drawCall, true); + renderContext.List->AddDrawCall(renderContext, chunkDrawModes, GetStaticFlags(), drawCall, true, SortOrder); } } @@ -450,6 +450,7 @@ void TextRender::Serialize(SerializeStream& stream, const void* otherObj) SERIALIZE(Font); SERIALIZE(ShadowsMode); SERIALIZE(DrawModes); + SERIALIZE(SortOrder); SERIALIZE_MEMBER(Bounds, _layoutOptions.Bounds); SERIALIZE_MEMBER(HAlignment, _layoutOptions.HorizontalAlignment); SERIALIZE_MEMBER(VAlignment, _layoutOptions.VerticalAlignment); @@ -470,6 +471,7 @@ void TextRender::Deserialize(DeserializeStream& stream, ISerializeModifier* modi DESERIALIZE(Font); DESERIALIZE(ShadowsMode); DESERIALIZE(DrawModes); + DESERIALIZE(SortOrder); DESERIALIZE_MEMBER(Bounds, _layoutOptions.Bounds); DESERIALIZE_MEMBER(HAlignment, _layoutOptions.HorizontalAlignment); DESERIALIZE_MEMBER(VAlignment, _layoutOptions.VerticalAlignment); diff --git a/Source/Engine/UI/TextRender.h b/Source/Engine/UI/TextRender.h index 6764b0e61..d69b5427b 100644 --- a/Source/Engine/UI/TextRender.h +++ b/Source/Engine/UI/TextRender.h @@ -110,6 +110,12 @@ public: API_FIELD(Attributes="EditorOrder(80), DefaultValue(ShadowsCastingMode.All), EditorDisplay(\"Text\")") ShadowsCastingMode ShadowsMode = ShadowsCastingMode::All; + /// + /// The object sort order key used when sorting drawable objects during rendering. Use lower values to draw object before others, higher values are rendered later (on top). Can be use to control transparency drawing. + /// + API_FIELD(Attributes="EditorOrder(85), DefaultValue(0), EditorDisplay(\"Text\")") + int16 SortOrder = 0; + /// /// Gets the layout options. Layout is defined in local space of the object (on XY plane). /// diff --git a/Source/Engine/Utilities/MeshDataCache.cs b/Source/Engine/Utilities/MeshDataCache.cs index daae03816..1550b7e42 100644 --- a/Source/Engine/Utilities/MeshDataCache.cs +++ b/Source/Engine/Utilities/MeshDataCache.cs @@ -101,13 +101,15 @@ namespace FlaxEngine.Utilities private void DownloadMeshData() { + var success = false; + try { if (!_model) - { - _meshDatasInProgress = false; return; - } + if (_model.WaitForLoaded()) + throw new Exception("WaitForLoaded failed"); + var lods = _model.LODs; _meshDatas = new MeshData[lods.Length][]; @@ -127,8 +129,7 @@ namespace FlaxEngine.Utilities }; } } - - Finished?.Invoke(); + success = true; } catch (Exception ex) { @@ -139,6 +140,11 @@ namespace FlaxEngine.Utilities finally { _meshDatasInProgress = false; + + if (success) + { + Finished?.Invoke(); + } } } } diff --git a/Source/Shaders/Atmosphere.hlsl b/Source/Shaders/Atmosphere.hlsl index 93fbf8d9c..2d68bd033 100644 --- a/Source/Shaders/Atmosphere.hlsl +++ b/Source/Shaders/Atmosphere.hlsl @@ -220,13 +220,9 @@ float3 TransmittanceWithDistance(float radius, float Mu, float D) float R1 = sqrt(radius * radius + D * D + 2.0 * radius * Mu * D); float Mu1 = (radius * Mu + D) / R1; if (Mu > 0.0) - { result = min(Transmittance(radius, Mu) / Transmittance(R1, Mu1), 1.0); - } else - { result = min(Transmittance(R1, -Mu1) / Transmittance(radius, -Mu), 1.0); - } return result; } @@ -249,7 +245,7 @@ float OpticalDepthWithDistance(float H, float radius, float Mu, float D) float particleDensity = 6.2831; // REK 04, Table 2 float a = sqrt(0.5 / H * radius); float2 A01 = a * float2(Mu, Mu + D / radius); - float2 A01Sign = sign(A01); + float2 A01Sign = (float2)sign(A01); float2 A01Squared = A01 * A01; float x = A01Sign.y > A01Sign.x ? exp(A01Squared.x) : 0.0; float2 y = A01Sign / (2.3193 * abs(A01) + sqrt(1.52 * A01Squared + 4.0)) * float2(1.0, exp(-D / H * (D / (2.0 * radius) + Mu))); diff --git a/Source/Shaders/GI/DDGI.hlsl b/Source/Shaders/GI/DDGI.hlsl index 2fe741133..ba91e632c 100644 --- a/Source/Shaders/GI/DDGI.hlsl +++ b/Source/Shaders/GI/DDGI.hlsl @@ -232,7 +232,7 @@ float3 SampleDDGIIrradiance(DDGIData data, Texture2D probesData, T weight *= Square(weight) * (1.0f / (minWeightThreshold * minWeightThreshold)); // Calculate trilinear weights based on the distance to each probe to smoothly transition between grid of 8 probes - float3 trilinear = lerp(1.0f - biasAlpha, biasAlpha, probeCoordsOffset); + float3 trilinear = lerp(1.0f - biasAlpha, biasAlpha, (float3)probeCoordsOffset); weight *= max(trilinear.x * trilinear.y * trilinear.z, 0.001f); // Sample irradiance texture diff --git a/Source/Shaders/GI/DDGI.shader b/Source/Shaders/GI/DDGI.shader index 7090b9f94..1c7b577b2 100644 --- a/Source/Shaders/GI/DDGI.shader +++ b/Source/Shaders/GI/DDGI.shader @@ -54,7 +54,7 @@ float3 GetSphericalFibonacci(float sampleIndex, float samplesCount) // Calculates a random normalized ray direction (based on the ray index and the current probes rotation phrase) float3 GetProbeRayDirection(DDGIData data, uint rayIndex) { - float3 direction = GetSphericalFibonacci(rayIndex, data.RaysCount); + float3 direction = GetSphericalFibonacci((float)rayIndex, (float)data.RaysCount); return normalize(QuaternionRotate(data.RaysRotation, direction)); } @@ -307,7 +307,7 @@ void CS_TraceRays(uint3 DispatchThreadId : SV_DispatchThreadID) else { // Ray hits sky - radiance.rgb = Skybox.SampleLevel(SamplerLinearClamp, probeRayDirection, 0); + radiance.rgb = Skybox.SampleLevel(SamplerLinearClamp, probeRayDirection, 0).rgb; radiance.a = 1e27f; // Sky is the limit } @@ -576,7 +576,7 @@ void PS_IndirectLighting(Quad_VS2PS input, out float4 output : SV_Target0) // Calculate lighting float3 diffuseColor = GetDiffuseColor(gBuffer); float3 diffuse = Diffuse_Lambert(diffuseColor); - output = float4(diffuse * irradiance * gBuffer.AO, saturate(length(irradiance))); + output.rgb = diffuse * irradiance * gBuffer.AO; } #endif diff --git a/Source/Shaders/GI/GlobalSurfaceAtlas.hlsl b/Source/Shaders/GI/GlobalSurfaceAtlas.hlsl index 7c1cdc489..8676e3f87 100644 --- a/Source/Shaders/GI/GlobalSurfaceAtlas.hlsl +++ b/Source/Shaders/GI/GlobalSurfaceAtlas.hlsl @@ -153,7 +153,7 @@ float4 SampleGlobalSurfaceAtlasTile(const GlobalSurfaceAtlasData data, GlobalSur bilinearWeights.w = (1 - bilinearWeightsUV.x) * (1 - bilinearWeightsUV.y); // Tile depth weight based on sample position occlusion - float4 tileZ = depth.Gather(SamplerLinearClamp, atlasUV, 0.0f); + float4 tileZ = depth.Gather(SamplerLinearClamp, atlasUV); float depthThreshold = 2.0f * surfaceThreshold / tile.ViewBoundsSize.z; float4 depthVisibility = 1.0f; UNROLL diff --git a/Source/Shaders/GI/GlobalSurfaceAtlas.shader b/Source/Shaders/GI/GlobalSurfaceAtlas.shader index 9c8aa7bcc..1a6f7a3d5 100644 --- a/Source/Shaders/GI/GlobalSurfaceAtlas.shader +++ b/Source/Shaders/GI/GlobalSurfaceAtlas.shader @@ -330,7 +330,7 @@ float4 PS_Debug(Quad_VS2PS input) : SV_Target else { // Sample skybox - float3 skybox = Skybox.SampleLevel(SamplerLinearClamp, viewRay, 0); + float3 skybox = Skybox.SampleLevel(SamplerLinearClamp, viewRay, 0).rgb; float3 sky = float3(0.4f, 0.4f, 1.0f) * saturate(hit.StepsCount / 80.0f); color = lerp(sky, skybox, SkyboxIntensity); } diff --git a/Source/Shaders/GUI.shader b/Source/Shaders/GUI.shader index 16b764707..b54fb77fa 100644 --- a/Source/Shaders/GUI.shader +++ b/Source/Shaders/GUI.shader @@ -34,7 +34,7 @@ VS2PS VS(Render2DVertex input) // Render2D::RenderingFeatures::VertexSnapping if ((int)input.CustomDataAndClipOrigin.y & 1) - input.Position = (int2)input.Position; + input.Position = (float2)(int2)input.Position; output.Position = mul(float4(input.Position, 0, 1), ViewProjection); output.Color = input.Color; diff --git a/Source/Shaders/GlobalSignDistanceField.shader b/Source/Shaders/GlobalSignDistanceField.shader index cface49ac..3d4f7dd46 100644 --- a/Source/Shaders/GlobalSignDistanceField.shader +++ b/Source/Shaders/GlobalSignDistanceField.shader @@ -34,7 +34,7 @@ META_CB_BEGIN(1, ModelsRasterizeData) int3 ChunkCoord; float MaxDistance; float3 CascadeCoordToPosMul; -int ObjectsCount; +uint ObjectsCount; float3 CascadeCoordToPosAdd; int CascadeResolution; int CascadeIndex; @@ -91,7 +91,11 @@ float DistanceToModelSDF(float minDistance, ObjectRasterizeData modelData, Textu BRANCH if (minDistance <= distanceToVolume) return distanceToVolume; // Sample SDF +#if defined(PLATFORM_PS4) || defined(PLATFORM_PS5) + float volumeDistance = 0; // TODO: fix shader compilation error +#else float volumeDistance = modelSDFTex.SampleLevel(SamplerLinearClamp, volumeUV, modelData.MipOffset).x * modelData.DecodeMul + modelData.DecodeAdd; +#endif volumeDistance *= volumeScale; // Apply uniform instance scale (non-uniform is not supported) // Combine distance to the volume with distance to the surface inside the model @@ -153,7 +157,11 @@ void CS_RasterizeHeightfield(uint3 DispatchThreadId : SV_DispatchThreadID) float2 heightfieldUV = float2(volumeUV.x, volumeUV.z); // Sample the heightfield +#if defined(PLATFORM_PS4) || defined(PLATFORM_PS5) + float4 heightmapValue = 0; // TODO: fix shader compilation error +#else float4 heightmapValue = ObjectsTextures[i].SampleLevel(SamplerLinearClamp, heightfieldUV, objectData.MipOffset); +#endif bool isHole = (heightmapValue.b + heightmapValue.a) >= 1.9f; if (isHole || any(heightfieldUV < 0.0f) || any(heightfieldUV > 1.0f)) continue; @@ -198,7 +206,7 @@ Texture3D GlobalSDFTex : register(t0); float SampleSDF(uint3 voxelCoordMip, int3 offset) { // Sample SDF - voxelCoordMip = (uint3)clamp((int3)voxelCoordMip * GenerateMipCoordScale + offset, 0, GenerateMipTexResolution - 1); + voxelCoordMip = (uint3)clamp((int3)(voxelCoordMip * GenerateMipCoordScale) + offset, int3(0, 0, 0), (int3)(GenerateMipTexResolution - 1)); voxelCoordMip.x += GenerateMipTexOffsetX; float result = GlobalSDFTex[voxelCoordMip].r; diff --git a/Source/Shaders/MaterialCommon.hlsl b/Source/Shaders/MaterialCommon.hlsl index 1f516a4fc..4bf44674c 100644 --- a/Source/Shaders/MaterialCommon.hlsl +++ b/Source/Shaders/MaterialCommon.hlsl @@ -83,9 +83,9 @@ struct Material float Opacity; float3 SubsurfaceColor; float Refraction; + float3 WorldDisplacement; float Mask; float TessellationMultiplier; - float3 WorldDisplacement; #if USE_CUSTOM_VERTEX_INTERPOLATORS float4 CustomVSToPS[CUSTOM_VERTEX_INTERPOLATORS_COUNT]; #endif diff --git a/Source/Shaders/ProbesFilter.shader b/Source/Shaders/ProbesFilter.shader index 5fc5a7241..29859076b 100644 --- a/Source/Shaders/ProbesFilter.shader +++ b/Source/Shaders/ProbesFilter.shader @@ -8,7 +8,7 @@ META_CB_BEGIN(0, Data) float2 Dummy0; int CubeFace; -int SourceMipIndex; +float SourceMipIndex; META_CB_END TextureCube Cube : register(t0); diff --git a/Source/Shaders/SSR.shader b/Source/Shaders/SSR.shader index e023e2070..999dd93a3 100644 --- a/Source/Shaders/SSR.shader +++ b/Source/Shaders/SSR.shader @@ -199,11 +199,11 @@ float4 PS_ResolvePass(Quad_VS2PS input) : SV_Target0 { float2 offsetUV = Offsets[i] * SSRtexelSize; offsetUV = mul(offsetRotationMatrix, offsetUV); - float4 sample = Texture0.SampleLevel(SamplerLinearClamp, uv + offsetUV, 0); + float4 value = Texture0.SampleLevel(SamplerLinearClamp, uv + offsetUV, 0); #if SSR_REDUCE_HIGHLIGHTS - sample.rgb /= 1 + Luminance(sample.rgb); + value.rgb /= 1 + Luminance(value.rgb); #endif - result += sample; + result += value; } // Calculate final result value diff --git a/Source/Shaders/ShadowsSampling.hlsl b/Source/Shaders/ShadowsSampling.hlsl index b51c4a8db..88f93de3d 100644 --- a/Source/Shaders/ShadowsSampling.hlsl +++ b/Source/Shaders/ShadowsSampling.hlsl @@ -145,7 +145,7 @@ float SampleShadowMapFixedSizePCF(Texture2DArray shadowMap, float2 shadowMapSize s.x += (1.0f - fc.y) * (v1[0].w * (CSMFilterWeights[row + FS_2][col + FS_2] - CSMFilterWeights[row + FS_2][col + FS_2] * fc.x) + v1[0].z * (fc.x * (CSMFilterWeights[row + FS_2][col + FS_2] - - CSMFilterWeights[row + FS_2][col + FS_2 + 1.0f]) + - CSMFilterWeights[row + FS_2][col + FS_2 + 1]) + CSMFilterWeights[row + FS_2][col + FS_2 + 1])); s.y += fc.y * (v1[0].x * (CSMFilterWeights[row + FS_2][col + FS_2] - CSMFilterWeights[row + FS_2][col + FS_2] * fc.x) diff --git a/Source/Shaders/TAA.shader b/Source/Shaders/TAA.shader index 0ef3dd402..30f4e7f35 100644 --- a/Source/Shaders/TAA.shader +++ b/Source/Shaders/TAA.shader @@ -69,7 +69,7 @@ float4 PS(Quad_VS2PS input) : SV_Target0 // Sample history by clamp it to the nearby colors range to reduce artifacts float4 history = SAMPLE_RT_LINEAR(InputHistory, prevUV); - float lumaOffset = abs(Luminance(neighborhoodAvg) - Luminance(current)); + float lumaOffset = abs(Luminance(neighborhoodAvg.rgb) - Luminance(current.rgb)); float aabbMargin = lerp(4.0, 0.25, saturate(velocityLength * 100.0)) * lumaOffset; history = ClipToAABB(history, neighborhoodMin - aabbMargin, neighborhoodMax + aabbMargin); //history = clamp(history, neighborhoodMin, neighborhoodMax); diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Parsing.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Parsing.cs index 1f8f46815..bca9b2d9d 100644 --- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Parsing.cs +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Parsing.cs @@ -337,6 +337,9 @@ namespace Flax.Build.Bindings case "attributes": currentParam.Attributes = tag.Value; break; + case "defaultvalue": + currentParam.DefaultValue = tag.Value; + break; default: bool valid = false; ParseFunctionParameterTag?.Invoke(ref valid, tag, ref currentParam);