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