Quantcast
Channel: Intel® Developer Zone - Havok
Viewing all 168 articles
Browse latest View live

Creating a simple game using Havok Physics

$
0
0

Hi everybody,
Here is an article describing how to build a simple 3D physics-based game using Havok 2011.3. The article has also been published on Game Coder Magazine Physics some weeks ago. Enjoy!

Physics is a crucial part of almost any modern 3D game, think about how objects move in a physically plausible way in The Elders Scrolls V: Skyrim (Bethesda Softworks) when you cast a spell on a pile of objects, or how buildings can be destroyed using rocket launchers or tanks in Battlefield 3 (EA DICE). Those titles rely on the services of the Havok Physics engine to move those objects in a physical way. While Havok is not the only company providing physics simulation capabilities to game developers, the Havok Physics engine is surely one of the most appreciated in the AAA market.

In this article we'll learn how to build a very simple physics-based game using Havok Physics. The game will be written in C++. A small Visual Studio 2010 project for this game can be downloaded from here, the archive contains all the code we are going to explain in this article.

Physical simulation is just one of the several components needed when building complex 3D games: graphics, user input and sound are also very important topics. This article will focus on Havok Physics usage, but the small game we are about to develop also requires some graphics capabilities and some user input control loop. For space reasons, we are not going to look closely at the code needed to render the 3D scene or establish the game loop in this game, but here is an overview of the components used:

  • The freeglut library is used to create the game window, establish the game loop and control user input. Freeglut is an open source alternative to the OpenGL Utility Toolkit (GLUT) with almost identical functionalities, but it also supports more recent versions of the OpenGL standard. Freeglut can be downloaded from http://freeglut.sourceforge.net/.
  • A small set of rendering functions have been written to draw the various objects in the scene, those functions also use freeglut services to draw simple primitives, this is all we need for the graphics side of our game and it's not even 150 lines of code. We are not going to look closely at those functions, but we'll learn what they basically do. Have a look at the full source download if you are interested.
  • The free, binary-only PC distribution of Havok Physics and Animation is used to access the services of the Havok Physics engine. This package can be downloaded from http://www.havok.com/solutions/students-and-education and contains full documentation, a complex demo framework to explore and understand the different features of Havok Physics and Animation, various tools and of course the precompiled havok libraries needed to build the game. We will use version 2011.3 of the Havok Physics and Animation SDK.

Let's now establish the gameplay rules for our small game.

In this small game the player controls a sphere that can roll on the surface of a plane, this works by applying torques to the ball based on user input. When a torque is applied to the ball, the friction between the ball and the plane will cause the ball to move around on the plane. The plane is not static, it behaves like if it was pinned in its center, so that it can rotate around it. This means that when the ball moves away from the center, the plane will rotate thanks to the weight of the ball. We'll also make sure that the rotation is limited to a maximum angle so that the ball doesn't fall off too easily. The objective of the game is to bring the ball inside two active areas on the plane without falling off.


Figure 1: waiting for user input to begin.


Figure 2: game started - the ball is at the center of the plane and the system is stable.


Figure 3: when the ball moves away from the center, the plane rotates around it's center because of the ball weight.


Figure 4: the player has to bring the ball inside the active areas on the plane to win the game.


Figure 5: when the player hits both areas without falling, the game ends.

Notice that we are relying on concepts such as friction and weight, which are physics concepts. The Havok Physics engine will make sure that everything happens as programmed.

Ok, we are now ready to have a look at the code.

Havok provides an easy way to control the size of the Havok code footprint in memory, this is based on a series of macros that might be defined to exclude or include specific Havok features. The following code listing shows how to do that for our simple game.

/* GAME CODE */
#include <Common/Base/keycode.cxx>
 
// we're not using any product apart from Havok Physics.
#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
 
// 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_MemoryTracker
 
#include <Common/Base/Config/hkProductFeatures.cxx>

hkProductFeatures.cxx is a file that must be always included in one of your game's translation units (.cpp files), several preprocessor macros might be defined prior to including it to exclude specific features. keycode.cxx must be included before hkProductFeatures.cxx and will define macros like HK_FEATURE_PRODUCT_* depending on the valid keycodes that your distribution contains (for the free binary-only distribution, Havok provides valid keycodes for Physics and Animation). Those macros can then be undefined if a specific product is not required, like Animation in our case. After including keycode.cxx, but before including hkProductFeatures.cxx, we might exclude additional features with macros like HK_EXCLUDE_FEATURE_*.

The following snippet shows the global structure holding all game data.

// GameData structure
/* This structure represent all the data associated with a game instance,
 * this includes persistent data for Havok engine operations,
 * variables used for user input, and game status variables.
 */
struct GameData {
    // Havok persistent objects
    hkpWorld* m_world;
    hkpRigidBody* m_sphereBody;
    hkpRigidBody* m_planeBody;
    #ifdef DEBUG
        hkVisualDebugger* m_vdb;
        hkpPhysicsContext* m_physicsContext;
    #endif
 
    // Sphere movement variables
    hkReal m_forward, m_strife; // variables for WASD movement
 
    // Game state
    enum StateEnum
    {
        STARTING = 0, // not started yet
        RUNNING, // game is running
        FINISHED // game finished
    };
    // Game state
    hkEnum<StateEnum, hkUint8> m_status;
    // Data associated with a specific game state
    /* STARTING:
        *     nothing
        * RUNNING:
        * FINISHED:
        *     binary 00000001 -> activated first phantom
        *     binary 00000010 -> activated second phantom
        */
    hkUint8 m_statusData;
 
    // Default constructor
    GameData()
    {
        m_world = NULL;
        m_sphereBody = NULL;
        m_planeBody = NULL;
        #ifdef DEBUG
            m_vdb = NULL;
            m_physicsContext = NULL;
        #endif
        m_forward = 0.0f;
        m_strife = 0.0f;
        m_status = STARTING;
        m_statusData = 0x00;
    }
 
    // Function to reset everything in the GameData object
    void reset()
    {
        // reset everything
        m_sphereBody->setPositionAndRotation(hkVector4(0.0f, 0.6f, 0.0f),
            hkQuaternion::getIdentity());
        m_sphereBody->setLinearVelocity(hkVector4(0.0f, 0.0f, 0.0f));
        m_sphereBody->setAngularVelocity(hkVector4(0.0f, 0.0f, 0.0f));
        m_planeBody->setPositionAndRotation(hkVector4(0.0f, 0.0f, 0.0f),
            hkQuaternion::getIdentity());
        m_planeBody->setLinearVelocity(hkVector4(0.0f, 0.0f, 0.0f));
        m_planeBody->setAngularVelocity(hkVector4(0.0f, 0.0f, 0.0f));
        m_forward = 0.0f;
        m_strife = 0.0f;
        m_statusData = 0x00;    
    }
} g_gameData;

This structure represents all data we need to keep track of while running the game. A single instance of this structure (g_gameData) is created to be used by all game functions (this is basically equivalent to having a group of global variables, but with better encapsulation). The first set of objects are pointers to Havok objects and are used to retrieve information about the running simulation (such as object position and rotation). The real members m_forward and m_strife are used to apply player actions on the ball. m_status represents the current game status. We are using a Havok hkEnum as type for m_status, which is basically a C++ enum with specified storage (in this case 8 bits). There are 3 possible game states:

  • STARTING: the game is ready, we are waiting for user input to begin.
  • RUNNING: the game is running, it will run until the ball falls off or the player wins the game.
  • FINISHED: the game is finished, either because the player won or because the ball fell off. The user than has the option to play again (going back to the STARTING state).

m_statusData represents some additional data associated with a specific state, when the game is RUNNING we need to remember which active areas on the plane were hit by the player.

Apart from the structure members, we also have a default constructor to set some initial meaningful values and a reset() function which is used to return to the original situation when the user wants to play another match. The reset function calls some methods on m_sphereBody and m_planeBody (that is the ball and the plane), those are objects of the hkpRigidBody class (part of Havok Physics). The purpose of reset() is clear: it stops the ball and the plane by setting their linear and angular velocities to zero, and resets their positions to some original value.

Notice that m_vdb and m_physicsContext are only present in the structure if the application is compiled in debug mode. The Havok binary-only distribution ships with the Havok Visual Debugger application (VDB), the VDB is a very important tool when programming physics simulation in a game as it shows the view that the physics engine has of the game world. In our case all objects (the sphere and the plane) will be rendered exactly as they are simulated by the physics engine, but in a real game the physics world will usually be way simpler than the graphics world (e.g. when you have a complex geometry with hundreds of thousands of polygons it is usually sufficient to use a simplified version of the shape to obtain fairly good results in term of physical simulation of the geometry). The VDB connects to the game as a client connects to a server in a client-server networked game, but because establishing and mantaining this connection requires resources we only allow that when the game is compiled in debug mode (so that we don't have any extra overhead when releasing the game).

Let's now have a look at how the game is initialized.

// Havok error reporting function
static inline void HK_CALL errorReport(const char* msg, void* userContext)
{
    std::cerr << msg << std::endl;
}
 
// Initialization function
void OnInit() {
    // Initialize Havok
    // The frameinfo buffer must NOT be zero if physics is being used
// (it is the solver buffer)
#ifdef DEBUG
    hkMemoryRouter* memoryRouter = hkMemoryInitUtil::initChecking(
hkMallocAllocator::m_defaultMallocAllocator, hkMemorySystem::FrameInfo(1024*1024) );
#else
    hkMemoryRouter* memoryRouter = hkMemoryInitUtil::initDefault(
hkMallocAllocator::m_defaultMallocAllocator, hkMemorySystem::FrameInfo(1024*1024) );
#endif
 
    hkBaseSystem::init( memoryRouter, errorReport );
    {
        // Create the simulation world
        {
            hkpWorldCinfo worldInfo;
            worldInfo.m_gravity.set(0.0f,-9.8f,0.0f);
            worldInfo.setBroadPhaseWorldSize(10.0f);
            g_gameData.m_world = new hkpWorld(worldInfo);
            // This is needed to detect collisions
            hkpAgentRegisterUtil::registerAllAgents( g_gameData.m_world->
getCollisionDispatcher() );
        }
#ifdef DEBUG
        // Connect to the visual debugger
        {
            g_gameData.m_physicsContext = new hkpPhysicsContext();
            g_gameData.m_physicsContext->addWorld( g_gameData.m_world );
            hkpPhysicsContext::registerAllPhysicsProcesses();
            hkArray<hkProcessContext*> contexts;
            contexts.pushBack( g_gameData.m_physicsContext ); 
            g_gameData.m_vdb = new hkVisualDebugger( contexts );
            g_gameData.m_vdb->serve();
        }
#endif
        // Create a sphere
        {
            hkpSphereShape* sphere = new hkpSphereShape(0.07f);
            // convex radius for spheres is exactly the sphere radius
            hkpRigidBodyCinfo rigidBodyInfo;
            rigidBodyInfo.m_shape = sphere;
            rigidBodyInfo.m_motionType = hkpMotion::MOTION_DYNAMIC;
            hkpInertiaTensorComputer::setShapeVolumeMassProperties(
                sphere, 1.0f, rigidBodyInfo);
            rigidBodyInfo.m_position.set(0.0f, 0.6f, 0.0f);
            rigidBodyInfo.m_friction = 1.0f;
            rigidBodyInfo.m_restitution = 0.2f;
 
            g_gameData.m_sphereBody = new hkpRigidBody(rigidBodyInfo);
            sphere->removeReference();
       
            g_gameData.m_world->addEntity(g_gameData.m_sphereBody);
        }
        // Create the level (plane) with the two phantom shapes
        {
            hkpRigidBodyCinfo rigidBodyInfo;
            hkArray<hkpShape*> shapeArray;
            {
                hkpBoxShape* planeBox = new hkpBoxShape(hkVector4(0.5f, 0.03f, 0.5f));
                planeBox->setRadius(0.005f); // adjust the convex radius to the usage
                shapeArray.pushBack(planeBox);
                hkpInertiaTensorComputer::setShapeVolumeMassProperties(planeBox, 10.0f,
rigidBodyInfo);
            }
            {
                MyPhantomShape1* phantom1 = new MyPhantomShape1();
                hkpBoxShape* box1 = new hkpBoxShape(hkVector4(0.1f, 0.08f, 0.1f));
                box1->setRadius(0.0f); // no need for convex radius here
                hkpConvexTranslateShape* transformBox1 = new hkpConvexTranslateShape(box1,
hkVector4(-0.4f, 0.11f, 0.4f), hkpShapeContainer::REFERENCE_POLICY_IGNORE);
                hkpBvShape* activeBox1 = new hkpBvShape(transformBox1, phantom1);
                phantom1->removeReference();
                transformBox1->removeReference();
                shapeArray.pushBack(activeBox1);
            }
            {
                MyPhantomShape2* phantom2 = new MyPhantomShape2();
                hkpBoxShape* box2 = new hkpBoxShape(hkVector4(0.1f, 0.08f, 0.1f));
                box2->setRadius(0.0f); // no need for convex radius here
                hkpConvexTranslateShape* transformBox2 = new hkpConvexTranslateShape(box2,
hkVector4(0.4f, 0.11f, -0.4f), hkpShapeContainer::REFERENCE_POLICY_IGNORE);
                hkpBvShape* activeBox2 = new hkpBvShape(transformBox2, phantom2);
                phantom2->removeReference();
                transformBox2->removeReference();
                shapeArray.pushBack(activeBox2);
            }
            hkpListShape* level = new hkpListShape(&shapeArray[0], shapeArray.getSize(),
hkpShapeContainer::REFERENCE_POLICY_IGNORE);
 
            rigidBodyInfo.m_shape = level;
            rigidBodyInfo.m_motionType = hkpMotion::MOTION_DYNAMIC;
            rigidBodyInfo.m_position.set(0.0f, 0.0f, 0.0f);
            rigidBodyInfo.m_friction = 1.0f;
            rigidBodyInfo.m_restitution = 0.5f;
            g_gameData.m_planeBody = new hkpRigidBody(rigidBodyInfo);
            level->removeReference();
 
            g_gameData.m_world->addEntity(g_gameData.m_planeBody);
        }
        // Create constraint on the level
        {
            hkpGenericConstraintData* data = new hkpGenericConstraintData();
            hkpConstraintConstructionKit kit;
            kit.begin(data);
            {
                kit.setPivotA(hkVector4(0.0f, 0.0f, 0.0f));
                kit.setPivotB(hkVector4(0.0f, 0.0f, 0.0f));
                kit.constrainAllLinearDof();
                kit.setAngularBasisABodyFrame();
                kit.setAngularBasisBBodyFrame();
                kit.setAngularLimit(0, -ANGLE_LIMIT, ANGLE_LIMIT);
                // do not limit rotation around Y axis
                kit.setAngularLimit(2, -ANGLE_LIMIT, ANGLE_LIMIT);
            }
            kit.end();
            hkpConstraintInstance* constraint = new hkpConstraintInstance
(g_gameData.m_planeBody, NULL, data);
            g_gameData.m_world->addConstraint(constraint);
            data->removeReference();
            constraint->removeReference();
        }
    }
 
    // initialize graphics
    initGraphics();
}

This listing is where the core Havok initialization and configuration takes place.

The first two operations are always the same when using the Havok engine: initialize the memory system (with hkMemoryInitUtil::init*()) and initialize the base system (with hkbaseSystem::init()). Note that initialization of the memory system is different when debugging the application, this is because in debug mode we are using a checking memory system. A checking memory system is less efficient than the default one, but performs some analysis on the memory used and when exiting the program it will highlight any Havok memory leak encountered during execution.

The next step is to create the simulation world, this happens by creating a new hkpWorld object. We do that by also setting a gravity vector to the real world gravity value (9.8 m/s2 towards -Y, and a new size for the collision detection broadphase (which means that we are optimizing collision detection performances to our scene). The broadphase size represents the side of a cube centered at the origin; generally, this cube should be large enough to encompass the whole scene, but not excessively larger than that.

When considering distances and masses in Havok we need to understand that by default the Havok engine works in meters and kilograms. If a different scale is being used, the most common approach is to scale up or down all the values that the game passes to Havok (like the value of the gravity vector). In any case, the unit scale of the engine cannot be changed by a large factor because of several hard-coded numerical tolerances in the engine. This practically means that using feet instead of meters is simple, but millimiters cannot be used.

After creating the physics world, we create the visual debugger object that will serve connections from the VDB application. This is done only when the application is configured in debug mode.

Now we have to actually create the rigid bodies that Havok Physics will simulate, and establish all the simulation parameters for those bodies. A Havok rigid body is an object of class hkpRigidBody, and it has a reference to a shape object which represents the geometry used for physical simulation. In the case of the sphere we create an hkpSphereShape having radius of 7 cm to be used as shape for the sphere rigid body. A rigid body might be configured as a dynamic object by setting m_motionType to be hkpMotion::MOTION_DYNAMIC (which is also the default value). A dynamic object is a fully-simulated, movable rigid body.

When creating a rigid body, we also have to set its mass properties. The mass value describes how the object reacts to translation actions performed on it (e.g. a force applied in its center of mass), but we also need to set the inertia tensor which describes how the object reacts to rotation actions such as torques. Computing the inertia tensor given the mass and shape of an object is very complicated even when the body density is constant, fortunately Havok provides a utility function to do that inside the hkpInertiaTensorComputer class.

Finally, we set some physical material properties for the sphere, a friction coefficient and a restitution value (which represents the elasticity of an object and governs velocities after collisions - it is the "bounciness" of an object).

Also note that we set a starting position for the sphere rigid body, this is slightly above the plane (60 cm) so that the first thing that will happen will be the sphere falling directly on the center of the plane.

When the sphere rigid body is built, it is assigned to the global storage g_gameData.m_sphereBody, and then we call removeReference() on the sphere shape. Shapes, like rigid bodies, are reference counted objects in Havok Physics. This is because shapes can be shared between rigid bodies and therefore when destroying a rigid body we can't always destroy its shape (because it might be used by other rigid bodies). By keeping track of the number of references to a shape, we can safely delete it when the counter drops down to zero (all referencing entities were destroyed). The reference counter is initialized to 1 (that is one user-owned reference) and when the rigid body is constructed it will add a new reference to the sphere shape, so that then the new value of the counter is 2. When closing the application we will destroy the sphere body by calling g_gameData.m_sphereBody->removeReference(), but this will not cause deletion of the sphere shape is the counter doesn't drop to 0. Therefore, after creation of the sphere body, we drop our reference to the sphere shape, the shape will not be destroyed because the sphere rigid body still owns a reference to it.

The last step for the sphere is the addition of the rigid body to the physics world, using the addEntity() function. Which registers the sphere as an entity in the physically simulated world.

Creation of the plane rigid body proceeds similarly, but there are a few important differences. First of all, we are not using a simple shape for the plane, but an hkpListShape, which represents a list of shapes. The reason for doing this is that while the plane itself will be represented by a simple hkpBoxShape, we also have to attach to the plane the two active box-shaped zones.

We start by creating the simple box shape that represents the main body of the moving plane, the only interesting thing to note here is that we are using the setRadius() function to set a specific value for the convex radius of the hkpBoxShape. The convex radius represents an extra "shell" around a convex shape which is actually used for collision detection and represents the effective surface of the object for the Physics engine. This approach is used because the core convex-convex collision detection algorithm is faster when the two shapes are not actually interpenetrating, adding a shell around the shapes makes it less likely that the shapes themselves will interpenetrate. The default values for the radius is 5 cm, which we change to 5 mm because 5 cm is too large for our small scene (and it would result in a visible gap between the objects). We add the new created hkpBoxShape to an array of shapes that we will then use to build the hkpListShape.

There are multiple ways in Havok Physics to build active zones that allow execution of user-provided code when objects enter or leave a volume. In our case we will be using two shapes of type hkpPhantomCallbackShape. This shape represents a "phantom" shape and has no physical effect in the scene apart from triggering events when other shapes interact with it. To build such a shape we have to derive a new class from hkpPhantomCallbackShape (which is abstract) and implement the two callback events (when something enters or leaves the area). Let's assume we derived two classes MyPhantomShape1 and MyPhantomShape2.

An hkpPhantomCallbackShape is usually used as child for an hkpBvShape. An hkpBvShape associates with any shape (in our case a hkpPhantomCallbackShape) a specified bounding volume shape. This practically means that the action specified our hkpPhantomCallbackShapes will be triggered when an object enters or exits their bounding volume. As bounding volumes we are using shapes of type hkpConvexTranslateShape. This is basically a shape that represents a standard convex shape (like an hkpBoxShape) translated by some vector, and is very handy to position child shapes correctly in an hkpListShape. Construction of an hkpConvexTranslateShape requires a convex shape and a translation vector, we are using hkpBoxShapes as convex shapes, and the translation specifies where to position the phantom shapes on the plane. The extra hkpShapeContainer::REFERENCE_POLICY_IGNORE argument simply says that the reference counter for the child box shape should not be incremented (by doing this, we can avoid removing a reference on the hkpBoxShape while still getting proper cleanup).

After having created the plane hkpBoxShape and the two active shapes, we may produce the final hkpListShape which represents the whole game level, this shape is then used to build the plane rigid body in the same way we did for the sphere.

We now have the two bodies in our physical world, the shape and the plane with the active shapes. Both of them are dynamic, which means they are affected by all physical actions such as gravity, collisions, etc... If we leave everything as it is, both the sphere and the plane will fall down because of gravity. We are therefore going to create a constraint on the plane: we want the plane to rotate around its center, but we don't want it to translate at all.

There are various types of constraints in Havok. For our small game we are going to build a generic constraint using the constraint construction kit (hkpConstraintConstructionKit). A constraint always works between two bodies, and when building a generic constraint we have to specify the relative degrees of freedom of the two. We start by specifying the two pivots, which are the two points on the objects that will be constrained by any linear condition. We specify the two pivot as being in the center of their relative objects frames, and then remove all linear degrees of freedom using constraintAllLinearDof(). This means that the two pivots should always be in the exact same position. The next task is setting the angular constraint basis for the two objects, and in our case we set them to the respective body frames. Using then setAngularLimit(), we enforce a limit on the rotation around X and Z (ANGLE_LIMIT represents a 7 degrees angle in radians).

To finally build the constraint, we use the hkpGenericConstraintData obtained using the constraint construction kit to create an hkpConstraintInstance. We pass plane rigid body and HK_NULL (NULL pointer) to the constructor. When the second object is NULL, Havok Physics implicitly assumes that we are referring to the world fixed body, which is exactly what we want here. After having obtained the constraint instance, we just add it to the physics world using addConstraint().

The last operation of the initialization function is initGraphics(), which basically initializes OpenGL to perform rendering, we'll not look at the body of any rendering function in this article, but the full source is available for download from here.

We saw that two concrete classes MyPhantomShape1 and MyPhantomShape2, inheriting from hkpPhantomCallbackShape, are necessary in the initialization function. The following listing shows their full code.

// Phantom shape class used for the first active area
class MyPhantomShape1 : public hkpPhantomCallbackShape
{
    public:
        void phantomEnterEvent(const hkpCollidable* phantomColl,
            const hkpCollidable* otherColl, const hkpCollisionInput& env)
        {
            g_gameData.m_statusData |= 0x01; // first phantom active
        }
 
        void phantomLeaveEvent( const hkpCollidable* phantomColl,
            const hkpCollidable* otherColl )
        {}
 
        MyPhantomShape1() : hkpPhantomCallbackShape() {}
        MyPhantomShape1( hkFinishLoadedObjectFlag flag ) : hkpPhantomCallbackShape(flag) {}
};
 
// Phantom shape class used for the second active area
class MyPhantomShape2 : public hkpPhantomCallbackShape
{
    public:
        void phantomEnterEvent(const hkpCollidable* phantomColl,
            const hkpCollidable* otherColl, const hkpCollisionInput& env)
    {
            g_gameData.m_statusData |= 0x02; // second phantom active
        }
 
        void phantomLeaveEvent( const hkpCollidable* phantomColl,
            const hkpCollidable* otherColl )
        {}
 
        MyPhantomShape2() : hkpPhantomCallbackShape() {}
        MyPhantomShape2( hkFinishLoadedObjectFlag flag ) : hkpPhantomCallbackShape(flag) {}
};

The action triggered when an object leaves the active area will do nothing, when an object enters the active area we will set one of the two phantoms as active in the g_gameData structure (depending on which shape was triggered).

Before examining the function that handles rendering of the scene and stepping of the physical simulation, let's have a look at the deinitialization function.

void OnExit() {
    deinitGraphics();
 
    // delete havok entities
    {
        g_gameData.m_planeBody->removeReference();
        g_gameData.m_sphereBody->removeReference();
#ifdef DEBUG
        g_gameData.m_vdb->removeReference();
        g_gameData.m_physicsContext->removeReference();
#endif
        g_gameData.m_world->removeReference();
    }
    hkBaseSystem::quit();
    hkMemoryInitUtil::quit();
}

Nothing surprising here, we remove all retained references to Havok objects, and then simply quit the havok memory and base system. The first operation is the deinitialization of the graphics system (because the last operation during initialization was initGraphics()).

The next listing contains the rendering and simulation stepping function.

// Render the whole game scene
static void renderScene(bool firstPhantomActive, bool secondPhantomActive)
{
    beginSceneRendering();
        drawSphere(g_gameData.m_sphereBody->getPosition());
        drawPlane(g_gameData.m_planeBody->getRotation(),
            firstPhantomActive,
            secondPhantomActive);
    endSceneRendering();
}
 
// Frame rendering function
void OnFrame() {
    switch(g_gameData.m_status)
    {
        case GameData::STARTING:
            {
                renderScene(false, false);
                drawText("Game Ready - Press SPACE to begin");
            }
            break;
        case GameData::RUNNING:
            {
                g_gameData.m_sphereBody->applyTorque(FRAME_PERIOD,
                    hkVector4(-g_gameData.m_forward, 0.0f, -g_gameData.m_strife));
 
                g_gameData.m_world->stepDeltaTime(FRAME_PERIOD);
                #ifdef DEBUG
                    g_gameData.m_vdb->step(FRAME_PERIOD);
                #endif
 
                bool firstPhantomActive = g_gameData.m_statusData & 0x01;
                bool secondPhantomActive = g_gameData.m_statusData & 0x02;
 
                renderScene(firstPhantomActive, secondPhantomActive);
 
                const hkVector4& spherePos = g_gameData.m_sphereBody->getPosition();
                if( (firstPhantomActive && secondPhantomActive) || // won the game
                    (spherePos.getComponent(1) < -4.0f) ) // lost the game
                {
                    g_gameData.m_status = GameData::FINISHED;
                }
            }
            break;
        case GameData::FINISHED:
            {
                bool firstPhantomActive = g_gameData.m_statusData & 0x01;
                bool secondPhantomActive = g_gameData.m_statusData & 0x02;
 
                renderScene(firstPhantomActive, secondPhantomActive);
                drawText("Game Over - Press SPACE to continue");
            }
            break;
    }
}

When launched, the game is in status STARTING, this means that every frame we will just call renderScene() and drawText(). renderScene() is a simple function that renders the whole scene using some simple graphics utility function which we are not going to examine, it draws the sphere in the position returned by g_gameData.m_sphereBody->getPosition() and also draws the plane using the orientation returned by g_gameData.m_planeBody->getRotation() (that is it draws the objects in the positions and orientations suggested by the physics engine). When drawing the plane, we also pass in two flags specifying the state of the active areas (this way we are able to use different colors depending on whether the phantoms have already been touched). On startup, the sphere position and plane orientation will be the initial ones, we are also specifying explicitly that the two active zones are both disabled at the beginning. drawText() is a simple OpenGL based function that allows rendering of some given string in the upper left corner of the viewport.

When the space bar is pressed, the game enters status RUNNING, the state transiction happens in the code that handles user input, and is not shown in this listing. While in status RUNNING, every frame, we apply a torque to the ball based on the two variables g_gameData.m_forward and g_gameData.m_strife. Those two variables are updated based on user input, their initial value is 0, which means that no torque is actually applied. The torque is applied in a way that the ball will roll to the right if g_gameData.m_strife is positive (negative action around the Z axis), and the ball will roll forward if g_gameData.m_forward is positive (negative action around the X axis). After applying the torque, we step the physical simulation forward in time using the hkpWorld function stepDeltaTime(). stepDeltaTime() is not the only way to step the simulation forward, but it is the simplest one. stepDeltaTime() is a single-threaded stepping call. Havok Physics also supports multi-threaded stepping (recommended for complex scenes), which is fully explained in the documentation.

When stepping forward the simulation, we have to pass in a value in seconds that describes the time to simulate in stepDeltaTime(). If the frame rate was stable at 60 fps, then we should always use a constant value of 0.0167 seconds (1/60) in stepDeltaTime(). This is actually what happens in our simple game FRAME_PERIOD is a constant with value 0.01667. It is recommended to use time intervals that don't vary a lot in stepDeltaTime(), in our case we are always using the same constant value.

Please note that when we apply the torque to the ball, we also pass in a time period which represents the time the action is applied for. This is needed because torques (and also forces) are appled immediately during a simulation step as impulses (instantaneous changes of the linear or angular velocity). A time interval is therefore needed to compute the correct impulse and it should usually be the simulation step time (if we want the force or torque to act on the object for the whole simulation step).

After stepping forward the simulation, we also step forward the visual debugger. This operation only happens in a debug build and will basically update the displayed scene in the visual debugger (if it is being used).

If in status RUNNING, we use the g_gameData.m_statusData variable (which is updated by our phantom shapes when the ball moves around) to understand which phantoms have been activated. We then call renderScene() with the proper flags depending on which areas have been touched.

After having rendered the scene, we perform a check to understand if the game is over (either the user won by touching both active zones or the user lost by falling off the plane). In both cases we switch to status FINISHED (so that the next frame something different will happen).

When the game is in status FINISHED, we do not step the simulation forward every frame (this effectively means that the simulation is paused, like when in status STARTING), but we keep rendering the scene with the proper colors for the zones that have been activated. In addition, we also render some text on top of the scene saying that the user should hit the space bar to play another match. When this happens, we will get back to status STARTING and the loop will begin again. This state transiction from FINISHED to STARTING happens in the user input handling functions.

For our simulation stepping we used a constant FRAME_PERIOD value assuming that the frame rate is 60 fps. To enforce this condition, we use the following code.

// Timer manager
void TimerManager(int) {
    // post a new display operation
    glutPostRedisplay();
    glutTimerFunc(static_cast<unsigned>(FRAME_PERIOD*1000.0f), TimerManager, 0);
}

This function is registered with freeglut as the callback for timer events. At the beginning of the execution freeglut will call this function once. In our case, the last operation of the TimerManager() function is a call to glutTimerFunc() which will schedule a new timer event with a specified delay in milliseconds. The delay is computed so that practically this TimerManager() function will be called about once every 0.016 seconds (that is with a frequency of about 60 Hz ). Every time this function is called, we schedule a new freeglut redisplay event, which will basically result in a call to OnFrame(). This ensures that OnFrame() will be called about once every 0.01667 seconds.

The last interesting bit of code to look at is the code that handles user input. Here is where the state transictions from STARTING to RUNNING and from FINISHED to STARTING happen. We'll also see how g_gameData.m_forward and g_gameData.m_strife are updated based on user input.

// Key manager function
void KeyManager(unsigned char key, int x, int y) {
    static bool fullscreen = false;
    switch(key) {
        case 'w': // move forward
        case 'W':
            g_gameData.m_forward = TORQUE_MULTIPLIER;
            break;
        case 's': // move backwards
        case 'S':
            g_gameData.m_forward = -TORQUE_MULTIPLIER;
            break;
        case 'd': // strife right
        case 'D':
            g_gameData.m_strife = TORQUE_MULTIPLIER;
            break;
        case 'a': // strife left
        case 'A':
            g_gameData.m_strife = -TORQUE_MULTIPLIER;
            break;
        case GLUT_KEY_TAB: // tabulation: toggle fullscreen
            if(!fullscreen) {
                glutFullScreen();
                fullscreen = true;
            } else {
                glutPositionWindow(0,0);
                glutReshapeWindow(WIDTH,HEIGHT);
                fullscreen = false;
            }
            break;
        case '':  // space: start or restart the game
            if(g_gameData.m_status == GameData::STARTING)
            {
                g_gameData.m_status = GameData::RUNNING;
            }
            else if(g_gameData.m_status == GameData::FINISHED)
            {
                g_gameData.reset();
                g_gameData.m_status = GameData::STARTING;
            }
 
            break;
        case GLUT_KEY_ESC: // escape: exit the program
            glutLeaveMainLoop();
            break;
        }
    return;
}
 
// Key up manager function
void KeyUpManager(unsigned char key, int x, int y) {
    switch(key) {
    case 'w':
    case 'W':
    case 's':
    case 'S':
        g_gameData.m_forward = 0.0f;
        break;
    case 'd':
    case 'D':
    case 'a':
    case 'A':
        g_gameData.m_strife = 0.0f;
        break;
    }
}

The KeyManager() functon will be called when a key is pressed. 'W', 'A', 'S' and 'D' are used to change the values for g_gameData.m_forward and g_gameData.m_strife. TORQUE_MULTIPLIER is a constant that specifies the strenght of the torque to be applied on the sphere. KeyUpManager() will be called when a key is released, if 'W' or 'S' were released we reset m_forward to 0, if 'D' or 'A' were released we reset m_strife to 0.KeyManager() also handles other events. If 'Esc' was pressed, we use the glutLeaveMainLoop() function to exit the game. if 'Tab' was pressed, we toggle fullscreen mode using the glutFullScreen() freeglut utility function. When the spacebar is pressed, we might change the game status depending on the current value of g_gameData.m_status as specified before. Note that when the game status is FINISHED and the space bar is pressed, we get back to status STARTING, but only after resetting the g_gameData structure using the reset() method.

Now that we have looked closely at Havok initialization, deinitialization, stepping during the rendering loop and user input, the reader should have a fairly clear idea about basic usage of the Havok Physics engine. An interesting exercise would be to introduce more levels in this game, creating different kinds of constraints and shapes. Everything should be fairly natural once the basic concepts are fully mastered.

This concludes our short tutorial on how to build a simple game using Havok Physics. I hope you enjoyed building this small game and that now you're eager to learn more about the engine.

AttachmentSize
Download1_23.png29.74 KB
Download2_18.png28.33 KB
Download3_19.png40.91 KB
Download4_13.png44.18 KB
Download5_12.png40.86 KB

Getting Started with Havok

$
0
0

So you've downloaded your free version of Havok Physics and Animation and realized you don't know how to get started with it...

Step 1: Getting Havok demos running

Firstly, open up the Quickstart Guide in the Docs folder. Now section "1.2 Evaluation Checklist" lists a few thing you might want to do if you're evaluating using Havok for a larger game or considering buying a full license but if you just want to get something working with Havok you can safely skip this section for now.

So jump ahead to section "1.3 Getting Started with Havok" and do as it says, as it steps through getting the example demos up and running. Off you go, come back when you've tried all that.

Step 2: Getting Havok into your own application.

So, now you have Havok's demos building and running and that's awesome but it's not very useful if you don't know how to get the functionality of the demos into your own application :) And with 500+ demos it can be hard to know where to begin.

Go find section "1.4 StepByStep Demos" which walks through one of the StepByStep demos. These "StepByStep" demos are pretty well commented and provide the absolute bare bones required to get Havok & Havok Physics in your application.

These demos also don't have a graphical element because Havok Physics is just that, physics. Of course, the 500+ demos we provide, which demonstrate particular features of the engine (located in Demo/Demos), are visualised in our DemoFramework so you can see what's happening. However the "StepByStep" and other "StandAloneDemos" strip away anything that isn't needed so you see what is required and what isn't required to get Havok set up and running. The lesson here is, how you chose to render the objects simulated by Havok in your own application is up to you.

So now you know how to get Havok into your own application, now the world is your oyster.

What you do next is completely up to you but I'd suggest

  • Finish reading the Quickstart Guide and having another look at the lists in section "1.2 Evaluation Checklist"
  • Check out the instructional videos by HavokEnthusiast on YouTube
  • Have a read of Daniele's brilliant "Creating a simple game using Havok Physics" sticky post. This post goes through the basics of using Havok Physics in a game (as well touching on how/when to draw the physical objects with Freeglut) with full source code available to download and dig through yourself.

If you aren't sure how to do something in particular, see if you can find one of our demos that does what you're trying to do (when the Demo/Demos application is running you can search them all by pressing "/" from the main menu). Note, the API demos are meant to be read mostly as source code because they were designed to show you how to use a particular function (or group of functions) in code, so the visual part of them is rarely very exciting.

The Manual/User Guide located in the Docs folder is also a great source of information. We know it's big (we've got a big engine) so we don't expect you to read it in one sitting but remember that it is there to help you. We don't just write over 1000 pages of documentation for the fun of it :)

Finally when you're stuck and banging you're head against a wall, have a read of "How to report a Havok crash" before posting a problem in the forums. As cliché as it sounds, following the advice in that post will help us help you.

Project Anarchy Released!

$
0
0

Hey Havok XS fans,

Havok has just announced the release of Project Anarchy. Project Anarchy is a complete mobile game engine and toolset that allows developers to ship games for free on iOS, Android and Tizen platforms. Project Anarchy ships with extensive sample materials and is supported by a vibrant online development community backed up by online courseware, tutorials and videos. Download it now at www.projectanarchy.com/download.

Simplifying mesh using hkQemMeshSimplifier

$
0
0

Hi.

I've been playing with havok since recently and have a question I'd like to ask.

I need to simplify a mesh to use with hkpExtendedMeshShape.

Is there a way to convert an ID3DXMesh mesh to hkQemMutableMesh, so I can simplify it using hkQemMeshSimplifier?

Thanks in advance.

How to load .3ds into the Havok.

Errors while loading exported files with hkSerializeUtil

$
0
0

HI,

    I'm building a 3D engine for my final year project at university and I decided to use Havok as the physics engine. I have some problems regarding file loading and file optimizations.

I use the latest version of Havok Content Tools and demo projects:

HavokContentTools_2013-1-0_20130717_64Bit_PcXs.exe

I tried to load a simple file (a box). I exported it with the Create Rigid Body and Write to Platform filters. I use 3D Studio Max 2014.

1) No matter what I do I get some errors about a random Havok class that can't be loaded. I tried using my own exported files or converting some from the demos with AssetCc2.exe. I use the following code:

hkSerializeUtil::ErrorDetails loadError;

hkStringBuf box("Resources/Havok/barrel.xml");

LoadedData = hkSerializeUtil::load(box.cString(), &loadError);

HK_ASSERT3(0xa6451543, LoadedData != HK_NULL, "Could not load file. The error is:\n"<< loadError.defaultMessage.cString() );

I get the following code:

Warning: Unable to load class hkpPairCollisionFilter, version 0x0

No information about this class exists in the serialization system. This could happen if:

* You have provided a custom classes file which does not include this class

* You have not specified keycodes before including hkProductFeatures.cxx

* Custom classes have not been registered path_to_file\engine\s

Could not load file. The error is:

Unable to load class hkpPairCollisionFilter, version 0x0

again same things as above

As you can see this is what I get from loading barrel.xml (asset from VehicleDemo converted to XML tagfile)

If I load my own exported asset I get other class as error: hkpShapeContainer , version 0x0

a) From what I've read from previous post this could happen if i use an old exported version of the file, but since I get this error using Max 2014 and the latest tool I not sure that can be the problem

b) Do I have to add certain #defines based on what am I loading from the file ? I mean do I have to add the definition for every single class that exists inside that file ? hkpPairCollisionFilter, hkpShapeContainer , and so on ?

2) Can exported files be optimized so that only information about RigidBodies to be avaiable and not everything about the PhysicWorld or other useless information about an object ? I've see that I can use Prune Filter but it still gives a lot of unrelated data, like animation, etc.

 

Binary Download doesn't start

$
0
0

Hello, I must not be understanding something here. When I go to download the latest free Havok binaries, I fill out the information requested, and click "submit", then the page just refreshes, but no download starts. At first, I thought maybe I was supposed to wait for someone to contact me with the license information and a download link, though that is not is not explicitly or implicitly stated anywhere as far as I can tell. Also, I have not received any such email. I've tried to get the download to several times, disabling my ad blocker and complying to varying degrees with regard to the amount of information I provide in survey; grasping at straws, I thought that maybe it wasn't downloading because I hadn't filled in all the fields. I've tried the download in both Firefox and IE. Can anyone hazard a guess as to what I'm doing wrong here? Thanks in advance.

Also, I've tried both the link at the top of the forum and the one linked from the sales page on the Havok website.

How to run Multiple 'hkpWorld' instances in Multiple thread?

$
0
0

Hi,
I'm doing a MMO Game now.
On server side,there is several region threads running,and every region contains one hkpWorld(thet are different and isolated from each other).
In main thread :
static hkMallocAllocator MallocBase;
m_ThreadMemoryRouter = hkMemoryInitUtil::initDefault(&MallocBase, hkMemorySystem::FrameInfo(2*1024*1024));

if (m_errorReport)
hkBaseSystem::init( m_ThreadMemoryRouter, m_errorReport );
else
hkBaseSystem::init( m_ThreadMemoryRouter, DefErrorReport );
In every region thread:
hkBaseSystem::initThread( m_ThreadMemoryRouter );

but while running,if I create two hkpWorld ,the game crash.all call stack is as follow:
CellServer.exe!hkCachedHashMap::findKey(unsigned long key) Line 168 + 0x8 bytes C++
CellServer.exe!hkCachedHashMap::get(unsigned long key, unsigned long * out) Line 214 + 0xd bytes C++
CellServer.exe!hkCachedHashMap::getWithDefault(unsigned long key, unsigned long def) Line 241 C++
CellServer.exe!StructArrayImplementation::_find(const char * nameIn) Line 2156 + 0x21 bytes C++
CellServer.exe!StructArrayImplementation::swizzleObjectMember(const char * name) Line 2589 C++
out put as follow:
First-chance exception at 0x00e8777b in CellServer.exe: 0xC0000005: Access violation reading location 0x1e282008.
Unhandled exception at 0x00e8777b in CellServer.exe: 0xC0000005: Access violation reading location 0x1e282008.

How can I make it work well?


Cant seem to get the download link

$
0
0

As the title says, the download link is not working for me to get the free Havok product.

There are a few reasons why it isn't, one being my firewall/ antivirus protection or even adblock, but after disabling all of them, no link or download file was initiated.

Second reason could be that the link is either broken or very simply not available.

Third, and probably most likely, is that I'm either on the wrong page or putting in the 'improper' information into the required fields.

To clarify on the third point, this was the page I was on to get the free version.

I was able to find an 'alternative' page that had the same fields here.

On the previous two, I put in these answers (excluding Contact Info):

  • Occupation - Enthusiast or Hobbyist
  • Best Describing Intended Use - Other non-commercial Development
  • Do you plan to - Use Privately

And to be more thorough, I even went here to see if i could get it, however, I could not fill in the 'website' field as I have none.

any help, advice or solution to help my inconvenience would be most appreciated.

These files are 3d objects or just havok internal data?

$
0
0

Hello people



I'm trying to analyze some 3d model formats, I found some havok files but I'm not familiarized with the format.

these are the description for each file.(checked with a hexadecimal editor)

hkClass.

hkClassMember.hkClassEnum.

hkClassEnumItem.

hkpConvexVerticesShape.

hkpConvexVerticesConnectivity

the second file say this:

hkClass.

hkClassMember.

hkClassEnum.

hkClassEnumItem.

hkpMoppBvTreeShape.

hkpMoppCode.

hkpCompressedMeshShape

and the final file say this:



hkClass.

hkClassMember.

hkClassEnum.

hkClassEnumItem.

hkBaseObject.

hkpConvexVerticesShape.fd.

hkpShape.

.hkpConvexVerticesShapeFourVectors.

hkReferencedObject.

hkpConvexShape.

hkpSphereRepShape



I need to know if these files are 3d models (compressed / encrypted or something...) or just is a havok internal data



files was attached



thanks

AttachmentSize
Downloadhavok_files.rar7.97 KB

Big Car Vehicle Setup

$
0
0

hello,I have a question in Vehicle Setup.


I studied the demo in SDK of Car,The demo use program data created a chassisShape,I test to execute it have no program.


Then,I modi the chassisShape data to scale Volume of car to 10xzoom,now the car length is 40.0f,width is 20.0f, height is 10.0f,mass is 7500


So I continue change many Parameter to diffurent value in VehicleSetup.cpp,


include :


Wheel:


wheel.radius = 3.0f;
wheel.width = 2.0f;
wheel.mass = 100.0f;


engine:


engine.maxTorque = 8000.0f;


 engine.minRPM = 10000.0f;
 engine.optRPM = 35000.0f;


 engine.maxRPM = 75000.0f;


transmission:


transmission.downshiftRPM = 35000.0f;
transmission.upshiftRPM = 65000.0f;


suspension:


hardPointFrontX = 8.8f;
hardPointBackX = -8.8f;
hardPointY = -0.2f;
hkReal hardPointZ = 8.8f;


but the car always fly and fly,or Still.


Can U give me a Vehicle setup parameter list  table of the 10xzoom big than the car demo?3Q

Shape penetrated by hkpCharacterProxy

$
0
0

I load a mesh and convert it to hkpMoppBvTreeShape(no simplify).


code as follow:


hkpSimpleMeshShape* storageMeshShape = new hkpSimpleMeshShape( 0.01f );


......build the storageMeshShape(abbreviation)


hkpMoppCompilerInput mci;
 {
  mci.m_cachePrimitiveExtents  = true;
  mci.m_enableChunkSubdivision = true;
 }


 hkpMoppCode* moppCode = hkpMoppUtility::buildCode(storageMeshShape, mci);


 hkpMoppBvTreeShape* moppBvTreeShape = new hkpMoppBvTreeShape(storageMeshShape, moppCode);


and create static rigidbody


hkpRigidBodyCinfo bodyinfo;
bodyinfo.m_restitution=0.0f;
bodyinfo.m_allowedPenetrationDepth=0.001f;
bodyinfo.m_collisionFilterInfo=hkpGroupFilter::calcFilterInfo(g_iHavokLayerStatic);


But in game,my hkpCharacterProxy can penetrate it in same position.


Is it because of concave faces in mesh?

Exception during hkRefVariant::set() / hkClass::getName()

$
0
0

Hi.

I am trying to serialize some Havok scene data from a C++ library I call from my C# app. However I get an exception when hkRootLevelContainer::NamedVariant::set() is called. I am linking against the debug_dll of the "Free Havok Physics & Animation" package for PC (Binary-only).

 

My code looks something like this:

void MyClass::SaveMesh()
{
    hkxScene *scene = new hkxScene;

    // Fill scene with hkxNode and hkxMesh
    // ...

    hkRootLevelContainer* currentRootContainer = new hkRootLevelContainer();
    currentRootContainer->m_namedVariants.setSize(1);
    hkRootLevelContainer::NamedVariant& sceneVariant = currentRootContainer->m_namedVariants[0];
    sceneVariant.set("Scene Data", scene, &hkxSceneClass);    // <- exception here

    // Serialize currentRootContainer
    // ...
}

 

When I run my app, I get the following exceptions:

First-chance exception at 0x572641da (MyLib.dll) in MyApp.exe: 0xC0000005: Access violation reading location 0x00000000. If there is a handler for this exception, the program may be safely continued.

 

The following is output to the console:

DBGHELP: Symbol Search Path: .

DBGHELP: SymSrv load failure: symsrv.dll

DBGHELP: MyLib - private symbols & lines 

         .\MyLib.pdb

DBGHELP: .\clr.pdb - file not found

DBGHELP: .\dll\clr.pdb - file not found

DBGHELP: .\symbols\dll\clr.pdb - file not found

DBGHELP: clr.pdb - file not found

DBGHELP: clr - export symbols

**************************************************************

* Cannot find symbol for an address

* Either debug information was not found or your version of

* dbghelp.dll may be too old to understand the debug format.

* For more information, see comments in hkStackTracerWin32.cxx

* Y:\NightlyJobs\07-18-Thu-01\Source\Common/Base/System/StackTracer/Impl/hkStackTracerWin32.cxx

**************************************************************

MyApp.exe has triggered a breakpoint

 

Finally, here is the Stack Trace:

MyLib.dll!hkClass::getName()  + 0xa bytes    

MyLib.dll!hkRefVariant::getClass()  + 0x156 bytes    

MyLib.dll!hkRefVariant::set()  + 0x14 bytes    

MyLib.dll!hkRootLevelContainer::NamedVariant::set(const char * name, void * object, const hkClass * klass)  Line 40    C++

MyLib.dll!MyClass::SaveMesh()  Line 229    C++

[External Code]    

MyLib.dll!MyLib::MyClass::SaveMesh() Line 70 + 0x46 bytes    C++

MyApp.exe!MyApp.App.App() Line 57 + 0x14 bytes    C#

[External Code]    

mscoreei.dll!6dc4f4f3()     

[Frames below may be incorrect and/or missing, no symbols loaded for mscoreei.dll]    

mscoree.dll!6dcc7f16()     

mscoree.dll!6dcc4de3()     

kernel32.dll!7559338a()     

ntdll.dll!777e9f72()     

ntdll.dll!777e9f45()    

 

I believe this is just caused by a string that is not correctly initialized. However, I cannot find which one ; all the name fields in the objects I use in my code seem correctly set. Can you see where the problem comes from?

 

 

 

 

 

 

Some questions about the hkt file,xml file and the hkx file include?

$
0
0

Accroding to study the Havok_Physics_Animation_2012-2-0_Pc_Xs_User_Guide,I have some questions:

1、I get to know there are three 3D format files can be load into havok.They are  hkt file,hkx file and xml file.But now I want to know what differences between these 3D format files? what information they include? 

2、if I want to load other 3D format files such as .3ds and .ply  into the havok,what should I do? Who have codes and metheds can load these 3D format files into the havok and wanna to share it to me?

I know there are many predecessors,so I want to get your help. thx!

                                                                                                                                                                                                                            Wang L

Physics: calculating forces.

$
0
0

Hi everyone,

I'm trying to simulate a penetration. Here are the simplified conditions:

I have a compound body consisting of triangles(flat ones), joined by their vertices, and a separate sphere. The sphere is launched at a body. The idea is, if it hits(or presses) the surface of any tringle hard enough, this triangle is destroyed and removed from the world. Thus, sphere creates a hole in the body.

I would like to know if there is a way to calculate how hard sphere and triangle press each other using havok. Thanks in advance.


I can't load a correct .htx model into the havok. please check out the description.

$
0
0

Hello everybody:

        I have a simple problem but I can't how to solve. After I create a simple .hkx model "teapot" by 3ds max,I want to load it into my Havok. The model shows like this      

But when I load it into my Havok, the model is bacome,

like this

  I don't know where I have a mistake,so I hope someone can give me some advanced issues.Thank you!

 

Weird havok linker error

$
0
0

I'm working with Havok Physics and when I was doing some learning and practicing I had a project just for Havok. Now I want to include it into my game but I get these errors.

  • Somefile.obj : error LNK2005: "public: static class hkTypeInfo const * const * const hkBuiltinTypeRegistry::StaticLinkedTypeInfos" (?StaticLinkedTypeInfos@hkBuiltinTypeRegistry@@2QBQBVhkTypeInfo@@B) already defined in
  • Somefile.obj : error LNK2005: "public: static class hkClass const * const * const hkBuiltinTypeRegistry::StaticLinkedClasses" (?StaticLinkedClasses@hkBuiltinTypeRegistry@@2QBQBVhkClass@@B) already defined in
  • Somefile.obj : error LNK2005: "char const * const HK_PHYSICS_2012_KEYCODE" (?HK_PHYSICS_2012_KEYCODE@@3QBDB) already defined in
  • Somefile.obj : error LNK2005: "char const * const HK_PHYSICS_KEYCODE" (?HK_PHYSICS_KEYCODE@@3QBDB) already defined in
  • Somefile.obj : error LNK2005: "char const * const HK_ANIMATION_KEYCODE" (?HK_ANIMATION_KEYCODE@@3QBDB) already defined in
  • Somefile.obj : error LNK2005: "char const * const HK_BEHAVIOR_KEYCODE" (?HK_BEHAVIOR_KEYCODE@@3QBDB) already defined in
  • Somefile.obj : error LNK2005: "char const * const HK_CLOTH_KEYCODE" (?HK_CLOTH_KEYCODE@@3QBDB) already defined in
  • Somefile.obj : error LNK2005: "char const * const HK_DESTRUCTION_2012_KEYCODE" (?HK_DESTRUCTION_2012_KEYCODE@@3QBDB) already defined in
  • Somefile.obj : error LNK2005: "char const * const HK_DESTRUCTION_KEYCODE" (?HK_DESTRUCTION_KEYCODE@@3QBDB) already defined in
  • Somefile.obj : error LNK2005: "char const * const HK_AI_KEYCODE" (?HK_AI_KEYCODE@@3QBDB) already defined in
  • Somefile.obj : error LNK2005: "public: static struct hkVersionRegistry::Updater const * * hkVersionRegistry::StaticLinkedUpdaters" (?StaticLinkedUpdaters@hkVersionRegistry@@2PAPBUUpdater@1@A) already defined in
  • Somefile.obj : error LNK2005: "public: static class hkStaticClassNameRegistry const * * hkVersionRegistry::StaticLinkedClassRegistries" (?StaticLinkedClassRegistries@hkVersionRegistry@@2PAPBVhkStaticClassNameRegistry@@A) already defined in
  • Somefile.obj : error LNK2005: "void __cdecl hkProductFeatures::initialize(void)" (?initialize@hkProductFeatures@@YAXXZ) already defined in

These errors appear for every file so for Somefile.obj Somefile2.obj Somefile3.obj etc.

I figured I get this error because the way I have files included into each other because when I include this into a cpp file unlike including it into my header file which gets included into all of my other header files then it works. So the reason I came to these forums to ask this question is because this only happens with the Havok SDK. Other includes like DirectX SDK and FBX SDK work fine if I include them this way.

To help you, this is how I have my files



I have an Include.h file which contains all my class declatations, includes for things like <vector> <Windows.h> and <d3d9.h>, and includes for every single other header file in my project except.

These are the Havoc headers I've included in my Include.h file.

#include <Common/Base/keycode.cxx>

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

#include <Common/Base/hkBase.h>

#include <Common/Base/System/hkBaseSystem.h>

#include <Common/Base/System/Error/hkDefaultError.h>

#include <Common/Base/Memory/System/hkMemorySystem.h>

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

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

#include <Common/Base/Thread/Job/ThreadPool/Cpu/hkCpuJobThreadPool.h>

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

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

#include <Physics2012\Collide\Shape\Convex\Box\hkpBoxShape.h>

#include <Physics2012\Dynamics\Entity\hkpRigidBody.h>

#include <Physics2012\Utilities\Dynamics\Inertia\hkpInertiaTensorComputer.h>

#include <Physics2012\Dynamics\World\hkpSimulationIsland.h>

Then all my other header files include Include.h and those files have my classes that I declared in them.

Hopefully this gives you enough information for you to help me with this problem and thank you.

Box freezes in mid air after bouncing.

$
0
0

I have a level set up where I have a box on the ground and I have a smaller box bouncing on it

This is the code I use to set that up.

hkVector4 halfExtents(0.5f, 0.5f, 0.5f);

    hkpBoxShape* boxShape = new hkpBoxShape(halfExtents);

    hkpRigidBodyCinfo ci;

    ci.m_shape = boxShape;

    ci.m_position = hkVector4(0, 30, 0);

    ci.m_motionType = hkpMotion::MOTION_DYNAMIC;

    boxShape->setRadius(0.00001f);

    const hkReal boxMass(10.0f);

    hkMassProperties massProps;

    hkpInertiaTensorComputer::computeShapeVolumeMassProperties(boxShape, boxMass, massProps);

    ci.setMassProperties(massProps);

    ci.m_restitution = 1.0f;

    hkpRigidBody* rigidBody = new hkpRigidBody(ci);

    boxShape->removeReference();

    box = static_cast<hkpRigidBody*>(g_pWorld->addEntity(rigidBody));

    rigidBody->removeReference();

    hkVector4 he(20.0f, 2.0f, 20.f);

    hkpBoxShape* bs = new hkpBoxShape(he);

    hkpRigidBodyCinfo cis;

    cis.m_shape = bs;

    cis.m_position = hkVector4(0, -2, 0);

    cis.m_motionType = hkpMotion::MOTION_FIXED;

    cis.m_restitution = 1.0f;

    bs->setRadius(0.00001f);

    hkpRigidBody* rigidBodyz = new hkpRigidBody(cis);

    bs->removeReference();

    g_pWorld->addEntity(rigidBodyz)->removeReference();

I have 2 boxes drawn on the screen and I update the transform for the dynamic on by geting the position from it like this.

hkVector4 pos = hkbox->getPosition();

UpdateBoxTransform(pos(0), pos(1), pos(2))

And when I do that the dynamic box bounces off the static box and as soon as its about to loose its upper velocity after bouncing and about to go for another bounce it freezes and stops in mid air.

Does anyone know how to solve the issue and is there anything I'm doing wrong? Thank you!

Box freezes in mid air after bouncing.

$
0
0

I have a level set up where I have a box on the ground and I have a smaller box bouncing on it

This is the code I use to set that up.

hkVector4 halfExtents(0.5f, 0.5f, 0.5f);

    hkpBoxShape* boxShape = new hkpBoxShape(halfExtents);

    hkpRigidBodyCinfo ci;

    ci.m_shape = boxShape;

    ci.m_position = hkVector4(0, 30, 0);

    ci.m_motionType = hkpMotion::MOTION_DYNAMIC;

    boxShape->setRadius(0.00001f);

    const hkReal boxMass(10.0f);

    hkMassProperties massProps;

    hkpInertiaTensorComputer::computeShapeVolumeMassProperties(boxShape, boxMass, massProps);

    ci.setMassProperties(massProps);

    ci.m_restitution = 1.0f;

    hkpRigidBody* rigidBody = new hkpRigidBody(ci);

    boxShape->removeReference();

    box = static_cast<hkpRigidBody*>(g_pWorld->addEntity(rigidBody));

    rigidBody->removeReference();

    hkVector4 he(20.0f, 2.0f, 20.f);

    hkpBoxShape* bs = new hkpBoxShape(he);

    hkpRigidBodyCinfo cis;

    cis.m_shape = bs;

    cis.m_position = hkVector4(0, -2, 0);

    cis.m_motionType = hkpMotion::MOTION_FIXED;

    cis.m_restitution = 1.0f;

    bs->setRadius(0.00001f);

    hkpRigidBody* rigidBodyz = new hkpRigidBody(cis);

    bs->removeReference();

    g_pWorld->addEntity(rigidBodyz)->removeReference();

I have 2 boxes drawn on the screen and I update the transform for the dynamic on by geting the position from it like this.

hkVector4 pos = hkbox->getPosition();

UpdateBoxTransform(pos(0), pos(1), pos(2))

And when I do that the dynamic box bounces off the static box and as soon as its about to loose its upper velocity after bouncing and about to go for another bounce it freezes and stops in mid air.

Does anyone know how to solve the issue and is there anything I'm doing wrong? Thank you!

error C3861: 'hkpHeightFieldAgent_registerSelf': identifier not found

$
0
0

I get these errors.

hkproductfeatures.cxx(75): error C3861: 'hkpHeightFieldAgent_registerSelf': identifier not found

hkproductfeatures.cxx(79): error C3861: 'hkpSimulation_registerSelf': identifier not found

hkproductfeatures.cxx(83): error C3861: 'hkpContinuousSimulation_registerSelf': identifier not found

hkproductfeatures.cxx(88): error C3861: 'hkpMultiThreadedSimulation_registerSelf': identifier not found

hkproductfeatures.cxx(93): error C3861: 'hkpAccurateInertiaTensorComputer_registerSelf': identifier not found

hkproductfeatures.cxx(97): error C3861: 'hkp3AxisSweep_registerSelf': identifier not found

hkproductfeatures.cxx(101): error C3861: 'hkpTreeBroadPhase_registerSelf': identifier not found

hkproductfeatures.cxx(111): error C3861: 'hkpSampledHeightField_registerAllRayCastFunctions': identifier not found

after including these files.

#include <Common\Base\Types\Geometry\hkGeometry.h>

#include <Common\Base\Types\Geometry\hkStridedVertices.h>

I've been spending hours trying to fix this error but completely no luck.

These are all my includes, am I missing something?

#include <Common/Base/hkBase.h>

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

#include <Common/Serialize/Version/hkVersionPatchManager.h>

#include <Common/Compat/hkHavokVersions.h>

#include <Common/Base/System/hkBaseSystem.h>

#include <Common/Base/System/Error/hkDefaultError.h>

#include <Common/Base/Memory/System/hkMemorySystem.h>

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

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

#include <Common/Base/Thread/Job/ThreadPool/Cpu/hkCpuJobThreadPool.h>

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

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

#include <Physics2012\Collide\Shape\Convex\Box\hkpBoxShape.h>

#include <Physics2012\Dynamics\Entity\hkpRigidBody.h>

#include <Physics2012\Utilities\Dynamics\Inertia\hkpInertiaTensorComputer.h>

#include <Physics2012\Dynamics\World\hkpSimulationIsland.h>

#include <Physics2012\Collide\Shape\Convex\hkpConvexShape.h>

#include <Physics2012/Internal/Collide/BvCompressedMesh/hkpBvCompressedMeshShape.h>

#include <Physics2012/Internal/Collide/BvCompressedMesh/hkpBvCompressedMeshShapeCinfo.h>

#include <Physics2012\Collide\Shape\Convex\ConvexVertices\hkpConvexVerticesShape.h>

#include <Common\Base\KeyCode.h>

#include <Common\Base\Types\Geometry\hkGeometry.h>

#include <Common\Base\Types\Geometry\hkStridedVertices.h>

Viewing all 168 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>