Model Collision Detection

Updated: 10/06/2022

Although the model itself does not have the ability to perform collision detection, the ability to obtain vertex information from the ArtMesh can be used to implement the collision detection process.
The “collision detection” described here refers to a test to see if the target mesh is at a specified point on the screen.

Prepare for Collision Detection

The ArtMesh is used to perform collision detection.
See “Setting Up Collision Detection in the Editor” for preparation of the ArtMesh for collision detection in the Editor.
After preparing collision detection, it is necessary to set up collision detection using the Cubism Viewer (for OW) function and incorporate it into the .model3.json file.

When you set up collision detection in Cubism Viewer (for OW) and output it, the .model3.json file will contain the following description.

{
    ...
       "HitAreas": [
                {
                        "Id": "HitArea",
                        "Name": "Body"
                }
        ]
}

In Cubism Viewer (for OW), only ArtMeshes with HitArea… and ID can be registered,
but if the .model3.json file is processed directly in a text editor, ArtMeshes other than HitArea… can be set for collision detection.

Make a Collision Detection

Use one of the following functions can be used for collision detection:

  • CubismUserModel::IsHit function in Native (C++)
  • CubismUserModel.isHit function in Web (TypeScript)
  • CubismUserModel.isHit function in Java

The first argument specifies the ID of the target drawable, and the second and third arguments specify the X and Y values on the drawing to be inspected.

// C++
CubismUserModel model;
CubismIdHandle drawId = CubismFramework::GetIdManager()->GetId("HitArea1");
if(model.IsHit(drawId, x, y))
{
  // Process
}
// TypeScript
let model: CubismUserModel;
let drawId: CubismIdHandle = CubismFramework.getIdManager().getId("HitArea1");
if(mode.isHit(drawId, x, y))
{
    // Process
}
// Java
CubismUserModel model;
CubismId drawId = CubismFramework.getIdManager().getId("HitArea1");
if(model.isHit(drawId, x, y)){
	// Process
}

Details and Notes on Collision Detection

// C++
csmBool CubismUserModel::IsHit(CubismIdHandle drawableId, csmFloat32 pointX, csmFloat32 pointY)
{
    csmInt32 drawIndex = _model->GetDrawableIndex(drawableId);

    if (drawIndex < 0)
    {
        return false; // false if not present.
    }

    csmInt32 count = _model->GetDrawableVertexCount(drawIndex);
    const csmFloat32* vertices = _model->GetDrawableVertices(drawIndex);

    csmFloat32 left = _model->GetCanvasWidth();
    csmFloat32 right = 0.0f;
    csmFloat32 top = _model->GetCanvasHeight();
    csmFloat32 bottom = 0.0f;

    for (csmInt32 j = 0; j < count; ++j)
    {
        csmFloat32 x = vertices[Constant::VertexOffset + j * Constant::VertexStep];
        csmFloat32 y = vertices[Constant::VertexOffset + j * Constant::VertexStep + 1];

        if (x < left)
        {
            left = x; // Min x
        }

        if (x > right)
        {
            right = x; // Max x
        }

        if (y < top)
        {
            top = y; // Min y
        }

        if (y > bottom)
        {
            bottom = y; // Max y
        }
    }

    csmFloat32 tx = _modelMatrix->InvertTransformX(pointX);
    csmFloat32 ty = _modelMatrix->InvertTransformY(pointY);

    return ((left <= tx) && (tx <= right) && (top <= ty) && (ty <= bottom));
}
// TypeScript
public isHit(drawableId: CubismIdHandle, pointX: number, pointY: number): boolean
{
    const drawIndex: number = this._model.getDrawableIndex(drawableId);

    if(drawIndex < 0)
    {
        return false; // false if not present.
    }
    
    const count: number = this._model.getDrawableVertexCount(drawIndex);
    const vertices: Float32Array = this._model.getDrawableVertices(drawIndex);

    let left: number = vertices[0];
    let right: number = vertices[0];
    let top: number = vertices[1];
    let bottom: number = vertices[1];

    for(let j: number = 1; j < count; ++j)
    {
        let x = vertices[Constant.vertexOffset + j * Constant.vertexStep];
        let y = vertices[Constant.vertexOffset + j * Constant.vertexStep + 1];

        if(x < left)
        {
            left = x; // Min x
        }
        
        if(x > right)
        {
            right = x; // Max x
        }

        if(y < top)
        {
            top = y; // Min y
        }

        if(y > bottom)
        {
            bottom = y; // Max y
        }
    }

    const tx: number = this._modelMatrix.invertTransformX(pointX);
    const ty: number = this._modelMatrix.invertTransformY(pointY);

    return ((left <= tx) && (tx <= right) && (top <= ty) && (ty <= bottom));
}
// Java
public boolean isHit(CubismId drawableId, float pointX, float pointY){
  final int drawIndex = _model.getDrawableIndex(drawableId);
  
  if (drawIndex < 0) {
    return false;
  }
  
  final int count = _model.getDrawableVertexCount(drawIndex);
  final float[] vertices = _model.getDrawableVertices(drawIndex);
  float left = vertices[0];
  float right = vertices[0];
  float top = vertices[1];
  float bottom = vertices[1];
  
  for (int i = 1; i < count; ++i)
  {
    float x = vertices[VERTEX_OFFSET + i * VERTEX_STEP];
    float y = vertices[VERTEX_OFFSET + i * VERTEX_STEP + 1];
    
    if (x < left) {
      // Min x
      left = x;
    }

    if (x > right) {
      // Max x
      right = x;
    }
    
    if (y < top) {
      // Min y
      top = y;
    }
    
    if (y > bottom) {
      // Max y
      bottom = y;
    }
  }

  final float tx = _modelMatrix.invertTransformX(pointX);
  final float ty = _modelMatrix.invertTransformY(pointY);
  return (left <= tx) && (tx <= right) && (top <= ty) && (ty <= bottom);
}

Collision detection is a mechanism that scans all vertices of the ArtMesh, creates a rectangular range from the maximum and minimum XY coordinates of the vertices,
inverts the screen coordinates to be inspected from the transformation matrix of the model, and checks if they fit within the rectangle.
When using this function, the following points should be noted.

  • If rotation is entered in the transformed coordinates of the model, it will not be transformed correctly.
  • An ArtMesh that is close to a rectangle changes size significantly when rotated by a rotation deformer or other means.
Please let us know what you think about this article.