bug + solution in cube create with ccd + fun cloth code

mkh42

13-11-2006 10:32:37

hello

sorry that my first post is a bug report.

i'm currently porting a little demo i wrote from ogrenewt to nxogre because i want to have cloth in the demo. the cloth is already running in a prototype. the other thing i need is ccd because a fast ball is used to 'manipulate' the envirement. there i discoved a little big in the cube create routine witg ccd set to true. the skeleton mesh you create must be SMALLER as the shape so the scaling factor has to be <= 0.5f and not 2.0f line in 0.4RC2 in the two line where you call createCDDSkeleton. I set it to 0.4f like below and it works fine for me

here the two changes i made:
createCDDSkeleton(NxTools::convert(Ogre::Vector3(_size,_size,_size) * 0.4f));
createCDDSkeleton(NxTools::convert(_size * 0.4f));

greetings
martin


ps: i just played with the value 0.4f. for me smaller values like 0.1f works even better. i will also try it with a single point as mesh which should be possible following the physx documentation.

betajaen

13-11-2006 11:42:01

Thankyou. I wondered why CCD wasn't working as it was in the PhysX Tutorials.

Also, I would be very interested in how you implemented cloth, and chance for a patch ;)

mkh42

13-11-2006 15:38:48

hello betajaen,

ok i file a little demo with the code here. It is a VERY rough implementation and normally really no code i would make public at all but finally i thought it makes to much fun to see a cloth falling on a nxOgre cube with full collision detection and that all rendered in Ogre. :lol:

Also the code ist very rought and there is no tight integration to nxogre it shows the 'how to does' like dynamic vertex changing in ogre and the binding to physx ( that as the primary goal of me for that stuff) . it is a rought mix of the physx tutorial code + a code i found on the ogre forum about a flag rendered in ogre but without collision detection.

Next steps i will take is that i implement tear lines so that cloth can be teared. After taht i will clean the code and if you are not much faster then myself try a integration to nxogre.

ok the next for post will keep the code.

greetings
Martin

mkh42

13-11-2006 15:42:36

save the following code as mycloth.cpp to the NxTutorials code folder
/*----------------------------------------------------------------------------*\
|
| AGEIA PhysX Technology
|
| www.ageia.com
|
\*----------------------------------------------------------------------------*/

//Test Cloth Implementation

/*
#if defined WIN32
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX //suppress windows' global min,max macros.
#include <windows.h> //needed for gl.h
#endif
*/
//#include <GL/glut.h>

//#include "nxOgre.h"
//#include <stdio.h>
#include "MyCloth.h"
//#include "nxOgre.h"
#include "Ogre.h"
/*
#include "Stream.h"
//#include "wavefront.h"
//#include "BmpLoader.h"
#include "NxCooking.h"
*/

#include "nxOgre_fluid.h"
#include "nxOgre_scene.h"
#include "nxOgre_converters.h"
#include "nxOgre_util_stream.h"
#include "NxCooking.h"

using namespace Ogre;

#define GLfloat float
#define VERTEX_BINDING 0
#define TEXCOORDBINDING 2
#define NORMAL_BINDING 1

#define TEAR_MEMORY_FACTOR 2

// -----------------------------------------------------------------------
MyCloth::MyCloth(NxScene *scene, NxClothDesc &desc, char *objFileName, NxReal scale)
{
mInitDone = false;
mTexId = 0;
mTexCoords = NULL;
NxClothMeshDesc meshDesc;
generateObjMeshDesc(meshDesc, objFileName, scale);
// todo: handle failure
init(scene, desc, meshDesc);
}


// -----------------------------------------------------------------------
MyCloth::MyCloth(NxScene *scene, NxClothDesc &desc, NxReal w, NxReal h, NxReal d, char *texFilename, bool tearLines)
{
mInitDone = false;
mTexId = 0;
mTexCoords = NULL;
NxClothMeshDesc meshDesc;
generateRegularMeshDesc(meshDesc, w, h, d, texFilename != NULL, tearLines);
init(scene, desc, meshDesc);
if (texFilename)
createTexture(texFilename);
}

// -----------------------------------------------------------------------
void MyCloth::init(NxScene *scene, NxClothDesc &desc, NxClothMeshDesc &meshDesc)
{
mScene = scene;

if (desc.flags & NX_CLF_HARDWARE) {
// cook the mesh for the usage on the PPU
meshDesc.target = NX_CLOTH_MESH_PPU_ATHENA;
// if we want tearing on the PPU we must tell the cooker
// this way it will generate some space for particles that will be generated during tearing
if (desc.flags & NX_CLF_TEARABLE)
meshDesc.flags |= NX_CLOTH_MESH_TEARABLE;
}
else {
// the cooked mesh will not be simulated on the PPU, only in software
// the software only version of the cooked mesh is smaller and takes less time to cook
meshDesc.target = NX_CLOTH_MESH_SOFTWARE;
}

cookMesh(meshDesc);
//releaseMeshDescBuffers(meshDesc);

allocateReceiveBuffers(meshDesc.numVertices, meshDesc.numTriangles);

desc.clothMesh = mClothMesh;
desc.meshData = mReceiveBuffers;
mCloth = scene->createCloth(desc);




mInitDone = true;
}

// -----------------------------------------------------------------------
MyCloth::~MyCloth()
{
if (mInitDone) {
mScene->releaseCloth(*mCloth);
mScene->getPhysicsSDK().releaseClothMesh(*mClothMesh);
releaseReceiveBuffers();
if (mTexCoords) free(mTexCoords);
}
}

// -----------------------------------------------------------------------
bool MyCloth::generateObjMeshDesc(NxClothMeshDesc &desc, char *filename, NxReal scale)
{

//not jet implemeted
return true;
}

// -----------------------------------------------------------------------
void MyCloth::generateRegularMeshDesc(NxClothMeshDesc &desc, NxReal w, NxReal h, NxReal d, bool texCoords, bool tearLines)
{
int numX = (int)(w / d) + 1;
int numY = (int)(h / d) + 1;

desc.numVertices = (numX+1) * (numY+1);
desc.numTriangles = numX*numY*2;
desc.pointStrideBytes = sizeof(NxVec3);
desc.triangleStrideBytes = 3*sizeof(NxU32);
desc.vertexMassStrideBytes = sizeof(NxReal);
desc.vertexFlagStrideBytes = sizeof(NxU32);
desc.points = (NxVec3*)malloc(sizeof(NxVec3)*desc.numVertices);
desc.triangles = (NxU32*)malloc(sizeof(NxU32)*desc.numTriangles*3);
desc.vertexMasses = 0;
desc.vertexFlags = 0;
desc.flags = 0;


mNumvertY = numY;
mNumvertX = numX;
mVertexCount = desc.numVertices;
mVec3Buffsize = sizeof(NxVec3) * mVertexCount;

mDirectDistance = d;
meshName = "FlagMesh";


// create mesh and sub-meshes
mMesh = Ogre::MeshManager::getSingleton().createManual(meshName,
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME) ;

//Init index buffer
mIndexCount = 6 * 2 * (mNumvertX)*(mNumvertY);
HardwareIndexBufferSharedPtr indexHardBuffer =
HardwareBufferManager::getSingleton().createIndexBuffer(
HardwareIndexBuffer::IT_32BIT,
mIndexCount,
HardwareBuffer::HBU_STATIC,
false); // use shadow buffer

mIndex = new uint [mIndexCount];

int i,j;
NxU32 *id = (NxU32*)mIndex;
for (i = 0; i < numY; i++) {
for (j = 0; j < numX; j++) {
NxU32 i0 = i * (numX+1) + j;
NxU32 i1 = i0 + 1;
NxU32 i2 = i0 + (numX+1);
NxU32 i3 = i2 + 1;
if ((j+i)%2) {
*id++ = i0; *id++ = i2; *id++ = i1;
*id++ = i1; *id++ = i2; *id++ = i3;
}
else {
*id++ = i0; *id++ = i2; *id++ = i3;
*id++ = i0; *id++ = i3; *id++ = i1;
}
}
}

indexHardBuffer->writeData(0,
sizeof(ushort) * mIndexCount, // size
mIndex, // source
true); // discard?

IndexData* mIndexData = new IndexData;
mIndexData->indexStart = 0;
mIndexData->indexCount = mIndexCount;
mIndexData->indexBuffer = indexHardBuffer;


//Init vertex buffer
mVertexData= new VertexData;
mVertexData->vertexStart = 0;
mVertexData->vertexCount = mVertexCount;

VertexDeclaration* decl = mVertexData->vertexDeclaration;
VertexBufferBinding* bind = mVertexData->vertexBufferBinding;

decl->addElement(VERTEX_BINDING, 0, VET_FLOAT3, VES_POSITION);
decl->addElement(NORMAL_BINDING, 0, VET_FLOAT3, VES_NORMAL);
decl->addElement(TEXCOORDBINDING, 0, VET_FLOAT2, VES_TEXTURE_COORDINATES);


HardwareVertexBufferSharedPtr posVertexHardBuffer;
HardwareVertexBufferSharedPtr texoordHardBuffer;
HardwareVertexBufferSharedPtr normVertexHardBuffer;

// Create shared vertex buffer
posVertexHardBuffer =
HardwareBufferManager::getSingleton().createVertexBuffer(
sizeof(Vector3),//decl->getVertexSize(VERTEX_BINDING),
mVertexCount,
//HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY);
HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE,
false); // use shadow buffer
bind->setBinding(VERTEX_BINDING, posVertexHardBuffer);

// Prepare buffer for normals - write only
normVertexHardBuffer =
HardwareBufferManager::getSingleton().createVertexBuffer(
sizeof(Vector3),//decl->getVertexSize(NORMAL_BINDING),
mVertexCount,
HardwareBuffer::HBU_STATIC, //HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE,
false); // use shadow buffer
bind->setBinding(NORMAL_BINDING, normVertexHardBuffer);

texoordHardBuffer =
HardwareBufferManager::getSingleton().createVertexBuffer(
sizeof(Vector2),//decl->getVertexSize(TEXCOORDBINDING),
mVertexCount,
HardwareBuffer::HBU_STATIC,
false); // use shadow buffer
bind->setBinding(TEXCOORDBINDING, texoordHardBuffer);


//Init vertex buffer:
mVertexBuffer = new Vector3[mVertexCount];
mNormalBuffer = new Vector3[mVertexCount];
mtexoordsBuffer = new Vector2[mVertexCount];




uint ArrayPos = 0;
Real y_distance = 0.0f;
Vector3 Vertex;
for (uint j = 0; j <= mNumvertY; j++)
{
Real x_distance = 0.0f;
const Real y_coord = static_cast<Real> (j) / (mNumvertY);
for (uint i = 0; i <= mNumvertX; i++)
{

Vertex = Vector3 (x_distance,0.0f,y_distance);
mVertexBuffer[ArrayPos] = Vertex;
mNormalBuffer[ArrayPos] = Vertex.crossProduct(Vertex);
mNormalBuffer[ArrayPos].normalise();
mtexoordsBuffer[ArrayPos] = Vector2 (1 - (static_cast<Real> (i) / (mNumvertX)),
1 - y_coord);

x_distance += mDirectDistance;
ArrayPos++;
}
y_distance += mDirectDistance;
}

posVertexHardBuffer->writeData(0,
mVec3Buffsize, // size
mVertexBuffer, // source
true); // discard?

normVertexHardBuffer->writeData(0,
mVec3Buffsize, // size
mNormalBuffer, // source
true); // discard?

texoordHardBuffer->writeData(0,
sizeof(Vector2) * mVertexCount, // size
mtexoordsBuffer, // source
true); // discard?

mFlagsubMesh= mMesh->createSubMesh();
mFlagsubMesh->useSharedVertices = false;
mFlagsubMesh->vertexData = mVertexData;
mFlagsubMesh->indexData = mIndexData;

mMaterialName = "nx.flag";
mFlagsubMesh->setMaterialName (mMaterialName);

mFlagsubMesh->operationType = RenderOperation::OT_TRIANGLE_LIST;

AxisAlignedBox meshBounds(-10.0f,
- 750.0f -10.0f,
-10.0f,
mNumvertX*mDirectDistance + 10.0f,
mNumvertY*mDirectDistance + 10.0f,
10.0f);
mMesh->_setBounds(meshBounds);

mMesh->load();
mMesh->touch();
desc.points = (NxVec3*)mVertexBuffer;
desc.triangles = (NxU32*)mIndex;


// mNumTexCoords = desc.numVertices;
// generate tear lines if necessary
if(tearLines)
generateTearLines(desc, numX + 1, numY + 1);
}

// -----------------------------------------------------------------------
void MyCloth::generateTearLines(NxClothMeshDesc& desc, NxU32 w, NxU32 h)
{
// allocate flag buffer
if(desc.vertexFlags == 0)
desc.vertexFlags = malloc(sizeof(NxU32)*desc.numVertices);

// create tear lines
NxU32* flags = (NxU32*)desc.vertexFlags;
NxU32 y;
for(y = 0; y < h; y++)
{
NxU32 x;
for(x = 0; x < w; x++)
{
if(((x + y) % 16 == 0) || ((x - y + 16) % 16 == 0))
flags[y * w + x] = NX_CLOTH_VERTEX_TEARABLE;
else
flags[y * w + x] = 0;
}
}
}

// -----------------------------------------------------------------------
void MyCloth::releaseMeshDescBuffers(const NxClothMeshDesc& desc)
{
NxVec3* p = (NxVec3*)desc.points;
NxU32* t = (NxU32*)desc.triangles;
NxReal* m = (NxReal*)desc.vertexMasses;
NxU32* f = (NxU32*)desc.vertexFlags;
free(p);
free(t);
free(m);
free(f);
}

// -----------------------------------------------------------------------
bool MyCloth::cookMesh(NxClothMeshDesc& desc)
{
// we cook the mesh on the fly through a memory stream
// we could also use a file stream and pre-cook the mesh
MemoryWriteBuffer wb;

// NxInitCooking();

if (!NxCookClothMesh(desc, wb)) //!! problem im debug mod vermutlich alloc im nxogrestream...
return false;

MemoryReadBuffer rb(wb.data);
mClothMesh = mScene->getPhysicsSDK().createClothMesh(rb);
return true;
}

// -----------------------------------------------------------------------
void MyCloth::allocateReceiveBuffers(int numVertices, int numTriangles)
{
// here we setup the buffers through which the SDK returns the dynamic cloth data
// we reserve more memory for vertices than the initial mesh takes
// because tearing creates new vertices
// the SDK only tears cloth as long as there is room in these buffers
NxU32 maxVertices = TEAR_MEMORY_FACTOR * numVertices;
mReceiveBuffers.verticesPosBegin = (NxVec3*)malloc(sizeof(NxVec3)*maxVertices);
mReceiveBuffers.verticesNormalBegin = (NxVec3*)malloc(sizeof(NxVec3)*maxVertices);
mReceiveBuffers.verticesPosByteStride = sizeof(NxVec3);
mReceiveBuffers.verticesNormalByteStride = sizeof(NxVec3);
mReceiveBuffers.maxVertices = maxVertices;
mReceiveBuffers.numVerticesPtr = (NxU32*)malloc(sizeof(NxU32));

// the number of triangles is constant, even if the cloth is torn
NxU32 maxIndices = 3*numTriangles;
mReceiveBuffers.indicesBegin = (NxU32*)malloc(sizeof(NxU32)*maxIndices);
mReceiveBuffers.indicesByteStride = sizeof(NxU32);
mReceiveBuffers.maxIndices = maxIndices;
mReceiveBuffers.numIndicesPtr = (NxU32*)malloc(sizeof(NxU32));

// the parent index information would be needed if we used textured cloth
NxU32 maxParentIndices = maxVertices;
mReceiveBuffers.parentIndicesBegin = (NxU32*)malloc(sizeof(NxU32)*maxParentIndices);
mReceiveBuffers.parentIndicesByteStride = sizeof(NxU32);
mReceiveBuffers.maxParentIndices = maxParentIndices;
mReceiveBuffers.numParentIndicesPtr = (NxU32*)malloc(sizeof(NxU32));

// init the buffers in case we want to draw the mesh
// before the SDK as filled in the correct values
*mReceiveBuffers.numVerticesPtr = 0;
*mReceiveBuffers.numIndicesPtr = 0;
}

// -----------------------------------------------------------------------
void MyCloth::releaseReceiveBuffers()
{
NxVec3* vp;
NxU32* up;
vp = (NxVec3*)mReceiveBuffers.verticesPosBegin; free(vp);
vp = (NxVec3*)mReceiveBuffers.verticesNormalBegin; free(vp);
up = (NxU32*)mReceiveBuffers.numVerticesPtr; free(up);

up = (NxU32*)mReceiveBuffers.indicesBegin; free(up);
up = (NxU32*)mReceiveBuffers.numIndicesPtr; free(up);

up = (NxU32*)mReceiveBuffers.parentIndicesBegin; free(up);
up = (NxU32*)mReceiveBuffers.numParentIndicesPtr; free(up);
}

// -----------------------------------------------------------------------
void MyCloth::draw(bool shadows)
{
NxU32 numVertices = *mReceiveBuffers.numVerticesPtr;
NxU32 numTriangles = *mReceiveBuffers.numIndicesPtr / 3;


// copy positions and indices
NxVec3 *vSrc = (NxVec3*)mReceiveBuffers.verticesPosBegin;
NxVec3 *vDest = (NxVec3*)mVertexBuffer;
for (int i = 0; i < mVertexCount; i++, vDest++, vSrc++)
*vDest = (*vSrc);
/*
// memcpy((NxU32*)desc.triangles, wo.mIndices, sizeof(NxU32)*desc.numTriangles*3);

NxVec3 *vSrc = (NxVec3*)mReceiveBuffers.verticesPosBegin;
NxVec3 *vDest = (NxVec3*)desc.points;
for (int i = 0; i < desc.mVertexCount; i++, vDest++, vSrc++)
*vDest = (*vSrc);
*/
VertexBufferBinding* bind = mVertexData->vertexBufferBinding;
HardwareVertexBufferSharedPtr HardBuffer= bind->getBuffer (VERTEX_BINDING);
HardBuffer->writeData(0,
mVec3Buffsize, // size
mVertexBuffer, // source
true); // discard?

/* here one should calculate the normals again and then put the normals to the hardware buffers
but then you nshould initialise the buffer with HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE instead of HBU_STATIC

HardBuffer = bind->getBuffer (NORMAL_BINDING);
HardBuffer->writeData(0,
mVec3Buffsize, // size
mNormalBuffer, // source
true); // discard?

*/
}


// -----------------------------------------------------------------------
bool MyCloth::createTexture(char *filename)
{
// obsolet
return true;
}

// -----------------------------------------------------------------------
void MyCloth::updateTextureCoordinates()
{
// this is important if i want to support tear lines
// not used until now

NxU32 numVertices = *mReceiveBuffers.numVerticesPtr;
NxU32 *parent = (NxU32 *)mReceiveBuffers.parentIndicesBegin + mNumTexCoords;
for (NxU32 i = mNumTexCoords; i < numVertices; i++) {
mTexCoords[2*i] = mTexCoords[2*(*parent)];
mTexCoords[2*i+1] = mTexCoords[2*(*parent)+1];
}

mNumTexCoords = numVertices;
}

mkh42

13-11-2006 15:43:57

save the following code as mycloth.h to the NxTutorials code folder

#define MYCLOTH_H

//#include "NxOgre.h"
#include "Ogre.h"
#include "NxPhysics.h"

class MyCloth {
public:
/* create mesh from obj file */
MyCloth(NxScene *scene, NxClothDesc &desc, char *objFileName, NxReal scale);
/* create regular mesh */
MyCloth(NxScene *scene, NxClothDesc &desc, NxReal w, NxReal h, NxReal d, char *texFilename = NULL, bool tearLines = false);

~MyCloth();

void draw(bool shadows);
NxCloth *getNxCloth() { return mCloth; }

private:
void init(NxScene *scene, NxClothDesc &desc, NxClothMeshDesc &meshDesc);
bool generateObjMeshDesc(NxClothMeshDesc &desc, char *filename, NxReal scale);
void generateRegularMeshDesc(NxClothMeshDesc &desc, NxReal w, NxReal h, NxReal d, bool texCoords, bool tearLines = false);
void generateTearLines(NxClothMeshDesc& desc, NxU32 w, NxU32 h);
void releaseMeshDescBuffers(const NxClothMeshDesc& desc);

bool cookMesh(NxClothMeshDesc& desc);

void allocateReceiveBuffers(int numVertices, int numTriangles);
void releaseReceiveBuffers();

bool createTexture(char *filename);
void updateTextureCoordinates();

bool mInitDone;

NxMeshData mReceiveBuffers;
NxScene *mScene;
NxCloth *mCloth;
NxClothMesh *mClothMesh;

NxU32 mNumTexCoords;

float *mTexCoords;
NxU32 mTexId;


Ogre::String mMaterialName;

Ogre::Real mDirectDistance;

Ogre::MeshPtr mMesh ;

Ogre::SubMesh *mFlagsubMesh;
Ogre::SubMesh *mPolesubMesh ;
Ogre::SubMesh *mArrowsubMesh ;


Ogre::uint mNumvertY;
Ogre::uint mNumvertX;
bool mInit;
Ogre::Real mUpdateTime;
size_t mVec3Buffsize;

protected :


Ogre::uint mVertexCount;
Ogre::VertexData *mVertexData;
Ogre::Vector3 *mVertexBuffer;
Ogre::Vector3 *mNormalBuffer;
Ogre::Vector2 *mtexoordsBuffer;

Ogre::uint *mIndex;
Ogre::ushort mIndexCount;

Ogre::String meshName;


};

#endif

mkh42

13-11-2006 15:50:39

make a backup of your 101.cpp and then save this file as 101.cpp to the NxTutorials code folder

add mycloth.cpp and mycloth.h to the '101 cube on a plane' project and then compile it in RELEASE version. in debug version it will crash because cooking seems not to work in debug mode. i know i know this info was in the forum but i learned it the hard way!!!
:)

Please see also next post for the material for the flag

/*

#####################################################################
# #
# NxOgre Tutorial 101 : Cube on a plane #
# #
# #
# Written by Robin Southern #
# #
#####################################################################

Preamble:

If you don't know the difference between a SceneManager and a Scene-
Node you should start with the Ogre tutorials at the Wiki[1]. As
these tutorials tend to push the Ogre code aside and deal more with
nxOgre.

[1] http://www.ogre3d.org/wiki/


Documentation and Tutorials:

- http://www.nxogre.org/NxTutorial101
- PhysX Training Programs, Lesson 101


Keys:

- Escape Quit
- F1 Save a screenshot
- F2 Toggle the debug renderer
- F3 Pause/Resume
- I,J,K,L Apply Forces to the cube in the X or Z Axis.
- U,M Apply forces to the cube in the Y axis.


*/

// TIP: Always include nxOgre.h before Ogre.h due to a conflict between PhysX and Ogre.
#include "nxOgre.h"

#include "Ogre.h"
#include "tutorialApplication.h"
#include "MyCloth.h"

using namespace nxOgre;
using namespace Ogre;


#define FLAG_MESH_NAME "FlagMesh"
#define FLAG_ENT_NAME "FlagMeshEntity"
#define FLAG_MATERIAL "nx.flag"

class NxTutorial : public SimpleTutorial {

public:


world *mWorld;
scene *mScene;
body *myBody;

MyCloth *regularCloth;
Entity *flagMeshEntity ;

//////////////////////////////////////////////////////////////////////////////////////////////////

void start() {

// 1. Start up NxOgre and pass on Ogre Root and the SceneManager as
// arguments.

mWorld = new world(mRoot);

// 2. Create our scene, this is where the physics is simulated into.
// We can have more than one scene, but physics objects of one
// scene cannot interact with another scene.

mScene = mWorld->createScene("myScene", mSceneMgr);

// 3. Better add some gravity.

mScene->hasGravity(Vector3(0,-3,0));

// 4. Let's add a floor.
// Floors have an infinite size so we don't have to worry
// about anything falling off!

mScene->hasFloor();
// 5. Create a simple cube at X:0, Y:10m , Z:0 with a size of 1 metre.
// Due the gravity it'll fall then come to a rest.

myBody = mScene->createBody(
"myCube", // Name
"cube.1m.mesh", // Mesh to use
new cubeShape(1.0f), // Collision Model to use
10.0f, // Density of the body (In Kilograms)
Vector3(0,0.5,0) // Where to put it. (In Metres)
);

NxClothDesc clothDesc;
clothDesc.globalPose.t = NxVec3( -2,5,-2);
clothDesc.thickness = 0.2f;
//clothDesc.density = 1.0f;
clothDesc.bendingStiffness = 0.5f;
clothDesc.stretchingStiffness = 1.0f;
//clothDesc.dampingCoefficient = 0.50f;
clothDesc.friction = 0.5f;
//clothDesc.collisionResponseCoefficient = 1.0f;
//clothDesc.attachmentResponseCoefficient = 1.0f;
//clothDesc.solverIterations = 5;
//clothDesc.flags |= NX_CLF_STATIC;
//clothDesc.flags |= NX_CLF_DISABLE_COLLISION;
//clothDesc.flags |= NX_CLF_VISUALIZATION;
//clothDesc.flags |= NX_CLF_GRAVITY;
clothDesc.flags |= NX_CLF_BENDING;
//clothDesc.flags |= NX_CLF_BENDING_ORTHO;
//clothDesc.flags |= NX_CLF_DAMPING;
//clothDesc.flags |= NX_CLF_COMDAMPING;
clothDesc.flags |= NX_CLF_COLLISION_TWOWAY;
clothDesc.flags |= NX_CLF_SELFCOLLISION;


//regularCloth = new MyCloth(mScene->mScene, clothDesc,"vorhang.mesh",1);
regularCloth = new MyCloth(mScene->mScene, clothDesc, 4.0f, 3.0f, 0.15f, NULL);
// That's it!


flagMeshEntity = mSceneMgr->createEntity(FLAG_ENT_NAME, FLAG_MESH_NAME);
flagMeshEntity->setMaterialName (FLAG_MATERIAL);

SceneNode *flagMeshNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();

flagMeshNode->translate (Vector3::ZERO);
flagMeshNode->attachObject(flagMeshEntity);


}

//////////////////////////////////////////////////////////////////////////////////////////////////


void stop() {
// 7. When you want to quit, just delete World, everything in it will
// be automatically deleted for you.

// TIP: However be careful, if you have a camera or anything in used attached
// to a SceneNode of a body or prefab those will get deleted as well which
// would most likely result in a crash.

delete mWorld;
}

//////////////////////////////////////////////////////////////////////////////////////////////////

void newFrame(float _time) {

// update cloth
regularCloth->draw(false);

if (isKeyDown(Z)) {
myBody->addForce(Ogre::Vector3(0,0,75));
}

if (isKeyDown(NEG_Z)) {
myBody->addForce(Ogre::Vector3(0,0,-75));
}

if (isKeyDown(X)) {
myBody->addForce(Ogre::Vector3(75,0,0));
}

if (isKeyDown(NEG_X)) {
myBody->addForce(Ogre::Vector3(-75,0,0));
}

if (isKeyDown(Y)) {
myBody->addForce(Ogre::Vector3(0,75,0));
}

if (isKeyDown(NEG_Y)) {
myBody->addForce(Ogre::Vector3(0,-75,0));
}

}


//////////////////////////////////////////////////////////////////////////////////////////////////

void getTutorialSettings() {
mTutorialName = "101";
mTutorialDescription = "Cube on a plane";
mMouseMode = CAMERA_CONTROL;
}

//////////////////////////////////////////////////////////////////////////////////////////////////

void prestart() {mCaption3->setCaption("Press either I J K L U or M, to apply a 75 newton force to the cube on an axis.");}
void prestop() {}

//////////////////////////////////////////////////////////////////////////////////////////////////

};


TUTORIAL_VOIDMAIN

mkh42

13-11-2006 15:53:37

save this file as nx.flag.material to the Tutorials/Media folder



material nx.flag
{

technique
{
pass
{
ambient 0.600000 0.6 0.60000
diffuse 1.00000 1.0000 1.000000
specular 0.500000 0.246996 0.000000 30.500000
shading phong
cull_hardware none
cull_software none



texture_unit
{
texture a.png
}

}
}
}

mkh42

13-11-2006 15:56:26

So after all this hard work you should be able to see a nice falling flag.

greetings
martin

betajaen

13-11-2006 16:58:29

Alright, thankyou. I'll have a little fiddle later and if I'm succesfull, I'll NxOgrise the classes.

betajaen

13-11-2006 18:04:53

Alright.

Basically it compiles and runs, but I do not see a cloth.

But here are some questions:

  1. Calling cloth->draw causes something to crash after the frame has been rendered. Not calling it works fine.[/*:m]
  2. The cloth is not being attached to anything. I did attach it to the cube as per the 1001 Lesson, but even the debug render with the cloth visulations on. Nothing was on the screen.[/*:m][/list:u]

    So something appears to be a foot. However I have had my own implementation done for a while now, I got the physics right but I couldn't get the render part right. Your way has given me plenty of new ideas ;)

ColeZero

13-11-2006 18:21:56

Yeah this works, i can see the flag falling on the cube, good job...
Looks great, big thx mkh42.

I've just made a screen:






Now i can analyse your good, and learn how you did it..:)

betajaen

13-11-2006 18:30:33

How did you get it working, and I didn't.

That, thats, thats, thats.......*head explodes*

ColeZero

13-11-2006 18:40:23

C&P...^^
I copied the code for the header, added a new file to the project(mycloth.h) and pasted the code in it..

Then i copied the code for the .cpp, added a new one the project(mycloth.cpp), and....pasted the code in it...^^

And last, but not least: i commented the old 101 code, and pasted the new one....compiled, ran and beeing happy..

Simple copy & paste, but as mkh42 said : most of the code is from a physx-sample, and its not very readable..^^.

betajaen

13-11-2006 19:01:55

So did I.

Only difference is, apart from minor NxOgre changes, is that I have a PhysX card which may be the culprit.

mkh42

13-11-2006 19:21:38

hello ColeZero

i'm happy to hear that it worked for you.
i will certainly have to clean up the code a lot.


hello betajaen,
sorry to hear that it doesn't work for.

do you use my material. if you do not use it, it could be that the flag is not visible because the normals point in the wrong direction.
the material switches of the culling.

in my demo it is indeed not attached but it falls slowly on the cube.
i made a demo with an attached flag. if you like i post a screenshot.

i sometimes also have problems with craches but if i start the release build version without debugging it works always fine (until now).

This crashes could certainly be an issue with the code . Perhaps some buffers which gets unintentionaly freed or something like that.
Because my little porting project is still in progress the code will get testes more an more.

greetings
Martin

mkh42

13-11-2006 22:20:30

hello betajaen

i found one issue which could cause the instability you experience

change the line

mIndexCount = 6 * 2 * (mNumvertX)*(mNumvertY);
to
mIndexCount = 3 * 2 * (mNumvertX)*(mNumvertY);

and a few lines below change

indexHardBuffer->writeData(0,
sizeof(ushort)*mIndexCount, // size
mIndex, // source
false); // discard?
to
indexHardBuffer->writeData(0,
sizeof(uint)*mIndexCount, // size
mIndex, // source
false); // discard?

changes are bold.
this error result in an index buffer which was only initialised half.

greetings
Martin

betajaen

13-11-2006 23:49:34

Nein :(

mkh42

14-11-2006 00:04:29

strange!
i played now a few hours with the code and experienced no new crash since i changed this two lines.

greetings
martin

betajaen

14-11-2006 00:08:30

A very late Ja! Apparently re-copying and pasting does actually work.



Some concerns
  1. The fixed code above crashes if I add it in.[/*:m]
  2. Ray casting does not work. It just crashes. It may be a forced static_cast on the casters fault (thinking that the cloth is a body) or a proper crash.[/*:m][/list:u]

    Once the bugs have been fixed, and the entire thing is optimized. I would like (with your help) to turn this class into a shape so it can be attached to a body, and used as normal.

    Of course that will be a week or two away

    Anyway, I'm going to play with my Virtual-Welsh flag now. ;)

mkh42

14-11-2006 07:36:56

nice to hear that it finally works for you. looks simply cool.

concerning the changes i post i'm quit sure that they are right but i will again take a look at them. it is important to make both chnages. so the only right combination is 3*2 in combination with uint then the buffer should be perfectly initialised.

can you explain the raycast thing a little bit more? do you make your raycasts in the ogre world (rayscenequery) or in the physic world ?
a line of code wouldn't be bad.

you can certainly use the code as you wish. i would be happy if the code could help to integrate cloth a little bit earlier/easier in nxogre.

greetings
martin

mkh42

14-11-2006 10:41:52

can you really integrate NxCloth as a Shape in NxOgre?
Unfortunately NxCloth seems not to be inherited from NxShape. Also the Raycast of cloth takes other params than the NxShape class.

i made some raycasts with direct calls to NxCloth->raycast and that worked fine. no crashes and the correct results.


greetings
martin

betajaen

14-11-2006 10:58:37

Well. I was thinking about it more last night, and I came up with two implementation.

  1. A full cloth class, based partly of the code of body but only half-capable. Intended for use for flags, pieces of cloth and rope.[/*:m]
  2. A cloth "shape" that can be attached to a body and it's intended use is only for deformable bodies.[/*:m][/list:u]

    I'll have a go at the raycast again today, I expect it's a null pointer or I'm casting it as a body when it is not. What do you get when you use the regular raycast?

mkh42

14-11-2006 11:18:06

here is the raycast code . I didn't evaluate hit and vertexid until now but only made the decision if i create a sphere or a cube as 'bullet'. so i can see if the boolean result works correct.

unfortunately cloth seems not to support ccd so i have to solve the problem that my bullets most of the time pass through the cloth. :cry:


NxRay ray(NxTools::convert(pos),NxTools::convert(dir));
NxVec3 hit;
NxU32 vertexId;
NxCloth* Cloth = regularCloth->getNxCloth();
nxOgre::body* bulletbody;

if (Cloth->raycast(ray, hit, vertexId))
{
bulletbody = mScene->createBody(
name, // Name
"sphere.50cm.mesh", // sphere.50cm.mesh Mesh name to use
new sphereShape(0.1f,_pose,NULL,true), // Sphere Shape with a 0.1 metre radius
10.0f, // Density
posi
);

}
else
{
bulletbody = mScene->createBody(
name, // Name
"cube.1m.mesh",
new cubeShape(0.2f,_pose ,NULL,true),
10.0f, // Density
posi
);
};

betajaen

14-11-2006 11:50:15

Excellent.

Well in Cellfactor if you shot the flag they would tear, I am assuming used raycasting the bullet, when the gun sight is over the cloth.

That way then you can get the hit position, and tear the cloth yourself and manually apply the force to the flag at that specific position.

mkh42

14-11-2006 12:23:45

tearing cloth is the next step i will do. i need it for my demo and it is one of the main reasons i convert from newt to physx.
hope i will bring it to work.
At moment i'm still not very happy with the ccd implemented in phsyx (or pherhaps i do not use it correctly). ccd in newton works very stable and is very user friendly. with ccd in physx i see somtimes strange behaviour and sticking objects.

so it seems there remains some work to do for us and ageia.

greetings
martin

mkh42

14-11-2006 19:24:42

hey i schould hurry to buy something against clothes moths, or ? :D





as you can see the tearing stuff makes nice progress.

greetings
martin

CaseyB

14-11-2006 19:26:14

@martin You ROCK! This is Sweet!

-=Edit=-
betajaen still rocks too! :D

betajaen

14-11-2006 19:58:57

Bloody hell.

I assume those cubes and spheres was your armaments?

p.s. I always rock ;)

Toby

14-11-2006 21:17:35

Great job mkh42. And if you can make an object deformation with cloth like technical demo on ageia. I am very very interrested. Or someone else.

mkh42

14-11-2006 22:44:51

Hello

i upload a zip file on my homepage.
installation is the same as described at the beginning of this thread.

a few notes:

the parameters of the cloth can have significant influence on the framrate.

with falling framerat the bullets more and more pass the cloth without collision. until now i do not have raycast the bullet to prevent that.

this is still a rough code nevertheless it make much fun to play with. :)

http://www.martinkirsch.de/nxogre/clothdemo_0_1.zip

hope you have fun.
greetings
martin

betajaen

14-11-2006 23:24:35

Cheers.

I've started to NxOgreise the cloth class and it uses a blueprint to define the parameters.

I've also "added" the option to allow meshes to be turned into cloth, i.e. that rubber cow in the PhysX lessons.

mkh42

15-11-2006 06:17:51

hello betajen,

that's great news.

betajaen

16-11-2006 23:00:37

Alright. It's implemented. Partly. I've found one problem though shadows:



It seems the stencil shadow is depth-fighting with the cloth mesh, weird.

Oh, look at that FPS. Not bad considering it's rendered on software ;)

mkh42

16-11-2006 23:17:39

looks cool :D (ignoring the shadow problem)

the framerate is fantastic. what physx parameter you used for the cloth and for the scene update? what size and what resolution you use for the mesh?

i have to admitt that i didn't played around with cloth and shadow.
i had shadows disabled. i will take a look at that but i'm not very expirienced with shadow casting.

betajaen

16-11-2006 23:23:30

Same parameters you put down, although I'm updating the mesh every other frame.

mkh42

16-11-2006 23:29:22

wow!!! i didn't get such frame rates.
ok my grahic card is a geforce 6800go. that could explain it.
what's your grahic card?

betajaen

16-11-2006 23:32:05

GeForce 7900GT

mkh42

16-11-2006 23:52:51

ok that's an good argument.
:)

mkh42

17-11-2006 08:39:29

i started looking into this shadow thing.

first of all i'm wondering that you get shadow at all. i do not call mesh->buildedgelist() in my code so stencil shadow should be switched off.

if i call buildedgelist() i get the same problem as you. (but no shadow on the ground)

this depth fighting problem comes from the material settings
cull_hardware none
cull_software none
but if you switch off this settings the flagg is not allways visible.

in a first step one could probably solve this if one check the position of every triangle of the flag and check wether it would be culled. if it would be culled one can invert the direction of the normal of this triangle.
at the end of each draw routine one had to call freeedgelist() and buildedgelist().

but actually my main problem is the missing shadow on the floor. how did you made it to get this shadow?

greetings
martin

betajaen

17-11-2006 09:44:16

Well it's your code, which I didn't change. It is in one of the tutorials though that uses the stencil shadows.

I'm releasing 0.4 RC2.1 later today so you can have a closer look though.

mkh42

17-11-2006 09:53:02

i just use
depth_bias 1
in my material settings and this depth fighting issue disapears. strange i didn't thought that this would help.

now it looks like this
...
shading phong
depth_bias 1
cull_hardware none
cull_software none
...


but my main problem with the missing shadow on the floor remains. so it seems to be something badly wrong with my shadow settings and so i can not say wether this depth_bias 1 helps you too. simply try it and pherhaps i works.

greetings
martin

betajaen

17-11-2006 10:38:56

Okay, that helped. However the shadow itself jitters, anything that it casts onto and any object which shadows casts onto the flag.

mkh42

17-11-2006 11:52:57

hmm :? ok i think i will look further into this matter after i get my fingers on your new release.

Vineeth@nxOgre

14-03-2008 11:41:05

I have basic understanding of how cloth is created in Ageia
The mycloth class as mkh42 described

I now tried in tutorial nxogre101 a simple program to create cloth



void start()
mWorld = newWorld();
mWorld->getPhysXDriver()->createDebuggerConnection();
mScene = mWorld->createScene("myScene", mSceneMgr);
mScene->setGravity(Ogre::Vector3(0,-9.8,0));
mScene->addFloor();


ClothParams cp;
cp.thickness = 0.2;
cp.bendingStiffness = 0.5;
cp.friction = 0.25;
cp.flags |= NX_CLF_BENDING;
cp.flags |= NX_CLF_COLLISION_TWOWAY;
cp.flags |= NX_CLF_HARDWARE;
cp.height=3;
cp.width=2;
cp.meshMaterial="nx.flag";
cp.density = 0.15;

mScene->createCloth("This is my cloth name",
NxOgre::Pose(Ogre::Vector3(0, 4, 0)),
cp);



But the program lands into trouble when accesing mcloth pointer in the NxOgreCloth.cpp with mcloth=0X00000000

what can I do? :cry:

p.s I have used the edit button this time beta

betajaen

14-03-2008 11:45:43

I would appreciate you not bumping threads that are TWO years old. Post this in a new thread.