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