afxParticlePool_T3D.cpp 16 KB

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