| 1 | //************************************ bs::framework - Copyright 2018 Marko Pintera **************************************// |
| 2 | //*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********// |
| 3 | #pragma once |
| 4 | |
| 5 | #include "BsRenderBeastPrerequisites.h" |
| 6 | #include "Renderer/BsRenderElement.h" |
| 7 | #include "Renderer/BsParamBlocks.h" |
| 8 | #include "RenderAPI/BsGpuPipelineParamInfo.h" |
| 9 | #include "Material/BsShaderVariation.h" |
| 10 | #include "Particles/BsParticleSystem.h" |
| 11 | #include "Allocators/BsPoolAlloc.h" |
| 12 | #include "Renderer/BsRendererMaterial.h" |
| 13 | #include "Utility/BsTextureRowAllocator.h" |
| 14 | #include "BsRendererLight.h" |
| 15 | #include "BsRendererReflectionProbe.h" |
| 16 | |
| 17 | namespace bs |
| 18 | { |
| 19 | struct ParticleMeshRenderData; |
| 20 | struct ParticleBillboardRenderData; |
| 21 | struct ParticleRenderData; |
| 22 | } |
| 23 | |
| 24 | namespace bs { namespace ct |
| 25 | { |
| 26 | class GpuParticleSystem; |
| 27 | class GpuParticleResources; |
| 28 | |
| 29 | /** @addtogroup RenderBeast |
| 30 | * @{ |
| 31 | */ |
| 32 | |
| 33 | BS_PARAM_BLOCK_BEGIN(ParticlesParamDef) |
| 34 | BS_PARAM_BLOCK_ENTRY(Vector4, gSubImageSize) |
| 35 | BS_PARAM_BLOCK_ENTRY(Vector2, gUVOffset) |
| 36 | BS_PARAM_BLOCK_ENTRY(Vector2, gUVScale) |
| 37 | BS_PARAM_BLOCK_ENTRY(Vector3, gAxisUp) |
| 38 | BS_PARAM_BLOCK_ENTRY(INT32, gTexSize) |
| 39 | BS_PARAM_BLOCK_ENTRY(Vector3, gAxisRight) |
| 40 | BS_PARAM_BLOCK_ENTRY(INT32, gBufferOffset) |
| 41 | BS_PARAM_BLOCK_END |
| 42 | |
| 43 | extern ParticlesParamDef gParticlesParamDef; |
| 44 | |
| 45 | BS_PARAM_BLOCK_BEGIN(GpuParticlesParamDef) |
| 46 | BS_PARAM_BLOCK_ENTRY(Vector2, gColorCurveOffset) |
| 47 | BS_PARAM_BLOCK_ENTRY(Vector2, gColorCurveScale) |
| 48 | BS_PARAM_BLOCK_ENTRY(Vector2, gSizeScaleFrameIdxCurveOffset) |
| 49 | BS_PARAM_BLOCK_ENTRY(Vector2, gSizeScaleFrameIdxCurveScale) |
| 50 | BS_PARAM_BLOCK_END |
| 51 | |
| 52 | extern GpuParticlesParamDef gGpuParticlesParamDef; |
| 53 | |
| 54 | /** Types of forward lighting supported on particle shaders. */ |
| 55 | enum class ParticleForwardLightingType |
| 56 | { |
| 57 | /** No forward lighting. */ |
| 58 | None, |
| 59 | |
| 60 | /** Using the modern clustered forward lighting approach (requires compute). */ |
| 61 | Clustered, |
| 62 | |
| 63 | /** Using the old-school standard forward lighting approach. */ |
| 64 | Standard |
| 65 | }; |
| 66 | |
| 67 | /** |
| 68 | * Returns a specific particle rendering shader variation. |
| 69 | * |
| 70 | * @tparam ORIENT Particle orientiation mode. |
| 71 | * @tparam LOCK_Y If true, billboard rotation will be locked around the Y axis, otherwise the rotation is free. |
| 72 | * @tparam GPU If true, the particle shader expects input from the GPU simulation instead of the CPU simulation. |
| 73 | * @tparam IS_3D If true, the particle shader will render meshes instead of billboards. |
| 74 | * @tparam FWD Determines what form of forward lighting should the shader support. |
| 75 | */ |
| 76 | template<ParticleOrientation ORIENT, bool LOCK_Y, bool GPU, bool IS_3D, ParticleForwardLightingType FWD> |
| 77 | static const ShaderVariation& getParticleShaderVariation() |
| 78 | { |
| 79 | static bool initialized = false; |
| 80 | static SmallVector<ShaderVariation::Param, 4> params({ |
| 81 | ShaderVariation::Param("ORIENT" , (UINT32)ORIENT), |
| 82 | ShaderVariation::Param("LOCK_Y" , LOCK_Y), |
| 83 | ShaderVariation::Param("GPU" , GPU), |
| 84 | ShaderVariation::Param("IS_3D" , IS_3D), |
| 85 | }); |
| 86 | |
| 87 | if(!initialized) |
| 88 | { |
| 89 | switch(FWD) |
| 90 | { |
| 91 | case ParticleForwardLightingType::Clustered: |
| 92 | params.add(ShaderVariation::Param("CLUSTERED" , true)); |
| 93 | break; |
| 94 | case ParticleForwardLightingType::Standard: |
| 95 | params.add(ShaderVariation::Param("CLUSTERED" , false)); |
| 96 | break; |
| 97 | case ParticleForwardLightingType::None: |
| 98 | break; |
| 99 | } |
| 100 | |
| 101 | initialized = true; |
| 102 | } |
| 103 | |
| 104 | static ShaderVariation variation = ShaderVariation(params); |
| 105 | return variation; |
| 106 | } |
| 107 | |
| 108 | /** |
| 109 | * Returns a particle material variation matching the provided parameters. |
| 110 | * |
| 111 | * @param[in] orient Determines in which direction are billboard particles oriented. |
| 112 | * @param[in] lockY If true, billboard rotation will be locked around the Y axis, otherwise the |
| 113 | * rotation is free. |
| 114 | * @param[in] gpu If true, the particle shader expects input from the GPU simulation instead of the |
| 115 | * CPU simulation. |
| 116 | * @param[in] is3d If true, the particle shader will render meshes instead of billboards. |
| 117 | * @param[in] forwardLighting Form of forward lighting the shader should support. |
| 118 | * @return Object that can be used for looking up the variation technique in the material. |
| 119 | */ |
| 120 | const ShaderVariation& getParticleShaderVariation(ParticleOrientation orient, bool lockY, bool gpu, bool is3d, |
| 121 | ParticleForwardLightingType forwardLighting); |
| 122 | |
| 123 | /** Contains information required for rendering a single particle system. */ |
| 124 | class ParticlesRenderElement : public RenderElement |
| 125 | { |
| 126 | public: |
| 127 | /** Parameters relevant for billboard rendering of the outputs of the particle CPU simulation. */ |
| 128 | struct CpuBillboardSimulationParams |
| 129 | { |
| 130 | /** Binding spot for the texture containing position and rotation information. */ |
| 131 | GpuParamTexture positionAndRotTexture; |
| 132 | |
| 133 | /** Binding spot for the texture containing color information. */ |
| 134 | GpuParamTexture colorTexture; |
| 135 | |
| 136 | /** Binding spot for the texture containing size and sub-image index information. */ |
| 137 | GpuParamTexture sizeAndFrameIdxTexture; |
| 138 | }; |
| 139 | |
| 140 | /** Parameters relevant for mesh rendering of the outputs of the particle CPU simulation. */ |
| 141 | struct CpuMeshSimulationParams |
| 142 | { |
| 143 | /** Binding spot for the texture containing position. */ |
| 144 | GpuParamTexture positionTexture; |
| 145 | |
| 146 | /** Binding spot for the texture containing color information. */ |
| 147 | GpuParamTexture colorTexture; |
| 148 | |
| 149 | /** Binding spot for the texture containing rotation. */ |
| 150 | GpuParamTexture rotationTexture; |
| 151 | |
| 152 | /** Binding spot for the texture containing size. */ |
| 153 | GpuParamTexture sizeTexture; |
| 154 | }; |
| 155 | |
| 156 | /** Parameters relevant for rendering the outputs of the particle GPU simulation. */ |
| 157 | struct GpuSimulationParams |
| 158 | { |
| 159 | /** Binding spot for the texture containing position (.xyz) and time (.w) information. */ |
| 160 | GpuParamTexture positionTimeTexture; |
| 161 | |
| 162 | /** Binding spot for the texture containing 2D size (.xy) and rotation (.z) information. */ |
| 163 | GpuParamTexture sizeRotationTexture; |
| 164 | |
| 165 | /** Binding spot for the texture containing quantized curves used for evaluating various particle properties. */ |
| 166 | GpuParamTexture curvesTexture; |
| 167 | }; |
| 168 | |
| 169 | /** Binding locations for the per-camera param block buffer. */ |
| 170 | GpuParamBinding perCameraBindings[GPT_COUNT]; |
| 171 | |
| 172 | /** Binding spot for the buffer containing instance id -> particle index mapping. */ |
| 173 | GpuParamBuffer indicesBuffer; |
| 174 | |
| 175 | /** Optional texture input for the depth buffer. */ |
| 176 | GpuParamTexture depthInputTexture; |
| 177 | |
| 178 | /** Parameters relevant for billboard rendering of the outputs of the particle CPU simulation. */ |
| 179 | CpuBillboardSimulationParams paramsCPUBillboard; |
| 180 | |
| 181 | /** Parameters relevant for mesh rendering of the outputs of the particle CPU simulation. */ |
| 182 | CpuMeshSimulationParams paramsCPUMesh; |
| 183 | |
| 184 | /** Parameters relevant for rendering the outputs of the particle GPU simulation. */ |
| 185 | GpuSimulationParams paramsGPU; |
| 186 | |
| 187 | /** Collection of parameters used for direct lighting using the forward rendering path. */ |
| 188 | ForwardLightingParams forwardLightingParams; |
| 189 | |
| 190 | /** Collection of parameters used for image based lighting. */ |
| 191 | ImageBasedLightingParams imageBasedParams; |
| 192 | |
| 193 | /** Number of particles to render. */ |
| 194 | UINT32 numParticles = 0; |
| 195 | |
| 196 | /** True if the particle should be drawn as a 3D mesh instead of a billboard. */ |
| 197 | bool is3D = false; |
| 198 | |
| 199 | /** Checks if the element has all the properties required for rendering. */ |
| 200 | bool isValid() const { return !is3D || mesh != nullptr; } |
| 201 | |
| 202 | /** @copydoc RenderElement::draw */ |
| 203 | void draw() const override; |
| 204 | }; |
| 205 | |
| 206 | /** Contains information about a ParticleSystem, used by the Renderer. */ |
| 207 | struct RendererParticles |
| 208 | { |
| 209 | /** Owner particle system. */ |
| 210 | ParticleSystem* particleSystem = nullptr; |
| 211 | |
| 212 | /** Variant of the particle system used for simulating the particles on the GPU. */ |
| 213 | GpuParticleSystem* gpuParticleSystem = nullptr; |
| 214 | |
| 215 | /** Matrix that transforms the particle system to world space. */ |
| 216 | Matrix4 localToWorld = Matrix4::IDENTITY; |
| 217 | |
| 218 | /** Element used for sorting and rendering the particle system. */ |
| 219 | mutable ParticlesRenderElement renderElement; |
| 220 | |
| 221 | /** Parameters used by the particle rendering shader. */ |
| 222 | SPtr<GpuParamBlockBuffer> particlesParamBuffer; |
| 223 | |
| 224 | /** Extra parameters required by the particle rendering shader if the particle system is GPU simulated. */ |
| 225 | SPtr<GpuParamBlockBuffer> gpuParticlesParamBuffer; |
| 226 | |
| 227 | /** Buffer containing the world transform data for the rendered object. */ |
| 228 | SPtr<GpuParamBlockBuffer> perObjectParamBuffer; |
| 229 | |
| 230 | /** Information about the color over lifetime curve stored in the global curve texture. */ |
| 231 | TextureRowAllocation colorCurveAlloc; |
| 232 | |
| 233 | /** Information about the size over lifetime / frame index curve stored in the global curve texture. */ |
| 234 | TextureRowAllocation sizeScaleFrameIdxCurveAlloc; |
| 235 | |
| 236 | /** |
| 237 | * Binds all the GPU program inputs required for rendering a particle system that is being simulated by the CPU. |
| 238 | * |
| 239 | * @param[in] renderData Render data representing the state of a CPU simulated particle system. |
| 240 | * @param[in] view View the particle system is being rendered from. |
| 241 | */ |
| 242 | void bindCPUSimulatedInputs(const ParticleRenderData* renderData, const RendererView& view) const; |
| 243 | |
| 244 | /** |
| 245 | * Binds all the GPU program inputs required for rendering a particle system that is being simulated by the GPU. |
| 246 | * |
| 247 | * @param[in] gpuSimResources Resources containing global data for all GPU simulated particle systems. |
| 248 | * @param[in] view View the particle system is being rendered from. |
| 249 | */ |
| 250 | void bindGPUSimulatedInputs(const GpuParticleResources& gpuSimResources, const RendererView& view) const; |
| 251 | }; |
| 252 | |
| 253 | /** Default material used for rendering particles, when no other is available. */ |
| 254 | class DefaultParticlesMat : public RendererMaterial<DefaultParticlesMat> { RMAT_DEF("ParticlesUnlit.bsl" ); }; |
| 255 | |
| 256 | /** |
| 257 | * Contains a set of textures used for rendering a particle system using billboards. Each pixel in a texture represent |
| 258 | * properties of a single particle. |
| 259 | */ |
| 260 | struct ParticleBillboardTextures |
| 261 | { |
| 262 | SPtr<Texture> positionAndRotation; |
| 263 | SPtr<Texture> color; |
| 264 | SPtr<Texture> sizeAndFrameIdx; |
| 265 | SPtr<GpuBuffer> indices; |
| 266 | }; |
| 267 | |
| 268 | /** |
| 269 | * Contains a set of textures used for rendering a particle system using 3D meshes. Each pixel in a texture represent |
| 270 | * properties of a single particle. |
| 271 | */ |
| 272 | struct ParticleMeshTextures |
| 273 | { |
| 274 | SPtr<Texture> position; |
| 275 | SPtr<Texture> color; |
| 276 | SPtr<Texture> size; |
| 277 | SPtr<Texture> rotation; |
| 278 | SPtr<GpuBuffer> indices; |
| 279 | }; |
| 280 | |
| 281 | /** Keeps a pool of textures used for the purposes of the particle system. */ |
| 282 | class ParticleTexturePool final |
| 283 | { |
| 284 | /** A set of created textures for billboard rendering, per size. */ |
| 285 | struct BillboardBuffersPerSize |
| 286 | { |
| 287 | Vector<ParticleBillboardTextures*> buffers; |
| 288 | UINT32 nextFreeIdx = 0; |
| 289 | }; |
| 290 | |
| 291 | /** A set of created textures for mesh rendering, per size. */ |
| 292 | struct MeshBuffersPerSize |
| 293 | { |
| 294 | Vector<ParticleMeshTextures*> buffers; |
| 295 | UINT32 nextFreeIdx = 0; |
| 296 | }; |
| 297 | |
| 298 | public: |
| 299 | ~ParticleTexturePool(); |
| 300 | |
| 301 | /** |
| 302 | * Returns a set of textures used for particle billboard rendering. The textures will contain the pixel data from |
| 303 | * the provided @p simulationData. Returned textures will remain in-use until the next call to clear(). |
| 304 | */ |
| 305 | const ParticleBillboardTextures* alloc(const ParticleBillboardRenderData& simulationData); |
| 306 | |
| 307 | /** |
| 308 | * Returns a set of textures used for particle mesh rendering. The textures will contain the pixel data from |
| 309 | * the provided @p simulationData. Returned textures will remain in-use until the next call to clear(). |
| 310 | */ |
| 311 | const ParticleMeshTextures* alloc(const ParticleMeshRenderData& simulationData); |
| 312 | |
| 313 | /** Frees all allocates textures and makes them available for re-use. */ |
| 314 | void clear(); |
| 315 | |
| 316 | private: |
| 317 | /** Creates a new set of textures for billboard rendering, with @p size width and height. */ |
| 318 | ParticleBillboardTextures* createNewBillboardTextures(UINT32 size); |
| 319 | |
| 320 | /** Creates a new set of textures for mesh rendering, with @p size width and height. */ |
| 321 | ParticleMeshTextures* createNewMeshTextures(UINT32 size); |
| 322 | |
| 323 | UnorderedMap<UINT32, BillboardBuffersPerSize> mBillboardBufferList; |
| 324 | PoolAlloc<sizeof(ParticleBillboardTextures), 32> mBillboardAlloc; |
| 325 | |
| 326 | UnorderedMap<UINT32, MeshBuffersPerSize> mMeshBufferList; |
| 327 | PoolAlloc<sizeof(ParticleMeshTextures), 32> mMeshAlloc; |
| 328 | }; |
| 329 | |
| 330 | /** Handles internal logic for rendering of particle systems. */ |
| 331 | class ParticleRenderer final : public Module<ParticleRenderer> |
| 332 | { |
| 333 | struct Members; |
| 334 | public: |
| 335 | ParticleRenderer(); |
| 336 | ~ParticleRenderer(); |
| 337 | |
| 338 | /** |
| 339 | * Returns a texture pool object that can be used for allocating textures required for holding particle system |
| 340 | * properties used for billboard particle rendering (position/color/etc). |
| 341 | */ |
| 342 | ParticleTexturePool& getTexturePool() { return mTexturePool; } |
| 343 | |
| 344 | /** Draws @p count quads used for billboard rendering, using instanced drawing. */ |
| 345 | void drawBillboards(UINT32 count); |
| 346 | |
| 347 | /** |
| 348 | * Updates the provided indices buffer so they particles are sorted from further to nearest with respect to |
| 349 | * some reference point. |
| 350 | * |
| 351 | * @param[in] refPoint Reference point respect to which to determine the distance of individual particles. |
| 352 | * Should be in the simulation space of the particle system. |
| 353 | * @param[in] positions Buffer containing positions of individual particles. |
| 354 | * @param[in] numParticles Number of particles in the provided position and indices buffers. |
| 355 | * @param[in] stride Offset between positions in the @p positions buffer, in number of floats. |
| 356 | * @param[out] indices Index buffer that will be sorted according to the particle distance, in descending |
| 357 | * order. |
| 358 | */ |
| 359 | static void sortByDistance(const Vector3& refPoint, const PixelData& positions, UINT32 numParticles, |
| 360 | UINT32 stride, Vector<UINT32>& indices); |
| 361 | private: |
| 362 | ParticleTexturePool mTexturePool; |
| 363 | Members* m; |
| 364 | }; |
| 365 | |
| 366 | /** @} */ |
| 367 | }} |
| 368 | |