ややプログラム紀行

博士2年のプログラムに関する日記

Havok神のお怒りじゃあ!

やっと部活の合宿から帰ってきたー

おかげで結構更新の間結構空いた・・・

ちょっとHavokを触ってみようと思い立ち、毎度おなじみマルペケつくろーを参考にさせてもらったんですが、まさかのバージョン違いの壁によりコードが実行できず(´・ω・`)

なんとかサンプルコードを参照して実行できる形まで持って行ったので書いておこうと思います

今回はとりあえず箱と床の衝突判定ができればそれでいいってことで進めます

ちなバージョンは2012年版です

・インクルードディレクト

ダウンロードしたHavok SDKファイル内のSourceというファイル

・ライブラリディレクト

Havok SDKファイル内のLib\win32_vs2010_noSimd\debug(Visual Studio2010、コード生成がマルチスレッドデバッグの場合)

ここから実際のコードを書いていきます

・インクルード

// Keycode

#include <Common/Base/keycode.cxx>

// Productfeatures

// We're using only physics - we undef products even if the keycode is present so

// that we don't get the usual initialization for these products.

#undef HK_FEATURE_PRODUCT_AI

#undef HK_FEATURE_PRODUCT_ANIMATION

#undef HK_FEATURE_PRODUCT_CLOTH

#undef HK_FEATURE_PRODUCT_DESTRUCTION

#undef HK_FEATURE_PRODUCT_BEHAVIOR

#undef HK_FEATURE_PRODUCT_MILSIM

#undef HK_FEATURE_PRODUCT_NEW_PHYSICS

// Also we're not using any serialization/versioning so we don't need any of these.

#define HK_EXCLUDE_FEATURE_SerializeDeprecatedPre700

#define HK_EXCLUDE_FEATURE_RegisterVersionPatches

//#define HK_EXCLUDE_FEATURE_RegisterReflectedClasses

#define HK_EXCLUDE_FEATURE_MemoryTracker

// This include generates an initialization function based on the products

// and the excluded features.

#include <Common/Base/Config/hkProductFeatures.cxx>

#pragma comment(lib,"hkBase.lib")

#pragma comment(lib,"hkCompat.lib")

#pragma comment(lib,"hkSceneData.lib")

#pragma comment(lib,"hkSerialize.lib")

#pragma comment(lib,"hkVisualize.lib")

#pragma comment(lib,"hkInternal.lib")

#pragma comment(lib,"hkGeometryUtilities.lib")

#pragma comment(lib,"hkcdInternal.lib")

#pragma comment(lib,"hkcdCollide.lib")

#pragma comment(lib,"hkpCollide.lib")

#pragma comment(lib,"hkpConstraint.lib")

#pragma comment(lib,"hkpConstraintSolver.lib")

#pragma comment(lib,"hkpDynamics.lib")

#pragma comment(lib,"hkpInternal.lib")

#pragma comment(lib,"hkpUtilities.lib")

#pragma comment(lib,"hkpVehicle.lib")

#include <Common/Base/hkBase.h>

#include <Common/Base/Memory/System/Util/hkMemoryInitUtil.h>

#include <Common/Base/Memory/Allocator/Malloc/hkMallocAllocator.h>

#include <Common/Base/Fwd/hkcstdio.h>

#include <Physics/Dynamics/World/hkpWorld.h>

#include <Physics/Dynamics/Entity/hkpRigidBody.h>

#include <Physics/Dynamics/Entity/hkpRigidBodyCinfo.h>

#include <Physics/Utilities/Dynamics/Inertia/hkpInertiaTensorComputer.h>

#include <Physics/Collide/Shape/Convex/Box/hkpBoxShape.h>

#include <Physics/Collide/Dispatch/hkpAgentRegisterUtil.h>

※<、>は大文字にしてあります

まるぺけのサンプルと比べて大幅にインクルードファイルが多い(´Д`)

まあHavokについてたサンプルをコピペしたらコンパイル通ったのでこれがベストな書き方ってことでしょうかね

今回はPhysicsしか使わないので、ほかの機能は#undefすることで、余計にファイルをインクルードしなくて済んでるようです

・Havokの初期化

hkMemoryRouter* memoryRouter = hkMemoryInitUtil::initDefault(hkMallocAllocator::m_defaultMallocAllocator, hkMemorySystem::FrameInfo(1024*1024));

hkBaseSystem::init(memoryRouter, HavokErrorReportFunction);

このinitDefault関数が、まるぺけだと引数なしになっていますが、2012年版だと引数が2つ必要なようです

1つめの引数にはデフォルトのアロケーターを、2つめのFrameInfoにはサンプルと同じ1024*1024を渡してます

・Worldの初期化

hkpWorldCinfo info;

info.m_gravity.set( 0,-9.8f,0);

info.m_collisionTolerance = 0.1f;

info.setBroadPhaseWorldSize( 10000.0f );

info.setupSolverInfo( hkpWorldCinfo::SOLVER_TYPE_4ITERS_MEDIUM );

info.m_simulationType = hkpWorldCinfo::SIMULATION_TYPE_CONTINUOUS; // Default

hkpWorld* world = new hkpWorld( info );

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

これはまるぺけと同じなんで、詳しくはそこを見てください

・床の作成

hkVector4 halfExtents(2000.0f, 20.0f, 2000.0f);

hkpShape* groundShape = new hkpBoxShape(halfExtents);

hkpRigidBodyCinfo bodyInfo;

bodyInfo.m_mass = 0.0f;

bodyInfo.m_shape = groundShape;

bodyInfo.m_motionType = hkpMotion::MOTION_FIXED;

bodyInfo.m_position.set(0.0f, -10.0f, 0.0f);

hkpRigidBody* groundBody = new hkpRigidBody(bodyInfo);

groundShape->removeReference();

world->addEntity(groundBody);

groundBody->removeReference();

ここもまるぺけと同じっすね

滅茶苦茶でかい床を作るからと言って、Worldより大きい床を作るとプログラムが止まるので注意してください(まんまと引っかかったわ・・・(´Д`))

・箱の作成

hkVector4 boxExtent(1.0f, 2.0f, 1.0f);

hkpShape* boxShape = new hkpBoxShape(boxExtent);

hkMassProperties massProperties;

hkpInertiaTensorComputer::computeShapeVolumeMassProperties(boxShape, 5.0f, massProperties);

hkpRigidBodyCinfo boxInfo;

boxInfo.m_mass = massProperties.m_mass;

boxInfo.m_centerOfMass = massProperties.m_centerOfMass;

boxInfo.m_inertiaTensor = massProperties.m_inertiaTensor;

boxInfo.m_shape = boxShape;

boxInfo.m_motionType = hkpMotion::MOTION_BOX_INERTIA;

hkpRigidBody* boxBody = new hkpRigidBody(boxInfo);

boxShape->removeReference();

boxBody->setPosition(hkVector4(0.f, 100.0f, 0.0f));

world->addEntity(boxBody);

boxBody->removeReference();

ここもまるぺけとほとんど変わらず

さっきの床にも言えますが、boxExtentで指定した値の2倍の大きさの物体が作られるので、それに合わせて描画するようにしてください

・Worldの更新

world->stepDeltaTime(1.0f/60.0f);

使いやすくてありがたや

・箱の座標の取得

const hkTransform& t = boxBody->getTransform();

カメラの注視点に使いました、正確には行列を取得しています

まるぺけでも書いてありましたが、この行列はD3DXMATRIXと配置が違うので使うときは並べ替える必要があります

また、X座標はt(0,3)、Y座標はt(1,3)、Z座標はt(2,3)とやれば取得できます

・後片付け

world->removeReference();

hkBaseSystem::quit();

hkMemoryInitUtil::quit();

まるぺけだとworldの消去にdeleteを使ってましたが、hkpWorldもhkpRigidBodyなどと同じように参照カウンタみたいなのがあるので、removeReferenceが使えます

これでメモリリークは0でした

とりまこれで箱を落下させて衝突判定させることはできる

最初実行できたときは謎の感動があったわ・・・

正直、自分もHavok触ったばっかりなのでこの記事も間違ってるかも

他にもオブジェクトの移動とかやってみたいのでもしかしたらほかにも記事にするかもしれないです

ただ、hkpBoxShapeで、引数2つに出来るんだけど、2つめのhkConvexShapeDefaultRadiusって何のことだろう・・・

分かったらまた書きます(´・ω・`)

追記

こんなのがあった

要するにConvex Radiusをある程度取っておくと、あたり判定でありがちな貫通がしにくくなるってことかな・・・