Extensions:2.6/Py/Scripts/Game Engine/BRIK ragdolls/Documentation

提供: wiki
移動先: 案内検索
in progress Inprogress100.jpg 80%

 

Only detailed game script explanations needed, but they are probably too well commented anyway so should be readable.

Summary


BRIK is the Blender Ragdoll Implementation Kit.

It aims to provide a selection of operators that ease the creation of rigid body structures, hit boxes, an internal text file describing the armature and the bare minimum game logic that is essential to the full operation of mesh deforming ragdolls in the game engine.

The addon also contains the necessary scripts for use within the game engine in a sub folder of the addon. The scripts are imported into Blender when the game logic is created so they can be packaged into the *.blend for distribution with the game.


Brief Workflow


Creating the first ragdoll

BRIK uses an armature as a template for it's operation.

The first step in the process of creating a ragdoll is to create a mesh that is rigged with an armature. BRIK will only create rigid body objects for bones in the armature that are set to deform the mesh.

The armature and mesh should be positioned on a layer that will be hidden in the game to enable them to be added.

An armature should be selected to display the buttons in the BRIK panel. Buttons that are not currently available will be greyed out.

With a layer active that will be hidden in the game, the user then presses all the buttons in the BRIK panel.

  • Create structure
  • Create hit boxes
  • Write game file
  • Create game logic

All objects are created on the currently active layer, the text file describing the armature is created as an internal text file and the basic game logic is created on those objects that require it.

During the operation of the "Create game logic" operator, an Empty object is created named BRIK_spawn_point. Logic is created on this spawn point that handles the spawning of the armature and mesh. This should be moved onto a layer that will be visible in the game engine and positioned at the location where the armature and mesh are to be spawned.

With all layers that are to be hidden in the game deselected and all layers that are to be visible in the game selected the game can then be started.

In the game, by default, the ⇆ Tab key will spawn the mesh and armature and the Space key will trigger ragdolling.


Detailed description of operators


BRIK_create_structure

Object creation
When the button is pressed to create the rigid body structure, objects are created for each bone in the armature in turn. The first object is created for the root bone (the bone that has no parents) and subsequent objects are created by following the chains of bones in the armature. This ensures that when a rigid body joint constraint is formed, the object to which it connects is already created.
The objects have the approximate size of the bone that they are created for and are positioned so that their object center is at the bone center and their orientation matches the bone's orientation in pose mode.
These objects have their game engine physics type set to "Rigid body" and have a rigid body joint constraint created that links them to another rigid body object that has been created from the parent bone. The rigid body object that corresponds to the root bone is the only one that has no rigid body joint constraint. All other rigid body objects have only a single rigid body joint constraint.
An Empty object is created called BRIK_<armature_name>_loc that is used to position the armature during ragdolling. This Empty is made a child of the root rigid body object and positioned at the location of the root bone's head.
Blender3D FreeTip.png
Setting up rigid body joint limits

BRIK will look for IK rotation limits on the armature bones. If it finds these limits then it will apply these limits to the rigid body joints. This enables the user to utilise the visual interface in pose mode to set up the rotation limits of the IK chain and thereby set up the rotation limits of the rigid body joints.


Armature changes
This operator also sets the physics types of both armature and mesh to "No collision". Due to the large number of objects required to implement ragdolling, I found that if the armature and/or mesh was set to "static, ghost" there was a large physics overhead since the objects are inside the physics area of both mesh and armature. Setting the armature and mesh to "No collision" removes this overhead.
Constraints are created for each deforming bone in the armature.
A copy rotation bone constraint is created for all deforming bones. The rigid body object corresponding to the bone is used as the target.
A copy location bone constraint is created for the root bone in addition to it's copy rotation bone constraint. The target for the copy location constraint is the Empty object named BRIK_<armature_name>_loc that has been made a child of the rigid body object corresponding to the root bone.
User-changeable options
After the operator has been called and created the rigid body objects there are a few options available to change in the "Last operator" panel that appears below the tool shelf of the 3d view.
Prefix is a prefix that is prepended to the name of the bone, and the rigid body object is named with the prefix and bone name that it is created for. The default prefix is "RB_" and this can be changed in the "Last operator" panel.
eg. An object is created for a bone called "Bone". It's default name will be "RB_Bone"
The length and width of the rigid body object is calculated based on the size of the bone it is created for. Width and length can be changed by using sliders in the "Last operator" panel.
By default, bones are grouped in a group called <prefix><armature_name>_Group. This grouping can be disabled or enabled by toggling the "Add to group" button in the "Last operator" panel.
Custom properties
Custom properties are created on the rigid body objects:
  • BRIK_bone_name stores the name of the bone that the rigid body is created for.
  • BRIK_joint_target stores the name of the rigid body that the rigid body joint will attach the current object to.
  • Other properties are created that describe the position of the rigid body joint pivot in relation to the object center and to define the max and min rotation limits for the rigid body joint.
Custom properties are created on the armature:
  • BRIK_bone_box_dict is a dictionary that has bone names as keys and the names of the rigid body objects that correspond to the bones as values. This is used to look up the names of the relevant objects and allows for the rigid body objects to assume any names rather than enforcing a strict naming convention.
  • BRIK_structure_created is a boolean that identifies whether the armature has had a rigid body strusture created for it.
Blender3D FreeTip.png
Making a nicely performing ragdoll

Once created, the rigid body objects can be safely edited in edit mode. It is not advisable to scale them in object mode.

Changing the shape of the rigid body objects so that they more accurately fit inside the mesh that they will be driving will improve the apparent collision of the mesh with the environment.

I plan to include a mass calculation for the rigid bodies so maintaining a trapezoid shape to the rigid body object is advised. Keeping the shape simple will also speed up the physics calculations.

One improvement that can yield good results is to change the collision bounds on the head rigid body to "Sphere" from the default "Box". This allows the head of the ragdoll to roll convincingly when on the ground.


BRIK_remove_structure

This operator looks at the BRIK_bone_box_dict custom property on the armature and removes all objects that have names in that dictionary from the *.blend file.

It then removes the custom properties BRIK_bone_box_dict and BRIK_structure_created from the armature.


BRIK_create_hit_boxes

This operator acts in a similar way to the "Create structure" operator.

Hit boxes are created for each deforming bone in the armature based on the bone size.

The hit boxes are then bone parented to their respective bones on the armature

The physics type of the hit boxes is set to "static, ghost" so they do not collide with anything resulting in physics conflicts, but they can be registered by ray casts in the game engine.

The prefix for this operator is set to "HIT" by default.

Hit boxes are given the custom property:

  • BRIK_bone_name storing the name of the bone that the hit box is created for.

The operator creates the custom properties on the armature:

  • BRIK_bone_hit_box_dict with bone names as keys and hit box names as values.
  • BRIK_hit_boxes_created is a boolean set to True.


BRIK_remove_hit_boxes

This operator acts much like the "Remove structure" operator.

Objects that have names in the BRIK_bone_hit_box dictionary on the armature are removed from the *.blend file.

The custom properties BRIK_bone_hit_box_dict and BRIK_hit_boxes_created are removed from the armature.


BRIK_write_game_file

This operator creates a custom property on the armature BRIK_optimal_order that is a list of bone names. The list is ordered with the root bone first followed by the bones that are joined to the root bone, followed by the bones that are joined to these previous bones, etc. This ordered list ensures that ultimately each bone can be considered only once per logic tick by the game engine, and that all bones that affect the currently considered bone have already been calculated.

The game file is then written with one piece of data per line and the whole file enclosed in the triple quotation marks of a Python block comment. This allows the file to be stored on a script game logic controller as a single string in the game. The file can be handled entirely internally to Blender and the game engine, thus leaving the game's file structure less cluttered.

The structure of the game file is:

Armature name box['armature_name']
Base bone pivot offset x Vector from armature centre
Base bone pivot offset y to pivot of base bone
Base bone pivot offset z
Base bone pivot displacement x Vector from centre of base RB object
Base bone pivot displacement y to pivot of base bone
Base bone pivot displacement z
NO LINE SPACE HERE, BUT THE FOLLOWING IS GIVEN FOR EACH BONE.
Bone name box['bone_name']
RB object name box.name
Parent object name box['joint_target']
Hit box name
Bone rest world orientation w
Bone rest world orientation x
Bone rest world orientation y
Bone rest world orientation z
THE FOLLOWING IS NOT GIVEN FOR THE ROOT BONE SINCE IT HAS NO RIGID BODY JOINT.
RB joint position x box['joint_position_x']
RB joint position y box['joint_position_y']
RB joint position z box['joint_position_z']
RB joint rotation limit max x box['rot_max_x']
RB joint rotation limit max y box['rot_max_y']
RB joint rotation limit max z box['rot_max_z']
RB joint rotation limit min x box['rot_min_x']
RB joint rotation limit min y box['rot_min_y']
RB joint rotation limit min z box['rot_min_z']


BRIK_create_game_logic

This operator imports the BRIK game engine scripts into the *.blend file and sets up the necessary game logic on the objects.

It also creates an Empty object called BRIK_spawn_location if it does not already exist.


Spawn point

The game property BRIK_mob_count is created as an int value set to 0. This property is used to distinguish how many different ragdoll structures are present in the scene. It is a 0 based index so a value of 0 indicates one ragdoll, a value of 1 indicates two ragdolls, etc.

Logic is created to run two scripts a single time at the start of the game:

  • BRIK_init_spawn.py initialises the spawn point itself with the name of the armature that is to be spawned at this spawn point and two game properties.
  • added_objects = [] is a list that contains references to all armature/mesh objects that are added during the game by this spawn point
  • add_count = 0 is a counter that counts how many objects this spawn point has added to the scene. The value of this counter is recorded on each added object when they are spawned as a tag to uniquely identify the added objects.
  • BRIK_load.py is the script that loads the data file for each rigid body structure present.

Logic is also created to spawn the armatures/meshes. By default this is set to a keyboard sensor for the Tab key.

There is also a dummy Python script controller added for each rigid body structure created. These use the generated text files as their scripts. These compile correctly since the files are essentially just single Python block comments.

NOTE:

The first time the "Create game logic" operator is run it will create the spawn point with a single dummy Python controller. Each subsequent time it is run it will simply add an extra dummy controller with the relevant generated text file for the newly created structure.


Armature

Two game properties are created:

  • BRIK_use_ragdoll = False; When set to True, this property triggers ragdolling.
  • BRIK_init_ragdoll = True; This is checked for during the BRIK_init_ragdoll.py game engine script. It ensures that the rigid body objects have been properly spawned before the BRIK_use_ragdoll.py script is allowed to run.

Other logic is created that enables the spawning of the rigid body objects by the BRIK_init_ragdoll.py script and the running of the BRIK_use_ragdoll.py script that handles the calculations required to apply the movement and rotation of the rigid body structure to the armature.


Hit boxes

The hit boxes simply have the game property BRIK_can_hit = True created. This property can be used by a ray cast to identify the hit boxes.


Rigid body objects

The rigid body objects have no logic on them. They simply follow the laws of the Bullet physics engine and have their position and orientation recorded by the BRIK_use_ragdoll.py script in the armature's logic.


Overview of BRIK operation in the game engine


I have tried to keep the logic required as simple as possible. The BRIK addon is not a complete ragdoll solution for a game, but is more of a basic implimentation that can be built upon by the game developer.

There are two main objects that handle the game logic, BRIK_spawn_point and the armatures that rigid body structures are created from.

BRIK_spawn_point

This is an Empty that is created by the BRIK Create Game Logic operator.

The logic on this Empty loads in the necessary data from files and sets up the various properties on objects that BRIK uses.

The logic on the empty also allows for a mob to be added to the scene.

The spawn point that is created by BRIK can be duplicated and each duplicated spawn point will perform individually with it's own record of objects that it adds to the scene and it's own logic for actually spawning mobs. This logic can be edited individually on each spawn point.

Something to test...
The use of multiple spawn points has been confirmed to work, but has not yet been extensively tested.


At the start of the game
Loading of data and assigning of this data to the various objects is conducted by the BRIK_load.py script. This is run from a Python script controller that is triggered by a single pulse from an Always sensor that occurs at the start of the game.
This pulse also triggers a controller that runs the script BRIK_init_spawn.py. This script sets up some properties on the spawn point that allows it to keep track of the objects that are added to the scene by that spawn point.
Spawning a mob
A mob is spawned by the script BRIK_spawn_mob.py by calling the BRIK_spawn_mob.main function from a Python module controller.
This controller is set up by default to be triggered by a keyboard sensor using the ⇆ Tab key.
Blender3D FreeTip.png
Changing the spawn trigger

To change how a mob is spawned simply change the sensor that triggers the BRIK_spawn_mob.main function. This might simply be a matter of changing the key that is pressed or it might be setting up further logic involving timers and/or property sensors that will spawn mobs at intervals or by events in the game such as reaching a certain point or performing a certain action.


Data
The final logic on the spawn point is a dummy Python script controller for each of the rigid body structures that have been created.
Each dummy controller is set to contain a text file that was generated by the BRIK Write Game File operator. This text file is a single Python block comment in triple quotation marks and so will not throw an error when set as a Python script on a Python script controller.
The reason I have placed this text file into a Python script controller is to make the text file easily transferred from Blender to the game engine. The script that is used by a Python script controller can be read in the game as a single string. These strings are parsed by the BRIK_load.py script.


The armature

The armature that the rigid body is created from contains the logic required to transfer control of the armature from actions to physics based motion using the rigid body driver structure.

When the armature is first spawned
When the armature is spawned, all child objects are also spawned (this is default behaviour for the game engine). Child objects comprise the bone parented hit boxes, and the mesh.
Using a physics mesh.

If the mob is to be controlled using dynamics then a physics mesh would be required. The armature would be the child of this physics mesh.

The physics mesh would be the object that is added to the scene by the spawn point and the armature would be one of the children that is added to the scene as a result.

Despawning of the physics mesh would need to be handlied prior to transitioning the armature from action animation to physics based animation. This is to avoid conflicts arising from the rigid body structure being spawned inside the physics mesh.


After spawning, normal mob behaviour can be used including ai, motion and action based animation.
Transition to ragdoll
When spawned, the mob has the boolean game property BRIK_use_ragdoll. This is set to False by default. Transitioning to ragdoll physics based animation is achieved by simply setting this property to True.
BRIK creates a keyboard sensor set by default to the Space key. This sensor triggers a "Property actuator" that sets the value of the game property BRIK_use_ragdoll to True.
When BRIK_use_ragdoll is changed to True, a "Property changed" actuator triggers the BRIK_init_ragdoll.main function from a Python module controller. This function handles the despawning of the hit boxes and the spawning of the rigid body structure. It also reinstates the rigid body joint constraints linking the structure together and the resets the targets of the bone constraints on the armature that allow the bones to copy the rotation and location of the rigid body objects. Recreating the constraints is necessary since rigid body joint constraints are lost completely when spawning the rigid body structure. The copy rotation/location bone constraint targets need to be reset to the recently spawned rigid body structure as they are still set to use the rigid body objects on the hidden layer as targets. (I may be mistaken about the exact performance of constraints during spawning, but it is certain that they need to be reinstated.)
While the ragdoll is active
The final logic on the armature is a Property sensor that is set to pulse mode and is triggered while BRIK_use_ragdoll is True.
The property sensor is linked to an "Armature actuator" set to "Run armature" and is triggered every logic tick that the armature is being driven by ragdoll physics. This allows the bones to be animated by the bone constraints.

Detailed description of game engine scripts


to do

 

BRIK_load.py

BRIK_init_spawn.py

BRIK_spawn_mob.py

BRIK_init_ragdoll.py

BRIK_spawn_ragdoll.py