aboutsummaryrefslogtreecommitdiff
path: root/APEX_1.4/module/iofx/include/ModifierSrc.h
diff options
context:
space:
mode:
Diffstat (limited to 'APEX_1.4/module/iofx/include/ModifierSrc.h')
-rw-r--r--APEX_1.4/module/iofx/include/ModifierSrc.h921
1 files changed, 921 insertions, 0 deletions
diff --git a/APEX_1.4/module/iofx/include/ModifierSrc.h b/APEX_1.4/module/iofx/include/ModifierSrc.h
new file mode 100644
index 00000000..c293c31a
--- /dev/null
+++ b/APEX_1.4/module/iofx/include/ModifierSrc.h
@@ -0,0 +1,921 @@
+/*
+ * 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.
+ */
+
+
+#if defined(__CUDACC__) && defined(__CUDA_ARCH__) && __CUDA_ARCH__ < 200
+#define _CUDA_OPT_LOC_MEM_ 1
+#else
+#define _CUDA_OPT_LOC_MEM_ 0
+#endif
+
+#define PI 3.141592653589793f
+
+//--- Helpers
+
+APEX_CUDA_CALLABLE PX_INLINE unsigned int binSearch(float val, unsigned int count, const float* data)
+{
+ unsigned int beg = 0;
+ unsigned int end = count;
+
+ while (beg < end)
+ {
+ unsigned int mid = beg + ((end - beg) >> 1);
+ if (val < data[mid])
+ {
+ end = mid;
+ }
+ else
+ {
+ beg = mid + 1;
+ }
+ }
+ return beg;
+}
+
+APEX_CUDA_CALLABLE PX_INLINE void approxAxisAngleToMat33(const PxVec3& axisAngle, PxMat33& rot)
+{
+ const float x = 0.5f * axisAngle.x;
+ const float y = 0.5f * axisAngle.y;
+ const float z = 0.5f * axisAngle.z;
+ const float xx = x * x;
+ const float yy = y * y;
+ const float zz = z * z;
+ const float xy = x * y;
+ const float yz = y * z;
+ const float zx = z * x;
+ const float twoRecipNorm2 = 2.0f / (1.0f + xx + yy + zz); // w = 1
+ rot(0, 0) = 1.0f - twoRecipNorm2 * (yy + zz);
+ rot(0, 1) = twoRecipNorm2 * (xy - z);
+ rot(0, 2) = twoRecipNorm2 * (zx + y);
+ rot(1, 0) = twoRecipNorm2 * (xy + z);
+ rot(1, 1) = 1.0f - twoRecipNorm2 * (zz + xx);
+ rot(1, 2) = twoRecipNorm2 * (yz - x);
+ rot(2, 0) = twoRecipNorm2 * (zx - y);
+ rot(2, 1) = twoRecipNorm2 * (yz + x);
+ rot(2, 2) = 1.0f - twoRecipNorm2 * (xx + yy);
+}
+
+
+APEX_CUDA_CALLABLE PX_INLINE bool approxEquals(float a, float b, float eps)
+{
+ const float diff = PxAbs(a - b);
+ return (diff < eps);
+}
+
+APEX_CUDA_CALLABLE PX_INLINE bool approxEquals(const PxVec3& a, const PxVec3& b, float eps)
+{
+ return approxEquals(a.x, b.x, eps) &&
+ approxEquals(a.y, b.y, eps) &&
+ approxEquals(a.z, b.z, eps);
+}
+
+APEX_CUDA_CALLABLE PX_INLINE int maxAbsElementIndex(const PxVec3& v)
+{
+ const PxVec3 a(PxAbs(v.x), PxAbs(v.y), PxAbs(v.z));
+ const int m01 = (a.y > a.x);
+ const int m2 = (a.z > a[(unsigned)m01]);
+ return (m2 << 1) | (m01 >> m2);
+}
+
+
+APEX_CUDA_CALLABLE PX_INLINE void generateRotationMatrix(const PxVec3& srcVec, const PxVec3& dstVec, PxMat33& outRotMat)
+{
+ if (approxEquals(srcVec, dstVec, 0.0001f))
+ {
+ outRotMat = PxMat33(PxIdentity);
+ return;
+ }
+
+ PxVec3 crossResult = srcVec.cross(dstVec);
+ crossResult *= PxAcos(srcVec.dot(dstVec));
+
+ approxAxisAngleToMat33(crossResult, outRotMat);
+}
+
+APEX_CUDA_CALLABLE PX_INLINE void generateRandomRotation(const PxVec3& srcVec, PxMat33& outRotMat, nvidia::RandState& randState)
+{
+ PxVec3 tmpRotVec(srcVec);
+ tmpRotVec *= randState.nextFloat(0.0f, 2 * PI);
+ approxAxisAngleToMat33(tmpRotVec, outRotMat);
+}
+
+// ------------------------------------------------------------------------------------------------
+
+
+//--- Rotation modifier ---
+
+//struct PARAMS_NAME(Rotation)
+#define INPLACE_TYPE_STRUCT_NAME PARAMS_NAME(Rotation)
+#define INPLACE_TYPE_STRUCT_FIELDS \
+ INPLACE_TYPE_FIELD(uint32_t, rollType) \
+ INPLACE_TYPE_FIELD(int32_t, rollAxis) \
+ INPLACE_TYPE_FIELD(float, rollSign) \
+ INPLACE_TYPE_FIELD(float, maxSettleRatePerSec) \
+ INPLACE_TYPE_FIELD(float, maxRotationRatePerSec) \
+ INPLACE_TYPE_FIELD(float, inAirRotationMultiplier) \
+ INPLACE_TYPE_FIELD(float, collisionRotationMultiplier) \
+ INPLACE_TYPE_FIELD(uint32_t, includeVerticalDirection)
+#define INPLACE_TYPE_STRUCT_LEAVE_OPEN 1
+#include INPLACE_TYPE_BUILD()
+
+ static const uint32_t RANDOM_COUNT = 3;
+};
+
+APEX_CUDA_CALLABLE PX_INLINE void chooseUp(PxVec3& outUp, unsigned int rollType, nvidia::RandState& randState)
+{
+ const float angle = randState.nextFloat(0.0f, 2 * PI);
+ const float up = angle < PI ? -1.0f : 1.0f;
+ const float cosAng = PxCos(angle);
+ const float sinAng = PxSin(angle);
+
+ switch (rollType)
+ {
+ default:
+ outUp = PxVec3(0.0f, 0.0f, 1.0f);
+ break;
+
+ case nvidia::apex::ApexMeshParticleRollType::FLAT_X:
+ outUp = PxVec3(up, 0.0f, 0.0f);
+ break;
+ case nvidia::apex::ApexMeshParticleRollType::FLAT_Y:
+ outUp = PxVec3(0.0f, up, 0.0f);
+ break;
+ case nvidia::apex::ApexMeshParticleRollType::FLAT_Z:
+ outUp = PxVec3(0.0f, 0.0f, up);
+ break;
+
+ case nvidia::apex::ApexMeshParticleRollType::LONG_X:
+ outUp = PxVec3(0.0f, cosAng, sinAng);
+ break;
+ case nvidia::apex::ApexMeshParticleRollType::LONG_Y:
+ outUp = PxVec3(cosAng, 0.0f, sinAng);
+ break;
+ case nvidia::apex::ApexMeshParticleRollType::LONG_Z:
+ outUp = PxVec3(cosAng, sinAng, 0.0f);
+ break;
+ }
+}
+
+APEX_CUDA_CALLABLE PX_INLINE void updateParticleRollBoxFromCollision(const PARAMS_NAME(Rotation)& params, PxVec3& particleAngularDelta, const PxMat33& rot, const PxVec3& collisionNormal, float timeSlice)
+{
+ const float maxSettle = params.maxSettleRatePerSec * timeSlice;
+ const float maxSettle2 = maxSettle * maxSettle; // where to compute this?
+
+ if (params.rollType != nvidia::apex::ApexMeshParticleRollType::SPHERICAL)
+ {
+ // Settling
+ PxVec3 a;
+ if (params.rollAxis < 0)
+ {
+ // Cubic rolling, must choose most normal-pointing mRollAxis
+ PxVec3 overlap;
+ overlap = rot.transform(collisionNormal);
+ const int32_t bestAxis = maxAbsElementIndex(overlap);
+ a = bestAxis == 0 ? rot.column0 : bestAxis == 1 ? rot.column1 : rot.column2;
+ }
+ else
+ {
+ // Flat or long box, mRollAxis is chosen
+ a = params.rollAxis == 0 ? rot.column0 : params.rollAxis == 1 ? rot.column1 : rot.column2;
+ }
+
+ PxVec3 settle = (params.rollSign * a.dot(collisionNormal)) * a.cross(collisionNormal);
+ if (maxSettle != 0.0f)
+ {
+ const float settle2 = settle.magnitudeSquared();
+ // Cap how much settling is allowed per simulation tick
+ if (settle2 > maxSettle2)
+ {
+ settle *= maxSettle * PxRecipSqrt(settle2);
+ }
+ }
+ particleAngularDelta += settle;
+ }
+}
+
+APEX_CUDA_CALLABLE PX_INLINE void updateParticleRollBoxNoCollision(const PARAMS_NAME(Rotation)& params, PxVec3& particleAngularDelta, float timeSlice)
+{
+ const float maxRotation = params.maxRotationRatePerSec * timeSlice;
+ const float maxRotation2 = maxRotation * maxRotation;
+
+ if (maxRotation != 0.0f)
+ {
+ // Cap the total amount of roll.
+ const float roll2 = particleAngularDelta.magnitudeSquared();
+ if (roll2 > maxRotation2)
+ {
+ particleAngularDelta *= maxRotation * PxRecipSqrt(roll2);
+ }
+ }
+}
+
+
+INPLACE_TEMPL_VA_ARGS_DEF(bool spawn, int usage, typename Input, typename PubState, typename PrivState)
+MODIFIER_DECL void modifierRotation(const PARAMS_NAME(Rotation)& params, const Input& input, PubState& pubState, PrivState& privState, const nvidia::iofx::ModifierCommonParams& common, nvidia::RandState& randState)
+{
+ if (usage == nvidia::apex::ModifierUsage_Mesh)
+ {
+ // TODO: This should really go into a 'settle' modifier, that says that objects should try to settle with one side up
+ // or another, but for now it's here.
+ if (spawn)
+ {
+ // Need to come up with a default pose.
+ PxMat33 rotationOnSpawn;
+ if (params.rollType == nvidia::apex::ApexMeshParticleRollType::SPHERICAL)
+ {
+ PxVec3 randomRotation;
+ randomRotation.x = randState.nextFloat(-PI, PI);
+ randomRotation.y = randState.nextFloat(-PI, PI);
+ randomRotation.z = randState.nextFloat(-PI, PI);
+ approxAxisAngleToMat33(randomRotation, rotationOnSpawn);
+ }
+ else
+ {
+ PxVec3 upVector;
+ chooseUp(upVector, params.rollType, randState);
+
+ PxVec3 unitSystemUp = common.upVector;
+ unitSystemUp.normalize();
+
+ PxMat33 rotateToUp, randomRotation;
+ generateRotationMatrix(upVector, unitSystemUp, rotateToUp);
+ generateRandomRotation(unitSystemUp, randomRotation, randState);
+
+ rotationOnSpawn = randomRotation * rotateToUp;
+ }
+ privState.rotation = rotationOnSpawn;
+ pubState.rotation = rotationOnSpawn;
+ }
+ else
+ {
+ PxVec3 rollDelta;
+ PxVec3 delta = input.velocity * common.deltaTime;
+
+ if (common.inputHasCollision)
+ {
+ if (input.collisionFlags != 0)
+ {
+ rollDelta = params.collisionRotationMultiplier * input.collisionNormal.cross(delta);
+ }
+ else
+ {
+ if (params.includeVerticalDirection)
+ {
+ // I'd like to use the absolute value of the "up" speed... just check it in first.
+ rollDelta = params.inAirRotationMultiplier * delta;
+ }
+ else
+ {
+ rollDelta = params.inAirRotationMultiplier * common.upVector.cross( delta );
+ }
+ }
+
+ updateParticleRollBoxFromCollision(params, rollDelta, privState.rotation, input.collisionNormal, common.deltaTime);
+ updateParticleRollBoxNoCollision(params, rollDelta, common.deltaTime);
+ }
+ else
+ {
+ if (params.includeVerticalDirection)
+ {
+ // I'd like to use the absolute value of the "up" speed... just check it in first.
+ rollDelta = params.inAirRotationMultiplier * delta;
+ }
+ else
+ {
+ rollDelta = params.inAirRotationMultiplier * common.upVector.cross( delta );
+ }
+ updateParticleRollBoxNoCollision(params, rollDelta, common.deltaTime);
+ }
+
+ if (rollDelta.magnitudeSquared() > 0.0f)
+ {
+ // update particle transform
+ // A) This is because maxAngle isn't really working properly
+ // B) This should be a configurable parameter of the system
+ PxMat33 rot;
+ approxAxisAngleToMat33(rollDelta, rot);
+ privState.rotation = rot * privState.rotation;
+ }
+ pubState.rotation = privState.rotation;
+ }
+ }
+}
+
+//--- SimpleScale modifier ---
+
+//struct PARAMS_NAME(SimpleScale)
+#define INPLACE_TYPE_STRUCT_NAME PARAMS_NAME(SimpleScale)
+#define INPLACE_TYPE_STRUCT_FIELDS \
+ INPLACE_TYPE_FIELD(PxVec3, scaleFactor)
+#define INPLACE_TYPE_STRUCT_LEAVE_OPEN 1
+#include INPLACE_TYPE_BUILD()
+
+ static const uint32_t RANDOM_COUNT = 0;
+};
+
+INPLACE_TEMPL_VA_ARGS_DEF(bool spawn, int usage, typename Input, typename PubState, typename PrivState)
+MODIFIER_DECL void modifierSimpleScale(const PARAMS_NAME(SimpleScale)& params, const Input& /*input*/, PubState& pubState, PrivState& /*privState*/, const nvidia::iofx::ModifierCommonParams& /*common*/, nvidia::RandState& /*nvidia::RandState*/)
+{
+ pubState.scale.x *= params.scaleFactor.x;
+ pubState.scale.y *= params.scaleFactor.y;
+ pubState.scale.z *= params.scaleFactor.z;
+}
+
+//--- RandomScale modifier ---
+
+//struct PARAMS_NAME(RandomScale)
+#define INPLACE_TYPE_STRUCT_NAME PARAMS_NAME(RandomScale)
+#define INPLACE_TYPE_STRUCT_FIELDS \
+ INPLACE_TYPE_FIELD(float, scaleFactorMin) \
+ INPLACE_TYPE_FIELD(float, scaleFactorMax)
+#define INPLACE_TYPE_STRUCT_LEAVE_OPEN 1
+#include INPLACE_TYPE_BUILD()
+
+ static const uint32_t RANDOM_COUNT = 1;
+};
+
+INPLACE_TEMPL_VA_ARGS_DEF(bool spawn, int usage, typename Input, typename PubState, typename PrivState)
+MODIFIER_DECL void modifierRandomScale(const PARAMS_NAME(RandomScale)& params, const Input& /*input*/, PubState& pubState, PrivState& /*privState*/, const nvidia::iofx::ModifierCommonParams& /*common*/, nvidia::RandState& randState)
+{
+ const float scaleFactor = randState.nextFloat(params.scaleFactorMin, params.scaleFactorMax);
+
+ pubState.scale *= scaleFactor;
+}
+
+//--- ScaleByMass modifier ---
+
+//struct PARAMS_NAME(ScaleByMass)
+#define INPLACE_TYPE_STRUCT_NAME PARAMS_NAME(ScaleByMass)
+#define INPLACE_TYPE_STRUCT_FIELDS \
+ INPLACE_TYPE_FIELD(float, scaleFactor)
+#define INPLACE_TYPE_STRUCT_LEAVE_OPEN 1
+#include INPLACE_TYPE_BUILD()
+
+ static const uint32_t RANDOM_COUNT = 0;
+};
+
+INPLACE_TEMPL_VA_ARGS_DEF(bool spawn, int usage, typename Input, typename PubState, typename PrivState)
+MODIFIER_DECL void modifierScaleByMass(const PARAMS_NAME(ScaleByMass)& /*params*/, const Input& input, PubState& pubState, PrivState& /*privState*/, const nvidia::iofx::ModifierCommonParams& /*common*/, nvidia::RandState& /*nvidia::RandState*/)
+{
+ pubState.scale *= input.mass;
+}
+
+//--- ColorVsLife modifier ---
+
+//struct PARAMS_NAME(ColorVsLife)
+#define INPLACE_TYPE_STRUCT_NAME PARAMS_NAME(ColorVsLife)
+#define INPLACE_TYPE_STRUCT_FIELDS \
+ INPLACE_TYPE_FIELD(uint32_t, channel) \
+ INPLACE_TYPE_FIELD(CURVE_TYPE, curve)
+#define INPLACE_TYPE_STRUCT_LEAVE_OPEN 1
+#include INPLACE_TYPE_BUILD()
+
+ static const uint32_t RANDOM_COUNT = 0;
+};
+
+INPLACE_TEMPL_VA_ARGS_DEF(bool spawn, int usage, typename Input, typename PubState, typename PrivState)
+MODIFIER_DECL void modifierColorVsLife(const PARAMS_NAME(ColorVsLife)& params, const Input& input, PubState& pubState, PrivState& /*privState*/, const nvidia::iofx::ModifierCommonParams& /*common*/, nvidia::RandState& /*nvidia::RandState*/)
+{
+#define _MODIFIER_CODE_(channel) \
+ { \
+ pubState.color[channel] *= EVAL_CURVE(params.curve, input.liferemain); \
+ }
+#if _CUDA_OPT_LOC_MEM_
+ if (params.channel == 0) _MODIFIER_CODE_(0)
+ else if (params.channel == 1) _MODIFIER_CODE_(1)
+ else if (params.channel == 2) _MODIFIER_CODE_(2)
+ else if (params.channel == 3) _MODIFIER_CODE_(3)
+#else
+ _MODIFIER_CODE_(params.channel)
+#endif
+#undef _MODIFIER_CODE_
+
+ }
+
+//--- ColorVsDensity modifier ---
+
+//struct PARAMS_NAME(ColorVsDensity)
+#define INPLACE_TYPE_STRUCT_NAME PARAMS_NAME(ColorVsDensity)
+#define INPLACE_TYPE_STRUCT_FIELDS \
+ INPLACE_TYPE_FIELD(uint32_t, channel) \
+ INPLACE_TYPE_FIELD(CURVE_TYPE, curve)
+#define INPLACE_TYPE_STRUCT_LEAVE_OPEN 1
+#include INPLACE_TYPE_BUILD()
+
+ static const uint32_t RANDOM_COUNT = 0;
+};
+
+INPLACE_TEMPL_VA_ARGS_DEF(bool spawn, int usage, typename Input, typename PubState, typename PrivState)
+MODIFIER_DECL void modifierColorVsDensity(const PARAMS_NAME(ColorVsDensity)& params, const Input& input, PubState& pubState, PrivState& /*privState*/, const nvidia::iofx::ModifierCommonParams& /*common*/, nvidia::RandState& /*nvidia::RandState*/)
+{
+#define _MODIFIER_CODE_(channel) \
+ { \
+ pubState.color[channel] *= EVAL_CURVE(params.curve, input.density); \
+ }
+#if _CUDA_OPT_LOC_MEM_
+ if (params.channel == 0) _MODIFIER_CODE_(0)
+ else if (params.channel == 1) _MODIFIER_CODE_(1)
+ else if (params.channel == 2) _MODIFIER_CODE_(2)
+ else if (params.channel == 3) _MODIFIER_CODE_(3)
+#else
+ _MODIFIER_CODE_(params.channel)
+#endif
+#undef _MODIFIER_CODE_
+ }
+
+//--- ColorVsVelocity modifier ---
+
+//struct PARAMS_NAME(ColorVsVelocity)
+#define INPLACE_TYPE_STRUCT_NAME PARAMS_NAME(ColorVsVelocity)
+#define INPLACE_TYPE_STRUCT_FIELDS \
+ INPLACE_TYPE_FIELD(float, velocity0) \
+ INPLACE_TYPE_FIELD(float, velocity1) \
+ INPLACE_TYPE_FIELD(uint32_t, channel) \
+ INPLACE_TYPE_FIELD(CURVE_TYPE, curve)
+#define INPLACE_TYPE_STRUCT_LEAVE_OPEN 1
+#include INPLACE_TYPE_BUILD()
+
+ static const uint32_t RANDOM_COUNT = 0;
+};
+
+INPLACE_TEMPL_VA_ARGS_DEF(bool spawn, int usage, typename Input, typename PubState, typename PrivState)
+MODIFIER_DECL void modifierColorVsVelocity(const PARAMS_NAME(ColorVsVelocity)& params, const Input& input, PubState& pubState, PrivState& /*privState*/, const nvidia::iofx::ModifierCommonParams& /*common*/, nvidia::RandState& /*nvidia::RandState*/)
+{
+ float velocity = (input.velocity.magnitude() - params.velocity0) / (params.velocity1 - params.velocity0);
+ velocity = PxClamp(velocity, 0.0f, 1.0f);
+
+#define _MODIFIER_CODE_(channel) \
+ { \
+ pubState.color[channel] *= EVAL_CURVE(params.curve, velocity); \
+ }
+#if _CUDA_OPT_LOC_MEM_
+ if (params.channel == 0) _MODIFIER_CODE_(0)
+ else if (params.channel == 1) _MODIFIER_CODE_(1)
+ else if (params.channel == 2) _MODIFIER_CODE_(2)
+ else if (params.channel == 3) _MODIFIER_CODE_(3)
+#else
+ _MODIFIER_CODE_(params.channel)
+#endif
+#undef _MODIFIER_CODE_
+}
+
+//--- SubtextureVsLife modifier ---
+
+//struct PARAMS_NAME(SubtextureVsLife)
+#define INPLACE_TYPE_STRUCT_NAME PARAMS_NAME(SubtextureVsLife)
+#define INPLACE_TYPE_STRUCT_FIELDS \
+ INPLACE_TYPE_FIELD(CURVE_TYPE, curve)
+#define INPLACE_TYPE_STRUCT_LEAVE_OPEN 1
+#include INPLACE_TYPE_BUILD()
+
+ static const uint32_t RANDOM_COUNT = 0;
+};
+
+INPLACE_TEMPL_VA_ARGS_DEF(bool spawn, int usage, typename Input, typename PubState, typename PrivState)
+MODIFIER_DECL void modifierSubtextureVsLife(const PARAMS_NAME(SubtextureVsLife)& params, const Input& input, PubState& pubState, PrivState& /*privState*/, const nvidia::iofx::ModifierCommonParams& /*common*/, nvidia::RandState& /*nvidia::RandState*/)
+{
+ if (usage == nvidia::apex::ModifierUsage_Sprite)
+ {
+ pubState.subTextureId += EVAL_CURVE(params.curve, input.liferemain);
+ }
+}
+
+//--- OrientAlongVelocity modifier ---
+
+APEX_CUDA_CALLABLE PX_INLINE bool buildRotationMatrix(const PxVec3& srcVec, const PxVec3& dstVec, PxMat33& outRotMat)
+{
+ PxVec3 axis = srcVec.cross(dstVec);
+
+ float cosAngle = srcVec.dot(dstVec);
+ float angle = PxAcos(cosAngle);
+
+ float axisLen = axis.normalize();
+ if (axisLen < 0.0001f)
+ {
+ return false;
+ }
+
+ PxQuat quat(angle, axis);
+ outRotMat = PxMat33(quat);
+ return true;
+}
+
+//struct PARAMS_NAME(OrientAlongVelocity)
+#define INPLACE_TYPE_STRUCT_NAME PARAMS_NAME(OrientAlongVelocity)
+#define INPLACE_TYPE_STRUCT_FIELDS \
+ INPLACE_TYPE_FIELD(PxVec3, modelForward)
+#define INPLACE_TYPE_STRUCT_LEAVE_OPEN 1
+#include INPLACE_TYPE_BUILD()
+
+ static const uint32_t RANDOM_COUNT = 0;
+};
+
+INPLACE_TEMPL_VA_ARGS_DEF(bool spawn, int usage, typename Input, typename PubState, typename PrivState)
+MODIFIER_DECL void modifierOrientAlongVelocity(const PARAMS_NAME(OrientAlongVelocity)& params, const Input& input, PubState& pubState, PrivState& privState, const nvidia::iofx::ModifierCommonParams& /*common*/, nvidia::RandState& /*nvidia::RandState*/)
+{
+ if (usage == nvidia::apex::ModifierUsage_Mesh)
+ {
+ PxVec3 vel = input.velocity;
+ float velMagnitude = vel.normalize(); // normalize it
+ // If travelling too slowly, this will be unstable, so don't do anything.
+ if (PxAbs(velMagnitude) >= 0.0001f)
+ {
+ PxMat33 rotMat;
+ if (buildRotationMatrix(params.modelForward, vel, rotMat))
+ {
+ privState.rotation = rotMat;
+ }
+ }
+ pubState.rotation = privState.rotation;
+ }
+}
+
+//--- ScaleAlongVelocity modifier ---
+
+///p,q -> p^q = n (n - must be normalized!)
+APEX_CUDA_CALLABLE PX_INLINE void buildPlaneBasis(const PxVec3& n, PxVec3& p, PxVec3& q)
+{
+ const float SQRT1_2 = PxSqrt(float(0.5));
+ if (PxAbs(n.z) > SQRT1_2)
+ {
+ // choose p in y-z plane
+ float k = sqrtf(n.y * n.y + n.z * n.z);
+ p.x = 0;
+ p.y = -n.z / k;
+ p.z = n.y / k;
+ // set q = n x p
+ q.x = k;
+ q.y = -n.x * p.z;
+ q.z = n.x * p.y;
+ }
+ else
+ {
+ // choose p in x-y plane
+ float k = PxSqrt(n.x * n.x + n.y * n.y);
+ p.x = -n.y / k;
+ p.y = n.x / k;
+ p.z = 0;
+ // set q = n x p
+ q.x = -n.z * p.y;
+ q.y = n.z * p.x;
+ q.z = k;
+ }
+}
+
+APEX_CUDA_CALLABLE PX_INLINE void buildScaleAlongAxis(const PxVec3& scaleAxis, float scale, PxMat33& scaleMat)
+{
+ PxVec3 axis0, axis1;
+ buildPlaneBasis(scaleAxis, axis0, axis1);
+
+ PxMat33 rotToAxisMat(axis0, axis1, scaleAxis);
+
+ scaleMat = rotToAxisMat;
+ scaleMat.column2 = scaleAxis * scale;
+
+ //scaleMat.setMultiplyTransposeRight(scaleMat, rotToAxisMat);
+
+ float a = scaleMat.column0.dot(rotToAxisMat.column0);
+ float b = scaleMat(0,0) * rotToAxisMat(0,1) + scaleMat(1,0) * rotToAxisMat(1,1) + scaleMat(2,0) * rotToAxisMat(2,1);
+ float c = scaleMat(0,0) * rotToAxisMat(0,2) + scaleMat(1,0) * rotToAxisMat(1,2) + scaleMat(2,0) * rotToAxisMat(2,2);
+ float d = scaleMat(0,1) * rotToAxisMat(0,0) + scaleMat(1,1) * rotToAxisMat(1,0) + scaleMat(2,1) * rotToAxisMat(2,0);
+ float e = scaleMat(0,1) * rotToAxisMat(0,1) + scaleMat(1,1) * rotToAxisMat(1,1) + scaleMat(2,1) * rotToAxisMat(2,1);
+ float f = scaleMat(0,1) * rotToAxisMat(0,2) + scaleMat(1,1) * rotToAxisMat(1,2) + scaleMat(2,1) * rotToAxisMat(2,2);
+ float g = scaleMat(0,2) * rotToAxisMat(0,0) + scaleMat(1,2) * rotToAxisMat(1,0) + scaleMat(2,2) * rotToAxisMat(2,0);
+ float h = scaleMat(0,2) * rotToAxisMat(0,1) + scaleMat(1,2) * rotToAxisMat(1,1) + scaleMat(2,2) * rotToAxisMat(2,1);
+ float i = scaleMat(0,2) * rotToAxisMat(0,2) + scaleMat(1,2) * rotToAxisMat(1,2) + scaleMat(2,2) * rotToAxisMat(2,2);
+
+ scaleMat(0,0) = a;
+ scaleMat(1,0) = b;
+ scaleMat(2,0) = c;
+
+ scaleMat(0,1) = d;
+ scaleMat(1,1) = e;
+ scaleMat(2,1) = f;
+
+ scaleMat(0,2) = g;
+ scaleMat(1,2) = h;
+ scaleMat(2,2) = i;
+}
+
+//struct PARAMS_NAME(ScaleAlongVelocity)
+#define INPLACE_TYPE_STRUCT_NAME PARAMS_NAME(ScaleAlongVelocity)
+#define INPLACE_TYPE_STRUCT_FIELDS \
+ INPLACE_TYPE_FIELD(float, scaleFactor)
+#define INPLACE_TYPE_STRUCT_LEAVE_OPEN 1
+#include INPLACE_TYPE_BUILD()
+
+ static const uint32_t RANDOM_COUNT = 0;
+};
+
+INPLACE_TEMPL_VA_ARGS_DEF(bool spawn, int usage, typename Input, typename PubState, typename PrivState)
+MODIFIER_DECL void modifierScaleAlongVelocity(const PARAMS_NAME(ScaleAlongVelocity)& params, const Input& input, PubState& pubState, PrivState& /*privState*/, const nvidia::iofx::ModifierCommonParams& /*common*/, nvidia::RandState& /*nvidia::RandState*/)
+{
+ if (usage == nvidia::apex::ModifierUsage_Mesh)
+ {
+ PxVec3 vel = input.velocity;
+ float velMagnitude = vel.normalize(); // normalize it
+
+ PxMat33 scaleMat(PxIdentity);
+ if (velMagnitude >= 0.0001f)
+ {
+ float scale = 1.0f + velMagnitude * params.scaleFactor;
+
+ buildScaleAlongAxis(vel, scale, scaleMat);
+ }
+ pubState.rotation = scaleMat * pubState.rotation;
+ }
+}
+
+//--- RandomSubtexture modifier ---
+
+//struct PARAMS_NAME(RandomSubtexture)
+#define INPLACE_TYPE_STRUCT_NAME PARAMS_NAME(RandomSubtexture)
+#define INPLACE_TYPE_STRUCT_FIELDS \
+ INPLACE_TYPE_FIELD(float, subtextureRangeMin) \
+ INPLACE_TYPE_FIELD(float, subtextureRangeMax)
+#define INPLACE_TYPE_STRUCT_LEAVE_OPEN 1
+#include INPLACE_TYPE_BUILD()
+
+ static const uint32_t RANDOM_COUNT = 1;
+};
+
+INPLACE_TEMPL_VA_ARGS_DEF(bool spawn, int usage, typename Input, typename PubState, typename PrivState)
+MODIFIER_DECL void modifierRandomSubtexture(const PARAMS_NAME(RandomSubtexture)& params, const Input& /*input*/, PubState& pubState, PrivState& /*privState*/, const nvidia::iofx::ModifierCommonParams& /*common*/, nvidia::RandState& randState)
+{
+ if (usage == nvidia::apex::ModifierUsage_Sprite)
+ {
+ pubState.subTextureId += randState.nextFloat(params.subtextureRangeMin, params.subtextureRangeMax);
+ }
+}
+
+//--- RandomRotation modifier ---
+
+//struct PARAMS_NAME(RandomRotation)
+#define INPLACE_TYPE_STRUCT_NAME PARAMS_NAME(RandomRotation)
+#define INPLACE_TYPE_STRUCT_FIELDS \
+ INPLACE_TYPE_FIELD(float, rotationRangeMin) \
+ INPLACE_TYPE_FIELD(float, rotationRangeMax)
+#define INPLACE_TYPE_STRUCT_LEAVE_OPEN 1
+#include INPLACE_TYPE_BUILD()
+
+ static const uint32_t RANDOM_COUNT = 1;
+};
+
+INPLACE_TEMPL_VA_ARGS_DEF(bool spawn, int usage, typename Input, typename PubState, typename PrivState)
+MODIFIER_DECL void modifierRandomRotation(const PARAMS_NAME(RandomRotation)& params, const Input& /*input*/, PubState& pubState, PrivState& /*privState*/, const nvidia::iofx::ModifierCommonParams& /*common*/, nvidia::RandState& randState)
+{
+ if (usage == nvidia::apex::ModifierUsage_Sprite)
+ {
+ const float DegToRad = PI / 180;
+ pubState.rotation += DegToRad * randState.nextFloat(params.rotationRangeMin, params.rotationRangeMax);
+ }
+}
+
+//--- ScaleVsLife modifier ---
+
+//struct PARAMS_NAME(ScaleVsLife)
+#define INPLACE_TYPE_STRUCT_NAME PARAMS_NAME(ScaleVsLife)
+#define INPLACE_TYPE_STRUCT_FIELDS \
+ INPLACE_TYPE_FIELD(uint32_t, axis) \
+ INPLACE_TYPE_FIELD(CURVE_TYPE, curve)
+#define INPLACE_TYPE_STRUCT_LEAVE_OPEN 1
+#include INPLACE_TYPE_BUILD()
+
+ static const uint32_t RANDOM_COUNT = 0;
+};
+
+INPLACE_TEMPL_VA_ARGS_DEF(bool spawn, int usage, typename Input, typename PubState, typename PrivState)
+MODIFIER_DECL void modifierScaleVsLife(const PARAMS_NAME(ScaleVsLife)& params, const Input& input, PubState& pubState, PrivState& /*privState*/, const nvidia::iofx::ModifierCommonParams& /*common*/, nvidia::RandState& /*nvidia::RandState*/)
+{
+#define _MODIFIER_CODE_(axis) \
+ { \
+ pubState.scale[axis] *= EVAL_CURVE(params.curve, input.liferemain); \
+ }
+#if _CUDA_OPT_LOC_MEM_
+ if (params.axis == 0) _MODIFIER_CODE_(0)
+ else if (params.axis == 1) _MODIFIER_CODE_(1)
+ else if (params.axis == 2) _MODIFIER_CODE_(2)
+#else
+ _MODIFIER_CODE_(params.axis)
+#endif
+#undef _MODIFIER_CODE_
+ }
+
+//--- ScaleVsDensity modifier ---
+
+//struct PARAMS_NAME(ScaleVsDensity)
+#define INPLACE_TYPE_STRUCT_NAME PARAMS_NAME(ScaleVsDensity)
+#define INPLACE_TYPE_STRUCT_FIELDS \
+ INPLACE_TYPE_FIELD(uint32_t, axis) \
+ INPLACE_TYPE_FIELD(CURVE_TYPE, curve)
+#define INPLACE_TYPE_STRUCT_LEAVE_OPEN 1
+#include INPLACE_TYPE_BUILD()
+
+ static const uint32_t RANDOM_COUNT = 0;
+};
+
+INPLACE_TEMPL_VA_ARGS_DEF(bool spawn, int usage, typename Input, typename PubState, typename PrivState)
+MODIFIER_DECL void modifierScaleVsDensity(const PARAMS_NAME(ScaleVsDensity)& params, const Input& input, PubState& pubState, PrivState& /*privState*/, const nvidia::iofx::ModifierCommonParams& /*common*/, nvidia::RandState& /*nvidia::RandState*/)
+{
+#define _MODIFIER_CODE_(axis) \
+ { \
+ pubState.scale[axis] *= EVAL_CURVE(params.curve, input.density); \
+ }
+#if _CUDA_OPT_LOC_MEM_
+ if (params.axis == 0) _MODIFIER_CODE_(0)
+ else if (params.axis == 1) _MODIFIER_CODE_(1)
+ else if (params.axis == 2) _MODIFIER_CODE_(2)
+#else
+ _MODIFIER_CODE_(params.axis)
+#endif
+#undef _MODIFIER_CODE_
+ }
+
+//--- ScaleVsCameraDistance modifier ---
+
+//struct PARAMS_NAME(ScaleVsCameraDistance)
+#define INPLACE_TYPE_STRUCT_NAME PARAMS_NAME(ScaleVsCameraDistance)
+#define INPLACE_TYPE_STRUCT_FIELDS \
+ INPLACE_TYPE_FIELD(uint32_t, axis) \
+ INPLACE_TYPE_FIELD(CURVE_TYPE, curve)
+#define INPLACE_TYPE_STRUCT_LEAVE_OPEN 1
+#include INPLACE_TYPE_BUILD()
+
+ static const uint32_t RANDOM_COUNT = 0;
+};
+
+INPLACE_TEMPL_VA_ARGS_DEF(bool spawn, int usage, typename Input, typename PubState, typename PrivState)
+MODIFIER_DECL void modifierScaleVsCameraDistance(const PARAMS_NAME(ScaleVsCameraDistance)& params, const Input& input, PubState& pubState, PrivState& /*privState*/, const nvidia::iofx::ModifierCommonParams& common, nvidia::RandState& /*nvidia::RandState*/)
+{
+ float cameraDistance = (input.position - common.eyePosition).magnitude();
+
+#define _MODIFIER_CODE_(axis) \
+ { \
+ pubState.scale[axis] *= EVAL_CURVE(params.curve, cameraDistance); \
+ }
+#if _CUDA_OPT_LOC_MEM_
+ if (params.axis == 0) _MODIFIER_CODE_(0)
+ else if (params.axis == 1) _MODIFIER_CODE_(1)
+ else if (params.axis == 2) _MODIFIER_CODE_(2)
+#else
+ _MODIFIER_CODE_(params.axis)
+#endif
+#undef _MODIFIER_CODE_
+ }
+
+//--- ViewDirectionSorting modifier ---
+
+//struct PARAMS_NAME(ViewDirectionSorting)
+#define INPLACE_TYPE_STRUCT_NAME PARAMS_NAME(ViewDirectionSorting)
+#define INPLACE_TYPE_STRUCT_LEAVE_OPEN 1
+#include INPLACE_TYPE_BUILD()
+
+ static const uint32_t RANDOM_COUNT = 0;
+};
+
+INPLACE_TEMPL_VA_ARGS_DEF(bool spawn, int usage, typename Input, typename PubState, typename PrivState)
+MODIFIER_DECL void modifierViewDirectionSorting(const PARAMS_NAME(ViewDirectionSorting)& /*params*/, const Input& /*input*/, PubState& /*pubState*/, PrivState& /*privState*/, const nvidia::iofx::ModifierCommonParams& /*common*/, nvidia::RandState& /*nvidia::RandState*/)
+{
+}
+
+//--- RotationRate modifier ---
+
+//struct PARAMS_NAME(RotationRate)
+#define INPLACE_TYPE_STRUCT_NAME PARAMS_NAME(RotationRate)
+#define INPLACE_TYPE_STRUCT_FIELDS \
+ INPLACE_TYPE_FIELD(float, rotationRate)
+#define INPLACE_TYPE_STRUCT_LEAVE_OPEN 1
+#include INPLACE_TYPE_BUILD()
+
+ static const uint32_t RANDOM_COUNT = 0;
+};
+
+INPLACE_TEMPL_VA_ARGS_DEF(bool spawn, int usage, typename Input, typename PubState, typename PrivState)
+MODIFIER_DECL void modifierRotationRate(const PARAMS_NAME(RotationRate)& params, const Input& /*input*/, PubState& pubState, PrivState& privState, const nvidia::iofx::ModifierCommonParams& common, nvidia::RandState& /*nvidia::RandState*/)
+{
+ if (usage == nvidia::apex::ModifierUsage_Sprite)
+ {
+ const float TwoPi = 2 * PI;
+ const float rotationDelta = params.rotationRate * TwoPi * common.deltaTime;
+ privState.rotation += rotationDelta;
+ pubState.rotation += privState.rotation;
+ }
+}
+
+//--- RotationRateVsLife modifier ---
+
+//struct PARAMS_NAME(RotationRateVsLife)
+#define INPLACE_TYPE_STRUCT_NAME PARAMS_NAME(RotationRateVsLife)
+#define INPLACE_TYPE_STRUCT_FIELDS \
+ INPLACE_TYPE_FIELD(CURVE_TYPE, curve)
+#define INPLACE_TYPE_STRUCT_LEAVE_OPEN 1
+#include INPLACE_TYPE_BUILD()
+
+ static const uint32_t RANDOM_COUNT = 0;
+};
+
+INPLACE_TEMPL_VA_ARGS_DEF(bool spawn, int usage, typename Input, typename PubState, typename PrivState)
+MODIFIER_DECL void modifierRotationRateVsLife(const PARAMS_NAME(RotationRateVsLife)& params, const Input& input, PubState& pubState, PrivState& privState, const nvidia::iofx::ModifierCommonParams& common, nvidia::RandState& /*nvidia::RandState*/)
+{
+ if (usage == nvidia::apex::ModifierUsage_Sprite)
+ {
+ const float TwoPi = 2 * PI;
+ const float rotationDelta = EVAL_CURVE(params.curve, input.liferemain) * TwoPi * common.deltaTime;
+ privState.rotation += rotationDelta;
+ pubState.rotation += privState.rotation;
+ }
+}
+
+//--- OrientScaleAlongScreenVelocity modifier ---
+
+//struct PARAMS_NAME(OrientScaleAlongScreenVelocity)
+#define INPLACE_TYPE_STRUCT_NAME PARAMS_NAME(OrientScaleAlongScreenVelocity)
+#define INPLACE_TYPE_STRUCT_FIELDS \
+ INPLACE_TYPE_FIELD(float, scalePerVelocity) \
+ INPLACE_TYPE_FIELD(float, scaleChangeLimit) \
+ INPLACE_TYPE_FIELD(float, scaleChangeDelay)
+#define INPLACE_TYPE_STRUCT_LEAVE_OPEN 1
+#include INPLACE_TYPE_BUILD()
+
+ static const uint32_t RANDOM_COUNT = 0;
+};
+
+INPLACE_TEMPL_VA_ARGS_DEF(bool spawn, int usage, typename Input, typename PubState, typename PrivState)
+MODIFIER_DECL void modifierOrientScaleAlongScreenVelocity(const PARAMS_NAME(OrientScaleAlongScreenVelocity)& params, const Input& input, PubState& pubState, PrivState& privState, const nvidia::iofx::ModifierCommonParams& common, nvidia::RandState& /*nvidia::RandState*/)
+{
+ if (usage == nvidia::apex::ModifierUsage_Sprite)
+ {
+ PxVec3 viewPos, viewVel; // position & velocity in view space
+
+ viewPos.x = (input.position - common.eyePosition).dot(common.eyeAxisX);
+ viewPos.y = (input.position - common.eyePosition).dot(common.eyeAxisY);
+ viewPos.z = (input.position - common.eyePosition).dot(common.eyeDirection); // eyeDir = eyeAxisZ
+
+ // 4 is simply a hack that looks decent in UE3 ATM, we should use the FOV to determine when to
+ // cull particles, otherwise you end up with particles around the zNear plane that have huge
+ // 'd' values, resulting in bad scaling
+ if (viewPos.z < common.zNear * 4)
+ {
+ pubState.rotation = privState.rotation;
+ pubState.scale.x = 0.0f;
+ pubState.scale.y = 0.0f;
+ return;
+ }
+
+ viewVel.x = (input.velocity).dot(common.eyeAxisX);
+ viewVel.y = (input.velocity).dot(common.eyeAxisY);
+ viewVel.z = (input.velocity).dot(common.eyeDirection); // eyeDir = eyeAxisZ
+
+ // tan(angle) = (Vy*Pz - Py*Vz) / (Vx*Pz - Px*Vz)
+ const float velX = viewVel.x * viewPos.z - viewPos.x * viewVel.z;
+ const float velY = viewVel.y * viewPos.z - viewPos.y * viewVel.z;
+
+ const float velLengthMultiplier = 1.0f / viewPos.z;
+
+ const float dx = velX * velLengthMultiplier;
+ const float dy = velY * velLengthMultiplier;
+
+ const float d = PxSqrt(dx * dx + dy * dy);
+
+ if (d >= 1e-5f)
+ {
+ // "Note that the order of arguments is reversed; the function atan2(y,x) computes
+ // the angle corresponding to the point (x,y)."
+ // see http://en.wikipedia.org/wiki/Atan2
+ privState.rotation = PxAtan2(velY, velX);
+
+ float scale = 1.0f + d * params.scalePerVelocity;
+ if (params.scaleChangeDelay > 0.0f)
+ {
+ const float blendFactor = PxExp(-common.deltaTime / params.scaleChangeDelay);
+ scale *= (1.0f - blendFactor);
+ scale += blendFactor * privState.scale;
+ }
+ if (params.scaleChangeLimit > 0.0f)
+ {
+ const float scaleChangeLimit = params.scaleChangeLimit * common.deltaTime;
+ const float scaleChange = scale - privState.scale;
+ if (scaleChange > +scaleChangeLimit)
+ {
+ scale = privState.scale + scaleChangeLimit;
+ }
+ else if (scaleChange < -scaleChangeLimit)
+ {
+ scale = privState.scale - scaleChangeLimit;
+ }
+ }
+ privState.scale = scale;
+ pubState.scale.x *= scale;
+ }
+ pubState.rotation = privState.rotation;
+ }
+}
+
+#undef _CUDA_OPT_LOC_MEM_