// Copyright (c) 2012-2021 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: /// /// 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; Vector4 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 { 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]; /// /// The location of the first index read by the GPU from the index buffer. /// int32 StartIndex; /// /// The indices count. /// int32 IndicesCount; } Geometry; /// /// The amount of instances of the geometry to draw. Set to 0 if use indirect draw arguments buffer. /// int32 InstanceCount; /// /// The indirect draw arguments offset. /// uint32 IndirectArgsOffset; /// /// The indirect draw arguments buffer. /// GPUBuffer* IndirectArgsBuffer; /// /// The target material to use. /// IMaterial* Material; // Particles don't use skinning nor lightmaps so pack those stuff together union { struct { /// /// Pointer to lightmap for static object with prebaked lighting. /// const Lightmap* Lightmap; /// /// The skinning data. If set then material should use GPU skinning during rendering. /// SkinnedMeshDrawData* Skinning; }; struct { /// /// The particles data. Used only by the particles shaders. /// class ParticleBuffer* Particles; /// /// The particle module to draw. /// class ParticleEmitterGraphCPUNode* Module; }; }; /// /// Object world transformation matrix. /// Matrix World; // Terrain and particles don't use previous world matrix so pack those stuff together union { /// /// Object world transformation matrix using during previous frame. /// Matrix PrevWorld; struct { Vector4 HeightmapUVScaleBias; Vector4 NeighborLOD; Vector2 OffsetUV; float CurrentLOD; float ChunkSizeNextLOD; float TerrainChunkSizeLOD0; const class TerrainPatch* Patch; } TerrainData; struct { int32 RibbonOrderOffset; float UVTilingDistance; float UVScaleX; float UVScaleY; float UVOffsetX; float UVOffsetY; uint32 SegmentCount; GPUBuffer* SegmentDistances; } Ribbon; }; /// /// Lightmap UVs area that entry occupies. /// Rectangle LightmapUVsArea; /// /// Object location in the world used for draw calls sorting. /// Vector3 ObjectPosition; /// /// 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; /// /// Object geometry size in the world (unscaled). /// Vector3 GeometrySize; /// /// The random per-instance value (normalized to range 0-1). /// float PerInstanceRandom; /// /// The model LOD transition dither factor. /// float LODDitherFactor; /// /// Does nothing. /// DrawCall() { } /// /// Determines whether world transform matrix is performing negative scale (then model culling should be inverted). /// /// true if world matrix contains negative scale; otherwise, false. FORCE_INLINE bool IsNegativeScale() const { return WorldDeterminantSign < 0; } }; 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; /// /// The previous frame index. In sync with Engine::FrameCount used to detect new frames and rendering gaps to reset state. /// uint64 PrevFrame; /// /// The previous frame model LOD index used. It's locked during LOD transition to cache the transition start LOD. /// char PrevLOD; /// /// 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; GeometryDrawStateData() { PrevWorld = Matrix::Identity; PrevFrame = 0; PrevLOD = -1; 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) \ { \ drawState.PrevWorld = worldMatrix; \ } #define GEOMETRY_DRAW_STATE_EVENT_END(drawState, worldMatrix) \ if (drawState.PrevFrame != frame) \ { \ drawState.PrevWorld = _world; \ drawState.PrevFrame = frame; \ }