// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
#pragma once
#include "Config.h"
#include "Engine/Core/Math/Rectangle.h"
#include "Engine/Core/Math/Color.h"
struct RenderView;
struct RenderContext;
struct DrawCall;
class IMaterial;
class RenderTask;
class SceneRenderTask;
class DirectionalLight;
class PointLight;
class SpotLight;
class SkyLight;
class EnvironmentProbe;
class Skybox;
class Decal;
class MaterialBase;
class SkinnedMeshDrawData;
class Lightmap;
class RenderBuffers;
class GPUTextureView;
class GPUContext;
class GPUBuffer;
class GPUTexture;
///
/// Interface for objects that can render custom sky
///
class ISkyRenderer
{
public:
///
/// Returns true if sky is realtime, otherwise it's static.
///
virtual bool IsDynamicSky() const = 0;
///
/// Apply sky material/shader state to the GPU pipeline with custom parameters set (render to GBuffer).
///
/// The context responsible for rendering commands.
/// The rendering context.
/// The world matrix to use during sky model vertices transformations.
virtual void ApplySky(GPUContext* context, RenderContext& renderContext, const Matrix& world) = 0;
};
///
/// Volumetric fog feature settings
///
struct VolumetricFogOptions
{
bool Enable;
float ScatteringDistribution;
Color Albedo;
Color Emissive;
float ExtinctionScale;
float Distance;
Float4 FogParameters;
bool UseVolumetricFog() const
{
return Enable && Distance > 0;
}
};
///
/// Interface for objects that can render custom fog/atmosphere
///
class IFogRenderer
{
public:
///
/// Gets the volumetric fog options.
///
/// The result.
virtual void GetVolumetricFogOptions(VolumetricFogOptions& result) const = 0;
///
/// Gets the exponential height fog data.
///
/// The rendering view.
/// The result.
virtual void GetExponentialHeightFogData(const RenderView& view, ExponentialHeightFogData& result) const = 0;
///
/// Draw fog using GBuffer inputs
///
/// Context responsible for rendering commands
/// The rendering context.
/// Output buffer
virtual void DrawFog(GPUContext* context, RenderContext& renderContext, GPUTextureView* output) = 0;
};
///
/// Interface for objects that can render custom atmospheric fog
///
class IAtmosphericFogRenderer
{
public:
///
/// Draw fog using GBuffer inputs
///
/// Context responsible for rendering commands
/// The rendering context.
/// Output buffer
virtual void DrawFog(GPUContext* context, RenderContext& renderContext, GPUTextureView* output) = 0;
};
///
/// Renderer draw call used for dynamic batching process.
///
struct DrawCall
{
///
/// The material to use for rendering.
///
IMaterial* Material;
struct
{
///
/// The geometry index buffer (cannot be null).
///
GPUBuffer* IndexBuffer;
///
/// The geometry vertex buffers.
///
GPUBuffer* VertexBuffers[3];
///
/// The geometry vertex buffers byte offsets.
///
uint32 VertexBuffersOffsets[3];
} Geometry;
///
/// The amount of instances of the geometry to draw. Set to 0 if use indirect draw arguments buffer.
///
int32 InstanceCount;
union
{
struct
{
///
/// The location of the first index read by the GPU from the index buffer.
///
int32 StartIndex;
///
/// The indices count.
///
int32 IndicesCount;
};
struct
{
///
/// The indirect draw arguments offset.
///
uint32 IndirectArgsOffset;
///
/// The indirect draw arguments buffer.
///
GPUBuffer* IndirectArgsBuffer;
};
} Draw;
// Per-material shader data packed into union
union
{
struct
{
const Lightmap* Lightmap;
Rectangle LightmapUVsArea;
} Features;
struct
{
const Lightmap* Lightmap;
Rectangle LightmapUVsArea;
SkinnedMeshDrawData* Skinning;
Float3 GeometrySize; // Object geometry size in the world (unscaled).
float LODDitherFactor; // The model LOD transition dither progress.
Matrix PrevWorld;
} Surface;
struct
{
const Lightmap* Lightmap;
Rectangle LightmapUVsArea;
Float4 HeightmapUVScaleBias;
Float4 NeighborLOD;
Float2 OffsetUV;
float CurrentLOD;
float ChunkSizeNextLOD;
float TerrainChunkSizeLOD0;
const class TerrainPatch* Patch;
} Terrain;
struct
{
class ParticleBuffer* Particles;
class ParticleEmitterGraphCPUNode* Module;
struct
{
int32 OrderOffset;
float UVTilingDistance;
float UVScaleX;
float UVScaleY;
float UVOffsetX;
float UVOffsetY;
uint32 SegmentCount;
} Ribbon;
struct
{
Float3 Position;
float Radius;
int32 ParticleIndex;
} VolumetricFog;
} Particle;
struct
{
GPUBuffer* SplineDeformation;
Matrix LocalMatrix; // Geometry transformation applied before deformation.
Float3 GeometrySize; // Object geometry size in the world (unscaled).
float Segment;
float ChunksPerSegment;
float MeshMinZ;
float MeshMaxZ;
} Deformable;
struct
{
byte Raw[96];
} Custom;
};
///
/// Object world transformation matrix.
///
Matrix World;
///
/// Object location in the world used for draw calls sorting.
///
Float3 ObjectPosition;
///
/// Object bounding sphere radius that contains it whole (sphere at ObjectPosition).
///
float ObjectRadius;
///
/// The world matrix determinant sign (used for geometry that is two sided or has inverse scale - needs to flip normal vectors and change triangles culling).
///
float WorldDeterminantSign;
///
/// The random per-instance value (normalized to range 0-1).
///
float PerInstanceRandom;
///
/// The sorting key for the draw call calculate by RenderList.
///
uint64 SortKey;
///
/// Zero-init.
///
FORCE_INLINE DrawCall()
{
Platform::MemoryClear(this, sizeof(DrawCall));
}
};
template<>
struct TIsPODType
{
enum { Value = true };
};
///
/// Data container for meshes and skinned meshes rendering with minimal state caching.
/// Used to update previous world transformation matrix for motion vectors pass and handle LOD transitions blending.
///
struct GeometryDrawStateData
{
///
/// The previous frame world transformation matrix for the given geometry instance.
///
Matrix PrevWorld = Matrix::Identity;
///
/// The previous frame index. In sync with Engine::FrameCount used to detect new frames and rendering gaps to reset state.
///
uint64 PrevFrame = 0;
///
/// The previous frame model LOD index used. It's locked during LOD transition to cache the transition start LOD.
///
char PrevLOD = -1;
///
/// The LOD transition timer. Value 255 means the end of the transition (aka no transition), value 0 means transition started.
/// Interpolated between 0-255 to smooth transition over several frames and reduce LOD changing artifacts.
///
byte LODTransition = 255;
};
template<>
struct TIsPODType
{
enum { Value = true };
};
#define GEOMETRY_DRAW_STATE_EVENT_BEGIN(drawState, worldMatrix) \
const auto frame = Engine::FrameCount; \
if (drawState.PrevFrame + 1 < frame && !renderContext.View.IsSingleFrame) \
{ \
drawState.PrevWorld = worldMatrix; \
}
#define GEOMETRY_DRAW_STATE_EVENT_END(drawState, worldMatrix) \
if (drawState.PrevFrame != frame && !renderContext.View.IsSingleFrame) \
{ \
drawState.PrevWorld = worldMatrix; \
drawState.PrevFrame = frame; \
}