Last active
January 4, 2016 02:08
-
-
Save andr3wmac/8552604 to your computer and use it in GitHub Desktop.
Torque3D 3.5 MIT - PhysX 3.3 Cloth
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//----------------------------------------------------------------------------- | |
// Copyright (c) 2014 Andrew MacIntyre | |
// | |
// Permission is hereby granted, free of charge, to any person obtaining a copy | |
// of this software and associated documentation files (the "Software"), to | |
// deal in the Software without restriction, including without limitation the | |
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | |
// sell copies of the Software, and to permit persons to whom the Software is | |
// furnished to do so, subject to the following conditions: | |
// | |
// The above copyright notice and this permission notice shall be included in | |
// all copies or substantial portions of the Software. | |
// | |
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | |
// IN THE SOFTWARE. | |
//----------------------------------------------------------------------------- | |
#include "platform/platform.h" | |
#include "T3D/physics/physx3/px3Cloth.h" | |
#include "T3D/physics/physx3/px3.h" | |
#include "T3D/physics/physx3/px3World.h" | |
#include "T3D/physics/physx3/px3Plugin.h" | |
#include "T3D/physics/physx3/px3Cast.h" | |
#include "T3D/physics/physx3/px3Stream.h" | |
#include "console/consoleTypes.h" | |
#include "scene/sceneManager.h" | |
#include "scene/sceneRenderState.h" | |
#include "renderInstance/renderPassManager.h" | |
#include "lighting/lightQuery.h" | |
#include "gfx/gfxDrawUtil.h" | |
#include "math/mathIO.h" | |
#include "core/stream/bitStream.h" | |
#include "materials/materialManager.h" | |
#include "materials/baseMatInstance.h" | |
#include "T3D/fx/particleEmitter.h" | |
IMPLEMENT_CO_NETOBJECT_V1( Px3Cloth ); | |
ConsoleDocClass( Px3Cloth, | |
"@brief Rectangular patch of cloth simulated by PhysX.\n\n" | |
"@ingroup Physics" | |
); | |
enum Px3ClothAttachment {}; | |
DefineBitfieldType( Px3ClothAttachment ); | |
ImplementBitfieldType( Px3ClothAttachment, | |
"Soon to be deprecated\n" | |
"@internal" ) | |
{ 0, "Bottom Right" }, | |
{ 1, "Bottom Left" }, | |
{ 2, "Top Right" }, | |
{ 3, "Top Left" }, | |
{ 4, "Top Center" }, | |
{ 5, "Bottom Center" }, | |
{ 6, "Right Center" }, | |
{ 7, "Left Center" }, | |
{ 8, "Top Edge" }, | |
{ 9, "Bottom Edge" }, | |
{ 10, "Right Edge" }, | |
{ 11, "Left Edge" } | |
EndImplementBitfieldType; | |
Px3Cloth::Px3Cloth() | |
: mWorld( NULL ), | |
mScene( NULL ), | |
mMatInst( NULL ) | |
{ | |
mVertexRenderBuffer = NULL; | |
mIndexRenderBuffer = NULL; | |
mClothMesh = NULL; | |
mCloth = NULL; | |
mVertices.clear(); | |
mPrimitives.clear(); | |
mPatchVerts.set( 8, 8 ); | |
mPatchSize.set( 8.0f, 8.0f ); | |
mNetFlags.set( Ghostable | ScopeAlways ); | |
mTypeMask |= StaticObjectType | StaticShapeObjectType; | |
mCollisionEnabled = false; | |
mWindEnabled = false; | |
mThickness = 0.1f; | |
mSolverFrequency = 120.0f; | |
mDampingCoef = 0.0f; | |
mStretchVertical = 1.0f; | |
mStretchHorizontal = 0.9f; | |
mStretchShearing = 0.75f; | |
mStretchBending = 0.5f; | |
mAttachmentMask = 0; | |
} | |
Px3Cloth::~Px3Cloth() | |
{ | |
} | |
bool Px3Cloth::onAdd() | |
{ | |
if ( !Parent::onAdd() ) | |
return false; | |
// Cloth is only created on the client. | |
if ( isClientObject() ) | |
{ | |
mWorld = dynamic_cast<Px3World*>( PHYSICSMGR->getWorld( "client" ) ); | |
if ( !mWorld || !mWorld->getScene() ) | |
{ | |
Con::errorf( "Px3Cloth::onAdd() - PhysXWorld not initialized... cloth disabled!" ); | |
return true; | |
} | |
mScene = mWorld->getScene(); | |
mResetXfm = getTransform(); | |
_createClothPatch(); | |
PhysicsPlugin::getPhysicsResetSignal().notify( this, &Px3Cloth::onPhysicsReset, 1053.0f ); | |
} | |
// On the server we use the static update | |
// to setup the bounds of the cloth. | |
if ( isServerObject() ) | |
_updateStaticCloth(); | |
addToScene(); | |
// Also the server object never ticks. | |
if ( isServerObject() ) | |
setProcessTick( false ); | |
return true; | |
} | |
void Px3Cloth::onRemove() | |
{ | |
SAFE_DELETE( mMatInst ); | |
if ( isClientObject() ) | |
{ | |
_releaseMesh(); | |
_releaseCloth(); | |
SAFE_DELETE(mVertexRenderBuffer); | |
SAFE_DELETE(mIndexRenderBuffer); | |
PhysicsPlugin::getPhysicsResetSignal().remove( this, &Px3Cloth::onPhysicsReset ); | |
} | |
removeFromScene(); | |
Parent::onRemove(); | |
} | |
void Px3Cloth::onPhysicsReset( PhysicsResetEvent reset ) | |
{ | |
// Store the reset transform for later use. | |
if ( reset == PhysicsResetEvent_Store ) | |
mResetXfm = getTransform(); | |
// Recreate the cloth at the last reset position. | |
_recreateCloth( mResetXfm ); | |
} | |
void Px3Cloth::initPersistFields() | |
{ | |
Parent::initPersistFields(); | |
addField( "material", TypeMaterialName, Offset( mMaterialName, Px3Cloth ), | |
"@brief Name of the material to render.\n\n" ); | |
addField( "size", TypePoint2F, Offset( mPatchSize, Px3Cloth ), | |
"@brief The width and height of the cloth.\n\n" ); | |
addField( "attachments", TYPEID< Px3ClothAttachment >(), Offset( mAttachmentMask, Px3Cloth ), | |
"@brief Optional way to specify cloth verts that will be attached to the world position " | |
"it is created at.\n\n" ); | |
addGroup( "Simulation" ); | |
addField( "frequency", TypeF32, Offset( mSolverFrequency, Px3Cloth ), | |
"@brief Iterations per second of cloth simulation.\n\n" ); | |
addField( "samples", TypePoint2I, Offset( mPatchVerts, Px3Cloth ), | |
"@brief The number of cloth vertices in width and length.\n\n" | |
"At least two verts should be defined.\n\n"); | |
endGroup( "Simulation" ); | |
addGroup( "Stretching" ); | |
addField( "damping_coef", TypeF32, Offset( mDampingCoef, Px3Cloth ), | |
"@brief Value between 0 and 1\n\n" ); | |
addField( "stretch_vertical", TypeF32, Offset( mStretchVertical, Px3Cloth ), | |
"@brief Value between 0 and 1\n\n" ); | |
addField( "stretch_horizontal", TypeF32, Offset( mStretchHorizontal, Px3Cloth ), | |
"@brief Value between 0 and 1\n\n" ); | |
addField( "stretch_shearing", TypeF32, Offset( mStretchShearing, Px3Cloth ), | |
"@brief Value between 0 and 1\n\n" ); | |
addField( "stretch_bending", TypeF32, Offset( mStretchBending, Px3Cloth ), | |
"@brief Value between 0 and 1\n\n" ); | |
endGroup( "Stretching" ); | |
addField( "Collision", TypeBool, Offset( mCollisionEnabled, Px3Cloth ), | |
"@brief Enables or disables collision with the rest of the world.\n\n" ); | |
addField( "Wind", TypeBool, Offset( mWindEnabled, Px3Cloth ), | |
"@brief Enables or disables wind driven by forest wind emitter.\n\n" ); | |
// Cloth doesn't support scale. | |
removeField( "scale" ); | |
} | |
void Px3Cloth::inspectPostApply() | |
{ | |
Parent::inspectPostApply(); | |
// Must have at least 2 verts. | |
mPatchVerts.x = getMax( 2, mPatchVerts.x ); | |
mPatchVerts.y = getMax( 2, mPatchVerts.y ); | |
if ( isServerObject() ) | |
_updateStaticCloth(); | |
setMaskBits( TransformMask | MaterialMask | ClothMask ); | |
} | |
U32 Px3Cloth::packUpdate( NetConnection *conn, U32 mask, BitStream *stream ) | |
{ | |
U32 retMask = Parent::packUpdate( conn, mask, stream ); | |
if ( stream->writeFlag( mask & TransformMask ) ) | |
mathWrite( *stream, getTransform() ); | |
if ( stream->writeFlag( mask & MaterialMask ) ) | |
stream->write( mMaterialName ); | |
if ( stream->writeFlag( mask & ClothMask ) ) | |
{ | |
mathWrite( *stream, mPatchVerts ); | |
mathWrite( *stream, mPatchSize ); | |
stream->write( mAttachmentMask ); | |
stream->writeFlag( mCollisionEnabled ); | |
stream->writeFlag( mWindEnabled ); | |
stream->write( mSolverFrequency ); | |
stream->write( mDampingCoef ); | |
stream->write( mStretchVertical ); | |
stream->write( mStretchHorizontal ); | |
stream->write( mStretchShearing ); | |
stream->write( mStretchBending ); | |
} | |
return retMask; | |
} | |
void Px3Cloth::unpackUpdate( NetConnection *conn, BitStream *stream ) | |
{ | |
Parent::unpackUpdate( conn, stream ); | |
// TransformMask | |
if ( stream->readFlag() ) | |
{ | |
MatrixF mat; | |
mathRead( *stream, &mat ); | |
setTransform( mat ); | |
} | |
// MaterialMask | |
if ( stream->readFlag() ) | |
{ | |
stream->read( &mMaterialName ); | |
SAFE_DELETE( mMatInst ); | |
} | |
// ClothMask | |
if ( stream->readFlag() ) | |
{ | |
Point2I patchVerts; | |
Point2F patchSize; | |
mathRead( *stream, &patchVerts ); | |
mathRead( *stream, &patchSize ); | |
if ( patchVerts != mPatchVerts || | |
!patchSize.equal( mPatchSize ) ) | |
{ | |
mPatchVerts = patchVerts; | |
mPatchSize = patchSize; | |
_releaseMesh(); | |
} | |
U32 attachMask; | |
stream->read( &attachMask ); | |
if ( attachMask != mAttachmentMask ) | |
{ | |
mAttachmentMask = attachMask; | |
_releaseCloth(); | |
} | |
mCollisionEnabled = stream->readFlag(); | |
mWindEnabled = stream->readFlag(); | |
stream->read( &mSolverFrequency ); | |
stream->read( &mDampingCoef ); | |
stream->read( &mStretchVertical ); | |
stream->read( &mStretchHorizontal ); | |
stream->read( &mStretchShearing ); | |
stream->read( &mStretchBending ); | |
if ( isClientObject() && | |
isProperlyAdded() && | |
mWorld && !mCloth ) | |
{ | |
_createClothPatch(); | |
} | |
_updateClothProperties(); | |
} | |
} | |
void Px3Cloth::_recreateCloth( const MatrixF &transform ) | |
{ | |
if ( !mWorld ) | |
{ | |
_updateStaticCloth(); | |
return; | |
} | |
mWorld->getPhysicsResults(); | |
Parent::setTransform( transform ); | |
_createClothPatch(); | |
} | |
void Px3Cloth::setTransform( const MatrixF &mat ) | |
{ | |
Parent::setTransform( mat ); | |
setMaskBits( TransformMask ); | |
// Only need to do this if we're on the server | |
// or if we're not currently ticking physics. | |
if ( !mWorld || !mWorld->isEnabled() ) | |
_updateStaticCloth(); | |
} | |
void Px3Cloth::setScale( const VectorF &scale ) | |
{ | |
// Cloth doesn't support scale as it has plenty | |
// of complications... sharing meshes, thickness, | |
// transform origin, etc. | |
return; | |
} | |
void Px3Cloth::prepRenderImage( SceneRenderState *state ) | |
{ | |
if ( mIsVBDirty ) | |
_updateVBIB(); | |
// Recreate the material if we need to. | |
if ( !mMatInst ) | |
_initMaterial(); | |
// If we don't have a material instance after the override then | |
// we can skip rendering all together. | |
BaseMatInstance *matInst = state->getOverrideMaterial( mMatInst ); | |
if ( !matInst ) | |
return; | |
MeshRenderInst *ri = state->getRenderPass()->allocInst<MeshRenderInst>(); | |
// If we need lights then set them up. | |
if ( matInst->isForwardLit() ) | |
{ | |
LightQuery query; | |
query.init( getWorldSphere() ); | |
query.getLights( ri->lights, 8 ); | |
} | |
ri->projection = state->getRenderPass()->allocSharedXform(RenderPassManager::Projection); | |
ri->objectToWorld = &MatrixF::Identity; | |
ri->worldToCamera = state->getRenderPass()->allocSharedXform(RenderPassManager::View); | |
ri->type = RenderPassManager::RIT_Mesh; | |
ri->primBuff = &mPrimBuffer; | |
ri->vertBuff = &mVB; | |
ri->matInst = matInst; | |
ri->prim = state->getRenderPass()->allocPrim(); | |
ri->prim->type = GFXTriangleList; | |
ri->prim->minIndex = 0; | |
ri->prim->startIndex = 0; | |
ri->prim->numPrimitives = mNumIndices / 3; | |
ri->prim->startVertex = 0; | |
ri->prim->numVertices = mNumVertices; | |
ri->defaultKey = matInst->getStateHint(); | |
ri->defaultKey2 = (U32)ri->vertBuff; | |
state->getRenderPass()->addInst( ri ); | |
} | |
void Px3Cloth::_releaseMesh() | |
{ | |
if ( !mClothMesh ) | |
return; | |
mClothMesh->release(); | |
} | |
void Px3Cloth::_releaseCloth() | |
{ | |
if ( !mCloth ) | |
return; | |
mScene->removeActor( *mCloth ); | |
mCloth->release(); | |
mCloth = NULL; | |
} | |
void Px3Cloth::_initBuffers() | |
{ | |
// Allocate Render Buffer for Vertices if it hasn't been done before+ | |
int maxVertices = mNumVertices * 3; | |
int maxIndicies = mNumIndices * 3; | |
mVertexRenderBuffer = new GFXVertexPNTT[maxVertices]; | |
mIndexRenderBuffer = new U16[maxIndicies]; | |
// Set up texture coords. | |
F32 dx = 1.0f / (F32)(mPatchVerts.x-1); | |
F32 dy = 1.0f / (F32)(mPatchVerts.y-1); | |
F32 *coord = (F32*)&mVertexRenderBuffer[0].texCoord; | |
for ( U32 i = 0; i < mPatchVerts.y; i++) | |
{ | |
for ( U32 j = 0; j < mPatchVerts.x; j++) | |
{ | |
coord[0] = j*dx; | |
coord[1] = i*-dy; | |
coord += sizeof( GFXVertexPNTT ) / sizeof( F32 ); | |
} | |
} | |
mMeshDirtyFlags = 0; | |
} | |
void Px3Cloth::_generateVertices() | |
{ | |
// Must have at least 2 verts. | |
mPatchVerts.x = getMax( 2, mPatchVerts.x ); | |
mPatchVerts.y = getMax( 2, mPatchVerts.y ); | |
// Generate a uniform cloth patch, | |
// w and h are the width and height, | |
// d is the distance between vertices. | |
mNumVertices = mPatchVerts.x * mPatchVerts.y; | |
mNumIndices = (mPatchVerts.x-1) * (mPatchVerts.y-1) * 2; | |
F32 patchWidth = mPatchSize.x / (F32)( mPatchVerts.x - 1 ); | |
F32 patchHeight = mPatchSize.y / (F32)( mPatchVerts.y - 1 ); | |
// Set up attachments | |
// Bottom right = bit 0 | |
// Bottom left = bit 1 | |
// Top right = bit 2 | |
// Top left = bit 3 | |
bool bRight = mAttachmentMask & BIT( 0 ); | |
bool bLeft = mAttachmentMask & BIT( 1 ); | |
bool tRight = mAttachmentMask & BIT( 2 ); | |
bool tLeft = mAttachmentMask & BIT( 3 ); | |
mVertices.clear(); | |
for (U32 i = 0; i < mPatchVerts.y; i++) | |
{ | |
for (U32 j = 0; j < mPatchVerts.x; j++) | |
{ | |
// Attachments handled with inverse weighting. | |
float weight = 0.8f; | |
if ( i == 0 && j == 0 && bLeft ) weight = 0.0f; | |
if ( i == 0 && j == (mPatchVerts.x - 1) && bRight ) weight = 0.0f; | |
if ( i == (mPatchVerts.y - 1) && j == 0 && tLeft ) weight = 0.0f; | |
if ( i == (mPatchVerts.y - 1) && j == (mPatchVerts.x - 1) && tRight ) weight = 0.0f; | |
mVertices.push_back(physx::PxClothParticle(physx::PxVec3(patchWidth * j, 0.0f, patchHeight * i), weight)); | |
} | |
} | |
int width = mPatchVerts.x; | |
int height = mPatchVerts.y; | |
// Generate list of primitives | |
mNumPrimitives = 0; | |
mPrimitives.clear(); | |
for (U32 y = 0; y < height - 1; y++) | |
{ | |
for (U32 x = 0; x < width - 1; x++) | |
{ | |
U32 x1 = x + (y * width); | |
mPrimitives.push_back(x1); | |
mPrimitives.push_back(x1 + 1); | |
U32 y1 = x1 + width; | |
mPrimitives.push_back(y1); | |
mPrimitives.push_back(y1 + 1); | |
mNumPrimitives++; | |
} | |
} | |
_initBuffers(); | |
} | |
bool Px3Cloth::_createClothPatch() | |
{ | |
// Make sure we can change the world. | |
mWorld->releaseWriteLock(); | |
// Generate Vert/Prim data. | |
_generateVertices(); | |
// Create Cloth Mesh Description. | |
physx::PxClothMeshDesc meshDesc; | |
meshDesc.points.data = &mVertices[0]; | |
meshDesc.points.count = mNumVertices; | |
meshDesc.points.stride = sizeof(physx::PxClothParticle); | |
meshDesc.invMasses.data = &mVertices[0].invWeight; | |
meshDesc.invMasses.count = mNumVertices; | |
meshDesc.invMasses.stride = sizeof(physx::PxClothParticle); | |
meshDesc.quads.data = &mPrimitives[0]; | |
meshDesc.quads.count = mNumPrimitives; | |
meshDesc.quads.stride = sizeof(physx::PxU32) * 4; | |
physx::PxClothFabric* clothFabric = physx::PxClothFabricCreate(*gPhysics3SDK, meshDesc, physx::PxVec3(0, 0, 0)); | |
// Apply transform | |
physx::PxTransform out; | |
QuatF q; | |
q.set(getTransform()); | |
out.q = px3Cast<physx::PxQuat>(q); | |
out.p = px3Cast<physx::PxVec3>(getTransform().getPosition()); | |
// Delete old cloth, create new cloth. | |
_releaseCloth(); | |
physx::PxCloth* cloth = gPhysics3SDK->createCloth(out, *clothFabric, &mVertices[0], physx::PxClothFlags()); | |
if ( cloth ) | |
{ | |
mScene->addActor(*cloth); | |
mCloth = cloth; | |
_updateClothProperties(); | |
mIsVBDirty = true; | |
} | |
_updateStaticCloth(); | |
return true; | |
} | |
void Px3Cloth::_updateClothProperties() | |
{ | |
if ( !mCloth ) | |
return; | |
mCloth->setClothFlag(physx::PxClothFlag::eSCENE_COLLISION, mCollisionEnabled); | |
mCloth->setSolverFrequency(mSolverFrequency); | |
mCloth->setDampingCoefficient(physx::PxVec3(mDampingCoef)); | |
// Stretch Config | |
mCloth->setStretchConfig(physx::PxClothFabricPhaseType::eVERTICAL, physx::PxClothStretchConfig(mStretchVertical)); //1.0f | |
mCloth->setStretchConfig(physx::PxClothFabricPhaseType::eHORIZONTAL, physx::PxClothStretchConfig(mStretchHorizontal)); //0.9f | |
mCloth->setStretchConfig(physx::PxClothFabricPhaseType::eSHEARING, physx::PxClothStretchConfig(mStretchShearing)); // 0.75f | |
mCloth->setStretchConfig(physx::PxClothFabricPhaseType::eBENDING, physx::PxClothStretchConfig(mStretchBending)); // 0.5f | |
} | |
void Px3Cloth::_initMaterial() | |
{ | |
SAFE_DELETE( mMatInst ); | |
Material *material = NULL; | |
if (mMaterialName.isNotEmpty() ) | |
Sim::findObject( mMaterialName, material ); | |
if ( material ) | |
mMatInst = material->createMatInstance(); | |
else | |
mMatInst = MATMGR->createMatInstance( "WarningMaterial" ); | |
GFXStateBlockDesc desc; | |
desc.setCullMode( GFXCullNone ); | |
mMatInst->addStateBlockDesc( desc ); | |
mMatInst->init( MATMGR->getDefaultFeatures(), getGFXVertexFormat<GFXVertexPNTT>() ); | |
} | |
void Px3Cloth::_updateVBIB() | |
{ | |
if ( !mCloth ) | |
return; | |
PROFILE_SCOPE( Px3Cloth_UpdateVBIB ); | |
mIsVBDirty = false; | |
// Don't set the VB if the vertex count is the same! | |
if ( mVB.isNull() || mVB->mNumVerts < mNumVertices ) | |
mVB.set( GFX, mNumVertices, GFXBufferTypeDynamic ); | |
GFXVertexPNTT *vpPtr = mVB.lock(); | |
dMemcpy( vpPtr, mVertexRenderBuffer, sizeof( GFXVertexPNTT ) * mNumVertices ); | |
mVB.unlock(); | |
if ( mPrimBuffer.isNull() || mPrimBuffer->mIndexCount < mNumIndices ) | |
mPrimBuffer.set( GFX, mNumIndices, 0, GFXBufferTypeDynamic ); | |
U16 *pbPtr; | |
mPrimBuffer.lock( &pbPtr ); | |
dMemcpy( pbPtr, mIndexRenderBuffer, sizeof( U16 ) * mNumIndices ); | |
mPrimBuffer.unlock(); | |
} | |
void Px3Cloth::_updateStaticCloth() | |
{ | |
// Setup the unsimulated world bounds. | |
mObjBox.set( 0, mThickness * -0.5f, 0, | |
mPatchSize.x, mThickness * 0.5f, mPatchSize.y ); | |
resetWorldBox(); | |
// If we don't have render buffers then we're done. | |
if ( !mVertexRenderBuffer || !mIndexRenderBuffer ) | |
return; | |
// Make sure the VBs are updated. | |
mIsVBDirty = true; | |
F32 patchWidth = mPatchSize.x / (F32)(mPatchVerts.x-1); | |
F32 patchHeight = mPatchSize.y / (F32)(mPatchVerts.y-1); | |
Point3F normal( 0, 1, 0 ); | |
getTransform().mulV( normal ); | |
GFXVertexPNTT *vert = mVertexRenderBuffer; | |
for (U32 y = 0; y < mPatchVerts.y; y++) | |
{ | |
for (U32 x = 0; x < mPatchVerts.x; x++) | |
{ | |
vert->point.set( patchWidth * x, 0.0f, patchHeight * y ); | |
getTransform().mulP( vert->point ); | |
vert->normal = normal; | |
vert++; | |
} | |
} | |
U16 *index = mIndexRenderBuffer; | |
mNumIndices = (mPatchVerts.x-1) * (mPatchVerts.y-1) * 6; | |
U16 yOffset = mPatchVerts.x; | |
for (U32 y = 0; y < mPatchVerts.y-1; y++) | |
{ | |
for (U32 x = 0; x < mPatchVerts.x-1; x++) | |
{ | |
U16 base = x + ( yOffset * y ); | |
index[0] = base; | |
index[1] = base + 1; | |
index[2] = base + 1 + yOffset; | |
index[3] = base + 1 + yOffset; | |
index[4] = base + yOffset; | |
index[5] = base; | |
index += 6; | |
} | |
} | |
} | |
void Px3Cloth::processTick( const Move *move ) | |
{ | |
// Make sure the cloth is created. | |
if ( !mCloth ) | |
return; | |
// Update bounds. | |
if ( mWorld->isEnabled() ) | |
{ | |
Point3F vel = ParticleEmitter::mWindVelocity; | |
physx::PxVec3 windVec( vel.x, vel.y, vel.z ); | |
mCloth->setExternalAcceleration(windVec); | |
// Update particle positions. | |
physx::PxClothParticleData* pData = mCloth->lockParticleData(physx::PxDataAccessFlag::eREADABLE); | |
if ( pData != NULL ) | |
{ | |
for(int i = 0; i < mNumVertices; i++) | |
{ | |
physx::PxClothParticle* particle = &pData->particles[i]; | |
mVertexRenderBuffer[i].point.set(particle->pos.x, particle->pos.y, particle->pos.z); | |
getTransform().mulP( mVertexRenderBuffer[i].point ); | |
} | |
pData->unlock(); | |
} | |
// Update Bounding Box : Currently Broken. | |
physx::PxBounds3 box; | |
box = mCloth->getWorldBounds(); | |
Point3F min = px3Cast<Point3F>( box.minimum ); | |
Point3F max = px3Cast<Point3F>( box.minimum ); | |
mWorldBox.set( min, max ); | |
mObjBox = mWorldBox; | |
getWorldTransform().mul( mObjBox ); | |
} | |
else | |
{ | |
mObjBox.set( 0, mThickness * -0.5f, 0, | |
mPatchSize.x, mThickness * 0.5f, mPatchSize.y ); | |
} | |
resetWorldBox(); | |
// Update the VB on the next render. | |
mIsVBDirty = true; | |
} | |
void Px3Cloth::interpolateTick( F32 delta ) | |
{ | |
// Nothing to do for now! | |
} | |
bool Px3Cloth::onNewDataBlock( GameBaseData *dptr, bool reload ) | |
{ | |
return false; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//----------------------------------------------------------------------------- | |
// Copyright (c) 2014 Andrew MacIntyre | |
// | |
// Permission is hereby granted, free of charge, to any person obtaining a copy | |
// of this software and associated documentation files (the "Software"), to | |
// deal in the Software without restriction, including without limitation the | |
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | |
// sell copies of the Software, and to permit persons to whom the Software is | |
// furnished to do so, subject to the following conditions: | |
// | |
// The above copyright notice and this permission notice shall be included in | |
// all copies or substantial portions of the Software. | |
// | |
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | |
// IN THE SOFTWARE. | |
//----------------------------------------------------------------------------- | |
#ifndef _Px3Cloth_H | |
#define _Px3Cloth_H | |
#ifndef _PHYSX3_H_ | |
#include "T3D/physics/physx3/px3.h" | |
#endif | |
#ifndef _T3D_PHYSICSCOMMON_H_ | |
#include "T3D/physics/physicsCommon.h" | |
#endif | |
#ifndef _GAMEBASE_H_ | |
#include "T3D/gameBase/gameBase.h" | |
#endif | |
#ifndef _GFXPRIMITIVEBUFFER_H_ | |
#include "gfx/gfxPrimitiveBuffer.h" | |
#endif | |
#ifndef _GFXVERTEXBUFFER_H_ | |
#include "gfx/gfxVertexBuffer.h" | |
#endif | |
class Material; | |
class BaseMatInstance; | |
class Px3World; | |
class Px3Cloth : public GameBase | |
{ | |
typedef GameBase Parent; | |
enum MaskBits | |
{ | |
TransformMask = Parent::NextFreeMask << 0, | |
ClothMask = Parent::NextFreeMask << 1, | |
MaterialMask = Parent::NextFreeMask << 3, | |
NextFreeMask = Parent::NextFreeMask << 4 | |
}; | |
public: | |
Px3Cloth(); | |
virtual ~Px3Cloth(); | |
DECLARE_CONOBJECT( Px3Cloth ); | |
static Point3F mWindVelocity; | |
static void setWindVelocity( const Point3F &vel ){ mWindVelocity = vel; } | |
// SimObject | |
virtual bool onAdd(); | |
virtual void onRemove(); | |
static void initPersistFields(); | |
virtual void inspectPostApply(); | |
void onPhysicsReset( PhysicsResetEvent reset ); | |
// NetObject | |
virtual U32 packUpdate( NetConnection *conn, U32 mask, BitStream *stream ); | |
virtual void unpackUpdate( NetConnection *conn, BitStream *stream ); | |
// SceneObject | |
virtual void setTransform( const MatrixF &mat ); | |
virtual void setScale( const VectorF &scale ); | |
virtual void prepRenderImage( SceneRenderState *state ); | |
// GameBase | |
virtual bool onNewDataBlock( GameBaseData *dptr, bool reload ); | |
virtual void processTick( const Move *move ); | |
virtual void interpolateTick( F32 delta ); | |
protected: | |
Px3World *mWorld; | |
physx::PxScene *mScene; | |
physx::PxClothFabric *mClothMesh; | |
physx::PxCloth *mCloth; | |
bool mCollisionEnabled; | |
bool mWindEnabled; | |
F32 mThickness; | |
F32 mSolverFrequency; | |
F32 mDampingCoef; | |
F32 mStretchVertical; //1.0f | |
F32 mStretchHorizontal; //0.9f | |
F32 mStretchShearing; // 0.75f | |
F32 mStretchBending; // 0.5f | |
U32 mAttachmentMask; | |
static EnumTable mAttachmentFlagTable; | |
String mMaterialName; | |
SimObjectPtr<Material> mMaterial; | |
BaseMatInstance *mMatInst; | |
String lookupName; | |
/// | |
GFXVertexPNTT *mVertexRenderBuffer; | |
U16 *mIndexRenderBuffer; | |
U32 mNumIndices; | |
U32 mNumVertices; | |
U32 mNumPrimitives; | |
Vector<physx::PxClothParticle> mVertices; | |
Vector<physx::PxU32> mPrimitives; | |
U32 mMeshDirtyFlags; | |
bool mIsVBDirty; | |
GFXPrimitiveBufferHandle mPrimBuffer; | |
GFXVertexBufferHandle<GFXVertexPNTT> mVB; | |
Point2I mPatchVerts; | |
Point2F mPatchSize; | |
MatrixF mResetXfm; | |
void _initMaterial(); | |
void _releaseMesh(); | |
void _releaseCloth(); | |
void _initBuffers(); | |
void _generateVertices(); | |
bool _createClothPatch(); | |
void _recreateCloth( const MatrixF &transform ); | |
void _updateClothProperties(); | |
void _updateStaticCloth(); | |
void _updateVBIB(); | |
}; | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment