v0.4 Release Notes

The focus of this update was to introduce two new major systems to Banshee: Audio and Animation. We also included a variety of minor bugfixes and smaller improvements.

Audio sub-system

The audio system is represented by two new components: AudioSource, AudioListener and an AudioClip resource. All audio components can be used directly in the editor, through C# scripting, or through low level C++ API. We support multi-channel 2D and 3D audio, with import for various formats, support audio streaming and decompression. The system runs on separate threads for minimal performance impact, and the entire system is implemented through a plugin interface so you may create your own audio backends.

2D audio

Support for traditional 2D audio playback, without any spatial distortions, useful for things like music and narration. Play back audio by instantiating AudioSource components, or manipulate them through script/C++ API for manual control over time, volume, looping and pitch.

3D audio

Support for 3D audio spatialization, where played sound is affected by position of the sound source and listener, as well as their velocity (Doppler effect). Position and velocity of the AudioSource and AudioListener is automatically deduced from the scene object they are on, allowing these effects to occurr without any additional setup. You may manipulate the scene objects manually, or through physics and animation to achieve different effects. You may also customize attenuation distances and audio source priority for full control.

Multi-channel

Support for multi-channel audio up to and including 7.1 surround has been implemented.

Multi-listener

Multiple audio listeners in a single scene are allowed, making it easy to create split-screen and other local multiplayer experiences.

Supported formats

All backends support .OGG, .FLAC and .WAV formats. FMOD backend also supports .MP3 and most other common audio formats. Audio is imported directly through drag-and-drop in the editor, or through the low-level C++ API for complete manual control. Audio clips can be converted to uncompressed PCM format on import, for minimal performance impact during playback, or to VORBIS format for minimal storage/memory footprint.

Streaming

When importing audio clips user can choose whether to fully load audio clips during playback, or to load only parts of the audio clip as the playback goes on. This ensures minimal memory footprint, and can be useful to avoid loading large audio clips like music, all at once. When combined with compressed audio, audio will also be decompressed on playback, at the cost of additional CPU performance. Streaming happens on a separate thread that does not disturb the primary threads so gameplay and rendering is not affected.

Decompression

With compressed audio you are given a choice whether to decompress the audio during import, during playback start or piece-wise as the playback is happening. This allows you to completely control CPU performance vs. storage vs. memory footprint of the audio system, on a per-clip basis. Runtime decompression happens on a separate thread that does not disturb the primary threads so gameplay and rendering is not affected.

Device enumeration

All audio devices on user's device are enumerated, and you may switch between them as required. You may use this to construct audio option menus and similar.
    // Enumerate all devices
    AudioDevice[] allDevices = Audio.AllDevices;
    foreach(var device in allDevices)
        Debug.Log("Found device: " + device.Name);

    // Get default device
    Debug.Log("Default device: " + Audio.DefaultDevice.Name);

    // Change device
    int selectedDeviceIdx = ...;
    Audio.ActiveDevice = allDevices[selectedDeviceIdx];
    

Multiple backends

As with most things in Banshee we wanted to make the audio system modular, therefore we created a plugin interface that you may use to create your own audio backends without having to modify the engine core, scripting API or the tools. We also decided to make use of this system right away, and have implemented audio on two separate backends: OpenAL and FMOD. We wanted OpenAL in order to keep in line with the open source nature of Banshee, but we also understand that bigger games need something more robust, so we have also added an FMOD backend. We don't yet expose all advanced FMOD features, but it is fairly trivial to do so, and we will be extending the audio system in the future.

Animation sub-system

Our animation sub-system consists of three separate parts: skeletal skinning animation, morph shape animation and animation clip editor - any of which a major feature upon itself. We focused a lot on performance, with all animation types being GPU accelerated and evaluated on a separate CPU thread. Aside from basic animation we tried to provide a variety of other features like blending, IK support and generic script animation.

Skeletal skinning animation

Full support for traditional skeletal animation with skinning. Animations can be easily imported from external files like .FBX. Animations are not tied to their meshes so user may import separate animations from different files, as long as the mesh skeletons match. Multiple animations can also be imported from a single file, by using an appropriate exporter or by using the animation split functionality on import.

Animation is exposed through the Animation component and AnimationClip resource on the high level, and objects be animated simply through editor's drag and drop functionality, C# scripting or low level C++ API. We also expose AnimationCurve to both C# and C++ APIs so you may manually create, manipulate and evaluate animations, if needed. Low level C++ API additionally exposes direct control over skeleton and animation clip import.

Morph shape animation

Use morph shape (per-vertex) animation to animate objects not suited for animation via traditional skeletal animation. Certain type of animations like facial expressions can yield better quality when implemented through morph shapes. Morph shape channels and be additively blended, where each channel can have one or multiple frames for sequential blending. Morph shapes can be exported from external files like .FBX similar to skeletal animation. Morph shape curves can be imported from external files, created within the editor or their weights can be manipulated directly from the scripting API.

Animation editor

Our animation editor allows you to create animation clips from within Banshee. This allows you to animate any scene object, allowing you to create things like cinematic camera paths, scripted character movement, custom morph shape curves and more. Not only that but you are allowed to animate any numeric script variable, including for your own custom scripts, giving you a large amount of control. Use this to create things like flickering lights, modify camera properties like zoom and similar.

Root motion

Extract animation of the root bone and use it for precise character movements. Moving your character using linear movement doesn't yield good effects - root motion allows your artists to determine how much and when your character moves so it is perfectly in sync with the animation. This property is exposed through scripting so you may use or ignore it at will.

IK post-processing

You may manipulate skeleton bones from within scripting or C++ APIs, allowing you to manually control their transforms, useful for systems like inverse kinematics and similar. You may also attach physics objects to animation bones for a ragdoll like effect.

Events

Set up animation events in the animation editor. Events trigger when a certain time in an animation is reached and automatically trigger the requested script method. For example you may want to hook up footstep sounds to play whenever character's foot touches the ground.

Sockets

Use sockets to bind scene object to animation bones. This allows you to attach items to animated objects like characters (e.g. attaching a sword to the character's hand), and the object will animate together with the bone.
    // Find, assign or create a scene object
    SceneObject sceneObject = ...;
    Animation animation = sceneObject.GetComponent<Animation>();
    
    // Create a bone component
    SceneObject boneSO = new SceneObject("Bone");
    Bone bone = boneSO.AddComponent<Bone>();
    bone.Name = "bn_L_wrist";

    // .. attach your custom objects or components to the bone scene object as needed ..
    

Culling

Fully control animation culling by manually setting up object bounds. Animated objects rarely have constant bounds and custom control over culling is important. You may also choose to either play or pause animations currently out of view. This can be useful for performance if the user is unlikely to notice such stops in animation.

Blending

Aside from morph shape blending, you may also blend multiple skeletal animations. We support 1D and 2D blending allowing you to control animation blending easily for animations like turn left/right (1D) or look (2D) animations. Blending is exposed through the C# and C++ API, and we also support fully manual control over played animations so you may construct custom blending models as needed.
    // Find, assign or create a scene object
    SceneObject sceneObject = ...;
    Animation animation = sceneObject.GetComponent<Animation>();
    
    // Assign animation clips from editor
    AnimationClip lookLeft = ...;
    AnimationClip lookForward = ...;
    AnimationClip lookRight = ...;

    Blend1DInfo blendInfo = new Blend1DInfo(3);
    blendInfo.clips[0].clip = lookLeft;
    blendInfo.clips[0].position = 0.0f;

    blendInfo.clips[1].clip = lookForward;
    blendInfo.clips[1].position = 0.5f;

    blendInfo.clips[2].clip = lookRight;
    blendInfo.clips[2].position = 1.0f;

    float t = ...; // Calculate t based on user input
    animation.Blend1D(blendInfo, t);
    

Cross fade

Smoothly transition from one animation to another by using the cross fade functionality. Previous animation will be faded out while the current one is faded in, over a specific time period. This functionality is exposed through the C# and C++ API.
    // Find, assign or create a scene object
    SceneObject sceneObject = ...;
    Animation animation = sceneObject.GetComponent<Animation>();

    // Assign animation clip from editor
    AnimationClip run = ...;

    // ... walk animation currently playing ...

    if (Input.IsButtonDown(ButtonCode.LeftShift))
        animation.CrossFade(run, 0.5f); // Fade in run animation when shift is pressed
    

Masking

Set up skeleton masking, allowing you to disable animation of certain bones. Useful if you want to animate certain bones manually, or using a different animation.

Additive animation

Play skeletal animation over multiple layers in order to blend them additively. Additive animations can play on top of base animation in order to increase animation variety without having to create many separate animations, reducing both animation time required and animation storage requirements. Consider a normal running animation vs. run while waving vs. run while shooting - to add walking animation you would need to create three more animations, but if you implement waving and shooting as additive animations they can be added on top of the walk animation, allowing you to create just one extra animation and re-use the additive animations. To use the functionality simply mark the animation clip as additive during import, and play it back using the C# or C++ API.

Caching

Animation curve evaluation uses a caching system, ensuring high performance. As long as animation being played is sequential, the chance of cache being hit is high, considerably reducing number of CPU cycles required for curve evaluation.

Keyframe reduction

Our animation curves are stored as Hermite curves, which aside from values also store tangents, allowing us to create more complex animations using less keyframes. This also means we do not require constant sample rate, allowing us to eliminate many keyframes, significantly reducing animation memory footprint.

GPU accelerated

Final animation pose is applied to either skinned or morph shape mesh on the GPU to ensure high performance. Morph shape animation blending is done on the CPU in order to ensure to minimize bandwidth to GPU and improve performance.

Multi-threaded

All animation evaluation, including skeletal pose evaluation, blending operations and morph shape combining takes places on a separate CPU thread, ensuring other systems can run in parallel.