loading from file/"multithreading" problems

loading from file/"multithreading" problems

Bild des Benutzers spectre-srs

Hello, im new to havok, and already runned into some problems. Cant figure out how to read collision meshes from file runtime and add them to the world. Serialize demo seems to load something, but adding that to world crashes havok. As I understood, there is a whole phys system or even world in every .hkx/hkt file, not just a shape. And lots of related functions only confuses, cause i dont know what they all do. Can somebody write an example "file loader-to world adder" for me?

Also i may have some troubles with multithreading. I have main thread for initializing havok and ogre, which I am using for rendering, and then launch another thread, which i want to use for stable separated havok stepping. But this is crashes havok, i managed to move his initialization to start of his thread and that gone fine, until i tried to add working rigid body to havok world from main thread, wich caused crash. Found something about "initThread", but that funk didnt helpt me.

My code with threads (havok described as class):

class HavokClass {
public:
...
	void initialize(void);
	void InitThread(void);
...
	hkMallocAllocator baseMalloc;	//have them static for being able to access anytime anywhere
	hkReal StepTime;				//Time between frames
	hkpWorld* world;
	hkpPhysicsContext* context;		//VDB
	hkVisualDebugger* visualDebugger;
};


void HavokClass::initialize(void)
{
	hkMemoryRouter* memoryRouter = hkMemoryInitUtil::initDefault( &baseMalloc, hkMemorySystem::FrameInfo(1024 * 1024) );
	hkBaseSystem::init( memoryRouter, errorReport );

	world = new hkpWorld( hkpWorldCinfo() );

	hkpAgentRegisterUtil::registerAllAgents( world->getCollisionDispatcher() );

	hkpPhysicsContext::registerAllPhysicsProcesses(); 

	context = new hkpPhysicsContext;
	context->addWorld(world); 

	hkArray contexts;
	contexts.pushBack(context);
	visualDebugger = new hkVisualDebugger(contexts);
	visualDebugger->serve();
}

void HavokClass::InitThread(void)
{
	hkMemoryRouter memoryRouter;
	hkMemorySystem::getInstance().threadInit( memoryRouter, "hkCpuJobThreadPool" );
	hkBaseSystem::initThread(&memoryRouter);
}

void HavokClass::step(void)
{
	world->stepDeltaTime(StepTime);
	visualDebugger->step();
}



HavokClass Havok; //also global, temporary primitive code until i got a grip on how everything works

//havok thread, started as _beginthread ( PhysThreadLoop, 0, 0 );
void PhysThreadLoop( void* arg ) {
	Havok.initialize();

	Havok.MakeFloor(); //creates big flat box, works fine
	Havok.StepTime = 1.0f / hkReal(60);

	while (true) {
		Havok.step();
		Sleep ( 16 );
	}
}


//everything works fine, until now
void cCoropcaMover::SpawnPhysHead(void)
{
	Havok.InitThread(); //supposed to register thread so it wont crash havok, but its not
	Havok.CreateBox(); //spawns rigid body box, works fine if used in havoks thread, but crashes if called from another, even through i call init thread
}
27 Beiträge / 0 neu
Letzter Beitrag
Nähere Informationen zur Compiler-Optimierung finden Sie in unserem Optimierungshinweis.
Bild des Benutzers havokcormac

Hi,

You say "Serialize demo seems to load something, but adding that to world crashes havok"
- is it a crash, or are you hitting an assert?
- do you get an error report?
- do you have a callstack at the time of the crash?
- what is it you're trying to load?

Similar questions for the multithreading crashes - an error report and/or callstack might help to figure out what's going wrong.

Also, when adding objects to the physics world from another thread, are you surrounding that code with a hkpWorld::lock(), hkpWorld::unlock() pair?

Cormac

Bild des Benutzers spectre-srs

>is it a crash, or are you hitting an assert?
Hi, im not sure, how do i recognize assert? It shows as typical windows program-shutdown error with report to microsoft. It contains some dump in report, though.

>what is it you're trying to load?
At first i tried to load .hkx file that was created by the demo, because demo succesfully uses that file internally when compares shapes. I took load code and tried to create box using loaded shape:

hkpRigidBody* HavokClass::CreateFile( void )
{
	hkIstream stream("Caropca.hkx");
	hkResource* resource = hkSerializeUtil::load(stream.getStreamReader());

	hkpRigidBodyCinfo bodyCinfo;

	if (resource)
	{
		hkpRigidBody* readRigidBody = resource->getContents();
		resource->removeReference();
		bodyCinfo.m_shape = readRigidBody->getCollidable()->getShape();
	}

//	hkpBoxShape* boxShape = new hkpBoxShape(halfExtents);	//tried through normal rigid body creation routine
//	bodyCinfo.m_shape = boxShape;

	const hkReal boxMass = 10.0f;
	hkpMassProperties massProperties;
	hkpInertiaTensorComputer::computeShapeVolumeMassProperties(bodyCinfo.m_shape, boxMass, massProperties);

	bodyCinfo.setMassProperties(massProperties);

	hkpRigidBody* rigidBody = new hkpRigidBody(bodyCinfo);
	return rigidBody;
}

Later i used custom box, exported from 3d max by havok content tools, with same results. Honestly, i dont know what am i doing. Interesting that my box shows fine in content viewer, but generated from demo - just empty.

>are you surrounding that code with a hkpWorld::lock(), hkpWorld::unlock() pair?
Yes, i have world->lock() in the begining of Havok::CreateBox(), and unlock just before its return (CreateBox returns pointer of hkpRigidBody for futher use). I even tried my own style of protection from accessing world simultaneously, but it keep crashing at box creation from parallel thread. Crash accompanied by the same windows report error.

My litle synch effort:

bool HavokBusy = false;
bool HavokPause = false;

while (true) {	//havok thread
	while(HavokPause);	//pause if someone writes to world
	HavokBusy = true;	//notice others that its too late for writing
	Havok.step();		//cause we are computing
	HavokBusy = false;	//can write again
	Sleep ( 16 );
}

{	//main thread
	HavokPause = true;	//notice havok that we are writing
	while(HavokBusy);	//wait until he allows
	Havok.CreateBox();	//try to create box, crash happens
	HavokPause = false;	//allow him go on
}

I suspect error goes not from accessing something simultaneously, i'm sure i excluded that problem in tests. Could it be from initializing havok as non-multithread? Maybe thats why he is not expecting any inputs by parallel thread.

Bild des Benutzers mehwoot

If it is an internal havok assert that fails, it should print something out to the console. Also, you should be running in debug mode in visual studio (I am assuming you are using visual studio) which should give you more information about the error if it is part of your code.

Bild des Benutzers havokcormac

Yes, you probably want to initialize Havok multithreaded.
Take a look at Demo/StandAloneDemos/ConsoleExampleMt for an example of this.

In your loading code, it looks like you're loading a rigid body as a resource, setting the shape pointer of a CInfo from that resource, deleting the resource, then trying to create a new rigid body from the now-deleted shape.
You probably want to keep that resource around for as long as the lifetime of the rigid body (i.e. call resource->removeReference() only when you don't need the body any more).

As for asserts, if you're not seeing them you're probably either running in Release mode or not using the console. I'd advise you to use the Fulldebug build configuration while you're developing. There are lots of sanity checks to make sure bad things aren't happening in the code, and the error messages you get can really help to pinpoint a problem.

Read this:
http://software.intel.com/en-us/forums/showthread.php?t=62766&o=a&s=lr

Bild des Benutzers havokcormac

Yes, you probably want to initialize Havok multithreaded.
Take a look at Demo/StandAloneDemos/ConsoleExampleMt for an example of this.

In your loading code, it looks like you're loading a rigid body as a resource, setting the shape pointer of a CInfo from that resource, deleting the resource, then trying to create a new rigid body from the now-deleted shape.
You probably want to keep that resource around for as long as the lifetime of the rigid body (i.e. call resource->removeReference() only when you don't need the body any more).

As for asserts, if you're not seeing them you're probably either running in Release mode or not using the console. I'd advise you to use the Fulldebug build configuration while you're developing. There are lots of sanity checks to make sure bad things aren't happening in the code, and the error messages you get can really help to pinpoint a problem.

If you haven't already, have a look at the sticky thread.

Bild des Benutzers havokcormac

Yes, you probably want to initialize Havok multithreaded.
Take a look at Demo/StandAloneDemos/ConsoleExampleMt for an example of this.

In your loading code, it looks like you're loading a rigid body as a resource, setting the shape pointer of a CInfo from that resource, deleting the resource, then trying to create a new rigid body from the now-deleted shape.
You probably want to keep that resource around for as long as the lifetime of the rigid body (i.e. call resource->removeReference() only when you don't need the body any more).

As for asserts, if you're not seeing them you're probably either running in Release mode or not using the console. I'd advise you to use the Fulldebug build configuration while you're developing. There are lots of sanity checks to make sure bad things aren't happening in the code, and the error messages you get can really help to pinpoint a problem.

Also, if you haven't already, have a look at the sticky thread:
http://software.intel.com/en-us/forums/showthread.php?t=62766&o=a&s=lr

Bild des Benutzers havokcormac

Apologies for multiple posting - something was wrong with my intertubes :(

Cormac

Bild des Benutzers spectre-srs

>it should print something out to the console.
You talking about error report function, which needed for hkBaseSystem::init? It doesn't print anything for me, neither at start of programm neither at the crash.

>Also, you should be running in debug mode in visual studio (I am assuming you are using visual studio) which should give you more information about the error if it is part of your code.
I do compile in debug, then manually run app from folder, had no any tips from visual. Or, should i somehow run it through visual studio? //Didn't really dig into visual internal functions.

>Yes, you probably want to initialize Havok multithreaded.
I'm little concerned about this, i heard it needs at least two threads for work, but i only need one havok processing thread, and another just adjusts/accesses it sometimes, is that possible?

>looks like you're loading a rigid body as a resource, setting the shape pointer of a CInfo from that resource, deleting the resource, then trying to create a new rigid body from the now-deleted shape.
Tried to remove that reference-removing from code, but it still crashed. By the way, do every created rigid body contains its own copy of shape, or several identical bodies can have only one copy of shape for all them? Is this why resource still needed, for containing shape, to which all bodies refer?

>As for asserts, if you're not seeing them you're probably either running in Release mode or not using the console.
Probably second, where i can find console?

>Read this
Well, there was no callstack in error message, as for assert - i'll post it as soon as i get console. I will try reproduce mesh loading in demo now.

Bild des Benutzers spectre-srs

Aha, moved code into "PhysicsVdb" standalone demo, and got the same crash, except for as this one was in console, it printed this:

.\Util\hkNativePackfileUtils.cpp(98): [0x3F7A4853] Warning: Asked for hkpRigidBody but contains hkRootLevelContainer. Returning null

Modifed rigid body creation in named demo as follows:

		hkpRigidBody* rigidBody;
		{
			// Create a box 1 by 2 by 3
//			hkVector4 halfExtents; halfExtents.set(0.5f, 1.0f, 1.5f); //removed
//			hkpBoxShape* boxShape = new hkpBoxShape(halfExtents); //removed

			hkIstream stream("Caropca.hkx"); //added
			hkResource* resource = hkSerializeUtil::load(stream.getStreamReader()); //added
			hkpRigidBody* readRigidBody = resource->getContents(); //added //i guess problem is here

			hkpRigidBodyCinfo bodyCinfo;
			bodyCinfo.m_shape = readRigidBody->getCollidable()->getShape(); //boxShape; //changed

			//  Calculate the mass properties for the shape
			const hkReal boxMass = 10.0f;
			hkpMassProperties massProperties;
			hkpInertiaTensorComputer::computeShapeVolumeMassProperties(bodyCinfo.m_shape, boxMass, massProperties); //changed

			bodyCinfo.setMassProperties(massProperties);

			// Create the rigid body
			rigidBody = new hkpRigidBody(bodyCinfo);

			// No longer need the reference on the boxShape, as the rigidBody now owns it
			bodyCinfo.m_shape->removeReference(); //changed
		}
		
		// Add the rigidBody to the world
		world->addEntity(rigidBody);
Bild des Benutzers spectre-srs

I still don't get it, like, at all. What is proper spell to load some rigid bodies from files? Is anywhere is a tutorial? The documentations do nothing, i can't understand what i supposed to do to toss some custom geometry into runtime :(.
//Other works fine, managed to plug Havok into Ogre, discarded for now my multithreading, runtime created geometry works too, but why so much trouble with serializing..

Bild des Benutzers havokTyler
Best Reply
resource->getContents();

is not correct unless the only thing in the file is an hkpRigidBody.

It looks like you are trying to load rigid bodies that were exported from the Havok content tools with Max or Maya. The exporter writes the entire physics scene, which is a collection of physics systems which contain rigid bodies. Loading a physics scene from the content tools exporter is common in many of the demos. A good example is in Demo\Demos\Common\Api\Serialize\SimpleLoad\SimpleLoadDemo.cpp

So it's going to look something like this:

hkIstream loadFileStream( filename );
hkResource* resource = hkSerializeUtil::load( loadFileStream.getStreamReader() );
if( resource != HK_NULL )
{
	if( hkRootLevelContainer* container = resource->getContents() )
	{
		hkpPhysicsData* physicsData = static_cast( container->findObjectByType( hkpPhysicsDataClass.getName()) );
		if( physicsData != HK_NULL )
		{
			// Add all the physics systems to the world
			for ( int i = 0; i < physicsData->getPhysicsSystems().getSize(); ++i )
			{
				world->addPhysicsSystem( physicsData->getPhysicsSystems()[i] );
			}
		}
	}
}
Bild des Benutzers spectre-srs

"is not correct unless the only thing in the file is an hkpRigidBody."
Well it's meant to be, i have one simple box for test in .hkx file, i exported it from max via content tools basic metod + prune data, should i export it some special way to have single body per file? I wanted to have pointers for loaded bodies, like load single body and attach it's XYZ-ROT to visual model.

"A good example is in Demo\Demos\Common\Api\Serialize\SimpleLoad\SimpleLoadDemo.cpp"
Tried earlier to replace hkx file that this demo uses with my own, crashed) Still loads other replaced demo files without problems. But content tools stand-alone loads my file fine, box even starts to fall due to gravity, i wonder why it crashes havok. //Always re-checking with reliable file from serialize demo (WindChime2_L4101.hkx) to see on which side problem is, demo refuses to load my box, while in my app it refuses to load anything.
//Can't try demos code directly in my app, had trouble locating origin of "m_loadedData" to compile it.

Thanx for code, it don't crashes, but don't loads anything either. it fails at "if( resource != HK_NULL )" check, with my box and with WindChime2_L4101.hkx too.

Bild des Benutzers havokTyler

i have one simple box for test in .hkx file, i exported it from max via content tools basic metod + prune data, should i export it some special way to have single body per file?

Let me clarify: If you export using the content tools it exports data about the entire scene. If there is only one body in the scene, you still have to inspect the scene and pull out the single body. The above code does this: Load the file, get the 'root container' object, look in it for the physicsData object, then get the physics systems (which each contain a list of rigid bodies) from that. If there is only one body in the scene, then there will be only one physics system with one body in it.

You will want to modify the above code to do something like:

hkpRigidBody* body = physicsData->getPhysicsSystems()[0]->getRigidBodies()[0];

Thanx for code, it don't crashes, but don't loads anything either. it fails at "if( resource != HK_NULL )" check, with my box and with WindChime2_L4101.hkx too.

If the resource is null then it failed to load the file. Check to make sure you're using the right file path and file name.

Cheers,
Tyler

Bild des Benutzers spectre-srs

So .hkx(and other formats) is a scene, but if i made it to contain only one rigid body, i can reliable find it in 0th slot? Thanx, thats enlights things a little.

I have file "Caropca.hkx" in the same directory as my executable, simple load demo seems to use relative path ("Resources/Common/Api/Serialize/SimpleLoad" + fileName), so i try to load file as loadFileStream( "Caropca.hkx" );, doesn't looks like path problem.
//Even if my file defective, loadFileStream( "WindChime2_L4101.hkx" ); ends without resource too.

Bild des Benutzers havokTyler

So .hkx(and other formats) is a scene, but if i made it to contain only one rigid body, i can reliable find it in 0th slot?

Correct.

Since it fails to load the WindChime file it sounds like your other problem still sounds like a file path problem. You can test the file stream like this :

loadFileStream.isOk() // returns false if it failed to find and open the file.

If the isOk() fails then you know the problem lies in opening the file. Are you building in debug? Check the console to see if any error or warnings are being printed.

-Tyler

Bild des Benutzers spectre-srs

Yes, i'm building in debug, and there's no file-related errors in console.

isOk() returns status about last load attempt? Placed it right after if( resource != HK_NULL ){} part of code, returns true, so, its a patch problem then? Stream reader uses global or relative?

Bild des Benutzers havokTyler

hkIStream::isOk() returns true if the stream is valid (so in this case if it was able to open the file). A stream reader is not global.

If isOk() returns true but hkSerializeUtil::load() returns HK_NULL then there's something strange with the file. You can get extra error debug info by passing an hkSerializeUtil::ErrorDetails to the load function. Like this:

hkSerializeUtil::ErrorDetails loadError;
hkResource* resource = hkSerializeUtil::load( loadFileStream.getStreamReader(), &loadError );  
if( resource == HK_NULL )
{
    hkcout << "Failed to load '" << filename << "'(stream ok: " << loadFileStream.isOk() <<") error: [" << loadError.id << "] " << loadError.defaultMessage.cString() << "n";
}

Try that and check the console for an error message.

Bild des Benutzers spectre-srs

I'm using log.txt instead of console, so i modified message to output in char:
sprintf(log, "Failed to load 'WindChime2_L4101.hkx'(stream ok: %d) error: [%d] %s\n", loadFileStream.isOk(), loadError.id, loadError.defaultMessage.cString());

Failed to load 'WindChime2_L4101.hkx'(stream ok: 1) error: [7] Packfile versioning support is not linked. Versioning packfiles at runtime was deprecated in Havok-7.0.0.
To do so requires linking some deprecated code from Source/Common/Compat/Deprecated
If you are using hkProductFeatures.cxx, ensure you do not define HK_EXCLUDE_FEATURE_SerializeDeprecatedPre700.
Note that by default this pulls in a lot of code and data (mainly previous versions of hkClasses).
Some extra effort is required to strip the unused code and data but it will still cost several hundred Kb.
Alternatively, you can use Tools/PackfileConvert/AsseetCc2 to convert your packfiles the the latest version before loading.

Oops) undefined exclude, got another error:

.\Version\hkVersionPatchManager.cpp(831): [0x3F79DDB1] Warning: Source contains hkpEntity version 2, but 3 is the current version.
Make sure required patches are registered to update this class.
resource == HK_NULL!! //my error from if( resource != HK_NULL ) { ... } else { log.Log ( "resource == HK_NULL!!\n" );
Failed to load 'WindChime2_L4101.hkx'(stream ok: 1) error: [4] Unable to version contents, check warning log

Why havok complains about version? I used the same windchime file that uses demos from package. //I guess, i should try to convert files to the last version..

Bild des Benutzers havokTyler

That particular demo happens to be fairly old, and so its assets are out of date with the current source version. The demo framework includes code to load and patch old asset files so that this is not an issue.

The second warning you are seeing means you defined 'HK_EXCLUDE_FEATURE_RegisterVersionPatches'. Defining this prevents you from patching asset files from previous versions.

I wouldn't worry about updating the demo assets. Is it important for you to load old demo assets in your game at runtime? Have you tried loading your newly exported assets to see if they load without error? If loading very old assets is not important then I would recommend re-defining 'HK_EXCLUDE_FEATURE_SerializeDeprecatedPre700'.

Cheers,
Tyler

Bild des Benutzers spectre-srs

Right, had both of them, i think i copied entire code from one of the demos... WindChime finally loaded, more important - my rigid body too. Uncommented both excludes back on, still working with my model, created another one, convex, loaded too, updating meshes wasn't needed. //I didn't found folder "Tools/PackfileConvert/AsseetCc2" anyway, not in havok directory nor in standalone tools, though both have "Tools" folder.

Thanks so much Tyler, i finally can start doing something there.
By the way, is there any, emm, tutorials about havok functions and systems? All i could find - few very dry and technical documentations, which ships with havok.

Bild des Benutzers havokcormac

Hey, have a look at these videos which have recently gone up on Youtube.

Cormac

Bild des Benutzers Guillaume L.B.

Hello

The video there are nice to get started, but as soon as you go deeper with Havok (like multithreading)
It doesn't explain very specialized things. (And it's not it's purpose, those videos are more like an introduction to Havok)

I think the best way is to make your own experience with Havok, encounter issue and solve it so that you can remember things after that.

BTW, Is there any good book about Havok that someone recommand ?

Kissy

Bild des Benutzers spectre-srs

Yeah, nice videos, but as Kissy said, they are pretty upperbound. I used to make mods earlier, games had rather big amount of amateur tutorials on programming, problem highlights and stuff. But havok is standalone, and looks like have only official documentation, some information starvation occurs.

Bild des Benutzers spectre-srs

It's me again, with brand new logic problem, but i'll ask it here. I'm finally making something playable, but then i tried to introduce entities health, i stuck into something like dead end.

Firstly i created just a class which holds pointers to its physics and visual components, and syncs visual part with physical coordinats. Collision detection soon was around too, rockets consistently aplied impulses to targets and been removed after hit. But when i added health variable to my class, i realized i cant access my class from rigid body which been hit by rockets - it dosen't even knows it's been monitored by some custom class. At first i thought i could use static cast to bring me from rigid body to it's full class, but i didn't inherited from rigid body, so it is not even a part of my class.

Okay, lets inherit my class from rigid body, but another thing stopped me - i no longer creating rigid bodies runtime, i use serialized .hkx files for my physboxes. But they are hkpRigidBody'es, not my inherited class, which i can't export from 3d max.

I also tried to edit rigid body header to add health function internally, but Havok didn't liked my idea and crashed. What can i do to make rigid bodies loaded from binary file be part of complex entities?

Bild des Benutzers havok_josh
Hey spectre-srs!

A better approach would be to use the userData field in your hkpRigidBody to store a pointer back to your own object. All hkpWorldObjects (hkpRigidBody's parent class) contain this field.

In your game, you have a hkpRigidBody representing a player in the physics world. It gets hit with a rocket and you want to deduct some hit points. To achieve this, we do the following:

1. Add a CollisionListener that will be notified when a collision occurs.
2. Inside the CollisionListener's callback, you must check that the type of rigidBodyA (or B) is a rocket and the type of rigidBodyB (or A) is a character.
3. If this is a rocket-character collision then deduct hit points from the character.

A simple way this could work is to declare a class that looks something like this:

class MyUserDataT : public hkReferencedObject {
public:
HK_DECLARE_CLASS_ALLOCATOR(HK_MEMORY_CLASS_USER_4);
int m_hitPoints;
};
Then we can use it this way:
MyUserDataT *myData;
myData = new MyUserDataT();
myData->m_hitPoints = 10;
//our userData field now points to our object
characterRigidBody->setUserData((hkUlong)myData);

Inside your collision callback you can adjust hitpoints in the following manner:

virtual void contactPointCallback( const hkpContactPointEvent& event ) {
hkpRigidBody* bodyA = HK_NULL;
hkpRigidBody* bodyB = HK_NULL;              
{                     
bodyA = event.getBody(0);
bodyB = event.getBody(1);
}

//adjust hit points by figuring out which is the 
{                
hkpRigidBody* character = (bodyA->getUserData() != HK_NULL) ? bodyA : bodyB;                
//cast the userData field back to our datatype                
MyUserDataT *myData = (MyUserDataT *)(character->getUserData());                 
myData->m_hitPoints--;                
hkcout << "My hit points: " << myData->m_hitPoints << "n";                
if (myData->m_hitPoints <= 0) { hkcout << "Killed!n"; }
}
}

I would also recommend taking a look at this demo Physics | Api | Collide | Contact Point Callbacks | User Collision Response
to see how collision callbacks work. In fact, all the Contact Point Callbacks demos are useful.

Good luck!

-Josh

Josh Developer Support Engineer Havok www.havok.com
Bild des Benutzers spectre-srs

Oh, thank you, example with user data is very handy, thats what i can work with.

Melden Sie sich an, um einen Kommentar zu hinterlassen.