Merge branch 'FlaxEngine:master' into master

This commit is contained in:
Filip Franik
2023-02-03 14:19:27 +01:00
committed by GitHub
112 changed files with 669 additions and 564 deletions

View File

@@ -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<typename ContextType>

View File

@@ -181,7 +181,8 @@ public:
/// <param name="world">The world transformation of the model.</param>
/// <param name="flags">The object static flags.</param>
/// <param name="receiveDecals">True if rendered geometry can receive decals, otherwise false.</param>
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;
/// <param name="sortOrder">Object sorting key.</param>
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;
/// <summary>
/// Draws the model.

View File

@@ -161,6 +161,11 @@ namespace FlaxEngine
}
}
/// <summary>
/// Gets the aspect ratio used by the viewport.
/// </summary>
public float AspectRatio => !Mathf.IsZero(Height) ? Width / Height : 0f;
/// <summary>
/// Determines whether the specified <see cref="Viewport"/> is equal to this instance.
/// </summary>
@@ -326,21 +331,5 @@ namespace FlaxEngine
vector /= w;
}
}
/// <summary>
/// Gets the aspect ratio used by the viewport.
/// </summary>
/// <value>The aspect ratio.</value>
public float AspectRatio
{
get
{
if (!Mathf.IsZero(Height))
{
return Width / Height;
}
return 0f;
}
}
}
}

View File

@@ -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<typename T>
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<baseType*>((type*)1))-1)

View File

@@ -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);
}

View File

@@ -514,7 +514,7 @@ public:
API_FIELD(ReadOnly) static BlendingMode Additive;
/// <summary>
/// Gets the alpha blending.
/// Gets the alpha blending. Source alpha controls the output color (0 - use destination color, 1 - use source color).
/// </summary>
API_FIELD(ReadOnly) static BlendingMode AlphaBlend;
@@ -591,22 +591,22 @@ API_ENUM() enum class Quality : byte
API_ENUM() enum class MaterialPostFxLocation : byte
{
/// <summary>
/// The after post processing pass using LDR input frame.
/// The 'after' post processing pass using LDR input frame.
/// </summary>
AfterPostProcessingPass = 0,
/// <summary>
/// The before post processing pass using HDR input frame.
/// The 'before' post processing pass using HDR input frame.
/// </summary>
BeforePostProcessingPass = 1,
/// <summary>
/// The before forward pass but after GBuffer with HDR input frame.
/// The 'before' forward pass but after GBuffer with HDR input frame.
/// </summary>
BeforeForwardPass = 2,
/// <summary>
/// The after custom post effects.
/// The 'after' custom post effects.
/// </summary>
AfterCustomPostEffects = 3,
@@ -620,6 +620,11 @@ API_ENUM() enum class MaterialPostFxLocation : byte
/// </summary>
AfterAntiAliasingPass = 5,
/// <summary>
/// The 'after' forward pass but before any post processing.
/// </summary>
AfterForwardPass = 6,
API_ENUM(Attributes="HideInEditor")
MAX,
};
@@ -635,7 +640,7 @@ API_ENUM() enum class PostProcessEffectLocation
Default = 0,
/// <summary>
///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.
/// </summary>
BeforePostProcessingPass = 1,
@@ -659,6 +664,16 @@ API_ENUM() enum class PostProcessEffectLocation
/// </summary>
CustomUpscale = 5,
/// <summary>
/// The 'after' GBuffer rendering pass. Can be used to render custom geometry into GBuffer. Output is light buffer, single-target only (no output).
/// </summary>
AfterGBufferPass = 6,
/// <summary>
/// The 'after' forward pass but before any post processing.
/// </summary>
AfterForwardPass = 7,
API_ENUM(Attributes="HideInEditor")
MAX,
};
@@ -874,7 +889,7 @@ API_ENUM() enum class ViewMode
/// <summary>
/// Frame rendering flags used to switch between graphics features.
/// </summary>
API_ENUM(Attributes="Flags") enum class ViewFlags : int64
API_ENUM(Attributes="Flags") enum class ViewFlags : uint64
{
/// <summary>
/// Nothing.
@@ -1011,20 +1026,25 @@ API_ENUM(Attributes="Flags") enum class ViewFlags : int64
/// </summary>
GlobalSDF = 1 << 25,
/// <summary>
/// Shows/hides the Sky/Skybox rendering.
/// </summary>
Sky = 1 << 26,
/// <summary>
/// Default flags for Game.
/// </summary>
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,
/// <summary>
/// Default flags for Editor.
/// </summary>
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,
/// <summary>
/// Default flags for materials/models previews generating.
/// </summary>
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);

View File

@@ -315,6 +315,12 @@ public:
/// <param name="rts">The array with render targets to bind.</param>
API_FUNCTION() virtual void SetRenderTarget(GPUTextureView* depthBuffer, const Span<GPUTextureView*>& rts) = 0;
/// <summary>
/// Sets the blend factor that modulate values for a pixel shader, render target, or both.
/// </summary>
/// <param name="value">Blend factors, one for each RGBA component.</param>
API_FUNCTION() virtual void SetBlendFactor(const Float4& value) = 0;
public:
/// <summary>
/// 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).

View File

@@ -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;

View File

@@ -134,7 +134,7 @@ public:
/// <summary>
/// Quad rendering shader
/// </summary>
GPUShader* QuadShader;
API_FIELD(ReadOnly) GPUShader* QuadShader;
/// <summary>
/// The current task being executed.

View File

@@ -24,16 +24,16 @@ public:
{
DECLARE_SCRIPTING_TYPE_NO_SPAWN(Description);
/// <summary>
/// Enable/disable depth (DepthFunc and DepthWriteEnable)
/// </summary>
API_FIELD() bool DepthEnable;
/// <summary>
/// Enable/disable depth write
/// </summary>
API_FIELD() bool DepthWriteEnable;
/// <summary>
/// Enable/disable depth test
/// </summary>
API_FIELD() bool DepthTestEnable;
/// <summary>
/// Enable/disable depth clipping
/// </summary>

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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)

View File

@@ -10,7 +10,7 @@
/// <summary>
/// Current materials shader version.
/// </summary>
#define MATERIAL_GRAPH_VERSION 159
#define MATERIAL_GRAPH_VERSION 161
class Material;
class GPUShader;

View File

@@ -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");

View File

@@ -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;

View File

@@ -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;
/// <summary>
/// Represents part of the model that is made of vertices and can be rendered using custom material and transformation.
@@ -275,77 +272,6 @@ public:
/// <param name="drawCall">The draw call.</param>
void GetDrawCallGeometry(DrawCall& drawCall) const;
/// <summary>
/// Model instance drawing packed data.
/// </summary>
struct DrawInfo
{
/// <summary>
/// The instance buffer to use during model rendering.
/// </summary>
ModelInstanceEntries* Buffer;
/// <summary>
/// The world transformation of the model.
/// </summary>
Matrix* World;
/// <summary>
/// The instance drawing state data container. Used for LOD transition handling and previous world transformation matrix updating.
/// </summary>
GeometryDrawStateData* DrawState;
/// <summary>
/// The lightmap.
/// </summary>
const Lightmap* Lightmap;
/// <summary>
/// The lightmap UVs.
/// </summary>
const Rectangle* LightmapUVs;
/// <summary>
/// The model instance vertex colors buffers (per-lod all meshes packed in a single allocation, array length equal to model lods count).
/// </summary>
GPUBuffer** VertexColors;
/// <summary>
/// The object static flags.
/// </summary>
StaticFlags Flags;
/// <summary>
/// The object draw modes.
/// </summary>
DrawPass DrawModes;
/// <summary>
/// The bounds of the model (used to select a proper LOD during rendering).
/// </summary>
BoundingSphere Bounds;
/// <summary>
/// The per-instance random value.
/// </summary>
float PerInstanceRandom;
/// <summary>
/// The LOD bias value.
/// </summary>
char LODBias;
/// <summary>
/// The forced LOD to use. Value -1 disables this feature.
/// </summary>
char ForcedLOD;
/// <summary>
/// The object sorting key.
/// </summary>
int16 SortOrder;
};
/// <summary>
/// Draws the mesh. Binds vertex and index buffers and invokes the draw call.
/// </summary>

View File

@@ -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;
/// <summary>
/// Base class for model resources meshes.
@@ -143,4 +151,95 @@ public:
/// <param name="count">The amount of items inside the result buffer.</param>
/// <returns>True if failed, otherwise false</returns>
virtual bool DownloadDataCPU(MeshBufferType type, BytesContainer& result, int32& count) const = 0;
public:
/// <summary>
/// Model instance drawing packed data.
/// </summary>
struct DrawInfo
{
/// <summary>
/// The instance buffer to use during model rendering
/// </summary>
ModelInstanceEntries* Buffer;
/// <summary>
/// The world transformation of the model.
/// </summary>
Matrix* World;
/// <summary>
/// The instance drawing state data container. Used for LOD transition handling and previous world transformation matrix updating.
/// </summary>
GeometryDrawStateData* DrawState;
union
{
struct
{
/// <summary>
/// The skinning.
/// </summary>
SkinnedMeshDrawData* Skinning;
/// <summary>
/// The blend shapes.
/// </summary>
BlendShapesInstance* BlendShapes;
};
struct
{
/// <summary>
/// The lightmap.
/// </summary>
const Lightmap* Lightmap;
/// <summary>
/// The lightmap UVs.
/// </summary>
const Rectangle* LightmapUVs;
};
};
/// <summary>
/// The model instance vertex colors buffers (per-lod all meshes packed in a single allocation, array length equal to model lods count).
/// </summary>
GPUBuffer** VertexColors;
/// <summary>
/// The object static flags.
/// </summary>
StaticFlags Flags;
/// <summary>
/// The object draw modes.
/// </summary>
DrawPass DrawModes;
/// <summary>
/// The bounds of the model (used to select a proper LOD during rendering).
/// </summary>
BoundingSphere Bounds;
/// <summary>
/// The per-instance random value.
/// </summary>
float PerInstanceRandom;
/// <summary>
/// The LOD bias value.
/// </summary>
char LODBias;
/// <summary>
/// The forced LOD to use. Value -1 disables this feature.
/// </summary>
char ForcedLOD;
/// <summary>
/// The object sorting key.
/// </summary>
int16 SortOrder;
};
};

View File

@@ -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

View File

@@ -6,11 +6,6 @@
#include "Types.h"
#include "BlendShape.h"
struct GeometryDrawStateData;
struct RenderContext;
class GPUBuffer;
class SkinnedMeshDrawData;
/// <summary>
/// Represents part of the skinned model that is made of vertices and can be rendered using custom material, transformation and skeleton bones hierarchy.
/// </summary>
@@ -170,62 +165,6 @@ public:
}
public:
/// <summary>
/// Model instance drawing packed data.
/// </summary>
struct DrawInfo
{
/// <summary>
/// The instance buffer to use during model rendering
/// </summary>
ModelInstanceEntries* Buffer;
/// <summary>
/// The skinning.
/// </summary>
SkinnedMeshDrawData* Skinning;
/// <summary>
/// The blend shapes.
/// </summary>
BlendShapesInstance* BlendShapes;
/// <summary>
/// The world transformation of the model.
/// </summary>
Matrix* World;
/// <summary>
/// The instance drawing state data container. Used for LOD transition handling and previous world transformation matrix updating.
/// </summary>
GeometryDrawStateData* DrawState;
/// <summary>
/// The object draw modes.
/// </summary>
DrawPass DrawModes;
/// <summary>
/// The bounds of the model (used to select a proper LOD during rendering).
/// </summary>
BoundingSphere Bounds;
/// <summary>
/// The per-instance random value.
/// </summary>
float PerInstanceRandom;
/// <summary>
/// The LOD bias value.
/// </summary>
char LODBias;
/// <summary>
/// The forced LOD to use. Value -1 disables this feature.
/// </summary>
char ForcedLOD;
};
/// <summary>
/// Draws the mesh. Binds vertex and index buffers and invokes the draw call.
/// </summary>

View File

@@ -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();

View File

@@ -45,10 +45,14 @@ public:
{
struct
{
GPUTexture* GBuffer0;
GPUTexture* GBuffer1;
GPUTexture* GBuffer2;
GPUTexture* GBuffer3;
/// <summary>Gets the GBuffer texture 0. RGB: Color, A: AO</summary>
API_FIELD(ReadOnly) GPUTexture* GBuffer0;
/// <summary>Gets the GBuffer texture 1. RGB: Normal, A: ShadingModel</summary>
API_FIELD(ReadOnly) GPUTexture* GBuffer1;
/// <summary>Gets the GBuffer texture 2. R: Roughness, G: Metalness, B:Specular</summary>
API_FIELD(ReadOnly) GPUTexture* GBuffer2;
/// <summary>Gets the GBuffer texture 3. RGBA: Custom Data</summary>
API_FIELD(ReadOnly) GPUTexture* GBuffer3;
};
GPUTexture* GBuffer[4];
@@ -174,6 +178,8 @@ public:
template<class T>
T* GetCustomBuffer(const StringView& name)
{
if (LinkedCustomBuffers)
return LinkedCustomBuffers->GetCustomBuffer<T>(name);
CustomBuffer* result = (CustomBuffer*)FindCustomBuffer(name);
if (!result)
{
@@ -202,6 +208,11 @@ public:
/// </remarks>
API_FIELD(ReadOnly) GPUTexture* MotionVectors;
/// <summary>
/// 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).
/// </summary>
API_FIELD() RenderBuffers* LinkedCustomBuffers = nullptr;
public:
/// <summary>
/// Allocates the buffers.

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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 Span<GPU
}
}
void GPUContextDX11::SetBlendFactor(const Float4& value)
{
CurrentBlendFactor = value;
if (CurrentBlendState)
_context->OMSetBlendState(CurrentBlendState, CurrentBlendFactor.Raw, D3D11_DEFAULT_SAMPLE_MASK);
}
void GPUContextDX11::ResetSR()
{
_srDirtyFlag = false;
@@ -560,8 +568,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)
{

View File

@@ -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<GPUTextureView*>& rts) override;
void SetBlendFactor(const Float4& value) override;
void ResetSR() override;
void ResetUA() override;
void ResetCB() override;

View File

@@ -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<int32>(desc.DepthFunc) + (desc.DepthTestEnable ? 0 : 9) + (desc.DepthWriteEnable ? 0 : 18);
DepthStencilStateIndex = static_cast<int32>(desc.DepthFunc) + (desc.DepthEnable ? 0 : 9) + (desc.DepthWriteEnable ? 0 : 18);
RasterizerStateIndex = static_cast<int32>(desc.CullMode) + (desc.Wireframe ? 0 : 3) + (desc.DepthClipEnable ? 0 : 6);
BlendState = _device->GetBlendState(desc.BlendMode);

View File

@@ -845,6 +845,11 @@ void GPUContextDX12::SetRenderTarget(GPUTextureView* depthBuffer, const Span<GPU
}
}
void GPUContextDX12::SetBlendFactor(const Float4& value)
{
_commandList->OMSetBlendFactor(value.Raw);
}
void GPUContextDX12::ResetSR()
{
for (int32 slot = 0; slot < GPU_MAX_SR_BINDED; slot++)

View File

@@ -166,6 +166,7 @@ public:
void SetRenderTarget(GPUTextureView* rt) override;
void SetRenderTarget(GPUTextureView* depthBuffer, GPUTextureView* rt) override;
void SetRenderTarget(GPUTextureView* depthBuffer, const Span<GPUTextureView*>& rts) override;
void SetBlendFactor(const Float4& value) override;
void ResetSR() override;
void ResetUA() override;
void ResetCB() override;

View File

@@ -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<D3D12_COMPARISON_FUNC>(desc.DepthFunc);
psDesc.DepthStencilState.StencilEnable = FALSE;

View File

@@ -84,6 +84,10 @@ public:
{
}
void SetBlendFactor(const Float4& value) override
{
}
void ResetSR() override
{
}

View File

@@ -966,6 +966,12 @@ void GPUContextVulkan::SetRenderTarget(GPUTextureView* depthBuffer, const Span<G
}
}
void GPUContextVulkan::SetBlendFactor(const Float4& value)
{
const auto cmdBuffer = _cmdBufferManager->GetCmdBuffer();
vkCmdSetBlendConstants(cmdBuffer->GetHandle(), value.Raw);
}
void GPUContextVulkan::ResetSR()
{
Platform::MemoryClear(_srHandles, sizeof(_srHandles));

View File

@@ -184,6 +184,7 @@ public:
void SetRenderTarget(GPUTextureView* rt) override;
void SetRenderTarget(GPUTextureView* depthBuffer, GPUTextureView* rt) override;
void SetRenderTarget(GPUTextureView* depthBuffer, const Span<GPUTextureView*>& rts) override;
void SetBlendFactor(const Float4& value) override;
void ResetSR() override;
void ResetUA() override;
void ResetCB() override;

View File

@@ -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;

View File

@@ -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);

View File

@@ -138,6 +138,12 @@ public:
API_FIELD(Attributes="EditorOrder(100), DefaultValue(DrawPass.Default), EditorDisplay(\"Skinned Model\")")
DrawPass DrawModes = DrawPass::Default;
/// <summary>
/// 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.
/// </summary>
API_FIELD(Attributes="EditorDisplay(\"Skinned Model\"), EditorOrder(110), DefaultValue(0)")
int16 SortOrder = 0;
/// <summary>
/// The shadows casting mode.
/// [Deprecated on 26.10.2022, expires on 26.10.2024]

View File

@@ -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)

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -334,7 +334,8 @@ public:
/// <summary>
/// Performs the full particles simulation update (postponed for the next particle manager update).
/// </summary>
API_FUNCTION() void UpdateSimulation();
/// <param name="singleFrame">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.</param>
API_FUNCTION() void UpdateSimulation(bool singleFrame = false);
/// <summary>
/// Updates the actor bounds.

View File

@@ -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<uint32> SortingKeys[2];
Array<int32> SortingIndices;
Array<int32> SortedIndices;
Array<float> RibbonTotalDistances;
}
class ParticleManagerService : public EngineService
@@ -289,14 +296,17 @@ void DrawEmitterCPU(RenderContext& renderContext, ParticleBuffer* buffer, DrawCa
{
// Prepare ribbon data
if (!buffer->GPU.RibbonIndexBufferDynamic)
{
buffer->GPU.RibbonIndexBufferDynamic = New<DynamicIndexBuffer>(0, (uint32)sizeof(uint16), TEXT("RibbonIndexBufferDynamic"));
}
buffer->GPU.RibbonIndexBufferDynamic->Clear();
else
buffer->GPU.RibbonIndexBufferDynamic->Clear();
if (!buffer->GPU.RibbonVertexBufferDynamic)
buffer->GPU.RibbonVertexBufferDynamic = New<DynamicVertexBuffer>(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];
@@ -313,74 +323,88 @@ void DrawEmitterCPU(RenderContext& renderContext, ParticleBuffer* buffer, DrawCa
int32 count = buffer->CPU.Count;
ASSERT(buffer->CPU.RibbonOrder.Count() == emitter->Graph.RibbonRenderingModules.Count() * buffer->Capacity);
int32* ribbonOrderData = buffer->CPU.RibbonOrder.Get() + module->RibbonOrderOffset;
ParticleBufferCPUDataAccessor<Float3> 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);
}
}
@@ -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;
@@ -1187,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)

View File

@@ -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)

View File

@@ -17,6 +17,7 @@ class ParticleEmitter;
class Particles;
class GPUBuffer;
class DynamicIndexBuffer;
class DynamicVertexBuffer;
/// <summary>
/// The particle attribute that defines a single particle layout component.
@@ -302,9 +303,9 @@ public:
DynamicIndexBuffer* RibbonIndexBufferDynamic = nullptr;
/// <summary>
/// The ribbon particles rendering segment distances buffer. Stored one per ribbon module.
/// The ribbon particles rendering vertex buffer (dynamic GPU access).
/// </summary>
GPUBuffer* RibbonSegmentDistances[PARTICLE_EMITTER_MAX_RIBBONS] = {};
DynamicVertexBuffer* RibbonVertexBufferDynamic = nullptr;
/// <summary>
/// The flag used to indicate that GPU buffers data should be cleared before next simulation.

View File

@@ -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");

View File

@@ -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;

View File

@@ -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

View File

@@ -221,7 +221,6 @@ struct DrawCall
float UVOffsetX;
float UVOffsetY;
uint32 SegmentCount;
GPUBuffer* SegmentDistances;
} Ribbon;
struct

View File

@@ -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();

View File

@@ -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<SkyboxCustomBuffer>(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");

View File

@@ -32,7 +32,7 @@ public:
/// </summary>
/// <param name="renderContext">The rendering context.</param>
/// <param name="lightBuffer">Light buffer to output material emissive light and precomputed indirect lighting</param>
void Fill(RenderContext& renderContext, GPUTextureView* lightBuffer);
void Fill(RenderContext& renderContext, GPUTexture* lightBuffer);
/// <summary>
/// Render debug view

View File

@@ -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)

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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(output->Width(), output->Height());
context->SetRenderTarget(*output);
context->Draw(input);
return;

View File

@@ -268,6 +268,7 @@ bool ProbesRenderer::Init()
ViewFlags::SkyLights |
ViewFlags::Decals |
ViewFlags::Shadows |
ViewFlags::Sky |
ViewFlags::Fog;
view.Mode = ViewMode::NoPostFx;
view.IsOfflinePass = true;

View File

@@ -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);
}

View File

@@ -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<Actor*>& 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();

View File

@@ -13,9 +13,21 @@ namespace FlaxEngine
/// <param name="task">Render task to use it's view description and the render buffers.</param>
/// <param name="output">The output texture. Must be valid and created.</param>
/// <param name="customActors">The custom set of actors to render. If empty, the loaded scenes will be rendered.</param>
[Unmanaged]
public static void DrawSceneDepth(GPUContext context, SceneRenderTask task, GPUTexture output, List<Actor> customActors)
{
Internal_DrawSceneDepth(FlaxEngine.Object.GetUnmanagedPtr(context), FlaxEngine.Object.GetUnmanagedPtr(task), FlaxEngine.Object.GetUnmanagedPtr(output), Utils.ExtractArrayFromList(customActors));
}
/// <summary>
/// Invoked drawing of the scene objects (collects draw calls into RenderList for a given RenderContext).
/// </summary>
/// <param name="renderContext">The rendering context.</param>
/// <param name="customActors">The custom set of actors to render. If empty, the loaded scenes will be rendered.</param>
[Unmanaged]
public static void DrawActors(ref RenderContext renderContext, List<Actor> customActors)
{
Internal_DrawActors(ref renderContext, Utils.ExtractArrayFromList(customActors));
}
}
}

View File

@@ -18,22 +18,18 @@ class Actor;
/// </summary>
API_CLASS(Static) class FLAXENGINE_API Renderer
{
DECLARE_SCRIPTING_TYPE_NO_SPAWN(Renderer);
DECLARE_SCRIPTING_TYPE_NO_SPAWN(Renderer);
public:
/// <summary>
/// Determines whether the scene rendering system is ready (all shaders are loaded and helper resources are ready).
/// </summary>
/// <returns><c>true</c> if this rendering service is ready for scene rendering; otherwise, <c>false</c>.</returns>
static bool IsReady();
/// <summary>
/// Performs rendering for the input task.
/// </summary>
/// <param name="task">The scene rendering task.</param>
static void Render(SceneRenderTask* task);
public:
API_FUNCTION() static void Render(SceneRenderTask* task);
/// <summary>
/// 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:
/// <param name="output">The output texture. Must be valid and created.</param>
/// <param name="input">The input texture. It's optional.</param>
API_FUNCTION() static void DrawPostFxMaterial(GPUContext* context, API_PARAM(Ref) const RenderContext& renderContext, MaterialBase* material, GPUTexture* output, GPUTextureView* input);
/// <summary>
/// Invoked drawing of the scene objects (collects draw calls into RenderList for a given RenderContext).
/// </summary>
/// <param name="renderContext">The rendering context.</param>
/// <param name="customActors">The custom set of actors to render. If empty, the loaded scenes will be rendered.</param>
API_FUNCTION() static void DrawActors(API_PARAM(Ref) RenderContext& renderContext, API_PARAM(DefaultValue=null) const Array<Actor*, HeapAllocation>& customActors);
};

View File

@@ -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;

View File

@@ -448,6 +448,7 @@ bool ShadowsOfMordor::Builder::initResources()
ViewFlags::DirectionalLights |
ViewFlags::PointLights |
ViewFlags::SpotLights |
ViewFlags::Sky |
ViewFlags::Shadows |
ViewFlags::Decals |
ViewFlags::SkyLights |

View File

@@ -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<int32>(box)];
}

View File

@@ -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;
}

View File

@@ -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"

View File

@@ -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<int32>(MaterialGraphBoxes::MAX))
// Ensure to have valid root node
else if (layer->Root->Boxes.Count() < static_cast<int32>(MaterialGraphBoxes::MAX))
{
#define ADD_BOX(type, valueType) \
if(layer->Root->Boxes.Count() <= static_cast<int32>(MaterialGraphBoxes::type)) \
if (layer->Root->Boxes.Count() <= static_cast<int32>(MaterialGraphBoxes::type)) \
layer->Root->Boxes.Add(MaterialGraphBox(layer->Root, static_cast<int32>(MaterialGraphBoxes::type), VariantType::valueType))
ADD_BOX(TessellationMultiplier, Float);
ADD_BOX(WorldDisplacement, Float3);