Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save tomkrikorian/488aacf2abc2b52a79f477c0712f6fbf to your computer and use it in GitHub Desktop.

Select an option

Save tomkrikorian/488aacf2abc2b52a79f477c0712f6fbf to your computer and use it in GitHub Desktop.

Revisions

  1. tomkrikorian created this gist Oct 25, 2024.
    69 changes: 69 additions & 0 deletions generateShapeResourceFromBoundingBox.swift
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,69 @@
    /// Generates a collision shape from the model's bounding box
    /// - Returns: A `ShapeResource` representing the collision shape, or `nil` if the generation fails
    func generateShapeResourceFromBoundingBox() async -> ShapeResource? {
    // Get the model entity and its mesh
    guard let modelEntity = self.children.first as? ModelEntity,
    let modelMesh = modelEntity.model?.mesh else {
    Logger.realitykit.error("Required model components not found")
    return nil
    }

    // Get bounding boxes and calculate scale factors
    let entityBoundingBox = self.visualBounds(relativeTo: nil)

    guard modelMesh.bounds.extents != .zero else {
    Logger.realitykit.error("Invalid mesh bounds")
    return nil
    }

    let scaleFactors = simd_float3(
    entityBoundingBox.extents.x / modelMesh.bounds.extents.x,
    entityBoundingBox.extents.y / modelMesh.bounds.extents.y,
    entityBoundingBox.extents.z / modelMesh.bounds.extents.z
    )
    // Transform mesh instances
    let newInstances = modelMesh.contents.instances.map { instance -> MeshResource.Instance in
    var newInstance = instance
    let transform = instance.transform

    // Extract current scale
    let currentScale = simd_float3(
    simd_length(transform.columns.0),
    simd_length(transform.columns.1),
    simd_length(transform.columns.2)
    )

    // Extract rotation
    let upperLeft = simd_float3x3(
    simd_normalize(simd_float3(transform.columns.0.x, transform.columns.0.y, transform.columns.0.z)),
    simd_normalize(simd_float3(transform.columns.1.x, transform.columns.1.y, transform.columns.1.z)),
    simd_normalize(simd_float3(transform.columns.2.x, transform.columns.2.y, transform.columns.2.z))
    )

    // Create rotation matrix at origin
    let rotationMatrix = float4x4(
    [upperLeft[0].x, upperLeft[0].y, upperLeft[0].z, 0],
    [upperLeft[1].x, upperLeft[1].y, upperLeft[1].z, 0],
    [upperLeft[2].x, upperLeft[2].y, upperLeft[2].z, 0],
    [0, 0, 0, 1]
    )

    // Apply combined scale
    let combinedScale = currentScale * scaleFactors
    newInstance.transform = rotationMatrix * float4x4(scale: combinedScale)
    return newInstance
    }

    // Generate new mesh resource
    do {
    var transformedContents = MeshResource.Contents()
    transformedContents.models = modelMesh.contents.models
    transformedContents.instances = MeshInstanceCollection(newInstances)

    let transformedMesh = try MeshResource.generate(from: transformedContents)
    return try await ShapeResource.generateConvex(from: transformedMesh)
    } catch {
    Logger.realitykit.error("Failed to generate collision shape: \(error)")
    return nil
    }
    }