aboutsummaryrefslogtreecommitdiff
path: root/APEX_1.4/module/emitter/src/EmitterGeomSphereShellImpl.cpp
diff options
context:
space:
mode:
authorgit perforce import user <a@b>2016-10-25 12:29:14 -0600
committerSheikh Dawood Abdul Ajees <Sheikh Dawood Abdul Ajees>2016-10-25 18:56:37 -0500
commit3dfe2108cfab31ba3ee5527e217d0d8e99a51162 (patch)
treefa6485c169e50d7415a651bf838f5bcd0fd3bfbd /APEX_1.4/module/emitter/src/EmitterGeomSphereShellImpl.cpp
downloadphysx-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/emitter/src/EmitterGeomSphereShellImpl.cpp')
-rw-r--r--APEX_1.4/module/emitter/src/EmitterGeomSphereShellImpl.cpp344
1 files changed, 344 insertions, 0 deletions
diff --git a/APEX_1.4/module/emitter/src/EmitterGeomSphereShellImpl.cpp b/APEX_1.4/module/emitter/src/EmitterGeomSphereShellImpl.cpp
new file mode 100644
index 00000000..6c03060d
--- /dev/null
+++ b/APEX_1.4/module/emitter/src/EmitterGeomSphereShellImpl.cpp
@@ -0,0 +1,344 @@
+/*
+ * 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 "ApexUsingNamespace.h"
+#include "EmitterGeomSphereShellImpl.h"
+//#include "ApexSharedSerialization.h"
+#include "RenderDebugInterface.h"
+#include "RenderDebugInterface.h"
+#include "ApexPreview.h"
+#include "EmitterGeomSphereShellParams.h"
+
+namespace nvidia
+{
+namespace emitter
+{
+
+
+
+EmitterGeomSphereShellImpl::EmitterGeomSphereShellImpl(NvParameterized::Interface* params)
+{
+ NvParameterized::Handle eh(*params);
+ const NvParameterized::Definition* paramDef;
+ const char* enumStr = 0;
+
+ mGeomParams = (EmitterGeomSphereShellParams*)params;
+ mRadius = &(mGeomParams->parameters().radius);
+ mShellThickness = &(mGeomParams->parameters().shellThickness);
+ mHemisphere = &(mGeomParams->parameters().hemisphere);
+
+ //error check
+ mGeomParams->getParameterHandle("emitterType", eh);
+ mGeomParams->getParamEnum(eh, enumStr);
+ paramDef = eh.parameterDefinition();
+
+ mType = EmitterType::ET_RATE;
+ for (int i = 0; i < paramDef->numEnumVals(); ++i)
+ {
+ if (!nvidia::strcmp(paramDef->enumVal(i), enumStr))
+ {
+ mType = (EmitterType::Enum)i;
+ break;
+ }
+ }
+}
+
+EmitterGeom* EmitterGeomSphereShellImpl::getEmitterGeom()
+{
+ return this;
+}
+
+
+#ifdef WITHOUT_DEBUG_VISUALIZE
+void EmitterGeomSphereShellImpl::visualize(const PxTransform& , RenderDebugInterface&)
+{
+}
+#else
+void EmitterGeomSphereShellImpl::visualize(const PxTransform& pose, RenderDebugInterface& renderDebug)
+{
+ using RENDER_DEBUG::DebugColors;
+ RENDER_DEBUG_IFACE(&renderDebug)->pushRenderState();
+
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::DarkGreen));
+
+ // outer sphere
+ RENDER_DEBUG_IFACE(&renderDebug)->setPose(pose);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugSphere(PxVec3(0.0f), *mRadius);
+
+ // intter sphere
+ RENDER_DEBUG_IFACE(&renderDebug)->debugSphere(PxVec3(0.0f), *mRadius + *mShellThickness);
+
+ const float radius = *mRadius + *mShellThickness;
+ const float radiusSquared = radius * radius;
+ const float hemisphere = *mHemisphere;
+ const float sphereCapBaseHeight = -radius + 2 * radius * hemisphere;
+ const float sphereCapBaseRadius = PxSqrt(radiusSquared - sphereCapBaseHeight * sphereCapBaseHeight);
+ // cone depicting the hemisphere
+ if(hemisphere > 0.0f)
+ {
+ RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::DarkPurple));
+ PxMat44 circlePose = PxMat44(PxIdentity);
+ circlePose.setPosition(PxVec3(0.0f, sphereCapBaseHeight, 0.0f));
+ RENDER_DEBUG_IFACE(&renderDebug)->setPose(circlePose);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugCircle(PxVec3(0.0f), sphereCapBaseRadius, 3);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(circlePose.getPosition(), circlePose.getPosition() + PxVec3(0.0f, radius - sphereCapBaseHeight, 0.0f));
+ for(float t = 0.0f; t < 2 * PxPi; t += PxPi / 3)
+ {
+ PxVec3 offset(PxSin(t) * sphereCapBaseRadius, 0.0f, PxCos(t) * sphereCapBaseRadius);
+ RENDER_DEBUG_IFACE(&renderDebug)->debugLine(circlePose.getPosition() + offset, circlePose.getPosition() + PxVec3(0.0f, radius - sphereCapBaseHeight, 0.0f));
+ }
+ RENDER_DEBUG_IFACE(&renderDebug)->setPose(PxIdentity);
+ }
+
+ RENDER_DEBUG_IFACE(&renderDebug)->popRenderState();
+}
+#endif
+
+
+#ifdef WITHOUT_DEBUG_VISUALIZE
+void EmitterGeomSphereShellImpl::drawPreview(float , RenderDebugInterface*) const
+{
+}
+#else
+void EmitterGeomSphereShellImpl::drawPreview(float scale, RenderDebugInterface* renderDebug) const
+{
+ using RENDER_DEBUG::DebugColors;
+
+ RENDER_DEBUG_IFACE(renderDebug)->pushRenderState();
+ RENDER_DEBUG_IFACE(renderDebug)->setCurrentColor(RENDER_DEBUG_IFACE(renderDebug)->getDebugColor(DebugColors::Yellow),
+ RENDER_DEBUG_IFACE(renderDebug)->getDebugColor(DebugColors::Yellow));
+
+ RENDER_DEBUG_IFACE(renderDebug)->debugSphere(PxVec3(0.0f), *mRadius * scale);
+
+ RENDER_DEBUG_IFACE(renderDebug)->setCurrentColor(RENDER_DEBUG_IFACE(renderDebug)->getDebugColor(DebugColors::DarkGreen),
+ RENDER_DEBUG_IFACE(renderDebug)->getDebugColor(DebugColors::DarkGreen));
+
+ RENDER_DEBUG_IFACE(renderDebug)->debugSphere(PxVec3(0.0f), (*mRadius + *mShellThickness) * scale);
+
+ const float radius = *mRadius + *mShellThickness;
+ const float radiusSquared = radius * radius;
+ const float hemisphere = *mHemisphere;
+ const float sphereCapBaseHeight = -radius + 2 * radius * hemisphere;
+ const float sphereCapBaseRadius = PxSqrt(radiusSquared - sphereCapBaseHeight * sphereCapBaseHeight);
+ if(hemisphere > 0.0f)
+ {
+ RENDER_DEBUG_IFACE(renderDebug)->setCurrentColor(RENDER_DEBUG_IFACE(renderDebug)->getDebugColor(DebugColors::DarkPurple));
+ PxMat44 circlePose = PxMat44(PxIdentity);
+ circlePose.setPosition(PxVec3(0.0f, sphereCapBaseHeight, 0.0f));
+ RENDER_DEBUG_IFACE(renderDebug)->setPose(circlePose);
+ RENDER_DEBUG_IFACE(renderDebug)->debugCircle(PxVec3(0.0f), sphereCapBaseRadius, 3);
+ RENDER_DEBUG_IFACE(renderDebug)->debugLine(PxVec3(0.0f), PxVec3(0.0f, radius - sphereCapBaseHeight, 0.0f));
+ for(float t = 0.0f; t < 2 * PxPi; t += PxPi / 3)
+ {
+ PxVec3 offset(PxSin(t) * sphereCapBaseRadius, 0.0f, PxCos(t) * sphereCapBaseRadius);
+ RENDER_DEBUG_IFACE(renderDebug)->debugLine(offset, PxVec3(0.0f, radius - sphereCapBaseHeight, 0.0f));
+ }
+ RENDER_DEBUG_IFACE(renderDebug)->setPose(PxIdentity);
+ }
+ RENDER_DEBUG_IFACE(renderDebug)->popRenderState();
+}
+#endif
+
+void EmitterGeomSphereShellImpl::setEmitterType(EmitterType::Enum t)
+{
+ mType = t;
+
+ NvParameterized::Handle eh(*mGeomParams);
+ const NvParameterized::Definition* paramDef;
+
+ //error check
+ mGeomParams->getParameterHandle("emitterType", eh);
+ paramDef = eh.parameterDefinition();
+
+ mGeomParams->setParamEnum(eh, paramDef->enumVal((int)mType));
+}
+
+float EmitterGeomSphereShellImpl::computeEmitterVolume() const
+{
+ const float radius = *mRadius;
+ const float bigRadius = *mRadius + *mShellThickness;
+ float hemisphere = 2 * radius * (*mHemisphere);
+ float bigHemisphere = 2 * bigRadius * (*mHemisphere);
+
+ bool moreThanHalf = true;
+
+ if (hemisphere > radius)
+ {
+ hemisphere -= radius;
+ bigHemisphere -= bigRadius;
+ moreThanHalf = false;
+ }
+
+ const float volumeBigSphere = 4.0f / 3.0f * PxPi * bigRadius * bigRadius * bigRadius;
+ const float volumeSmallSphere = 4.0f / 3.0f * PxPi * *mRadius * *mRadius * *mRadius;
+ const float halfSphereShellVolume = (volumeBigSphere - volumeSmallSphere) / 2.0f;
+
+ const float bigCapVolume = 1.0f / 3.0f * PxPi * bigHemisphere * bigHemisphere * (3 * bigRadius - bigHemisphere);
+ const float smallCapVolume = 1.0f / 3.0f * PxPi * hemisphere * hemisphere * (3 * radius - hemisphere);
+
+ const float sphereShellCapVolume = bigCapVolume - smallCapVolume;
+
+ if (moreThanHalf)
+ {
+ return halfSphereShellVolume + sphereShellCapVolume;
+ }
+ else
+ {
+ return sphereShellCapVolume;
+ }
+}
+
+
+PxVec3 EmitterGeomSphereShellImpl::randomPosInFullVolume(const PxMat44& pose, QDSRand& rand) const
+{
+ float hemisphere = 2.0f * *mHemisphere - 1.0f;
+
+ bool moreThanHalf = true;
+
+ if (*mHemisphere > 0.5f)
+ {
+ moreThanHalf = false;
+ }
+
+ // There are two cases here - 1-st for hemisphere cut above the center of the sphere
+ // and 2-nd for hemisphere cut below the center of the sphere.
+ // The reason for this is that in case very high hemisphere cut is set, so the area
+ // of the actual emitter is very small in compare to the whole sphere emitter, it would take too
+ // much time [on average] to generate suitable point using randomPointOnUnitSphere
+ // function, so in this case it is more efficient to use another method.
+ // in case we have at least half of the sphere shell present the randomPointOnUnitSphere should
+ // be sufficient.
+ PxVec3 pos;
+ if(!moreThanHalf)
+ {
+ // 1-st case :
+ // * generate random unit vector within a cone
+ // * clamp to big radius
+ const float sphereCapBaseHeight = -1.0f + 2 * (*mHemisphere);
+ const float phi = rand.getScaled(0.0f, PxTwoPi);
+ const float cos_theta = sphereCapBaseHeight;
+ const float z = rand.getScaled(cos_theta, 1.0f);
+ const float oneMinusZSquared = PxSqrt(1.0f - z * z);
+ pos = PxVec3(oneMinusZSquared * PxCos(phi), z, oneMinusZSquared * PxSin(phi));
+ }
+ else
+ {
+ // 2-nd case :
+ // * get random pos on unit sphere, until its height is above hemisphere cut
+ do
+ {
+ pos = randomPointOnUnitSphere(rand);
+ } while(pos.y < hemisphere);
+ }
+
+ // * add negative offset withing the thickness
+ // * solve edge case [for the 1-st case] - regenerate offset from the previous step
+ // in case point is below hemisphere cut
+
+ PxVec3 tmp;
+ const float sphereCapBaseHeight = -(*mRadius + *mShellThickness) + 2 * (*mRadius + *mShellThickness) * (*mHemisphere);
+ do
+ {
+ float thickness = rand.getScaled(0, *mShellThickness);
+ tmp = pos * (*mRadius + *mShellThickness - thickness);
+ } while(tmp.y < sphereCapBaseHeight);
+
+ pos = tmp;
+ pos += pose.getPosition();
+
+ return pos;
+}
+
+
+bool EmitterGeomSphereShellImpl::isInEmitter(const PxVec3& pos, const PxMat44& pose) const
+{
+ PxVec3 localPos = pose.inverseRT().transform(pos);
+ const float sphereCapBaseHeight = -(*mRadius + *mShellThickness) + 2 * (*mRadius + *mShellThickness) * (*mHemisphere);
+ float d2 = localPos.x * localPos.x + localPos.y * localPos.y + localPos.z * localPos.z;
+ bool isInBigSphere = d2 < (*mRadius + *mShellThickness) * (*mRadius + *mShellThickness);
+ bool isInSmallSphere = d2 < *mRadius * *mRadius;
+ bool higherThanHemisphereCut = pos.y > sphereCapBaseHeight;
+ return isInBigSphere && !isInSmallSphere && higherThanHemisphereCut;
+}
+
+
+void EmitterGeomSphereShellImpl::computeFillPositions(physx::Array<PxVec3>& positions,
+ physx::Array<PxVec3>& velocities,
+ const PxTransform& pose,
+ const PxVec3& scale,
+ float objRadius,
+ PxBounds3& outBounds,
+ QDSRand&) const
+{
+ PX_UNUSED(scale);
+
+ const float bigRadius = *mRadius + *mShellThickness;
+ const float radiusSquared = bigRadius * bigRadius;
+ const float hemisphere = *mHemisphere;
+ const float sphereCapBaseHeight = -bigRadius + 2 * bigRadius * hemisphere;
+ const float sphereCapBaseRadius = PxSqrt(radiusSquared - sphereCapBaseHeight * sphereCapBaseHeight);
+ const float horizontalExtents = hemisphere < 0.5f ? bigRadius : sphereCapBaseRadius;
+
+ // we're not doing anything with the velocities array
+ PX_UNUSED(velocities);
+
+ // we don't want anything outside the emitter
+ uint32_t numX = (uint32_t)PxFloor(horizontalExtents / objRadius);
+ numX -= numX % 2;
+ uint32_t numY = (uint32_t)PxFloor((bigRadius - sphereCapBaseHeight) / objRadius);
+ numY -= numY % 2;
+ uint32_t numZ = (uint32_t)PxFloor(horizontalExtents / objRadius);
+ numZ -= numZ % 2;
+
+ for (float x = -(numX * objRadius); x <= bigRadius - objRadius; x += 2 * objRadius)
+ {
+ for (float y = -(numY * objRadius); y <= bigRadius - objRadius; y += 2 * objRadius)
+ {
+ for (float z = -(numZ * objRadius); z <= bigRadius - objRadius; z += 2 * objRadius)
+ {
+ const float magnitudeSquare = PxVec3(x, y, z).magnitudeSquared();
+ if ((magnitudeSquare > (*mRadius + objRadius) * (*mRadius + objRadius)) &&
+ (magnitudeSquare < (bigRadius - objRadius) * (bigRadius - objRadius)))
+ {
+ positions.pushBack(pose.transform(PxVec3(x, y, z)));
+ outBounds.include(positions.back());
+ }
+ }
+ }
+ }
+}
+
+
+PxVec3 EmitterGeomSphereShellImpl::randomPointOnUnitSphere(QDSRand& rand) const
+{
+ // uniform distribution on the sphere around pos (Cook, Marsaglia Method. TODO: is other method cheaper?)
+ float x0, x1, x2, x3, div;
+ do
+ {
+ x0 = rand.getNext();
+ x1 = rand.getNext();
+ x2 = rand.getNext();
+ x3 = rand.getNext();
+ div = x0 * x0 + x1 * x1 + x2 * x2 + x3 * x3;
+ }
+ while (div >= 1.0f);
+
+ // coordinates on unit sphere
+ float x = 2 * (x1 * x3 + x0 * x2) / div;
+ float y = 2 * (x2 * x3 - x0 * x1) / div;
+ float z = (x0 * x0 + x3 * x3 - x1 * x1 - x2 * x2) / div;
+
+ return PxVec3(x, y, z);
+}
+
+}
+} // namespace nvidia::apex