Raycasting (Cocos Creator)

最終更新: 2023年3月14日

概述

Raycasting是用于判定用户指定的Cubism网格是否与任意座标相交的功能。
可以获得单击/点击座标、场景中任意物体与指定网格之间的重叠检测。
参考此处了解如何使用Raycasting。

Cubism SDK for Cocos Creator中的Raycasting包括两个主要元素。

  1. 用于指定要判断的图形网格的组件
  2. 进行指定输入座标的图形网格重叠检测的组件。

1. 用于指定要判断的图形网格的组件

使用CubismRaycastable指定用于重叠检测的网格。

CubismRaycastable通过附加到置入[Prefab根]/Drawables/下的Node来使用。
与附加的Node具有相同ID的图形网格将用于重叠检测。

CubismRaycastable具有设置该网格的重叠检测精度的参数。

@ccclass('CubismRaycastable')
export default class CubismRaycastable extends Component {
  /** The precision. */
  @property({
    type: Enum(CubismRaycastablePrecision),
    serializable: true,
    visible: true,
    readonly: false,
  })
  public precision: CubismRaycastablePrecision = CubismRaycastablePrecision.boundingBox;
}

CubismRaycastable.Precision有两个可设置的值,每个值如下。

  • BoundingBox
    包围网格并具有水平或垂直边的矩形用作重叠检测。
    根据网格的形状,即使在网格外的座标处也会执行重叠检测,但它比Triangles具有更好的性能。
  • Triangles
    网格的形状被用作重叠检测的范围。
    虽然性能不如BoundingBox,但可以在准确的范围内做出判断。
enum CubismRaycastablePrecision {
  /** Cast against bounding box. */
  boundingBox,

  /** Cast against triangles. */
  triangles,
}

2. 进行指定输入座标的图形网格重叠检测的组件。

使用CubismRaycaster获得实际的重叠检测。
使用CubismRaycaster时,将其附加到Cubism的Prefab根部。

当CubismRaycaster原始化时,获取对附加到Prefab的所有CubismRaycastables的参考。
在执行过程中追加/删除重叠检测的网格时,会调用CubismRaycaster.refresh()再次获取参考。

  /** Refreshes the controller. Call this method after adding and/or removing {@link CubismRaycastable}. */
  private refresh(): void {
    const candidates = ComponentExtensionMethods.findCubismModel(this)?.drawables ?? null;
    if (candidates == null) {
      console.error('CubismRaycaster.refresh(): candidates is null.');
      return;
    }

    // Find raycastable drawables.
    const raycastables = new Array<CubismRenderer>();
    const raycastablePrecisions = new Array<CubismRaycastablePrecision>();

    for (var i = 0; i < candidates.length; i++) {
      // Skip non-raycastables.
      if (candidates[i].getComponent(CubismRaycastable) == null) {
        continue;
      }
      const renderer = candidates[i].getComponent(CubismRenderer);
      console.assert(renderer);
      raycastables.push(renderer!);

      const raycastable = candidates[i].getComponent(CubismRaycastable);
      console.assert(raycastable);
      console.assert(raycastable!.precision);
      raycastablePrecisions.push(raycastable!.precision!);
    }

    // Cache raycastables.
    this.raycastables = raycastables;
    this.raycastablePrecisions = raycastablePrecisions;
  }

  /** Called by Cocos Creator. Makes sure cache is initialized. */
  protected start(): void {
    // Initialize cache.
    this.refresh();
  }

使用CubismRaycaster.raycast1()或CubismRaycaster.raycast2()从座标中获取重叠检测。

  public raycast1(
    origin: Vector3,
    direction: Vector3,
    result: CubismRaycastHit[],
    maximumDistance: number = Number.POSITIVE_INFINITY
  ): number {
    return this.raycast2(
      geometry.Ray.create(origin.x, origin.y, origin.z, direction.x, direction.y, direction.z),
      result,
      maximumDistance
    );
  }

  /**
   * Casts a ray.
   * @param ray
   * @param result  The result of the cast.
   * @param maximumDistance [Optional] The maximum distance of the ray.
   * @returns
   * true in case of a hit; false otherwise.
   *
   * The numbers of drawables had hit
   */
  public raycast2(
    ray: geometry.Ray,
    result: CubismRaycastHit[],
    maximumDistance: number = Number.POSITIVE_INFINITY
  ): number {
    // Cast ray against model plane.
    const origin = Vector3.from(ray.o);
    const direction = Vector3.from(ray.d);
    const intersectionInWorldSpace = origin.add(
      direction.multiplySingle(direction.z / origin.z)
    );
    let intersectionInLocalSpace = Vector3.from(
      this.node.inverseTransformPoint(new math.Vec3(), intersectionInWorldSpace.toBuiltinType())
    );
    intersectionInLocalSpace = intersectionInLocalSpace.copyWith({ z: 0 });
    const distance = intersectionInWorldSpace.magnitude();
    // Return non-hits.
    if (distance > maximumDistance) {
      return 0;
    }
    // Cast against each raycastable.
    let hitCount = 0;
    console.assert(this.raycastables);
    const raycastables = this.raycastables!;
    console.assert(this.raycastablePrecisions);
    const raycastablePrecisions = this.raycastablePrecisions!;
    for (let i = 0; i < raycastables.length; i++) {
      const raycastable = raycastables[i];
      const raycastablePrecision = raycastablePrecisions[i];
      // Skip inactive raycastables.
      console.assert(raycastable.meshRenderer);
      if (!raycastable.meshRenderer!.enabled) {
        continue;
      }
      const bounds = raycastable.mesh.calculateBounds();

      // Skip non hits (bounding box)
      if (!bounds.contains(intersectionInLocalSpace)) {
        continue;
      }

      // Do detailed hit-detection against mesh if requested.
      if (raycastablePrecision == CubismRaycastablePrecision.triangles) {
        if (!this.containsInTriangles(raycastable.mesh, intersectionInLocalSpace)) {
          continue;
        }
      }

      result[hitCount] = new CubismRaycastHit({
        drawable: raycastable.getComponent(CubismDrawable),
        distance: distance,
        localPosition: intersectionInLocalSpace,
        worldPosition: intersectionInWorldSpace,
      });

      ++hitCount;

      // Exit if result buffer is full.
      if (hitCount == result.length) {
        break;
      }
    }

    return hitCount;
  }

CubismRaycaster.raycast()在返回值中返回获得重叠检测的网格数。
此外,对于传递给参数的CubismRaycastHit[]类型的副本,设置获得重叠检测的网格信息。

      result[hitCount] = new CubismRaycastHit({
        drawable: raycastable.getComponent(CubismDrawable),
        distance: distance,
        localPosition: intersectionInLocalSpace,
        worldPosition: intersectionInWorldSpace,
      });

      ++hitCount;

当多个网格在同一座标上重叠时,CubismRaycaster.raycast()会获得CubismRaycastHit[]类型副本的元素数量。
如果超过元素数量的网格重叠,将不会获得超出部分网格的结果。

CubismRaycastHit是包含已获得重叠检测的网格信息的类。

  /** The hit {@link CubismDrawable} */
  public readonly drawable: CubismDrawable | null;

  /** The distance the ray traveled until it hit the {@link CubismDrawable}. */
  public readonly distance: number;

  /** The hit position local to the {@link CubismDrawable}. */
  public readonly localPosition: Vector3;

  /** The hit position in world coordinates. */
  public readonly worldPosition: Vector3;
  • drawable
    它是获得重叠检测的图形网格的参考。
  • distance
    与指定座标的距离。
    传递给CubismRaycaster.Raycast()参数的origin或ray.origin与Drawable的Transform.position之间的线性距离。
  • localPosition
    获得重叠检测的图形网格的局部座标。
  • worldPosition
    获得重叠检测的图形网格的世界座标。
请问这篇文章对您有帮助吗?
关于本报道,敬请提出您的意见及要求。