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.
- Loading the controller model asynchronously. The limitation for this API is that
WVR_GetCurrentControllerModel
orWVR_GetCurrentControllerEmitter
should not be called at render thread (or any thread that will block frame update). - Initializing the imported data to the graphics card. It includes all vertex attributes of every component, and the textures of the controller.
- 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.