aboutsummaryrefslogtreecommitdiff
path: root/APEX_1.4/module/basicios/src/BasicIosActorImpl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'APEX_1.4/module/basicios/src/BasicIosActorImpl.cpp')
-rw-r--r--APEX_1.4/module/basicios/src/BasicIosActorImpl.cpp1221
1 files changed, 1221 insertions, 0 deletions
diff --git a/APEX_1.4/module/basicios/src/BasicIosActorImpl.cpp b/APEX_1.4/module/basicios/src/BasicIosActorImpl.cpp
new file mode 100644
index 00000000..5bb6ecd4
--- /dev/null
+++ b/APEX_1.4/module/basicios/src/BasicIosActorImpl.cpp
@@ -0,0 +1,1221 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "Apex.h"
+#include "SceneIntl.h"
+#include "ApexSDKIntl.h"
+#include "ScopedPhysXLock.h"
+
+#include "BasicIosActor.h"
+#include "BasicIosActorImpl.h"
+#include "BasicIosAssetImpl.h"
+#include "IofxAsset.h"
+#include "IofxActor.h"
+#include "ModuleBasicIosImpl.h"
+#include "BasicIosScene.h"
+#include "RenderDebugInterface.h"
+#include "AuthorableObjectIntl.h"
+#include "ModuleIofxIntl.h"
+#include "FieldSamplerManagerIntl.h"
+#include "FieldSamplerQueryIntl.h"
+#include "ApexMirroredArray.h"
+#include "ApexResourceHelper.h"
+#include "PsAsciiConversion.h"
+
+#include "PxTask.h"
+
+#include <PxScene.h>
+#include <PxConvexMesh.h>
+
+#include <PxShape.h>
+#include <geometry/PxBoxGeometry.h>
+#include <geometry/PxSphereGeometry.h>
+#include <geometry/PxCapsuleGeometry.h>
+#include <geometry/PxPlaneGeometry.h>
+#include <geometry/PxTriangleMeshGeometry.h>
+#include <geometry/PxTriangleMesh.h>
+
+#include <PxMaterial.h>
+
+#include <PxRigidActor.h>
+#include <PxRigidBody.h>
+#include <extensions/PxShapeExt.h>
+
+#include <PsAsciiConversion.h>
+
+#include "Lock.h"
+
+namespace nvidia
+{
+ namespace basicios
+ {
+ using namespace physx;
+
+ class BasicIosInjectTask : public PxTask, public UserAllocated
+ {
+ public:
+ BasicIosInjectTask(BasicIosActorImpl* actor) : mActor(actor) {}
+
+ const char* getName() const
+ {
+ return "BasicIosActorImpl::InjectTask";
+ }
+ void run()
+ {
+ mActor->injectNewParticles();
+ }
+
+ protected:
+ BasicIosActorImpl* mActor;
+ };
+
+ void BasicIosActorImpl::initStorageGroups(InplaceStorage& storage)
+ {
+ mSimulationStorageGroup.init(storage);
+ }
+
+ BasicIosActorImpl::BasicIosActorImpl(
+ ResourceList& list,
+ BasicIosAssetImpl& asset,
+ BasicIosScene& scene,
+ nvidia::apex::IofxAsset& iofxAsset,
+ bool isDataOnDevice)
+ : mAsset(&asset)
+ , mBasicIosScene(&scene)
+ , mIofxMgr(NULL)
+ , mTotalElapsedTime(0.0f)
+ , mParticleCount(0)
+ , mParticleBudget(UINT_MAX)
+ , mInjectedCount(0)
+ , mLastActiveCount(0)
+ , mLastBenefitSum(0)
+ , mLastBenefitMin(+FLT_MAX)
+ , mLastBenefitMax(-FLT_MAX)
+ , mLifeSpan(scene.getApexScene(), PX_ALLOC_INFO("mLifeSpan", PARTICLES))
+ , mLifeTime(scene.getApexScene(), PX_ALLOC_INFO("mLifeTime", PARTICLES))
+ , mInjector(scene.getApexScene(), PX_ALLOC_INFO("mInjector", PARTICLES))
+ , mBenefit(scene.getApexScene(), PX_ALLOC_INFO("mBenefit", PARTICLES))
+ , mConvexPlanes(scene.getApexScene(), PX_ALLOC_INFO("mConvexPlanes", PARTICLES))
+ , mConvexVerts(scene.getApexScene(), PX_ALLOC_INFO("mConvexVerts", PARTICLES))
+ , mConvexPolygonsData(scene.getApexScene(), PX_ALLOC_INFO("mConvexPolygonsData", PARTICLES))
+ , mTrimeshVerts(scene.getApexScene(), PX_ALLOC_INFO("mTrimeshVerts", PARTICLES))
+ , mTrimeshIndices(scene.getApexScene(), PX_ALLOC_INFO("mTrimeshIndices", PARTICLES))
+ , mInjectorsCounters(scene.getApexScene(), PX_ALLOC_INFO("mInjectorsCounters", PARTICLES))
+ , mGridDensityGrid(scene.getApexScene(), PX_ALLOC_INFO("mGridDensityGrid", PARTICLES))
+ , mGridDensityGridLowPass(scene.getApexScene(), PX_ALLOC_INFO("mGridDensityGridLowPass", PARTICLES))
+ , mFieldSamplerQuery(NULL)
+ , mField(scene.getApexScene(), PX_ALLOC_INFO("mField", PARTICLES))
+ , mDensityOrigin(0.f,0.f,0.f)
+ , mOnStartCallback(NULL)
+ , mOnFinishCallback(NULL)
+ {
+ list.add(*this);
+
+ mMaxParticleCount = mAsset->mParams->maxParticleCount;
+ mParticleBudget = mMaxParticleCount;
+ float maxInjectCount = mAsset->mParams->maxInjectedParticleCount;
+ mMaxTotalParticleCount = mMaxParticleCount + uint32_t(maxInjectCount <= 1.0f ? mMaxParticleCount * maxInjectCount : maxInjectCount);
+
+
+ IofxManagerDescIntl desc;
+ desc.iosAssetName = mAsset->getName();
+ desc.iosSupportsDensity = mAsset->getSupportsDensity();
+ desc.iosSupportsCollision = true;
+ desc.iosSupportsUserData = true;
+ desc.iosOutputsOnDevice = isDataOnDevice;
+ desc.maxObjectCount = mMaxParticleCount;
+ desc.maxInputCount = mMaxTotalParticleCount;
+ desc.maxInStateCount = mMaxTotalParticleCount;
+
+ ModuleIofxIntl* moduleIofx = mAsset->mModule->getInternalModuleIofx();
+ if (moduleIofx)
+ {
+ mIofxMgr = moduleIofx->createActorManager(*mBasicIosScene->mApexScene, iofxAsset, desc);
+ mIofxMgr->createSimulationBuffers(mBufDesc);
+ }
+
+ mCollisionFilterData = ApexResourceHelper::resolveCollisionGroup128(mAsset->mParams->fieldSamplerFilterDataName);
+
+ FieldSamplerManagerIntl* fieldSamplerManager = mBasicIosScene->getInternalFieldSamplerManager();
+ if (fieldSamplerManager)
+ {
+ FieldSamplerQueryDescIntl queryDesc;
+ queryDesc.maxCount = mMaxParticleCount;
+ queryDesc.samplerFilterData = ApexResourceHelper::resolveCollisionGroup128(mAsset->mParams->fieldSamplerFilterDataName);
+
+ mFieldSamplerQuery = fieldSamplerManager->createFieldSamplerQuery(queryDesc);
+
+ if (isDataOnDevice)
+ {
+#if APEX_CUDA_SUPPORT
+ mField.reserve(mMaxParticleCount, ApexMirroredPlace::GPU);
+#endif
+ }
+ else
+ {
+ mField.reserve(mMaxParticleCount, ApexMirroredPlace::CPU);
+ }
+ }
+
+ mInjectTask = PX_NEW(BasicIosInjectTask)(this);
+
+ // Pull Grid Density Parameters
+ {
+ if(mBufDesc.pmaDensity)
+ {
+ BasicIOSAssetParam* gridParams = (BasicIOSAssetParam*)(mAsset->getAssetNvParameterized());
+ mGridDensityParams.Enabled = gridParams->GridDensity.Enabled;
+ mGridDensityParams.GridSize = gridParams->GridDensity.GridSize;
+ mGridDensityParams.GridMaxCellCount = gridParams->GridDensity.MaxCellCount;
+ mGridDensityParams.GridResolution = general_string_parsing2::PxAsc::strToU32(&gridParams->GridDensity.Resolution[4],NULL);
+ mGridDensityParams.DensityOrigin = mDensityOrigin;
+ }
+ else
+ {
+ mGridDensityParams.Enabled = false;
+ mGridDensityParams.GridSize = 1.f;
+ mGridDensityParams.GridMaxCellCount = 1u;
+ mGridDensityParams.GridResolution = 8;
+ mGridDensityParams.DensityOrigin = mDensityOrigin;
+ }
+ }
+
+ addSelfToContext(*scene.mApexScene->getApexContext()); // add self to Scene
+ addSelfToContext(*DYNAMIC_CAST(ApexContext*)(&scene)); // add self to BasicIosScene
+ }
+
+ BasicIosActorImpl::~BasicIosActorImpl()
+ {
+ PX_DELETE(mInjectTask);
+ }
+
+ void BasicIosActorImpl::release()
+ {
+ if (mInRelease)
+ {
+ return;
+ }
+ mInRelease = true;
+ mAsset->releaseIosActor(*this);
+ }
+
+ void BasicIosActorImpl::destroy()
+ {
+ ApexActor::destroy();
+
+ setPhysXScene(NULL);
+
+ // remove ourself from our asset's resource list, in case releasing our emitters
+ // causes our asset's resource count to reach zero and for it to be released.
+ ApexResource::removeSelf();
+
+ // Release all injectors, releasing all emitters and their IOFX asset references
+ while (mInjectorList.getSize())
+ {
+ BasicParticleInjector* inj = DYNAMIC_CAST(BasicParticleInjector*)(mInjectorList.getResource(mInjectorList.getSize() - 1));
+ inj->release();
+ }
+
+ if (mIofxMgr)
+ {
+ mIofxMgr->release();
+ }
+ if (mFieldSamplerQuery)
+ {
+ mFieldSamplerQuery->release();
+ }
+
+ delete this;
+ }
+
+ void BasicIosActorImpl::setPhysXScene(PxScene* scene)
+ {
+ if (scene)
+ {
+ putInScene(scene);
+ }
+ else
+ {
+ removeFromScene();
+ }
+ }
+ PxScene* BasicIosActorImpl::getPhysXScene() const
+ {
+ return NULL;
+ }
+ void BasicIosActorImpl::putInScene(PxScene* scene)
+ {
+ SCOPED_PHYSX_LOCK_READ(scene);
+ PxVec3 gravity = scene->getGravity();
+ setGravity(gravity);
+ }
+
+ void BasicIosActorImpl::getLodRange(float& min, float& max, bool& intOnly) const
+ {
+ PX_UNUSED(min);
+ PX_UNUSED(max);
+ PX_UNUSED(intOnly);
+ APEX_INVALID_OPERATION("not implemented");
+ }
+
+
+ float BasicIosActorImpl::getActiveLod() const
+ {
+ APEX_INVALID_OPERATION("BasicIosActor does not support this operation");
+ return -1.0f;
+ }
+
+
+ void BasicIosActorImpl::forceLod(float lod)
+ {
+ PX_UNUSED(lod);
+ APEX_INVALID_OPERATION("not implemented");
+ }
+
+
+ void BasicIosActorImpl::removeFromScene()
+ {
+ mParticleCount = 0;
+ }
+
+
+ const PxVec3* BasicIosActorImpl::getRecentPositions(uint32_t& count, uint32_t& stride) const
+ {
+ APEX_INVALID_OPERATION("not implemented");
+
+ count = 0;
+ stride = 0;
+ return NULL;
+ }
+
+ PxVec3 BasicIosActorImpl::getGravity() const
+ {
+ return mGravityVec;
+ }
+
+ void BasicIosActorImpl::setGravity(PxVec3& gravity)
+ {
+ mGravityVec = gravity;
+ mUp = mGravityVec;
+
+ // apply asset's scene gravity scale and external acceleration
+ mUp *= mAsset->getSceneGravityScale();
+ mUp += mAsset->getExternalAcceleration();
+
+ mGravity = mUp.magnitude();
+ if (!PxIsFinite(mGravity))
+ {
+ // and they could set both to 0,0,0
+ mUp = PxVec3(0.0f, -1.0f, 0.0f);
+ mGravity = 1.0f;
+ }
+ mUp *= -1.0f;
+
+ mIofxMgr->setSimulationParameters(getObjectRadius(), mUp, mGravity, getObjectDensity());
+ }
+
+ IosInjectorIntl* BasicIosActorImpl::allocateInjector(IofxAsset* iofxAsset)
+ {
+ BasicParticleInjector* inj = 0;
+ //createInjector
+ {
+ uint32_t injectorID = mBasicIosScene->getInjectorAllocator().allocateInjectorID();
+ if (injectorID != BasicIosInjectorAllocator::NULL_INJECTOR_INDEX)
+ {
+ inj = PX_NEW(BasicParticleInjector)(mInjectorList, *this, injectorID);
+ }
+ }
+ if (inj == 0)
+ {
+ APEX_INTERNAL_ERROR("Failed to create new BasicIos injector.");
+ return NULL;
+ }
+
+ inj->init(iofxAsset);
+ return inj;
+ }
+
+ void BasicIosActorImpl::releaseInjector(IosInjectorIntl& injector)
+ {
+ BasicParticleInjector* inj = DYNAMIC_CAST(BasicParticleInjector*)(&injector);
+
+ //destroyInjector
+ {
+ //set mLODBias to FLT_MAX to mark released injector
+ //all particles from released injectors will be removed in simulation
+ InjectorParams injParams;
+ mBasicIosScene->fetchInjectorParams(inj->mInjectorID, injParams);
+ injParams.mLODBias = FLT_MAX;
+ mBasicIosScene->updateInjectorParams(inj->mInjectorID, injParams);
+
+ mBasicIosScene->getInjectorAllocator().releaseInjectorID(inj->mInjectorID);
+ inj->destroy();
+ }
+
+ if (mInjectorList.getSize() == 0)
+ {
+ //if we have no injectors - release self
+ release();
+ }
+ }
+
+
+ void BasicIosActorImpl::visualize()
+ {
+ if ( !mEnableDebugVisualization ) return;
+#ifndef WITHOUT_DEBUG_VISUALIZE
+ RenderDebugInterface* renderer = mBasicIosScene->mDebugRender;
+ const physx::PxMat44& savedPose = *RENDER_DEBUG_IFACE(renderer)->getPoseTyped();
+ RENDER_DEBUG_IFACE(renderer)->setIdentityPose();
+ if(mBasicIosScene->mBasicIosDebugRenderParams->VISUALIZE_BASIC_IOS_GRID_DENSITY)
+ {
+ if(mGridDensityParams.Enabled)
+ {
+ RENDER_DEBUG_IFACE(renderer)->setCurrentColor(0x0000ff);
+ float factor = PxMin((float)(mGridDensityParams.GridResolution-4) / (mGridDensityParams.GridResolution),0.75f);
+ uint32_t onScreenRes = (uint32_t)(factor*mGridDensityParams.GridResolution);
+ for (uint32_t i = 0 ; i <= onScreenRes; i++)
+ {
+ float u = 2.f*((float)i/(onScreenRes))-1.f;
+ PxVec4 a = mDensityDebugMatInv.transform(PxVec4(u,-1.f,0.1f,1.f));
+ PxVec4 b = mDensityDebugMatInv.transform(PxVec4(u, 1.f,0.1f,1.f));
+ PxVec4 c = mDensityDebugMatInv.transform(PxVec4(-1.f,u,0.1f,1.f));
+ PxVec4 d = mDensityDebugMatInv.transform(PxVec4( 1.f,u,0.1f,1.f));
+ RENDER_DEBUG_IFACE(renderer)->debugLine(PxVec3(a.getXYZ()/a.w), PxVec3(b.getXYZ()/b.w));
+ RENDER_DEBUG_IFACE(renderer)->debugLine(PxVec3(c.getXYZ()/c.w), PxVec3(d.getXYZ()/d.w));
+ }
+ }
+ }
+ if(mBasicIosScene->mBasicIosDebugRenderParams->VISUALIZE_BASIC_IOS_COLLIDE_SHAPES)
+ {
+ INPLACE_STORAGE_GROUP_SCOPE(mSimulationStorageGroup);
+ SimulationParams simParams;
+ mSimulationParamsHandle.fetch(_storage_, simParams);
+
+ RenderDebugInterface* renderer = mBasicIosScene->mDebugRender;
+ RENDER_DEBUG_IFACE(renderer)->setCurrentColor(RENDER_DEBUG_IFACE(renderer)->getDebugColor(RENDER_DEBUG::DebugColors::Blue));
+
+ for(uint32_t i = 0; i < (uint32_t)simParams.boxes.getSize(); ++i)
+ {
+ CollisionBoxData boxData;
+ simParams.boxes.fetchElem(_storage_, boxData, i);
+
+ const PxTransform& pose = boxData.pose;
+ PxVec3 position = pose.p;
+ PxVec3 halfSize = boxData.halfSize;
+ RENDER_DEBUG_IFACE(renderer)->setPose(pose);
+ RENDER_DEBUG_IFACE(renderer)->debugBound(PxBounds3(-halfSize, halfSize));
+ }
+
+ for(uint32_t i = 0; i < (uint32_t)simParams.spheres.getSize(); ++i)
+ {
+ CollisionSphereData sphereData;
+ simParams.spheres.fetchElem(_storage_, sphereData, i);
+
+ float r = sphereData.radius;
+ PxVec3 pos = sphereData.pose.p;
+ RENDER_DEBUG_IFACE(renderer)->debugSphere(pos, r);
+ }
+
+ for(uint32_t i = 0; i < (uint32_t)simParams.capsules.getSize(); ++i)
+ {
+ CollisionCapsuleData capsuleData;
+ simParams.capsules.fetchElem(_storage_, capsuleData, i);
+
+ float r = capsuleData.radius, h = capsuleData.halfHeight;
+ const PxTransform& pose = capsuleData.pose;
+ RENDER_DEBUG_IFACE(renderer)->setPose(pose);
+ RENDER_DEBUG_IFACE(renderer)->debugCapsule(r, 2 * h);
+ }
+ }
+ RENDER_DEBUG_IFACE(renderer)->setPose(savedPose);
+#endif
+ }
+
+ void BasicIosActorImpl::FillCollisionData(CollisionData& baseData, PxShape* shape)
+ {
+ PxTransform actorGlobalPose = shape->getActor()->getGlobalPose();
+
+ if (PxRigidBody* pxBody = shape->getActor()->is<physx::PxRigidBody>())
+ {
+ baseData.bodyCMassPosition = actorGlobalPose.transform(pxBody->getCMassLocalPose().p);
+ baseData.bodyLinearVelocity = pxBody->getLinearVelocity();
+ baseData.bodyAngluarVelocity = pxBody->getAngularVelocity();
+
+ baseData.materialRestitution = mAsset->mParams->restitutionForDynamicShapes;
+ }
+ else
+ {
+ baseData.bodyCMassPosition = actorGlobalPose.p;
+ baseData.bodyLinearVelocity = PxVec3(0, 0, 0);
+ baseData.bodyAngluarVelocity = PxVec3(0, 0, 0);
+
+ baseData.materialRestitution = mAsset->mParams->restitutionForStaticShapes;
+ }
+ //PxMaterial* PxMaterial = shape->getMaterialFromInternalFaceIndex(0);
+ //PX_ASSERT(PxMaterial);
+ //baseData->materialRestitution = PxMaterial->getRestitution();
+ }
+
+ void BasicIosActorImpl::submitTasks()
+ {
+ PxTaskManager* tm = mBasicIosScene->getApexScene().getTaskManager();
+ tm->submitUnnamedTask(*mInjectTask);
+
+ //compile a list of actually colliding objects and process them to be used by the simulation
+ INPLACE_STORAGE_GROUP_SCOPE(mSimulationStorageGroup);
+
+ SimulationParams simParams;
+ if (mSimulationParamsHandle.allocOrFetch(_storage_, simParams))
+ {
+ //one time initialization on alloc
+ simParams.collisionThreshold = mAsset->mParams->collisionThreshold;
+ simParams.collisionDistance = mAsset->mParams->particleRadius * mAsset->mParams->collisionDistanceMultiplier;
+#if APEX_CUDA_SUPPORT
+#define GET_PTR(x) x.getGpuPtr() ? x.getGpuPtr() : x.getPtr()
+#else
+#define GET_PTR(x) x.getPtr()
+#endif
+ simParams.convexPlanes = GET_PTR(mConvexPlanes);
+ simParams.convexVerts = GET_PTR(mConvexVerts);
+ simParams.convexPolygonsData = GET_PTR(mConvexPolygonsData);
+
+ simParams.trimeshVerts = GET_PTR(mTrimeshVerts);
+ simParams.trimeshIndices = GET_PTR(mTrimeshIndices);
+ }
+
+ uint32_t numBoxes = 0;
+ uint32_t numSpheres = 0;
+ uint32_t numCapsules = 0;
+ uint32_t numHalfSpaces = 0;
+ uint32_t numConvexMeshes = 0;
+ uint32_t numTriMeshes = 0;
+
+ mConvexPlanes.setSize(0);
+ mConvexVerts.setSize(0);
+ mConvexPolygonsData.setSize(0);
+
+ mTrimeshVerts.setSize(0);
+ mTrimeshIndices.setSize(0);
+
+ const float collisionRadius = simParams.collisionThreshold + simParams.collisionDistance;
+ uint32_t numCollidingObjects = 0;
+ PxBounds3 bounds = mIofxMgr->getBounds();
+ if ((mAsset->mParams->staticCollision || mAsset->mParams->dynamicCollision) && !bounds.isEmpty())
+ {
+ PX_ASSERT(!bounds.isEmpty());
+ bounds.fattenFast(collisionRadius);
+
+ const uint32_t maxCollidingObjects = mAsset->mParams->maxCollidingObjects;
+
+ mOverlapHits.resize(maxCollidingObjects);
+ PxBoxGeometry overlapGeom(bounds.getExtents());
+ PxTransform overlapPose(bounds.getCenter());
+
+ PxQueryFilterData overlapFilterData;
+ overlapFilterData.data = mCollisionFilterData;
+
+ overlapFilterData.flags = PxQueryFlag::eNO_BLOCK | PxQueryFlag::ePREFILTER;
+ if (mAsset->mParams->staticCollision) overlapFilterData.flags |= PxQueryFlag::eSTATIC;
+ if (mAsset->mParams->dynamicCollision) overlapFilterData.flags |= PxQueryFlag::eDYNAMIC;
+
+ SCOPED_PHYSX_LOCK_READ(mBasicIosScene->getModulePhysXScene());
+
+ class OverlapFilter : public physx::PxQueryFilterCallback
+ {
+ public:
+ virtual PxQueryHitType::Enum preFilter(
+ const PxFilterData& filterData, const PxShape* shape, const PxRigidActor* actor, physx::PxHitFlags& queryFlags)
+ {
+ PX_UNUSED(queryFlags);
+
+ const PxFilterData shapeFilterData = shape->getQueryFilterData();
+ const physx::PxFilterObjectAttributes iosAttributes = PxFilterObjectType::ePARTICLE_SYSTEM;
+ physx::PxFilterObjectAttributes actorAttributes = actor->getType();
+ if (const PxRigidBody* rigidBody = actor->is<physx::PxRigidBody>())
+ {
+ if (rigidBody->getRigidBodyFlags() & PxRigidBodyFlag::eKINEMATIC)
+ {
+ actorAttributes |= PxFilterObjectFlag::eKINEMATIC;
+ }
+ }
+
+ physx::PxPairFlags pairFlags;
+ physx::PxFilterFlags filterFlags = mFilterShader(iosAttributes, filterData, actorAttributes, shapeFilterData, pairFlags, mFilterShaderData, mFilterShaderDataSize);
+ return (filterFlags & (PxFilterFlag::eKILL | PxFilterFlag::eSUPPRESS)) ? PxQueryHitType::eNONE : PxQueryHitType::eTOUCH;
+ }
+
+ virtual PxQueryHitType::Enum postFilter(const PxFilterData& filterData, const PxQueryHit& hit)
+ {
+ PX_UNUSED(filterData);
+ PX_UNUSED(hit);
+ return PxQueryHitType::eNONE;
+ }
+
+ OverlapFilter(PxScene* scene)
+ {
+ mFilterShader = scene->getFilterShader();
+ mFilterShaderData = scene->getFilterShaderData();
+ mFilterShaderDataSize = scene->getFilterShaderDataSize();
+ }
+
+ private:
+ physx::PxSimulationFilterShader mFilterShader;
+ const void* mFilterShaderData;
+ uint32_t mFilterShaderDataSize;
+
+ } overlapFilter(mBasicIosScene->getModulePhysXScene());
+
+ physx::PxOverlapBuffer ovBuffer(&mOverlapHits[0], mOverlapHits.size());
+ mBasicIosScene->getModulePhysXScene()->overlap(overlapGeom, overlapPose, ovBuffer, overlapFilterData, &overlapFilter);
+ numCollidingObjects = ovBuffer.getNbTouches();
+
+ for (uint32_t iShape = 0; iShape < numCollidingObjects; iShape++)
+ {
+ PxShape* shape = mOverlapHits[iShape].shape;
+
+ switch (shape->getGeometryType())
+ {
+ case PxGeometryType::eBOX:
+ {
+ ++numBoxes;
+ }
+ break;
+ case PxGeometryType::eSPHERE:
+ {
+ ++numSpheres;
+ }
+ break;
+ case PxGeometryType::eCAPSULE:
+ {
+ ++numCapsules;
+ }
+ break;
+ case PxGeometryType::ePLANE:
+ {
+ ++numHalfSpaces;
+ }
+ break;
+ case PxGeometryType::eCONVEXMESH:
+ {
+ if (mAsset->mParams->collisionWithConvex)
+ {
+ ++numConvexMeshes;
+ }
+ }
+ break;
+ case PxGeometryType::eTRIANGLEMESH:
+ {
+ if (mAsset->mParams->collisionWithTriangleMesh)
+ {
+ ++numTriMeshes;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ simParams.boxes.resize(_storage_ , numBoxes);
+ simParams.spheres.resize(_storage_ , numSpheres);
+ simParams.capsules.resize(_storage_ , numCapsules);
+ simParams.halfSpaces.resize(_storage_ , numHalfSpaces);
+ simParams.convexMeshes.resize(_storage_ , numConvexMeshes);
+ simParams.trimeshes.resize(_storage_ , numTriMeshes);
+
+ numBoxes = 0;
+ numSpheres = 0;
+ numCapsules = 0;
+ numHalfSpaces = 0;
+ numConvexMeshes = 0;
+ numTriMeshes = 0;
+
+ if (numCollidingObjects > 0)
+ {
+ SCOPED_PHYSX_LOCK_READ(mBasicIosScene->getModulePhysXScene());
+ for (uint32_t iShape = 0; iShape < numCollidingObjects; iShape++)
+ {
+ PxShape* shape = mOverlapHits[iShape].shape;
+ PxRigidActor* actor = mOverlapHits[iShape].actor;
+
+ PxBounds3 shapeWorldBounds = PxShapeExt::getWorldBounds(*shape, *actor);
+ PxTransform actorGlobalPose = shape->getActor()->getGlobalPose();
+ PxTransform shapeGlobalPose = actorGlobalPose.transform(shape->getLocalPose());
+
+ PX_ASSERT(!shapeWorldBounds.isEmpty());
+ shapeWorldBounds.fattenFast(collisionRadius);
+
+ switch (shape->getGeometryType())
+ {
+ case PxGeometryType::eBOX:
+ {
+ PxBoxGeometry boxGeom;
+ shape->getBoxGeometry(boxGeom);
+
+ CollisionBoxData data;
+
+ data.aabb = shapeWorldBounds;
+ data.pose = shapeGlobalPose;
+ data.inversePose = data.pose.getInverse();
+
+ data.halfSize = boxGeom.halfExtents;
+
+ FillCollisionData(data, shape);
+ simParams.boxes.updateElem(_storage_, data, numBoxes++);
+ }
+ break;
+ case PxGeometryType::eSPHERE:
+ {
+ PxSphereGeometry sphereGeom;
+ shape->getSphereGeometry(sphereGeom);
+
+ CollisionSphereData data;
+
+ data.aabb = shapeWorldBounds;
+ data.pose = shapeGlobalPose;
+ data.inversePose = data.pose.getInverse();
+
+ data.radius = sphereGeom.radius;
+ //extend
+ data.radius += simParams.collisionDistance;
+
+ FillCollisionData(data, shape);
+ simParams.spheres.updateElem(_storage_, data, numSpheres++);
+ }
+ break;
+ case PxGeometryType::eCAPSULE:
+ {
+ PxCapsuleGeometry capsuleGeom;
+ shape->getCapsuleGeometry(capsuleGeom);
+
+ CollisionCapsuleData data;
+
+ data.aabb = shapeWorldBounds;
+ data.pose = shapeGlobalPose;
+ data.inversePose = data.pose.getInverse();
+
+ data.halfHeight = capsuleGeom.halfHeight;
+ data.radius = capsuleGeom.radius;
+ //extend
+ data.radius += simParams.collisionDistance;
+
+ FillCollisionData(data, shape);
+ simParams.capsules.updateElem(_storage_, data, numCapsules++);
+ }
+ break;
+ case PxGeometryType::ePLANE:
+ {
+ CollisionHalfSpaceData data;
+
+ data.origin = shapeGlobalPose.p;
+ data.normal = shapeGlobalPose.rotate(PxVec3(1, 0, 0));
+ //extend
+ data.origin += data.normal * simParams.collisionDistance;
+
+ FillCollisionData(data, shape);
+ simParams.halfSpaces.updateElem(_storage_, data, numHalfSpaces++);
+ }
+ break;
+ case PxGeometryType::eCONVEXMESH:
+ {
+ if (mAsset->mParams->collisionWithConvex)
+ {
+ PxConvexMeshGeometry convexGeom;
+ shape->getConvexMeshGeometry(convexGeom);
+
+ CollisionConvexMeshData data;
+
+ data.aabb = shapeWorldBounds;
+ data.pose = shapeGlobalPose;
+ data.inversePose = data.pose.getInverse();
+
+ //get ConvexMesh
+ const PxConvexMesh* convexMesh = convexGeom.convexMesh;
+
+ uint32_t numPolygons = convexMesh->getNbPolygons();
+ uint32_t numVertices = convexMesh->getNbVertices();
+ uint32_t polygonsDataSize = 0;
+ for (uint32_t i = 0; i < numPolygons; i++)
+ {
+ physx::PxHullPolygon polygon;
+ bool polygonDataTest = convexMesh->getPolygonData(i, polygon);
+ PX_UNUSED( polygonDataTest );
+ PX_ASSERT( polygonDataTest );
+
+ polygonsDataSize += (1 + polygon.mNbVerts);
+ }
+
+ if (mConvexPlanes.getSize() + numPolygons <= mConvexPlanes.getCapacity() &&
+ mConvexVerts.getSize() + numVertices <= mConvexVerts.getCapacity() &&
+ mConvexPolygonsData.getSize() + polygonsDataSize <= mConvexPolygonsData.getCapacity())
+ {
+ data.numPolygons = numPolygons;
+ data.firstPlane = mConvexPlanes.getSize();
+ data.firstVertex = mConvexVerts.getSize();
+ data.polygonsDataOffset = mConvexPolygonsData.getSize();
+
+ PxPlane* convexPlanes = mConvexPlanes.getPtr() + data.firstPlane;
+ PxVec4* convexVerts = mConvexVerts.getPtr() + data.firstVertex;
+ uint32_t* convexPolygonsData = mConvexPolygonsData.getPtr() + data.polygonsDataOffset;
+
+ mConvexPlanes.setSize(data.firstPlane + numPolygons);
+ mConvexVerts.setSize(data.firstVertex + numVertices);
+ mConvexPolygonsData.setSize(data.polygonsDataOffset + polygonsDataSize);
+
+ const PxMeshScale convexScaleInv( convexGeom.scale.getInverse() );
+ //copy Convex Planes & Polygon Data
+ const uint8_t* srcIndices = convexMesh->getIndexBuffer();
+ for (uint32_t i = 0; i < numPolygons; i++)
+ {
+ physx::PxHullPolygon polygon;
+ bool polygonDataTest = convexMesh->getPolygonData(i, polygon);
+ PX_UNUSED( polygonDataTest );
+ PX_ASSERT( polygonDataTest );
+ PxPlane plane(polygon.mPlane[0], polygon.mPlane[1], polygon.mPlane[2], polygon.mPlane[3]);
+ plane.n = convexScaleInv.transform(plane.n);
+ plane.normalize();
+ *convexPlanes++ = plane;
+
+ const uint32_t polygonVertCount = polygon.mNbVerts;
+ const uint8_t* polygonIndices = srcIndices + polygon.mIndexBase;
+
+ *convexPolygonsData++ = polygonVertCount;
+ for (uint32_t j = 0; j < polygonVertCount; ++j)
+ {
+ *convexPolygonsData++ = *polygonIndices++;
+ }
+ }
+
+ //copy Convex Vertices
+ const PxVec3* srcVertices = convexMesh->getVertices();
+ for (uint32_t i = 0; i < numVertices; i++)
+ {
+ *convexVerts++ = PxVec4(convexGeom.scale.transform(*srcVertices++), 0);
+ }
+ }
+ else
+ {
+ APEX_DEBUG_WARNING("BasicIosActorImpl: out of memory to store Convex data");
+
+ data.numPolygons = 0;
+ data.firstPlane = 0;
+ data.firstVertex = 0;
+ data.polygonsDataOffset = 0;
+ }
+
+ FillCollisionData(data, shape);
+ simParams.convexMeshes.updateElem(_storage_, data, numConvexMeshes++);
+ }
+ break;
+ }
+ case PxGeometryType::eTRIANGLEMESH:
+ {
+ if (mAsset->mParams->collisionWithTriangleMesh)
+ {
+ PxTriangleMeshGeometry trimeshGeom;
+ shape->getTriangleMeshGeometry(trimeshGeom);
+
+ CollisionTriMeshData data;
+
+ data.aabb = shapeWorldBounds;
+ PX_ASSERT(!data.aabb.isEmpty());
+ data.aabb.fattenFast( simParams.collisionDistance + simParams.collisionThreshold );
+ data.pose = shapeGlobalPose;
+ data.inversePose = data.pose.getInverse();
+
+ //triangle mesh data
+ const PxTriangleMesh* trimesh = trimeshGeom.triangleMesh;
+
+ const uint32_t numTrimeshIndices = trimesh->getNbTriangles() * 3;
+ const uint32_t numTrimeshVerts = trimesh->getNbVertices();
+
+ if (mTrimeshIndices.getSize() + numTrimeshIndices <= mTrimeshIndices.getCapacity() &&
+ mTrimeshVerts.getSize() + numTrimeshVerts <= mTrimeshVerts.getCapacity())
+ {
+ data.numTriangles = trimesh->getNbTriangles();
+ data.firstIndex = mTrimeshIndices.getSize();
+ data.firstVertex = mTrimeshVerts.getSize();
+
+ mTrimeshIndices.setSize(data.firstIndex + numTrimeshIndices);
+ //copy TriangleMesh indices
+ uint32_t* trimeshIndices = mTrimeshIndices.getPtr() + data.firstIndex;
+
+ const bool has16BitIndices = (trimesh->getTriangleMeshFlags() & PxTriangleMeshFlag::e16_BIT_INDICES);
+ if (has16BitIndices)
+ {
+ const uint16_t* srcIndices = static_cast<const uint16_t*>(trimesh->getTriangles());
+ for( uint32_t i = 0; i < numTrimeshIndices; i++)
+ {
+ trimeshIndices[i] = srcIndices[i];
+ }
+ }
+ else
+ {
+ const uint32_t* srcIndices = static_cast<const uint32_t*>(trimesh->getTriangles());
+ for( uint32_t i = 0; i < numTrimeshIndices; i++)
+ {
+ trimeshIndices[i] = srcIndices[i];
+ }
+ }
+
+ mTrimeshVerts.setSize(data.firstVertex + numTrimeshVerts);
+ //copy TriangleMesh vertices
+ PxVec4* trimeshVerts = mTrimeshVerts.getPtr() + data.firstVertex;
+ const PxVec3* srcVertices = trimesh->getVertices();
+ for( uint32_t i = 0; i < numTrimeshVerts; i++)
+ {
+ trimeshVerts[i] = PxVec4(trimeshGeom.scale.transform(srcVertices[i]), 0);
+ }
+ }
+ else
+ {
+ APEX_DEBUG_WARNING("BasicIosActorImpl: out of memory to store TriangleMesh data");
+
+ data.numTriangles = 0;
+ data.firstIndex = 0;
+ data.firstVertex = 0;
+ }
+
+ FillCollisionData(data, shape);
+ simParams.trimeshes.updateElem(_storage_, data, numTriMeshes++);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ }
+
+ }
+ mSimulationParamsHandle.update(_storage_, simParams);
+ }
+
+ void BasicIosActorImpl::setTaskDependencies(PxTask* iosTask, bool isDataOnDevice)
+ {
+ PxTaskManager* tm = mBasicIosScene->getApexScene().getTaskManager();
+
+ iosTask->startAfter(mInjectTask->getTaskID());
+
+ if (mFieldSamplerQuery != NULL)
+ {
+ float deltaTime = mBasicIosScene->getApexScene().getPhysXSimulateTime();
+
+ FieldSamplerQueryDataIntl queryData;
+ queryData.timeStep = deltaTime;
+ queryData.count = mParticleCount;
+ queryData.isDataOnDevice = isDataOnDevice;
+ queryData.positionStrideBytes = sizeof(PxVec4);
+ queryData.velocityStrideBytes = sizeof(PxVec4);
+ queryData.massStrideBytes = sizeof(PxVec4);
+ queryData.pmaInIndices = 0;
+ if (isDataOnDevice)
+ {
+#if APEX_CUDA_SUPPORT
+ queryData.pmaInPosition = (float*)mBufDesc.pmaPositionMass->getGpuPtr();
+ queryData.pmaInVelocity = (float*)mBufDesc.pmaVelocityLife->getGpuPtr();
+ queryData.pmaInMass = &mBufDesc.pmaPositionMass->getGpuPtr()->w;
+ queryData.pmaOutField = mField.getGpuPtr();
+#endif
+ }
+ else
+ {
+ queryData.pmaInPosition = (float*)mBufDesc.pmaPositionMass->getPtr();
+ queryData.pmaInVelocity = (float*)mBufDesc.pmaVelocityLife->getPtr();
+ queryData.pmaInMass = &mBufDesc.pmaPositionMass->getPtr()->w;
+ queryData.pmaOutField = mField.getPtr();
+ }
+ mFieldSamplerQuery->submitFieldSamplerQuery(queryData, iosTask->getTaskID());
+ }
+
+ PxTaskID postIofxTaskID = tm->getNamedTask(AST_PHYSX_FETCH_RESULTS);
+ PxTaskID iofxTaskID = mIofxMgr->getUpdateEffectsTaskID(postIofxTaskID);
+ if (iofxTaskID == (PxTaskID)0xFFFFFFFF)
+ {
+ iofxTaskID = postIofxTaskID;
+ }
+ iosTask->finishBefore(iofxTaskID);
+ }
+
+ void BasicIosActorImpl::fetchResults()
+ {
+ for(uint32_t i = 0; i < mInjectorList.getSize(); ++i)
+ {
+ BasicParticleInjector* inj = DYNAMIC_CAST(BasicParticleInjector*)(mInjectorList.getResource(i));
+ inj->assignSimParticlesCount(mInjectorsCounters.get(i));
+ }
+ }
+
+ void BasicIosActorImpl::injectNewParticles()
+ {
+ mInjectedBenefitSum = 0;
+ mInjectedBenefitMin = +FLT_MAX;
+ mInjectedBenefitMax = -FLT_MAX;
+
+ uint32_t maxInjectCount = (mMaxTotalParticleCount - mParticleCount);
+
+ uint32_t injectCount = 0;
+ uint32_t lastInjectCount = 0;
+ do
+ {
+ lastInjectCount = injectCount;
+ for (uint32_t i = 0; i < mInjectorList.getSize(); i++)
+ {
+ BasicParticleInjector* inj = DYNAMIC_CAST(BasicParticleInjector*)(mInjectorList.getResource(i));
+ if (inj->mInjectedParticles.size() == 0)
+ {
+ continue;
+ }
+
+ if (injectCount < maxInjectCount)
+ {
+ IosNewObject obj;
+ if (inj->mInjectedParticles.popFront(obj))
+ {
+ uint32_t injectIndex = mParticleCount + injectCount;
+
+ float particleMass = mAsset->getParticleMass();
+ mBufDesc.pmaPositionMass->get(injectIndex) = PxVec4(obj.initialPosition.x, obj.initialPosition.y, obj.initialPosition.z, particleMass);
+ mBufDesc.pmaVelocityLife->get(injectIndex) = PxVec4(obj.initialVelocity.x, obj.initialVelocity.y, obj.initialVelocity.z, 1.0f);
+ mBufDesc.pmaActorIdentifiers->get(injectIndex) = obj.iofxActorID;
+
+ mBufDesc.pmaUserData->get(injectIndex) = obj.userData;
+
+ mLifeSpan[injectIndex] = obj.lifetime;
+ mInjector[injectIndex] = inj->mInjectorID;
+ mBenefit[injectIndex] = obj.lodBenefit;
+
+ mInjectedBenefitSum += obj.lodBenefit;
+ mInjectedBenefitMin = PxMin(mInjectedBenefitMin, obj.lodBenefit);
+ mInjectedBenefitMax = PxMax(mInjectedBenefitMax, obj.lodBenefit);
+
+ ++injectCount;
+ }
+ }
+ }
+ }
+ while (injectCount > lastInjectCount);
+
+ mInjectedCount = injectCount;
+
+ //clear injectors FIFO
+ for (uint32_t i = 0; i < mInjectorList.getSize(); i++)
+ {
+ BasicParticleInjector* inj = DYNAMIC_CAST(BasicParticleInjector*)(mInjectorList.getResource(i));
+
+ IosNewObject obj;
+ while (inj->mInjectedParticles.popFront(obj))
+ {
+ ;
+ }
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ BasicParticleInjector::BasicParticleInjector(ResourceList& list, BasicIosActorImpl& actor, uint32_t injectorID)
+ : mIosActor(&actor)
+ , mIofxClient(NULL)
+ , mVolume(NULL)
+ , mLastRandomID(0)
+ , mVolumeID(IofxActorIDIntl::NO_VOLUME)
+ , mInjectorID(injectorID)
+ , mSimulatedParticlesCount(0)
+ {
+ mRand.setSeed(actor.mBasicIosScene->getApexScene().getSeed());
+
+ list.add(*this);
+
+ setLODWeights(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f);
+
+ mInjectedParticles.reserve(actor.mMaxTotalParticleCount);
+ }
+
+ BasicParticleInjector::~BasicParticleInjector()
+ {
+ }
+
+ void BasicParticleInjector::setListIndex(ResourceList& list, uint32_t index)
+ {
+ m_listIndex = index;
+ m_list = &list;
+
+ InjectorParams injParams;
+ mIosActor->mBasicIosScene->fetchInjectorParams(mInjectorID, injParams);
+
+ injParams.mLocalIndex = index;
+
+ mIosActor->mBasicIosScene->updateInjectorParams(mInjectorID, injParams);
+ }
+
+
+ /* Emitter calls this function to adjust their particle weights with respect to other emitters */
+ void BasicParticleInjector::setLODWeights(float maxDistance, float distanceWeight, float speedWeight, float lifeWeight, float separationWeight, float bias)
+ {
+ PX_UNUSED(separationWeight);
+
+ InjectorParams injParams;
+ mIosActor->mBasicIosScene->fetchInjectorParams(mInjectorID, injParams);
+
+ //normalize weights
+ float totalWeight = distanceWeight + speedWeight + lifeWeight;
+ if (totalWeight > PX_EPS_F32)
+ {
+ distanceWeight /= totalWeight;
+ speedWeight /= totalWeight;
+ lifeWeight /= totalWeight;
+ }
+
+ injParams.mLODMaxDistance = maxDistance;
+ injParams.mLODDistanceWeight = distanceWeight;
+ injParams.mLODSpeedWeight = speedWeight;
+ injParams.mLODLifeWeight = lifeWeight;
+ injParams.mLODBias = bias;
+
+ mIosActor->mBasicIosScene->updateInjectorParams(mInjectorID, injParams);
+ }
+
+
+ PxTaskID BasicParticleInjector::getCompletionTaskID() const
+ {
+ return mIosActor->mInjectTask->getTaskID();
+ }
+
+ void BasicParticleInjector::setObjectScale(float objectScale)
+ {
+ PX_ASSERT(mIofxClient);
+ IofxManagerClientIntl::Params params;
+ mIofxClient->getParams(params);
+ params.objectScale = objectScale;
+ mIofxClient->setParams(params);
+ }
+
+ void BasicParticleInjector::init(IofxAsset* iofxAsset)
+ {
+ mIofxClient = mIosActor->mIofxMgr->createClient(iofxAsset, IofxManagerClientIntl::Params());
+
+ /* add this injector to the IOFX asset's context (so when the IOFX goes away our ::release() is called) */
+ iofxAsset->addDependentActor(this);
+
+ mRandomActorClassIDs.clear();
+ if (iofxAsset->getMeshAssetCount() < 2)
+ {
+ mRandomActorClassIDs.pushBack(mIosActor->mIofxMgr->getActorClassID(mIofxClient, 0));
+ return;
+ }
+
+ /* Cache actorClassIDs for this asset */
+ physx::Array<uint16_t> temp;
+ for (uint32_t i = 0 ; i < iofxAsset->getMeshAssetCount() ; i++)
+ {
+ uint32_t w = iofxAsset->getMeshAssetWeight(i);
+ uint16_t acid = mIosActor->mIofxMgr->getActorClassID(mIofxClient, (uint16_t) i);
+ for (uint32_t j = 0 ; j < w ; j++)
+ {
+ temp.pushBack(acid);
+ }
+ }
+
+ mRandomActorClassIDs.reserve(temp.size());
+ while (temp.size())
+ {
+ uint32_t index = (uint32_t)mRand.getScaled(0, (float)temp.size());
+ mRandomActorClassIDs.pushBack(temp[ index ]);
+ temp.replaceWithLast(index);
+ }
+ }
+
+
+ void BasicParticleInjector::release()
+ {
+ if (mInRelease)
+ {
+ return;
+ }
+ mInRelease = true;
+ mIosActor->releaseInjector(*this);
+ }
+
+ void BasicParticleInjector::destroy()
+ {
+ ApexActor::destroy();
+
+ mIosActor->mIofxMgr->releaseClient(mIofxClient);
+
+ delete this;
+ }
+
+ void BasicParticleInjector::setPreferredRenderVolume(nvidia::apex::RenderVolume* volume)
+ {
+ mVolume = volume;
+ mVolumeID = mVolume ? mIosActor->mIofxMgr->getVolumeID(mVolume) : IofxActorIDIntl::NO_VOLUME;
+ }
+
+ /* Emitter calls this virtual injector API to insert new particles. It is safe for an emitter to
+ * call this function at any time except for during the IOS::fetchResults(). Since
+ * ParticleScene::fetchResults() is single threaded, it should be safe to call from
+ * emitter::fetchResults() (destruction may want to do this because of contact reporting)
+ */
+ void BasicParticleInjector::createObjects(uint32_t count, const IosNewObject* createList)
+ {
+ PX_PROFILE_ZONE("BasicIosCreateObjects", GetInternalApexSDK()->getContextId());
+
+ if (mRandomActorClassIDs.size() == 0)
+ {
+ return;
+ }
+
+ PxVec3 eyePos;
+ {
+ SceneIntl& apexScene = mIosActor->mBasicIosScene->getApexScene();
+ READ_LOCK(apexScene);
+ eyePos = apexScene.getEyePosition();
+ }
+ InjectorParams injParams;
+ mIosActor->mBasicIosScene->fetchInjectorParams(mInjectorID, injParams);
+ // Append new objects to our FIFO. We do copies because we must perform buffering for the
+ // emitters. We have to hold these new objects until there is room in the TurbulenceFS and the
+ // injector's virtID range to emit them.
+ for (uint32_t i = 0 ; i < count ; i++)
+ {
+ if (mInjectedParticles.size() == mInjectedParticles.capacity())
+ {
+ break;
+ }
+
+ IosNewObject obj = *createList++;
+
+ obj.lodBenefit = calcParticleBenefit(injParams, eyePos, obj.initialPosition, obj.initialVelocity, 1.0f);
+ obj.iofxActorID.set(mVolumeID, mRandomActorClassIDs[ mLastRandomID++ ]);
+ mLastRandomID = mLastRandomID == mRandomActorClassIDs.size() ? 0 : mLastRandomID;
+ //mInjectedParticleBenefit += obj.lodBenefit;
+ mInjectedParticles.pushBack(obj);
+ }
+ }
+
+#if APEX_CUDA_SUPPORT
+ void BasicParticleInjector::createObjects(ApexMirroredArray<const IosNewObject>& createArray)
+ {
+ PX_UNUSED(createArray);
+
+ // An emitter will call this API when it has filled a host or device buffer. The injector
+ // should trigger a copy to the location it would like to see the resulting data when the
+ // IOS is finally ticked.
+
+ PX_ALWAYS_ASSERT(); /* Not yet supported */
+ }
+#endif
+
+ }
+} // namespace nvidia
+