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
17namespace bs
18{
19 struct ParticleMeshRenderData;
20 struct ParticleBillboardRenderData;
21 struct ParticleRenderData;
22}
23
24namespace 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