"Find Collision UV" always returns zero for Skeletal Meshes

Would be great if this could be integrated into the engine.

Thanks, Guitarana. However, I’m pretty new to the C++ side of things and I’m not altogether sure where to put that code. Are you able to help please?

It’s a static function, so you’d want to put it in a static library of your own. Something along the lines of this (derive from UObject)

 #pragma once
 
 // Epic includes
 #include "CoreMinimal.h"
 #include "UObject/NoExportTypes.h"
 
 // YourGame Includes
 #include "YourStaticLibrary.generated.h"
 
 /**
  * 
  */
 UCLASS()
 class YOURGAME_API UYourGameStaticLibrary : public UObject
 {
     GENERATED_BODY()

public:

UFUNCTION(BlueprintCallable,Category=HitDetection)
static void FindCollisionUVOnSkeletalMesh(const struct FHitResult& Hit,  FVector2D& UV);

};

Ah, that was just the little nudge I needed. I have it working now. Thanks!

One thing that’s worth mentioning is that this code won’t work in shipping builds. You will need to wrap it in editor-only defines

It’s not shippable code, so they wont do that.

Hey guys,

I made a version of Guitaran’s function that should be useable in non-editor builds. It can be considered a full replacement for Epic’s FindCollisionUV() as it will work for both skeletal and static meshes.

Enjoy!

You are amazing! Thank you!

Very powerful, but still lacking something, the pickup points of the skeletal mesh need to be converted to the local space of the initial pose:

    UFUNCTION(BlueprintCallable, BlueprintPure)
    static FTransform GetSkeletalMeshRefPose(USkeletalMesh* SkeletalMesh,int BoneIndex)
    {
        FTransform MeshBonePoseTransform;
        MeshBonePoseTransform.SetIdentity();
        MeshBonePoseTransform = SkeletalMesh->RefSkeleton.GetRefBonePose()[BoneIndex];
        int ParentBoneIndex = SkeletalMesh->RefSkeleton.GetParentIndex(BoneIndex);
        if (ParentBoneIndex == INDEX_NONE)
        {
            return MeshBonePoseTransform;
        }
        else
        {
            return MeshBonePoseTransform * GetSkeletalMeshRefPose(SkeletalMesh, ParentBoneIndex);
        }
    }

    UFUNCTION(BlueprintCallable,BlueprintPure)
    static bool GetHitResultPointInRefPose(const struct FHitResult& HitResult, FVector &Point)
    {
        if (UPrimitiveComponent* HitPrimComp = HitResult.Component.Get())
        {
            FVector HitPoint = HitResult.ImpactPoint;
            if (USkeletalMeshComponent* SkelComp = Cast<USkeletalMeshComponent>(HitPrimComp))
            {
                int BoneIndex = SkelComp->SkeletalMesh
->RefSkeleton.FindBoneIndex(HitResult.BoneName);
                FTransform PoseTransform = SkelComp->SkeletalMesh->RefSkeleton.GetRefBonePose()[BoneIndex];
                HitPoint = SkelComp
->GetSocketTransform(HitResult.BoneName).InverseTransformPosition(HitPoint);
                Point= GetSkeletalMeshRefPose(SkelComp->SkeletalMesh, BoneIndex).TransformPosition(HitPoint);
                return true;
            }
        }
        return false;
    }

Thank you for providing the method to read skeletal mesh renderdata.I have solved it.

  1. For skelemesh need convert impact
    point and impact normal from world
    space to ref pose’s local space.
  2. Then, create line segment by
    converted impact point and converted
    impact normal.
  3. Then, use the line segment to get
    Intersection with triangle in
    skeletal mesh. PS:the target
    triangle can get intersection
  4. At Last,use the intersection to get
    UV from the target triangle. It is
    workable but the efficiency may need
    to be optimized.

also:

  1. For skelemesh need convert impact
    point and impact normal from world
    space to ref pose’s local space.

  2. Then, create line segment by
    converted impact point and converted
    impact normal.

  3. Use the line segment linetrace
    staticmesh which is build from
    skeletal mesh,but by this way the
    line segment need convert to
    component space.

  4. Find UV from the hitresult.

can you post the code? lol i dont understand nothing im just copy and paste things and im stuck here

You should delete this as it isn’t an answer and you could be down-voted.

can you post the code? lol i dont understand nothing im just copy and paste things and im stuck here

  • A few months have passed…
  • Their answer solved for me the problem of how to read the triangles from skelemesh.The spatial arrangement of these triangles is the initial pose.
  • So if you want to pick up more correct triangles at runtimer,You must first understand the principle of skeletal animation.you need to convert the collision point and its direction into the coordinate system of the initial pose at first.
  • But the serious impact of collision fit on the results.For better results, unless Epic provides a better way to create skeletal collision bodies: for example, generate them based on user-selected vertices.
  • My code relies on an extension plugin that I wrote, so I can only provide algorithms and ideas.

Roughly as follows:

  • From the HitResult, you can get the impact point and impact normal.They are in the world space.You also can read the bone name from the HitResult.
  • Get the bone’s world transform(It is actually the transformation matrix) form the skelemesh by bone’s name.get the Inverse of this transform.
  • Convert impact point and impact normal by the Inverse of transform,now the point and normal into the bone space.

UFUNCTION(BlueprintCallable, BlueprintPure)
static FTransform GetSkeletalMeshRefPose(USkeletalMesh* SkeletalMesh,int BoneIndex)
{
FTransform MeshBonePoseTransform;
MeshBonePoseTransform.SetIdentity();
MeshBonePoseTransform = SkeletalMesh->RefSkeleton.GetRefBonePose()[BoneIndex];
int ParentBoneIndex = SkeletalMesh->RefSkeleton.GetParentIndex(BoneIndex);
if (ParentBoneIndex == INDEX_NONE)
{
return MeshBonePoseTransform;
}
else
{
return MeshBonePoseTransform * GetSkeletalMeshRefPose(SkeletalMesh, ParentBoneIndex);
}
}

             UFUNCTION(BlueprintCallable,BlueprintPure)
             static bool GetHitResultPointInRefPose(const struct FHitResult& HitResult, FVector &Point)
             {
                 if (UPrimitiveComponent* HitPrimComp = HitResult.Component.Get())
                 {
                     FVector HitPoint = HitResult.ImpactPoint;
                     if (USkeletalMeshComponent* SkelComp = Cast<USkeletalMeshComponent>(HitPrimComp))
                     {
                         int BoneIndex = SkelComp->SkeletalMesh
         ->RefSkeleton.FindBoneIndex(HitResult.BoneName);
                         FTransform PoseTransform = SkelComp->SkeletalMesh->RefSkeleton.GetRefBonePose()[BoneIndex];
                         HitPoint = SkelComp
         ->GetSocketTransform(HitResult.BoneName).InverseTransformPosition(HitPoint);
                         Point= GetSkeletalMeshRefPose(SkelComp->SkeletalMesh, BoneIndex).TransformPosition(HitPoint);
                         return true;
                     }
                 }
                 return false;
             }
  • You can find the bone index by bone name.
  • and use the function I pasted.you can get the bone’s transform of Initial pose/ref pose.
  • Convert the point and normal which is in the bone space by this transform.
  • Use the point and normal which is now in the initial pose space to pick the triangles.

PS:It is not a good idea to traverse all triangles, especially if the number of faces is particularly high, all it takes is to build data structures to optimize them, but that is another matter.

Hi, would anyone know how to implement @BarrierAbyss’ answer into @Guitarana’s answer? I cant figure out where this function would be called in the get UV loc function

When you get the coordinates and directions of the collision points in RefPose space, you can easily draw up a start point and an end point and replace them directly into the functions given by @Guitarana .