Torque3D Documentation / _generateds / afxParticlePool_T3D.cpp

afxParticlePool_T3D.cpp

Engine/source/afx/util/afxParticlePool_T3D.cpp

More...

Detailed Description

  1
  2
  3//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  4// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
  5// Copyright (C) 2015 Faust Logic, Inc.
  6//
  7// Permission is hereby granted, free of charge, to any person obtaining a copy
  8// of this software and associated documentation files (the "Software"), to
  9// deal in the Software without restriction, including without limitation the
 10// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 11// sell copies of the Software, and to permit persons to whom the Software is
 12// furnished to do so, subject to the following conditions:
 13//
 14// The above copyright notice and this permission notice shall be included in
 15// all copies or substantial portions of the Software.
 16//
 17// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 18// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 19// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 20// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 21// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 22// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 23// IN THE SOFTWARE.
 24//
 25//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
 26
 27#include "afx/arcaneFX.h"
 28
 29#include "scene/sceneRenderState.h"
 30#include "T3D/fx/particleEmitter.h"
 31#include "renderInstance/renderPassManager.h"
 32#include "lighting/lightInfo.h"
 33#include "lighting/lightManager.h"
 34
 35#include "afx/util/afxParticlePool.h"
 36
 37void afxParticlePool::prepRenderImage(SceneRenderState* state)
 38{ 
 39  const LightInfo *sunlight = LIGHTMGR->getSpecialLight( LightManager::slSunLightType );
 40  pool_prepBatchRender(state->getRenderPass(), state->getCameraPosition(), sunlight->getAmbient());
 41};
 42
 43void afxParticlePool::pool_prepBatchRender(RenderPassManager *renderManager, const Point3F &camPos, const LinearColorF &ambientColor)
 44{
 45  if (emitters.empty()) 
 46    return;
 47
 48  switch (mDataBlock->pool_type)
 49  {
 50  case afxParticlePoolData::POOL_TWOPASS :
 51    pool_renderObject_TwoPass(renderManager, camPos, ambientColor);
 52    break;
 53  case afxParticlePoolData::POOL_NORMAL :
 54  default:
 55    pool_renderObject_Normal(renderManager, camPos, ambientColor);
 56  }
 57}
 58
 59void afxParticlePool::pool_renderObject_Normal(RenderPassManager *renderManager, const Point3F &camPos, const LinearColorF &ambientColor)
 60{
 61  S32 n_parts = 0;
 62  for (S32 i = 0; i < emitters.size(); i++)
 63    n_parts += emitters[i]->n_parts;
 64
 65  if (n_parts == 0)
 66    return;
 67
 68  ParticleEmitterData* main_emitter_data = emitters[0]->mDataBlock;
 69  
 70  main_emitter_data->allocPrimBuffer(n_parts);
 71
 72  orderedVector.clear();
 73
 74  MatrixF modelview = GFX->getWorldMatrix();
 75  Point3F viewvec; modelview.getRow(1, &viewvec);
 76
 77  for (U32 i=0; i < emitters.size(); i++)
 78  {
 79    // add each particle and a distance based sort key to orderedVector
 80    for (Particle* pp = emitters[i]->part_list_head.next; pp != NULL; pp = pp->next)
 81    {
 82      orderedVector.increment();
 83      orderedVector.last().p = pp;
 84      orderedVector.last().k = mDot(pp->pos, viewvec);
 85      orderedVector.last().emitter = emitters[i];
 86    }
 87  }
 88
 89  // qsort the list into far to near ordering
 90  dQsort(orderedVector.address(), orderedVector.size(), sizeof(SortParticlePool), cmpSortParticlePool);
 91
 92  static Vector<GFXVertexPCT> tempBuff(2048);
 93  tempBuff.reserve(n_parts*4 + 64); // make sure tempBuff is big enough
 94  GFXVertexPCT *buffPtr = tempBuff.address(); // use direct pointer (faster)
 95
 96  Point3F basePoints[4];
 97  basePoints[0] = Point3F(-1.0, 0.0, -1.0);
 98  basePoints[1] = Point3F( 1.0, 0.0, -1.0);
 99  basePoints[2] = Point3F( 1.0, 0.0,  1.0);
100  basePoints[3] = Point3F(-1.0, 0.0,  1.0);
101
102  MatrixF camView = GFX->getWorldMatrix();
103  camView.transpose();  // inverse - this gets the particles facing camera
104
105  for (U32 i = 0; i < orderedVector.size(); i++)
106  {
107    Particle* particle = orderedVector[i].p;
108    ParticleEmitter* emitter = orderedVector[i].emitter;
109
110    if (emitter->mDataBlock->orientParticles)
111      emitter->setupOriented(particle, camPos, ambientColor, buffPtr);
112    else
113      emitter->setupBillboard(particle, basePoints, camView, ambientColor, buffPtr);
114    buffPtr+=4;
115  }
116
117  // create new VB if emitter size grows
118  if( !mVertBuff || n_parts > mCurBuffSize )
119  {
120    mCurBuffSize = n_parts;
121    mVertBuff.set(GFX, n_parts*4, GFXBufferTypeDynamic);
122  }
123  // lock and copy tempBuff to video RAM
124  GFXVertexPCT *verts = mVertBuff.lock();
125  dMemcpy( verts, tempBuff.address(), n_parts * 4 * sizeof(GFXVertexPCT) );
126  mVertBuff.unlock();
127
128  //MeshRenderInst *ri = gRenderInstManager->allocInst<MeshRenderInst>();
129  ParticleRenderInst *ri = renderManager->allocInst<ParticleRenderInst>();
130  ri->vertBuff = &mVertBuff;
131  ri->primBuff = &main_emitter_data->primBuff;
132  ri->translucentSort = true;
133  ri->type = RenderPassManager::RIT_Particle;
134  ri->sortDistSq = getWorldBox().getSqDistanceToPoint( camPos );
135
136  ri->defaultKey = (-sort_priority*100);
137
138  ri->modelViewProj = renderManager->allocUniqueXform(  GFX->getProjectionMatrix() * 
139                                                        GFX->getViewMatrix() * 
140                                                        GFX->getWorldMatrix() );
141
142  ri->count = n_parts;
143
144  ri->blendStyle = main_emitter_data->blendStyle;
145
146  // use first particle's texture unless there is an emitter texture to override it
147  if (main_emitter_data->textureHandle)
148    ri->diffuseTex = &*(main_emitter_data->textureHandle);
149  else
150    ri->diffuseTex = &*(main_emitter_data->particleDataBlocks[0]->textureHandle);
151
152  ri->softnessDistance = main_emitter_data->softnessDistance;
153
154  // Sort by texture too.
155  //ri->defaultKey = ri->diffuseTex ? (U32)ri->diffuseTex : (U32)ri->vertBuff;
156
157  renderManager->addInst( ri );
158}
159
160void afxParticlePool::pool_renderObject_TwoPass(RenderPassManager *renderManager, const Point3F &camPos, const LinearColorF &ambientColor)
161{
162  S32 n_parts = 0;
163  for (S32 i = 0; i < emitters.size(); i++)
164    n_parts += emitters[i]->n_parts;
165
166  if (n_parts == 0)
167    return;
168
169  ParticleEmitterData* main_emitter_data = emitters[0]->mDataBlock;
170  
171  main_emitter_data->allocPrimBuffer(n_parts);
172
173  orderedVector.clear();
174
175  F32 min_d=0.0f, max_d=0.0f;
176
177  for (U32 i=0; i < emitters.size(); i++)
178  {
179    if (!emitters[i]->mDataBlock->pool_depth_fade || !emitters[i]->mDataBlock->pool_radial_fade)
180      continue;
181
182    // add particles to orderedVector and calc distance and min/max distance
183    for (Particle* pp = emitters[i]->part_list_head.next; pp != NULL; pp = pp->next)
184    {
185      F32 dist = (pp->pos-camPos).len();
186      if (dist > max_d)
187        max_d = dist;
188      else if (dist < min_d)
189        min_d = dist;
190
191      orderedVector.increment();
192      orderedVector.last().p = pp;
193      orderedVector.last().k = dist;
194      orderedVector.last().emitter = emitters[i];
195    }
196  }
197
198  // Add remaining emitters particles to the orderedVector that do not participate in the 
199  // above depth computations:
200  for (U32 i=0; i < emitters.size(); i++)
201  {
202    if (emitters[i]->mDataBlock->pool_depth_fade || emitters[i]->mDataBlock->pool_radial_fade)
203      continue;
204
205    for (Particle* pp = emitters[i]->part_list_head.next; pp != NULL; pp = pp->next)
206    {
207      orderedVector.increment();
208      orderedVector.last().p = pp;
209      orderedVector.last().k = 0;  // no need to compute depth here
210      orderedVector.last().emitter = emitters[i];
211    }
212  }
213
214  static Vector<GFXVertexPCT> tempBuff(2048);
215  tempBuff.reserve(n_parts*4 + 64); // make sure tempBuff is big enough
216  GFXVertexPCT *buffPtr = tempBuff.address(); // use direct pointer (faster)
217
218  Point3F basePoints[4];
219  basePoints[0] = Point3F(-1.0, 0.0, -1.0);
220  basePoints[1] = Point3F( 1.0, 0.0, -1.0);
221  basePoints[2] = Point3F( 1.0, 0.0,  1.0);
222  basePoints[3] = Point3F(-1.0, 0.0,  1.0);
223
224  MatrixF camView = GFX->getWorldMatrix();
225  camView.transpose();  // inverse - this gets the particles facing camera
226
227  //~~~~~~~~~~~~~~~~~~~~//
228
229  Point3F bbox_center; mObjBox.getCenter(&bbox_center);
230  F32 d_range = max_d - min_d;
231  bool d_safe = (d_range>0.0001);
232  F32 d_half = min_d + (d_range*0.5f);
233
234  //~~~~~~~~~~~~~~~~~~~~//
235
236  for (U32 i = 0; i < orderedVector.size(); i++)
237  {
238    Particle* particle = orderedVector[i].p;
239    ParticleEmitter* emitter = orderedVector[i].emitter;
240
241    LinearColorF color_save = particle->color;
242    particle->color.set(mDataBlock->base_color.red, mDataBlock->base_color.green, mDataBlock->base_color.blue, mDataBlock->base_color.alpha*particle->color.alpha);
243    emitter->setupBillboard(particle, basePoints, camView, ambientColor, buffPtr);
244    particle->color = color_save;
245
246    buffPtr+=4;
247  }
248
249  // create new VB if emitter size grows
250  if( !mVertBuff || n_parts > mCurBuffSize )
251  {
252    mCurBuffSize = n_parts;
253    mVertBuff.set(GFX, n_parts*4, GFXBufferTypeDynamic);
254  }
255  // lock and copy tempBuff to video RAM
256  GFXVertexPCT *verts = mVertBuff.lock();
257  dMemcpy( verts, tempBuff.address(), n_parts * 4 * sizeof(GFXVertexPCT) );
258  mVertBuff.unlock();
259
260  ParticleRenderInst *ri = renderManager->allocInst<ParticleRenderInst>();
261  ri->vertBuff = &mVertBuff;
262  ri->primBuff = &main_emitter_data->primBuff;
263  ri->translucentSort = true;
264  ri->type = RenderPassManager::RIT_Particle;
265  ri->sortDistSq = getWorldBox().getSqDistanceToPoint( camPos );
266
267  ri->defaultKey = (-sort_priority*100);
268
269  ri->modelViewProj = renderManager->allocUniqueXform(  GFX->getProjectionMatrix() * 
270                                                        GFX->getViewMatrix() * 
271                                                        GFX->getWorldMatrix() );
272
273  ri->count = n_parts;
274
275  ri->blendStyle = ParticleRenderInst::BlendNormal;
276
277  // use first particle's texture unless there is an emitter texture to override it
278  //if (main_emitter_data->textureHandle)
279  //  ri->diffuseTex = &*(main_emitter_data->textureHandle);
280  //else
281    ri->diffuseTex = &*(main_emitter_data->particleDataBlocks[0]->textureExtHandle);
282
283  F32 save_sort_dist = ri->sortDistSq;
284
285  ri->softnessDistance = main_emitter_data->softnessDistance;
286
287  renderManager->addInst( ri );
288
289  //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//
290  //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//
291  // 2nd-pass
292
293  buffPtr = tempBuff.address();
294
295  bbox_center.z = mObjBox.minExtents.z;
296  F32 max_radius = (max_d-min_d)*0.5f;
297
298  // gather fade settings
299  bool do_mixed_fades = false;
300  bool do_radial_fades = (emitters[0]->mDataBlock->pool_radial_fade && (max_radius>0.0001f));
301  bool do_depth_fades = (emitters[0]->mDataBlock->pool_depth_fade && d_safe);
302  for (U32 i = 1; i < emitters.size(); i++)
303  {
304    if ( (do_radial_fades != (emitters[i]->mDataBlock->pool_radial_fade && (max_radius>0.0001f))) ||
305      (do_depth_fades != (emitters[i]->mDataBlock->pool_depth_fade && d_safe)))
306    {
307      do_mixed_fades = true;
308      break;
309    }
310  }
311
312  if (do_mixed_fades)
313  {
314    for (U32 i = 0; i < orderedVector.size(); i++)
315    {
316      Particle* particle = orderedVector[i].p;
317      ParticleEmitter* emitter = orderedVector[i].emitter;
318
319      F32 bf = 1.0;  // blend factor
320
321      // blend factor due to radius
322      if (emitter->mDataBlock->pool_radial_fade && (max_radius>0.0001f))
323      {
324        F32 p_radius = (particle->pos-bbox_center).len();
325        F32 bf_radius = p_radius/max_radius;
326        if (bf_radius>1.0f) bf_radius = 1.0f;
327        bf *= bf_radius*bf_radius;  // quadratic for faster falloff
328      }
329
330      // blend factor, depth based
331      if (emitter->mDataBlock->pool_depth_fade && d_safe && (orderedVector[i].k > d_half))
332      {
333        F32 bf_depth = ((max_d-orderedVector[i].k) / (d_range*0.5f));
334        bf *= bf_depth;
335      }
336
337      // overall blend factor weight
338      bf *= mDataBlock->blend_weight;
339
340      LinearColorF color_save = particle->color;
341      particle->color = particle->color*bf;
342      emitter->setupBillboard(particle, basePoints, camView, ambientColor, buffPtr);
343      particle->color = color_save;
344
345      buffPtr+=4;
346    }
347  }
348  else if (do_radial_fades && do_depth_fades)
349  {
350    for (U32 i = 0; i < orderedVector.size(); i++)
351    {
352      Particle* particle = orderedVector[i].p;
353      ParticleEmitter* emitter = orderedVector[i].emitter;
354
355      F32 bf = 1.0;  // blend factor
356
357      // blend factor due to radius
358      F32 p_radius = (particle->pos-bbox_center).len();
359      F32 bf_radius = p_radius/max_radius;
360      if (bf_radius>1.0f) bf_radius = 1.0f;
361      bf *= bf_radius*bf_radius;  // quadratic for faster falloff
362
363      // blend factor, depth based
364      if (orderedVector[i].k > d_half)
365      {
366        F32 bf_depth = ((max_d-orderedVector[i].k) / (d_range*0.5f));
367        bf *= bf_depth;
368      }
369
370      // overall blend factor weight
371      bf *= mDataBlock->blend_weight;
372
373      LinearColorF color_save = particle->color;
374      particle->color = particle->color*bf;
375      emitter->setupBillboard(particle, basePoints, camView, ambientColor, buffPtr);
376      particle->color = color_save;
377
378      buffPtr+=4;
379    }
380  }
381  else if (do_radial_fades) // && !do_depth_fades
382  {
383    for (U32 i = 0; i < orderedVector.size(); i++)
384    {
385      Particle* particle = orderedVector[i].p;
386      ParticleEmitter* emitter = orderedVector[i].emitter;
387
388      F32 bf = 1.0;  // blend factor
389
390      // blend factor due to radius
391      F32 p_radius = (particle->pos-bbox_center).len();
392      F32 bf_radius = p_radius/max_radius;
393      if (bf_radius>1.0f) bf_radius = 1.0f;
394      bf *= bf_radius*bf_radius;  // quadratic for faster falloff
395
396      // overall blend factor weight
397      bf *= mDataBlock->blend_weight;
398
399      LinearColorF color_save = particle->color;
400      particle->color = particle->color*bf;
401      emitter->setupBillboard(particle, basePoints, camView, ambientColor, buffPtr);
402      particle->color = color_save;
403
404      buffPtr+=4;
405    }
406  }
407  else if (do_depth_fades) // && !do_radial_fades
408  {
409    for (U32 i = 0; i < orderedVector.size(); i++)
410    {
411      Particle* particle = orderedVector[i].p;
412      ParticleEmitter* emitter = orderedVector[i].emitter;
413
414      F32 bf = 1.0;  // blend factor
415
416      // blend factor, depth based
417      if (orderedVector[i].k > d_half)
418      {
419        F32 bf_depth = ((max_d-orderedVector[i].k) / (d_range*0.5f));
420        bf *= bf_depth;
421      }
422
423      // overall blend factor weight
424      bf *= mDataBlock->blend_weight;
425
426      LinearColorF color_save = particle->color;
427      particle->color = particle->color*bf;
428      emitter->setupBillboard(particle, basePoints, camView, ambientColor, buffPtr);
429      particle->color = color_save;
430
431      buffPtr+=4;
432    }
433  }
434  else // (no fades)
435  {
436    for (U32 i = 0; i < orderedVector.size(); i++)
437    {
438      Particle* particle = orderedVector[i].p;
439      ParticleEmitter* emitter = orderedVector[i].emitter;
440
441      F32 bf = mDataBlock->blend_weight;  // blend factor
442
443      LinearColorF color_save = particle->color;
444      particle->color = particle->color*bf;
445      emitter->setupBillboard(particle, basePoints, camView, ambientColor, buffPtr);
446      particle->color = color_save;
447
448      buffPtr+=4;
449    }
450  }
451
452  // create new VB if emitter size grows
453  if( !mVertBuff2 || n_parts > mCurBuffSize2 )
454  {
455    mCurBuffSize2 = n_parts;
456    mVertBuff2.set(GFX, n_parts*4, GFXBufferTypeDynamic);
457  }
458
459  // lock and copy tempBuff to video RAM
460  verts = mVertBuff2.lock();
461  dMemcpy( verts, tempBuff.address(), n_parts * 4 * sizeof(GFXVertexPCT) );
462  mVertBuff2.unlock();
463
464  ri = renderManager->allocInst<ParticleRenderInst>();
465  ri->vertBuff = &mVertBuff2;
466  ri->primBuff = &main_emitter_data->primBuff;
467  ri->translucentSort = true;
468  ri->type = RenderPassManager::RIT_Particle;
469  ri->sortDistSq = save_sort_dist;
470
471  ri->defaultKey = (-sort_priority*100) + 1;
472
473  ri->modelViewProj = renderManager->allocUniqueXform(  GFX->getProjectionMatrix() * 
474                                                        GFX->getViewMatrix() * 
475                                                        GFX->getWorldMatrix() );
476
477  ri->count = n_parts;
478
479  ri->blendStyle = ParticleRenderInst::BlendAdditive;
480
481  // use first particle's texture unless there is an emitter texture to override it
482  if (main_emitter_data->textureHandle)
483    ri->diffuseTex = &*(main_emitter_data->textureHandle);
484  else
485    ri->diffuseTex = &*(main_emitter_data->particleDataBlocks[0]->textureHandle);
486
487  ri->softnessDistance = main_emitter_data->softnessDistance;
488
489  renderManager->addInst( ri );
490}
491
492//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
493