模型重叠检测

最終更新: 2022年10月6日

模型本身不具备重叠检测功能,但利用可以获取图形网格顶点信息的功能,可以实装重叠检测处理。
这里描述的“重叠检测”是指测试对象网格是否位于画面上的指定点。

重叠检测准备

在重叠检测中使用图形网格。
有关在Editor上为重叠检测准备图形网格,请参考“Editor上的重叠检测设置”
准备好重叠检测后,需要用Cubism Viewer(for OW)的功能设置重叠检测,并嵌入到.model3.json文件中。

如果在Cubism Viewer(for OW)上设置重叠检测并输出,在.model3.json文件中会描述如下。

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

在Cubism Viewer(for OW)中,只能注册设置了HitArea~和ID的图形网格,但是,
如果您直接使用文本编辑器加工.model3.json文件,则即使是HitArea~以外的图形网格,您也可以将其设置为重叠检测。

执行重叠检测

您可以使用以下任意函数进行重叠检测。

  • Native(C++)的CubismUserModel::IsHit函数
  • Web(TypeScript)的CubismUserModel.isHit函数
  • Java的CubismUserModel.isHit函数

第一个参数指定对象Drawable的ID,第二个和第三个参数指定要检查的绘制上的X和Y值。

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

重叠检测的内容及注意事项

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

    if (drawIndex < 0)
    {
        return false; // 不存在时为false
    }

    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
    }
    
    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);
}

重叠检测的机制是扫描图形网格的所有顶点,并通过顶点的XY座标的最大值和最小值创建一个矩形范围,
从模型的变换矩形对检查对象的画面座标进行逆向转变,检查是否在矩形内。
使用此函数时请注意以下事项:

  • 如果模型的转变座标中包含旋转,将无法正确转变。
  • 当接近四边形的图形网格通过旋转变形器等旋转时,尺寸会发生显著变化。
关于本报道,敬请提出您的意见及要求。