SDK Getting Started

Directory structure

  • bin : Executables and DLL files
  • docs : Documentations for DCC Plugin and Viewer
  • external: DXUT libraries used to run samples
  • include : Header files for HairWorks library integration
  • media : Sample art resources
  • samples : Sample projects for HairWorks library integration
_images/HairWorks_API_Overview_Diagram.jpg

API Overview

HairWorks SDK provides various API functions to manage assets and GPU resources, render and simulate hairs. Above diagram summarizes how each API calls relates to user inputs (left) and internal resources (right). Main header file is located in include\GFSDK_HairWorks.h and must be included to use HairWorks data structures and runtime APIs. All the API functions are encapsuled by an abstract API class GFSDK_HairSDK. HairWorks runs in any DirectX11 capable GPU devices and require dx11 runtime.

Initialization

Loading the library

The first step is to locate and load the HairWorks dll (located in bin\win32 and bin\win64). Make sure your runtime path points to the directory or copy the dll to your bin path.

To load the library:

#include "GFSDK_HairWorks.h" // hairworks main header file

GFSDK_HairSDK* g_pHairSDK = GFSDK_LoadHairSDK("GFSDK_HairWorks.win64.dll",
                                              GFSDK_HAIRWORKS_VERSION);

A custom memory allocator may be supplied as an optional argument. See the header file.

Hair Assets and Instances

HairWorks defines two different types of hair data - asset (GFSDK_HairAssetDescriptor) and instance (GFSDK_HairInstanceDescriptor).

A hair asset stores all the geometry data such as hair curves, skinning weights, etc., which are authored outside of HairWorks runtime and do not change during runtime. All the asset data reside in CPU memory once loaded and do not consume any GPU memory, thus do not require DirectX runtime to exist.

From each asset, users can instantiate multiple hair instances and its runtime behavior is controlled by the instance descriptor. Creation of each instance requires GPU buffers to be allocated and managed, thus requires DirectX runtime to be initialized beforehand. Separation of assets from instances allows users to share the same hair asset to create multiple characters, and efficiently manage GPU resources when hairs are not needed in certain parts of game.

Loading the hair asset

HairWorks provides multiple ways to load hair asset data.

  1. You can load a hair asset from the .apx/.apb file (generated by DCC tool or FurViewer) using the API:

    g_pHairSDK->LoadHairAssetFromFile(
            "test.apx",  // file path to the .apx/.apb file
            &hairAssetID); // output hair asset ID from HairWorks
    
  2. , or you can directly load it from memory buffer (e.g. when custom file system is used) using the API:

    g_pHairSDK->LoadHairAssetFromMemory(
            pMemoryBuffer,  // user pointer that stores the entire apx file in memory
            memoryBufferSizeBytes, // size of the user memory buffer
            &hairAssetID); // output hair asset ID from HairWorks
    
  3. , or you can manually fill in the asset descriptor (GFSDK_HairAssetDescriptor) and create a hair asset from it:

    GFSDK_HairAssetDescriptor hairAssetDescriptor;
    hairAssetDescriptor.m_NumGuideHairs = 4; // number of guide hairs
    hairAssetDescriptor.m_NumVertices = 20;  // number of total hair cvs
    hairAssetDescriptor.m_pVertices = vertices; // cv position data
    hairAssetDescriptor.m_pEndIndices = endIndices; // index to last cv for each guide curve
    ...
    
    g_pHairSDK->CreateHairAsset(hairAssetDescriptor, &hairAssetID);
    

All above APIs output a unique hair asset ID (GFSDK_HairAssetID) that can be later used to identify the hair asset for further modification and instance creation, so save this ID somewhere.

Initializing D3D runtime

When D3D device is created and intialized, initialize HairWorks runtime using the API:

g_pHairSDK->InitRenderResources(pd3dDevice);

This will initialize all the global GPU resources used by HairWorks runtime such as shaders, etc.

Creating and deleting hair instances

Once the DirectX runtime was initialized, we can start creating hair instances using the API:

GFSDK_HairInstanceID hairInstanceID;
g_pHairSDK->CreateHairInstance(hairAssetID, &hairInstanceID);

When hair instances are no longer needed, delete the resource using the API:

g_pHairSDK->FreeHairInstance(hairInstanceID);

Runtime Controls

To simulate and render hairs, use the API functions described in this section. In many situations, users may want to separate code path for animation/simulation from rendering control flow. For each such code path, one needs to set the followings.

Setting context and camera

  1. set render context for HairWorks:

    g_pHairSDK->SetCurrentContext(pd3dContext);
    
  2. set view matrix and projection matrix:

    D3DXMATRIX projection; // ... get projection matrix from your camera definition
    D3DXMATRIX view; // // ... get model view matrix from your camera definition
    g_pHairSDK->SetViewProjection((const gfsdk_float4x4*)&view,(const gfsdk_float4x4*)&projection);
    

A hint about handedness of the camera may be supplied (used for backface culling feature). It is important to provide correct camera information as many features such as LOD rely on camera info. If your application has multiple windows with different camera settings, make sure to provide each camera info properly before calling the APIs below.

Updating control parameters

By default, HairWorks use control parameters stored in the asset. By updating instance descriptor, users can change all the control parameters anytime during runtime:

GFSDK_HairInstanceDescriptor hairInstanceDescriptor;
hairInstanceDescriptor.m_width = 0.2;
hairInstanceDescriptor.m_density = 1.0;
hairInstanceDescriptor.m_lengthNoise = 0.0f;
hairInstanceDescriptor.m_simulate = true;
...
g_pHairSDK->UpdateInstanceDescriptor(hairInstanceID, hairInstanceDescriptor);

Animating Hairs

To move and animate hairs, a typical process is to give it an animation first, by updating bones used to skin animated hair shapes. Once skinning data are set, we call StepSimulation() to simulate motion of hairs for each frame.

Updating skinning data

A skinning matrix is defined as inverse(bind pose) * world space bone matrix. This is exactly the same matrix you would use to skin underlying character mesh vertices.

Note that number of bones and bone orders must match the ones defined in the asset descriptor. (see the SetBoneRemapping() API to deal with bone number/order mismatch issue).

HairWorks provide the following options to update skinning.

  1. Updating the skinning with linear matrix:

    g_pHairSDK->UpdateSkinningMatrices(hairInstanceID, numBones, pSkinningMatrices);
    
  2. Updating the skinning with dual quaternion:

    g_pHairSDK->UpdateSkinningDQs(hairInstanceID, numBones, pDQs);
    

Note: If skinning update APIs are not used, HairWorks uses identity transform for all the skinning data.

Simulating/Animating Hair

  1. To activate simulation, m_simulate member of GFSDK_HairInstanceDescriptor must be set to true:

    // store hairInstanceDescriptor somewhere
    
    hairInstanceDescriptor.m_simulate = true;
    
    g_pHairSDK->UpdateInstanceDescriptor(hairInstanceID, hairInstanceDescriptor);
    
  2. To simulate hairs, use the following API:

    g_pHairSDK->StepSimulation();
    

This function simulates all active hair instances in a batch call. Note that if m_simulate is set to false, hairs will be animated due to the skinning data. So it is important to use this function even if you only want skinning based animation.

Rendering

To render hairs, users need to set device context and camera info as above. Then users would set pixel shader and other rendering resources if needed. Then calling RenderHairs() API will draw hairs onto current render target buffers.

Managing custom hair shaders

To provide maximum flexibility in hair rendering, HairWorks doesn’t use any hair shaders. Instead, we provide various example hair shaders in the included sample codes. Users can use such hair shaders or modified version of them which suit their needs the best. It is user’s responsibility to create and manage such shaders.

Set your hair pixel shader before rendering hairs:

pd3dContext->PSSetShader(myCustomHairWorksShader, NULL, 0);

Rendering hair instance

To render a hair instance, use the API:

g_pHairSDK->RenderHairs(hairInstanceID);

Customizing shader resources and constant buffers

HairWorks provide the following APIs for customized shader resource managment.

  1. GFSDK_HairShaderSettings

    In RenderHairs() call, users can provide additional shader settings to indicate what part of shader pipeline will be customized by the users.

  2. PrepareShaderConstantBuffer()

    HairWorks shaders need some global info such as camera projection, hair materials to be defined in a constant buffer. This API facilitate preparation of such constant buffers.

See sample codes for more details of how these APIs and hair shaders work.

Clean up and shutdown

To release the instance, asset, render resource and library, call the following APIs:

g_pHairSDK->FreeHairInstance(hairInstanceID); // deletes a hair instance
g_pHairSDK->FreeHairAsset(hairAssetID); // deletes a hair asset
g_pHairSDK->FreeRenderResources(); // shut down global GPU resources
g_pHairSDK->Release(); // deletes the SDK