Overview
Purpose: This example demonstrates how to control articulated parts on DI-Guy human characters in VR-Forces simulations. It shows the pattern for implementing an actuator component that animates human joints, specifically the left shoulder joint with sinusoidal motion.
Observable Behavior: When running this example, you will see:
- Human character's left shoulder joint animates automatically
- Shoulder rotates through elevation angles (0° to 90°)
- Smooth sinusoidal motion over 4-second intervals
- Animation pauses when simulation is paused
- Motion applies to DI-Guy characters with articulated part definitions
Prerequisites:
- Understanding of VR-Forces simulation architecture
- Familiarity with actuator component patterns
- Knowledge of articulated parts and DIS representation
- Basic understanding of DI-Guy human character system
Related Examples:
- VR-Forces articulated parts documentation
- DI-Guy character integration guides
Key Concepts Demonstrated
This example demonstrates:
- Actuator Component Pattern - Implementing
DtActuatorComponent for entity behavior
- Inherits from
DtActuatorComponent base class
- Per-frame tick processing for continuous animation
- Unique aspect: Direct manipulation of human joint angles
- Articulated Part Control - Accessing and modifying DIS articulated parts
- Uses
DtPlatformLocalObjectFacade to access platform-specific data
- Retrieves articulated part repositories by DIS art part type
- Sets joint angles and angular rates each frame
- DI-Guy Integration - Working with DI-Guy character skeleton
- Art part types defined in
DtDiGuyArtPartLinkMapper.h
- Maps DIS articulated parts to DI-Guy skeleton joints
- Requires entity definition to specify available articulated parts
- Time-Based Animation - Creating smooth periodic motion
- Sinusoidal motion computed from simulation time
- Angular rate calculated for smooth visual interpolation
- Handles simulation pause/resume correctly
Code Walkthrough
Actuator Component Structure
The actuator inherits from DtActuatorComponent and maintains animation state:
class DtExampleHumanArtPartActuator : public DtActuatorComponent
{
public:
DtExampleHumanArtPartActuator(const DtString& name, DtLocalObject* owner,
DtSimulationServices* simManager,
DtComponentDescriptor* desc = 0,
DtReaderWriterRegistry* parentRegistry = 0);
virtual bool init() override;
virtual void tick() override;
virtual const char* type() const override;
static DtSimComponent* creator(const DtString& name, DtLocalObject* owner,
DtSimulationServices* simManager,
DtComponentDescriptor* desc = 0,
DtReaderWriterRegistry* parentRegistry = 0);
protected:
DtPlatformLocalObjectFacade myPlatformLocalObjectFacade;
makVrf::DtArticulatedPartStateRepository* myLeftShoulder;
double myAnimationInterval;
double myTimeInInterval;
};
Key Points:
DtPlatformLocalObjectFacade provides platform-specific data access
DtArticulatedPartStateRepository controls individual joint state
- Animation timing maintained independently of frame rate
- Static
creator() enables factory instantiation
Accessing Articulated Parts
The tick method retrieves the shoulder joint on first access:
void DtExampleHumanArtPartActuator::tick()
{
if (!myLeftShoulder)
{
myLeftShoulder = myPlatformLocalObjectFacade.nextFramePart(
static_cast<DtArtPartType>(makVrv::DiGuyDisArtPartShoulderLeft));
}
if (!myLeftShoulder)
{
return;
}
}
Why This Matters:
DiGuyDisArtPartShoulderLeft is a DIS articulated part type constant
- Part lookup deferred until first tick (entity may not be fully initialized at
init())
- Null check handles entities without this articulated part defined
nextFramePart() retrieves the repository for modifying joint state
Sinusoidal Joint Animation
The joint angle and rate are computed using trigonometry:
void DtExampleHumanArtPartActuator::tick()
{
myTimeInInterval += dT();
if (myTimeInInterval > myAnimationInterval)
{
myTimeInInterval = 0;
}
double maxAngle = M_PI_2;
double theta = myTimeInInterval / myAnimationInterval * 2 * M_PI;
double newPartAngle = maxAngle * sin(theta);
double newPartAngleRate = (4 * maxAngle / myAnimationInterval) * cos(theta);
myLeftShoulder->setElevation(newPartAngle);
myLeftShoulder->setElevationRate(newPartAngleRate);
myLeftShoulder->setAzimuth(0);
myLeftShoulder->setAzimuthRate(0);
myLeftShoulder->setRotation(0);
myLeftShoulder->setRotationRate(0);
}
Why This Matters:
dT() provides frame delta time in seconds
- Theta ranges from 0 to 2π over the animation interval
- Sine wave produces smooth up-down motion
- Angular rate (derivative of sine) enables smooth interpolation on remote clients
- All three joint degrees of freedom (azimuth, elevation, rotation) must be set
Handling Simulation Pause
The actuator detects when simulation is paused and stops motion:
void DtExampleHumanArtPartActuator::tick()
{
if (DtIsZero<double>(dT()))
{
if (myLeftShoulder)
{
myLeftShoulder->setAzimuthRate(0);
myLeftShoulder->setElevationRate(0);
myLeftShoulder->setRotationRate(0);
}
return;
}
}
Key Points:
- Zero delta time indicates simulation pause
- Angular rates set to zero to stop motion
- Joint angles retained (freeze in current position)
- Animation timer does not advance during pause
Component Factory Registration
The plugin registers the actuator with VR-Forces component factory:
DT_VRF_DLL_PLUGIN bool DtInitializeVrfPlugin(DtCgf* cgf)
{
DtFactoryManager* factoryManager = cgf->factoryManager();
factoryManager->componentFactory()->addCreatorFcn(
DtExampleHumanArtPartActuatorType,
DtExampleHumanArtPartActuator::creator);
return true;
}
Why This Matters:
- Type string
DtExampleHumanArtPartActuatorType identifies the component
- Factory enables instantiation from entity configuration files
- Registration during plugin initialization phase
Deployment and Testing
Installation
Build the example (see Environment Setup & Build Guide):
cd examples\build
cmake --build . --config RelWithDebInfo --target humanArtPartActuator
Install the plugin to the VR-Engage installation:
cmake --install . --config RelWithDebInfo
This copies the plugin to <VR-Engage-Install-Dir>\plugins64\vrForces\release\exampleHumanArtPartActuator.dll
Verify installation:
dir "<VR-Engage-Install-Dir>\plugins64\vrForces\release\exampleHumanArtPartActuator.dll"
Configuration
Backend plugin loads automatically: The VR-Engage toolkit installer automatically installs the backend plugin configuration file appData/plugins/exampleHumanArtPartActuator.xml which tells VR-Forces to load the DLL. No manual plugin configuration is required.
Add actuator to entity definition (.entity file):
<entity name="AnimatedHuman">
<entityType domain="1" kind="3" country="225" category="11" subcategory="1"/>
<articulatedParts>
<part id="1" type="ShoulderLeft" typeClass="4"/>
</articulatedParts>
<components>
<component type="vre-example-human-art-part-actuator"/>
</components>
</entity>
Note: The articulated part must be defined in the entity file for the actuator to control it. See TestHuman.entity in the VR-Forces installation for a complete example.
Testing Procedure
- Launch VR-Forces with the plugin loaded
- Create entity using the configured entity type with the actuator
- Start simulation
- Expected Behavior:
- Human character appears in scene
- Left shoulder joint begins animating immediately
- Shoulder moves smoothly between 0° and 90° elevation
- Animation completes one cycle every 4 seconds
- Motion stops when simulation paused
- Network Verification (if using DIS/HLA):
- Articulated parts PDUs transmitted for the entity
- Remote visualization shows synchronized joint motion
- Angular rates enable smooth interpolation
Verification:
- Check VR-Forces log for plugin initialization:
[Plugin] Loaded exampleHumanArtPartActuator
[Component Factory] Registered vre-example-human-art-part-actuator
- Enable articulated parts visualization in VR-Vantage
- Use network capture tools to verify articulated parts PDUs
Troubleshooting
Plugin not loading:
- Verify DLL is in
<VR-Engage-Install-Dir>\plugins64\vrForces\release\
- Check plugin package configuration includes correct path
- Review VR-Forces log for load errors
Joint not animating:
- Symptom: Entity appears but shoulder doesn't move
- Cause: Articulated part not defined in entity file
- Solution: Add
<part id="1" type="ShoulderLeft" typeClass="4"/> to entity definition
Jerky motion:
- Symptom: Joint animation appears stuttering or discontinuous
- Cause: Network latency or missing angular rate
- Solution: Verify angular rates are set correctly, check network conditions
Wrong joint moving:
- Symptom: Different joint animates instead of left shoulder
- Cause: Articulated part ID mismatch between code and entity definition
- Solution: Ensure DIS art part type matches entity file part definition
Technical Reference
File Structure
examples/humanArtPartActuator/
├── CMakeLists.txt # Build configuration
├── README.md # This documentation
├── plugin.cxx # VR-Forces plugin entry point
├── exampleHumanArtPartActuator.h # Actuator class declaration
└── exampleHumanArtPartActuator.cxx # Actuator implementation
Key Classes
| Class | Base Class | Purpose | Header |
DtExampleHumanArtPartActuator | DtActuatorComponent | Animates human shoulder joint | exampleHumanArtPartActuator.h |
DtPlatformLocalObjectFacade | N/A | Facade for accessing platform-specific data | vrfobjcore/platformLocalObjectFacade.h |
DtArticulatedPartStateRepository | N/A | Interface for controlling joint state | VR-Forces core |
API Methods Used
DtActuatorComponent::tick() - Per-frame update for actuator behavior
DtActuatorComponent::dT() - Frame delta time in seconds
DtPlatformLocalObjectFacade::nextFramePart() - Retrieve articulated part by type
DtArticulatedPartStateRepository::setElevation() - Set joint elevation angle (radians)
DtArticulatedPartStateRepository::setElevationRate() - Set joint angular rate (radians/second)
DtArticulatedPartStateRepository::setAzimuth() - Set joint azimuth angle
DtArticulatedPartStateRepository::setRotation() - Set joint rotation angle
DtFactoryManager::componentFactory() - Access component factory for registration
DI-Guy Articulated Part Types
Common DIS art part types for DI-Guy characters (from DtDiGuyArtPartLinkMapper.h):
| Joint | DIS Art Part Type Constant |
| Left Shoulder | DiGuyDisArtPartShoulderLeft |
| Right Shoulder | DiGuyDisArtPartShoulderRight |
| Left Elbow | DiGuyDisArtPartElbowLeft |
| Right Elbow | DiGuyDisArtPartElbowRight |
| Left Hip | DiGuyDisArtPartHipLeft |
| Right Hip | DiGuyDisArtPartHipRight |
| Left Knee | DiGuyDisArtPartKneeLeft |
| Right Knee | DiGuyDisArtPartKneeRight |
| Neck | DiGuyDisArtPartNeck |
| Head | DiGuyDisArtPartHead |
Joint Degrees of Freedom
Each articulated part has three rotational degrees of freedom:
| Axis | Description | Zero Position |
| Azimuth | Rotation about vertical axis | Forward-facing |
| Elevation | Rotation about lateral axis | Arm at side (shoulder), straight (elbow) |
| Rotation | Rotation about longitudinal axis | Neutral/natural position |
All angles specified in radians. Positive angles follow right-hand rule.
Build Targets
- Plugin:
exampleHumanArtPartActuator.dll (Windows)
- Install Location:
plugins64/vrForces/release/
Related Documentation:
- VR-Engage Examples Overview
- VR-Forces Articulated Parts System Documentation
- DI-Guy Character Integration Guide
- VR-Forces Actuator Component Development
- DIS Articulated Parts PDU Specification