How to Use Controller ModelΒΆ

With VIVE Wave™, developers can get the controller model of the currently connected device. The structure WVR_CtrlerModel_t is used to represent the render model. Throught this structure, you can get the vertex attributes (position, normal, texture coordinate) of each component of controller model, the texture of its body, the touchpad plane (simulates where you touch the touchpad) and battery information (shows the remaining battery power of a controller).

The structure WVR_VertexBuffer_t is used to record the vertex attributes of the mesh.

  • The variable buffer is an array for storing vertex attributes and has size length.
  • The variable dimension tells you how many elements are in a set of vertex attribute.

If you want to initialize the vertex attribute, use the following code (example in OpenGL):

//Bind buffer.
glGenBuffers(1, &vaBufID);
glBindBuffer(GL_ARRAY_BUFFER, vaBufID);
glBufferData(GL_ARRAY_BUFFER, (*mCachedData).compInfos.table[wvrCompID].vertices.buffer * sizeof(float), (*mCachedData).compInfos.table[wvrCompID].vertices.buffer, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
//...
//Enable vertex attribute.
glBindBuffer(GL_ARRAY_BUFFER, vaBufID);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, (*mCachedData).compInfos.table[wvrCompID].vertices.dimension, GL_FLOAT, GL_FALSE, sizeof(float) * (*mCachedData).compInfos.table[wvrCompID].vertices.dimension, 0);

The structure WVR_IndexBuffer_t is used to record the vertex index of each face in the mesh.

  • The variable buffer is an array used to store indices and has size length.
  • The variable type represents the number indices are in a face.
  • In the VIVE controller model, the variable type is usually equal to 3 in each component.

If you want to initialize the indices, use the following code (example in OpenGL):

//Bind buffer
glGenBuffers(1, &idxBufID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, idxBufID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, (*mCachedData).compInfos.table[wvrCompID].indices.size * sizeof(uint32_t), (*mCachedData).compInfos.table[wvrCompID].indices.buffer, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

The structure WVR_CtrlerTexBitmap_t is used to record all the textures in the controller model. This structure is the same as AndroidBitmap in NDK. In the controller model, the format of the texture is RGBA8888.

If you want to initialize a texture, use the following code (example in OpenGL):

//wvrBitmap is WVR_CtrlerTexBitmap_t.
glGenTextures(1, &texID);
if (wvrBitmap.format == ANDROID_BITMAP_FORMAT_RGBA_8888) {
    glBindTexture(GL_TEXTURE_2D, texID);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); //only one leve1.
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, wvrBitmap.width, wvrBitmap.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, wvrBitmap.bitmap);
}

The structure WVR_CtrlerCompInfo_t is used to record the mesh part of the controller model. Vertex attributes vertices, normals, texCoords and index buffer indices store the shape of this component.

  • The variable texIndex indicates which texture you need to use in the texture table (usually equal to 0).
  • The variable localMat is the transformation matrix from the origin of the controller. Its format follows the OpenGL convention (column-major).
  • The final variable name is the name of this component. Its length is smaller than 63 bytes.

The name of each controller model component is defined as:

Component Name
Body __CM__Body
Trigger __CM__TriggerKey
Touchpad __CM__TouchPad
Grip __CM__Grip
DPad_Left __CM__DPad_Left
DPad_Right __CM__DPad_Right
DPad_Up __CM__DPad_Up
DPad_Down __CM__DPad_Down
Menu __CM__AppButton
Home __CM__HomeButton
Volume __CM__VolumeKey, or divide into __CM__VolumeUp and __CM__VolumeDown
DigitalTrigger __CM__DigitalTriggerKey (for supporting old device service)
Touchpad Effect __CM__TouchPad_Touch
Emitter __CM__Emitter
Battery __CM__Battery
Bumper __CM__BumperKey

The components of the controller model are not mandatory. Therefore, developers may not be able to get all the components described above.

Note : The component __CM__Body is made out of all the controller appearance related meshes from all the components (except battery, emitter and touchpad touch indicator). Usually, the components should be hidden unless the corresponding button is pressed.

The structure WVR_TouchPadPlane_t holds the geometric information about the touchpad plane. The fields u, v, w, and center represent the origin and axis of the touchpad plane.

  • The field floatingDistance is used to adjust the distance between the touchpad touch indicator and the touchpad plane.
  • radius shows the touchpad range in the plane.
  • valid is a flag that indicates whether the touchpad plane information is read from the device service description file. If valid is false, then the values are calculated estimations. If this happens, convert the analog Y-axis using the following sample code:
WVR_Axis_t axis = WVR_GetInputAnalogAxis(mCtrlerType, WVR_InputId_Alias1_Touchpad);//get the touched pt on touchpad.
//1. calculate touchpad touch pos.
float invAxisY = 1.0f;
if (touchpadPlane.valid == true) {
    invAxisY = -1.0f;
}
//
Vector3 Tp;
//Pout = Pc + Ax * R + Ay * R;
Tp.x = axis.x * mRadius;
Tp.y = mFloatingDistance;
Tp.z = invAxisY * axis.y * mRadius;
Matrix4 offsetMat;
offsetMat[12] = Tp.x;
offsetMat[13] = Tp.y;
offsetMat[14] = Tp.z;
offsetMat[15] = 1.0f;
//
Matrix4 dotFinalMat = mTouchPadPlaneMat * offsetMat;//Use this as transformation matrix in ctrler space.

The structure WVR_BatteryLevelTable_t is used to record the battery level information about the rendering controller. The fields texTable, minLvTable and maxLvTable can be used to deduce the correct texture that corresponds to certain battery percentage levels. The texture is used to render component __CM__Battery. The sample code below shows how to update the battery level every second using the corresponding texture:

//Check battery is exist or not.
if (mCompExistFlags[CtrlerComp_Battery] == false) {
    return;
}
std::chrono::system_clock::time_point current = std::chrono::system_clock::now();
float diffs = std::chrono::duration_cast<std::chrono::seconds>(
    current - mLastUpdateTime).count();
if (diffs >= 1.0f) {
    mLastUpdateTime = current;
    float power = WVR_GetDeviceBatteryPercentage(mCtrlerType);
    for (uint32_t lv = 0; lv < mBatMinLevels.size(); ++lv) {
        uint32_t percentage = static_cast<uint32_t>(power * 100.0f);
        if (percentage >= mBatMinLevels[lv] && percentage <= mBatMaxLevels[lv]) {
            mBatteryLevel = lv;//Indicate target interval.
            break;
        }
    }
}

The process to draw the controller can be divided into three parts.

  1. Loading the controller model asynchronously. The limitation for this API is that WVR_GetCurrentControllerModel or WVR_GetCurrentControllerEmitter should not be called at render thread (or any thread that will block frame update).
  2. Initializing the imported data to the graphics card. It includes all vertex attributes of every component, and the textures of the controller.
  3. Render __CM__Body and __CM__Battery (if it exists) of controller. Hide button components at the beginning. If some buttons are pressed, show these buttons and add visual effects to highlight the corresponding components.

To see a more detailed explanation, refer to the Controller class in the wvr_hellovr sample.