diff options
| author | git perforce import user <a@b> | 2016-10-25 12:29:14 -0600 |
|---|---|---|
| committer | Sheikh Dawood Abdul Ajees <Sheikh Dawood Abdul Ajees> | 2016-10-25 18:56:37 -0500 |
| commit | 3dfe2108cfab31ba3ee5527e217d0d8e99a51162 (patch) | |
| tree | fa6485c169e50d7415a651bf838f5bcd0fd3bfbd /APEX_1.4/module/forcefield/include/ForceFieldFSCommon.h | |
| download | physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.tar.xz physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.zip | |
Initial commit:
PhysX 3.4.0 Update @ 21294896
APEX 1.4.0 Update @ 21275617
[CL 21300167]
Diffstat (limited to 'APEX_1.4/module/forcefield/include/ForceFieldFSCommon.h')
| -rw-r--r-- | APEX_1.4/module/forcefield/include/ForceFieldFSCommon.h | 554 |
1 files changed, 554 insertions, 0 deletions
diff --git a/APEX_1.4/module/forcefield/include/ForceFieldFSCommon.h b/APEX_1.4/module/forcefield/include/ForceFieldFSCommon.h new file mode 100644 index 00000000..f2811f6d --- /dev/null +++ b/APEX_1.4/module/forcefield/include/ForceFieldFSCommon.h @@ -0,0 +1,554 @@ +/* + * 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. + */ + + +#ifndef __FORCEFIELD_FS_COMMON_SRC_H__ +#define __FORCEFIELD_FS_COMMON_SRC_H__ + +#include "../../fieldsampler/include/FieldSamplerCommon.h" +#include "SimplexNoise.h" +#include "TableLookup.h" +#include "PxMat33.h" + +namespace nvidia +{ +namespace apex +{ + +template <> struct InplaceTypeTraits<TableLookup> +{ + template <int _inplace_offset_, typename R, typename RA> + APEX_CUDA_CALLABLE PX_INLINE static void reflectType(R& r, RA ra, TableLookup& t) + { + InplaceTypeHelper::reflectType<APEX_OFFSETOF(TableLookup, xVals) + _inplace_offset_>(r, ra, t.xVals, InplaceTypeMemberDefaultTraits()); + InplaceTypeHelper::reflectType<APEX_OFFSETOF(TableLookup, yVals) + _inplace_offset_>(r, ra, t.yVals, InplaceTypeMemberDefaultTraits()); + InplaceTypeHelper::reflectType<APEX_OFFSETOF(TableLookup, x1) + _inplace_offset_>(r, ra, t.x1, InplaceTypeMemberDefaultTraits()); + InplaceTypeHelper::reflectType<APEX_OFFSETOF(TableLookup, x2) + _inplace_offset_>(r, ra, t.x2, InplaceTypeMemberDefaultTraits()); + InplaceTypeHelper::reflectType<APEX_OFFSETOF(TableLookup, multiplier) + _inplace_offset_>(r, ra, t.multiplier, InplaceTypeMemberDefaultTraits()); + } +}; + +} +namespace forcefield +{ + +struct ForceFieldShapeType +{ + enum Enum + { + SPHERE = 0, + CAPSULE, + CYLINDER, + CONE, + BOX, + NONE, + }; +}; + +struct ForceFieldFalloffType +{ + enum Enum + { + LINEAR = 0, + STEEP, + SCURVE, + CUSTOM, + NONE, + }; +}; + +struct ForceFieldCoordinateSystemType +{ + enum Enum + { + CARTESIAN = 0, + SPHERICAL, + CYLINDRICAL, + TOROIDAL, + }; +}; + +struct ForceFieldKernelType +{ + enum Enum + { + RADIAL = 0, + GENERIC + }; +}; + +//struct ForceFieldShapeDesc +#define INPLACE_TYPE_STRUCT_NAME ForceFieldShapeDesc +#define INPLACE_TYPE_STRUCT_FIELDS \ + INPLACE_TYPE_FIELD(InplaceEnum<ForceFieldShapeType::Enum>, type) \ + INPLACE_TYPE_FIELD(PxMat44, forceFieldToShape) \ + INPLACE_TYPE_FIELD(PxVec3, dimensions) +#include INPLACE_TYPE_BUILD() + + +//struct NoiseParams +#define INPLACE_TYPE_STRUCT_NAME NoiseParams +#define INPLACE_TYPE_STRUCT_FIELDS \ + INPLACE_TYPE_FIELD(float, strength) \ + INPLACE_TYPE_FIELD(float, spaceScale) \ + INPLACE_TYPE_FIELD(float, timeScale) \ + INPLACE_TYPE_FIELD(uint32_t, octaves) +#include INPLACE_TYPE_BUILD() + +//struct ForceFieldCoordinateSystem +#define INPLACE_TYPE_STRUCT_NAME ForceFieldCoordinateSystem +#define INPLACE_TYPE_STRUCT_FIELDS \ + INPLACE_TYPE_FIELD(InplaceEnum<ForceFieldCoordinateSystemType::Enum>, type) \ + INPLACE_TYPE_FIELD(float, torusRadius) +#include INPLACE_TYPE_BUILD() + +//struct ForceFieldFSKernelParams +#define INPLACE_TYPE_STRUCT_NAME ForceFieldFSKernelParams +#define INPLACE_TYPE_STRUCT_FIELDS \ + INPLACE_TYPE_FIELD(PxMat44, pose) \ + INPLACE_TYPE_FIELD(float, strength) \ + INPLACE_TYPE_FIELD(ForceFieldShapeDesc, includeShape) +#include INPLACE_TYPE_BUILD() + +//struct GenericForceFieldFSKernelParams +#define INPLACE_TYPE_STRUCT_NAME GenericForceFieldFSKernelParams +#define INPLACE_TYPE_STRUCT_BASE ForceFieldFSKernelParams +#define INPLACE_TYPE_STRUCT_FIELDS \ + INPLACE_TYPE_FIELD(ForceFieldCoordinateSystem, cs) \ + INPLACE_TYPE_FIELD(PxVec3, constant) \ + INPLACE_TYPE_FIELD(PxMat33, positionMultiplier) \ + INPLACE_TYPE_FIELD(PxVec3, positionTarget) \ + INPLACE_TYPE_FIELD(PxMat33, velocityMultiplier) \ + INPLACE_TYPE_FIELD(PxVec3, velocityTarget) \ + INPLACE_TYPE_FIELD(PxVec3, noise) \ + INPLACE_TYPE_FIELD(PxVec3, falloffLinear) \ + INPLACE_TYPE_FIELD(PxVec3, falloffQuadratic) +#include INPLACE_TYPE_BUILD() + +//struct RadialForceFieldFSKernelParams +#define INPLACE_TYPE_STRUCT_NAME RadialForceFieldFSKernelParams +#define INPLACE_TYPE_STRUCT_BASE ForceFieldFSKernelParams +#define INPLACE_TYPE_STRUCT_FIELDS \ + INPLACE_TYPE_FIELD(float, radius) \ + INPLACE_TYPE_FIELD(TableLookup, falloffTable) \ + INPLACE_TYPE_FIELD(NoiseParams, noiseParams) +#include INPLACE_TYPE_BUILD() + +APEX_CUDA_CALLABLE PX_INLINE bool isPosInShape(const ForceFieldShapeDesc& shapeParams, const PxVec3& pos) +{ + // Sphere: x = radius + // Capsule: x = radius, y = height + // Cylinder: x = radius, y = height + // Cone: x = top radius, y = height, z = bottom radius + // Box: x,y,z = half-dimensions + + // transform position from force field coordinates to local shape coordinates + PxVec3 shapePos = shapeParams.forceFieldToShape.transform(pos); + + switch (shapeParams.type) + { + case ForceFieldShapeType::SPHERE: + { + return (shapePos.magnitude() <= shapeParams.dimensions.x); + } + case ForceFieldShapeType::CAPSULE: + { + float halfHeight = shapeParams.dimensions.y / 2.0f; + + // check if y-position is within height of cylinder + if (shapePos.y >= -halfHeight && shapePos.y <= halfHeight) + { + // check if x and z positions is inside radius height of cylinder + if (PxSqrt(shapePos.x * shapePos.x + shapePos.z * shapePos.z) <= shapeParams.dimensions.x) + { + return true; + } + } + + // check if position falls inside top sphere in capsule + PxVec3 spherePos = shapePos - PxVec3(0, halfHeight, 0); + if (spherePos.magnitude() <= shapeParams.dimensions.x) + { + return true; + } + + // check if position falls inside bottom sphere in capsule + spherePos = shapePos + PxVec3(0, halfHeight, 0); + if (spherePos.magnitude() <= shapeParams.dimensions.x) + { + return true; + } + + return false; + } + case ForceFieldShapeType::CYLINDER: + { + float halfHeight = shapeParams.dimensions.y / 2.0f; + + // check if y-position is within height of cylinder + if (shapePos.y >= -halfHeight && shapePos.y <= halfHeight) + { + // check if x and z positions is inside radius height of cylinder + if (PxSqrt(shapePos.x * shapePos.x + shapePos.z * shapePos.z) <= shapeParams.dimensions.x) + { + return true; + } + } + return false; + } + case ForceFieldShapeType::CONE: + { + float halfHeight = shapeParams.dimensions.y / 2.0f; + + // check if y-position is within height of cone + if (shapePos.y >= -halfHeight && shapePos.y <= halfHeight) + { + // cone can be normal or inverted + float smallerBase; + float heightFromSmallerBase; + float radiusDiff; + if (shapeParams.dimensions.x > shapeParams.dimensions.z) + { + smallerBase = shapeParams.dimensions.z; + heightFromSmallerBase = shapePos.y + halfHeight; + radiusDiff = shapeParams.dimensions.x - shapeParams.dimensions.z; + } + else + { + smallerBase = shapeParams.dimensions.x; + heightFromSmallerBase = halfHeight - shapePos.y; + radiusDiff = shapeParams.dimensions.z - shapeParams.dimensions.x; + } + + // compute radius at y-position along height of cone + float radiusAlongCone = smallerBase + (heightFromSmallerBase / shapeParams.dimensions.y) * radiusDiff; + + // check if x and z positions is inside radius at a specific height of cone + if (PxSqrt(shapePos.x * shapePos.x + shapePos.z * shapePos.z) <= radiusAlongCone) + { + return true; + } + } + return false; + } + case ForceFieldShapeType::BOX: + { + return (PxAbs(shapePos.x) <= shapeParams.dimensions.x && + PxAbs(shapePos.y) <= shapeParams.dimensions.y && + PxAbs(shapePos.z) <= shapeParams.dimensions.z); + } + default: + { + return false; + } + } +} + +APEX_CUDA_CALLABLE PX_INLINE PxVec3 getNoise(const NoiseParams& params, const PxVec3& pos, const uint32_t& totalElapsedMS) +{ + PxVec3 point = params.spaceScale * pos; + float time = (params.timeScale * 1e-3f) * totalElapsedMS; + + PxVec4 dFx; + dFx.setZero(); + PxVec4 dFy; + dFy.setZero(); + PxVec4 dFz; + dFz.setZero(); + int seed = 0; + float amp = 1.0f; + for (uint32_t i = 0; i < params.octaves; ++i) + { + dFx += amp * SimplexNoise::eval4D(point.x, point.y, point.z, time, ++seed); + dFy += amp * SimplexNoise::eval4D(point.x, point.y, point.z, time, ++seed); + dFz += amp * SimplexNoise::eval4D(point.x, point.y, point.z, time, ++seed); + + point *= 2; + time *= 2; + amp *= 0.5f; + } + + //get rotor + PxVec3 rot; + rot.x = dFz.y - dFy.z; + rot.y = dFx.z - dFz.x; + rot.z = dFy.x - dFx.y; + + return params.strength * rot; +} + +APEX_CUDA_CALLABLE PX_INLINE PxVec3 executeForceFieldMainFS(const RadialForceFieldFSKernelParams& params, const PxVec3& pos, const uint32_t& totalElapsedMS) +{ + // bring pos to force field coordinate system + PxVec3 localPos = params.pose.inverseRT().transform(pos); + + if (isPosInShape(params.includeShape, localPos)) + { + PxVec3 result = localPos.getNormalized(); + result = result * params.strength; + + // apply falloff + result = result * params.falloffTable.lookupTableValue(localPos.magnitude() / params.radius); + + // apply noise + result = result + getNoise(params.noiseParams, localPos, totalElapsedMS); + + // rotate result back to world coordinate system + return params.pose.rotate(result); + } + + return PxVec3(0, 0, 0); +} + +// function to compute the Scalar falloff for the cylinderical, toroidal, cartesian and generic +// force fields so that the falloff does not make the direction of the force vector change. +APEX_CUDA_CALLABLE PX_INLINE float falloff(PxVec3 val, PxVec3 linearff, PxVec3 quadraticff) +{ + float magnitude = val.magnitude(); + float v = (linearff.x * magnitude + quadraticff.x * magnitude * magnitude) + + (linearff.y * magnitude + quadraticff.y * magnitude * magnitude) + + (linearff.z * magnitude + quadraticff.z * magnitude * magnitude); + v += 1.0f; + //PX_ASSERT(v>0); + return 1.0f/v; +} + +APEX_CUDA_CALLABLE PX_INLINE PxVec3 genericEvalLinearKernel(const PxVec3& localPos, const PxVec3& localVel, const GenericForceFieldFSKernelParams& params) +{ + const bool useFalloff = params.falloffLinear.magnitudeSquared() + + params.falloffQuadratic.magnitudeSquared() != 0; + + const bool useVelMul = !(params.velocityMultiplier.column0.isZero() && + params.velocityMultiplier.column1.isZero() && + params.velocityMultiplier.column2.isZero()); + + const bool usePosMul = !(params.positionMultiplier.column0.isZero() && + params.positionMultiplier.column1.isZero() && + params.positionMultiplier.column2.isZero()); + + + PxVec3 ffPosErr; + PxMat33 tangentFrame; + PxVec3 ffForce = params.constant; + switch(params.cs.type) + { + case ForceFieldCoordinateSystemType::CARTESIAN: + { + ffPosErr = params.positionTarget - (localPos); + } + break; + case ForceFieldCoordinateSystemType::SPHERICAL: + { + const float& r = localPos.x; + ffPosErr = PxVec3(params.positionTarget.x - r, 0, 0); + } + break; + case ForceFieldCoordinateSystemType::CYLINDRICAL: + { + const float& r = localPos.x; + ffPosErr = PxVec3(params.positionTarget.x - r, params.positionTarget.y - localPos.y, 0); + } + break; + case ForceFieldCoordinateSystemType::TOROIDAL: + { + float r = 0.0f; + PxVec3 t0; + PxVec3 circleDir(localPos.x, 0.0f, localPos.z); + float l2 = circleDir.magnitudeSquared(); + if(l2<1e-4f*1e-4f) + { + circleDir = PxVec3(0); + } + else + { + circleDir /= PxSqrt(l2); // Normalize circleDir + PxVec3 circlePoint = circleDir * params.cs.torusRadius; + t0 = localPos - circlePoint; + l2 = t0.magnitudeSquared(); + if(l2<1e-4f*1e-4f) + { + circleDir = PxVec3(0); + t0 = PxVec3(0); + } + else + { + r = PxSqrt(l2); + t0 /= r; // Normalize t0 + } + } + PxVec3 t1(-circleDir.z, 0.0f, circleDir.x); // PxVec3 t1 = circleDir.cross(PxVec3(0,1,0)); + tangentFrame.column0 = t0; + tangentFrame.column1 = t1; + tangentFrame.column2 = t0.cross(t1); + ffPosErr = PxVec3(params.positionTarget.x - r, 0, 0); + } + break; + } + + PxVec3 ffVel = (params.cs.type == ForceFieldCoordinateSystemType::TOROIDAL) ? tangentFrame.getInverse() * localVel : localVel; + + if(useVelMul) + { + ffForce += params.velocityMultiplier * (params.velocityTarget - ffVel); + } + + if(usePosMul) + { + ffForce += params.positionMultiplier * ffPosErr; + } + + //TODO, enable noise, with existing noise functionality + //applyNoise(ffForce, params.noise, NpPhysicsSDK::instance->getNpPhysicsTls()->mNpLinearKernelRnd); + //ffForce *= PxVec3(1) + params.noise * [-1, 1]^3 + + if(useFalloff) + { + ffForce *= falloff(ffPosErr, params.falloffLinear, params.falloffQuadratic); + } + + PxVec3 force = (params.cs.type == ForceFieldCoordinateSystemType::TOROIDAL) ? tangentFrame * ffForce : ffForce; + return force; +} + +APEX_CUDA_CALLABLE PX_INLINE void genericEvalCartesian(PxVec3& force, const PxVec3& localPos, const PxVec3& localVel, const GenericForceFieldFSKernelParams& params) +{ + // compute tangent frame + // -- none here + + // evaluate kernel + force = genericEvalLinearKernel(localPos, localVel, params); +} + +APEX_CUDA_CALLABLE PX_INLINE void genericEvalSpherical(PxVec3& force, const PxVec3& localPos, const PxVec3& localVel, const GenericForceFieldFSKernelParams& params) +{ + // compute tangent frame + PxMat33 tangentFrame(PxZero); + float l2 = localPos.magnitudeSquared(); + PxVec3 tangentPos; + if(l2>1e-4f*1e-4f) + { + float r = PxSqrt(l2); + PxVec3 t0 = localPos/r; + tangentFrame.column0 = t0; + tangentPos = PxVec3(r, 0, 0); + } + else + { + tangentPos = PxVec3(0); + } + + // compute tangent frame velocity + const PxVec3 tangentVel = tangentFrame.getInverse() * localVel; + + // evaluate kernel + force = genericEvalLinearKernel(tangentPos, tangentVel, params); + + // transform back to local space + force = tangentFrame * force; +} + +APEX_CUDA_CALLABLE PX_INLINE void genericEvalCylindrical(PxVec3& force, const PxVec3& localPos, const PxVec3& localVel, const GenericForceFieldFSKernelParams& params) +{ + // compute tangent frame + PxMat33 tangentFrame; + PxVec3 t0(localPos.x, 0, localPos.z); // Project to Cylindrical + const float len = t0.magnitude(); + PxVec3 tangentPos; + if(len > 1e-4f) + { + t0 /= len; + tangentPos = PxVec3(len, localPos.y, 0); + } + else + { + t0 = PxVec3(0); + tangentPos = PxVec3(0, localPos.y, 0); + } + tangentFrame.column0 = t0; + tangentFrame.column1 = PxVec3(0.0f, 1.0f, 0.0f); // t1 + tangentFrame.column2 = PxVec3(-t0.z, 0.0f, t0.x); // t0.cross(t1) + + // compute tangent frame velocity + const PxVec3 tangentVel = tangentFrame.getInverse() * localVel; + + // evaluate kernel + force = genericEvalLinearKernel(tangentPos, tangentVel, params); + + // transform back to local space + force = tangentFrame * force; +} + +APEX_CUDA_CALLABLE PX_INLINE void genericEvalToroidal(PxVec3& force, const PxVec3& localPos, const PxVec3& localVel, const GenericForceFieldFSKernelParams& params) +{ + // evaluate kernel + force = genericEvalLinearKernel(localPos, localVel, params); +} + +/** +This is more or less a 1:1 copy of PhysX 2.8.4/UE3 generic force fields. +Since 2.8.4 supported more flexible callbacks, we should probably optimize +this quite a bit. +*/ +APEX_CUDA_CALLABLE PX_INLINE PxVec3 executeForceFieldMainFS(const GenericForceFieldFSKernelParams& params, const PxVec3& pos, const PxVec3& vel, const uint32_t&) +{ + // bring pos to force field coordinate system + PxVec3 localPos = params.pose.inverseRT().transform(pos); + + if (isPosInShape(params.includeShape, localPos)) + { + PxVec3 localVel = params.pose.inverseRT().rotate(vel); + + PxVec3 result(0); + switch (params.cs.type) + { + case ForceFieldCoordinateSystemType::CARTESIAN: + genericEvalCartesian(result, localPos, localVel, params); + break; + case ForceFieldCoordinateSystemType::SPHERICAL: + genericEvalSpherical(result, localPos, localVel, params); + break; + case ForceFieldCoordinateSystemType::CYLINDRICAL: + genericEvalCylindrical(result, localPos, localVel, params); + break; + case ForceFieldCoordinateSystemType::TOROIDAL: + genericEvalToroidal(result, localPos, localVel, params); + break; + default: + break; + } + + // apply strength + result = result * params.strength; + + // rotate result back to world coordinate system + return params.pose.rotate(result); + } + + return PxVec3(0, 0, 0); +} + +APEX_CUDA_CALLABLE PX_INLINE PxVec3 executeForceFieldFS(const RadialForceFieldFSKernelParams& params, const PxVec3& pos, const uint32_t& totalElapsedMS) +{ + PxVec3 resultField(0, 0, 0); + resultField += executeForceFieldMainFS(params, pos, totalElapsedMS); + return resultField; +} + +APEX_CUDA_CALLABLE PX_INLINE PxVec3 executeForceFieldFS(const GenericForceFieldFSKernelParams& params, const PxVec3& pos, const PxVec3& vel, const uint32_t& totalElapsedMS) +{ + PxVec3 resultField(0, 0, 0); + resultField += executeForceFieldMainFS(params, pos, vel, totalElapsedMS); + return resultField; +} + +} +} // end namespace nvidia + +#endif |