HitResult.FaceIndex alwasy -1 for SkelMeshes

We have function in SkelMesh: GetMaterialFromCollisionFaceIndex but we can’t use it with skel meshes as HitResult.FaceIndex will always return -1 for Skeletal Meshes.

Repro:

  • Create LineTrace with Complex and ReturnFaceIndex,
  • If you trace block with static mesh FaceIndex will work,
  • If you trace block skel mesh FaceIndex will be alwasy -1

This way we can’t get material from skel meshes traces.

2019 and still no solution :frowning:

I found a solution that I used to use with my landscape and maybe you can use surface types instead of face index
Basically you have to pull out directly from the out hit the Get Surface Type and use it.

In that way, the different materials from your sk mesh must have different physical materials with different surface types. You can add surface types in project settings > Physics > Physical Surface (the last section).

The answer below doesn’t work. Any solution to detect the material of a hit skeletal mesh?

My plugin called “Runtime Vertex Color Paint & Detection Plugin” makes this possible by getting the closest vertex data, then it can get the material based on that.

Im still stuck on this problem, really dont know why skeletal meshes just cant return a ■■■■ face when they obviously have a mesh. Could you please elaborate on your solution in how to implement your method?
Thanks!

It can be done because i have a whole bunch of logic to get the closest section and vertex to a hit location, and using the section you can get the material index from skeletla mesh render data, and using the material index, oyu can get the material from the skeletal mesh component

Here’s a snippet of logic that use the section to get the material.

const FSkeletalMeshLODRenderData& skelMeshRenderData_Local = calculateColorsInfo_Global.vertexPaintSkelComponent->GetSkeletalMeshRenderData()->LODRenderData[0];

materialAtClosestPaintVertex_Global = calculateColorsInfo_Global.vertexPaintSkelComponent->GetMaterial(skelMeshRenderData_Local.RenderSections[closestSectionFound_Paint_Global].MaterialIndex);

1 Like

Heres a function to obtain UV-coordinates from SkeletalMeshComponent without FaceIndex. However it still doesnt work since my USkeletalMeshComponents doesnt have UVInformation…

FVector2D FaceIndexSkeletalMesh(FHitResult& HitInfo) const
{
    FVector2D UVCoordinates(-1, -1);

    TArray<USkeletalMeshComponent*> SkelMeshComps;
    HitInfo.GetActor()->GetComponents(SkelMeshComps, false);
    if (SkelMeshComps.Num() == 0) return UVCoordinates*2;

    UBodySetup* BodySetup = SkelMeshComps[0]->GetBodySetup();

    //UPrimitiveComponent* PrimComp = HitInfo.GetComponent();

    //UBodySetup* BodySetup = PrimComp->GetBodySetup();
    if (!BodySetup) return UVCoordinates*3;

    FBodySetupUVInfo UVInfo = BodySetup->UVInfo;

    // Get the vertex positions
    const TArray<FVector>& VertPositions = UVInfo.VertPositions;
    // Get the index buffer
    const TArray<int32> IndexBuffer = UVInfo.IndexBuffer;
    // ImpactPoint in Local Perspective
    const FVector LocalHitPos = SkelMeshComps[0]->GetComponentToWorld().InverseTransformPosition(HitInfo.ImpactPoint);
    // Normal of Surface
    const FVector SurfaceNormal = HitInfo.ImpactNormal;
    // Iterate over the triangles of the mesh
    int UVChannel = 0;
    while ((UVCoordinates.X < 0.f || UVCoordinates.X > 1.f || UVCoordinates.Y < 0.f || UVCoordinates.Y > 1.f) && UVChannel < 4) {
        if ( !UVInfo.VertUVs.IsValidIndex(UVChannel) ) return UVCoordinates*4;

        // Get the vertex UV coordinates
        const TArray<FVector2D> VertUVs = UVInfo.VertUVs[UVChannel];
        if (VertUVs.Num() == 0) return UVCoordinates*5;

        UVChannel++;

        for (int32 i = 0; i < IndexBuffer.Num(); i += 3)
        {
            // Get the vertex indices of the current triangle
            int32 VertexIndex0 = IndexBuffer[i];
            int32 VertexIndex1 = IndexBuffer[i + 1];
            int32 VertexIndex2 = IndexBuffer[i + 2];

            // Get the vertex positions of the current triangle
            const FVector& Position0 = VertPositions[VertexIndex0];
            const FVector& Position1 = VertPositions[VertexIndex1];
            const FVector& Position2 = VertPositions[VertexIndex2];

            FVector Input1, Input2;
            // Check if the impact point lies on this triangle
            if (FMath::SegmentTriangleIntersection(LocalHitPos - SurfaceNormal * 0.1f, LocalHitPos + SurfaceNormal * 0.1f, Position0, Position1, Position2, Input1, Input2))
            {
                // Get the UV coordinates of the current triangle
                const FVector2D UV0 = VertUVs[VertexIndex0];
                const FVector2D UV1 = VertUVs[VertexIndex1];
                const FVector2D UV2 = VertUVs[VertexIndex2];

                // Barycentric interpolation to get the UV coordinates of the impact point
                FVector BaryCoords = FMath::ComputeBaryCentric2D(LocalHitPos, Position0, Position1, Position2);
                UVCoordinates = UV0 * BaryCoords.X + UV1 * BaryCoords.Y + UV2 * BaryCoords.Z;
                break;
            }
        }
    }
    return UVCoordinates;
}

UE 4.26