How would I get what part of a skeletal mesh I hit using c++?

I have a bullet and a player I need to be able to detect what part of the mesh I’m hitting for things like head shots.

#PrimitiveComponent::LineTraceComponent

/** 
	 *  Trace a ray against just this component.
	 *  @param  OutHit          Information about hit against this component, if true is returned
	 *  @param  Start           Start location of the ray
	 *  @param  End             End location of the ray
	 *  @param  Params          Additional parameters used for the trace
	 *  @return true if a hit is found
	 */
	virtual bool LineTraceComponent( FHitResult& OutHit, const FVector Start, const FVector End, const FCollisionQueryParams& Params );

#Example Usage

//could replace NULL with this if you want to ignore the owner of the trace.
FCollisionQueryParams CombatCollisionQuery(FName(TEXT("CombatTrace")), true, NULL); //trace complex, ignore nothing
CombatCollisionQuery.bTraceComplex 				= true;
CombatCollisionQuery.bTraceAsyncScene 			= false;
CombatCollisionQuery.bReturnPhysicalMaterial 		= false;

//Stores the info about the hit
FHitResult CombatHit(ForceInit);

//if tracing other’s skel mesh you can use OtherCharacter->Mesh->LineTrace…

//returns whether hit occurred
if(Mesh->LineTraceComponent( 
	CombatHit, 
	TraceStart, 
	TraceStart, 
	CombatCollisionQuery)
) {
	//UE_LOG
    //A Hit Occurred!!!
	
	//UE_LOG
	//CombatHit.BoneName   //<----tells you the bone name!!!!
}

//Rest of HitResult Info Provided from Above Function

#EngineTypes::FHitResult

/** Structure containing information about one hit of the trace */
USTRUCT(BlueprintType)
struct ENGINE_API FHitResult
{
	GENERATED_USTRUCT_BODY()

	/** Indicates if this hit was requesting a block - if false, was requesting a touch instead */
	UPROPERTY()
	uint32 bBlockingHit:1;

	/**
	 * Whether the trace started in penetration, i.e. with an initial blocking overlap.
	 * In the case of penetration, if PenetrationDepth > 0.f, then it will represent the distance along the Normal vector that will result in
	 * minimal contact between the swept shape and the object that was hit. In this case, ImpactNormal will be the normal opposed to movement at that location
	 * (ie, Normal may not equal ImpactNormal).
	 */
	UPROPERTY()
	uint32 bStartPenetrating:1;

	/* 'Time' of hit along ray (between 0.0 and 1.0), between TraceStart and TraceEnd. */
	UPROPERTY()
	float Time;
	
	/** Location of the hit in world space.  If this was a Swept Shape test, this is the location where we can place the shape in the world where it will not inter-penetrate. */
	UPROPERTY()
	FVector_NetQuantize Location;

	/** Normal of the hit in world space, for the object that was swept. This is computed for capsules and spheres, otherwise it will be the same as ImpactNormal.*/
	UPROPERTY()
	FVector_NetQuantizeNormal Normal;

	/** Location of the actual contact of the trace shape (box, sphere, etc.) with the world. (e.g. A box was swept.  This is the point where a side of the box touched something.) */
	UPROPERTY()
	FVector_NetQuantize ImpactPoint;

	/** Normal of the hit in world space, for the object that was hit by the sweep. */
	UPROPERTY()
	FVector_NetQuantizeNormal ImpactNormal;

	/** Start location of the trace. */
	UPROPERTY()
	FVector_NetQuantize TraceStart;

	/** End location of the trace. This is NOT where the impact occurred (if any), but the furthest point in the attempted sweep. */
	UPROPERTY()
	FVector_NetQuantize TraceEnd;

	/**
	  * If this test started in penetration (bStartPenetrating is true), and a depenetration vector can be computed,
	  * this value is the distance along Normal that will result in moving out of penetration.
	  * If the distance cannot be computed, this distance will be zero.
	  */
	UPROPERTY()
	float PenetrationDepth;

	/** Extra data about item that was hit (hit primitive specific) */
	UPROPERTY()
	int32 Item;

	/** Physical material that was hit. Must set bReturnPhysicalMaterial to true in the query params for this to be returned. */
	UPROPERTY()
	TWeakObjectPtr PhysMaterial;

	/** Actor that the check hit. */
	UPROPERTY()
	TWeakObjectPtr Actor;

	/** PrimitiveComponent that the check hit. */
	UPROPERTY(NotReplicated)
	TWeakObjectPtr Component;

	/** Name of bone we hit (for skeletal meshes). */
	UPROPERTY()
	FName BoneName;

	/** Face index we hit (for complex hits with triangle meshes) */
	UPROPERTY()
	int32 FaceIndex;

:slight_smile:

#Enjoy!

A great solution (as expected of ). It’s nice having an engine that can do this kind of stuff. My previous experiences with this subject have been frustrating to say the least (I’m looking at you Unity3D!).

Hey Lewis,

's solution is pretty solid. It works especially well if you wanted highly-accurate collision detection, as it is tracing against the mesh itself (not against hand placed collision boxes like my suggestion). It does, however, make it a bit difficult to detect exactly where the bullet hit (you would have to check the name of the bone against a list of compatible target bones, a messy and inaccurate process, especially with an abundance of facial joints or sloppy weighting). This isn’t a problem at all if you have multiple skeletal mesh components making up the body, but I’m going to assume that you don’t.

A more tried-and-tested solution is to attach a number of small ‘collision boxes’ to important parts of your character. I’m going to use Counter Strike as an example, a popular networked FPS in case you are unfamiliar with it.


This is obviously less accurate than 's solution of tracing against the mesh directly, but it does offer some advantages you may or may not be interested in:

  • It is very easy for you to determine which area was hit, as well as providing per-area hit handling (such as damage modifiers (feet vs. head), per-component trace layers (so explosions hit only certain pieces, etc), and wound tracking).
  • You can extrapolate network latency for more accurate hit detection without moving the visible mesh:


By no means are collision boxes the only way to do these things. You could do them with mesh tracing too, if you really wanted, it would just require a different implementation.

Lastly, [here is the article][3] that I sourced (pun intended) the second image from. It is a worthwhile read if networked games interest you, even if you don’t use collision boxes for your implementation.

EDIT

I talked a lot about the upsides of the collision box system. I thought I should mention some of the downsides, so you had the complete picture:

  • Requires manual setup for each mesh, leading to difficulties if you decide to change the setup down the track (for example split the chest box into two boxes, you would need to go through each mesh you had already worked on).
  • Decals (such as blood) applied on hit could ‘float’ in some circumstances, as the underlying mesh is no longer used for collision detection.

These can both be overcome with varying implementations, but I figured I would put them here for completion sake.

From what I recall, bTraceComplex only traces againsst the actual mesh when traced against static meshes. For skeletal, it will return the physics asset bodies, which is the same as what you describe.

Hmm, interesting. I looked into it a bit more myself, and you’re right. The bone name returned by the hit should be accurate enough then (since it would be based on the physic body instead of a direct trace, returning the nearest bone like I had incorrectly assumed) to be used for location detection.

The only reason to manually set up the boxes like in my solution would be to apply per-area modifiers to them, but you could achieve that anyway with a list of bone modifiers on the character. My solution is a bit out-dated I think, Unreal has already solved it.

#Video Proof of My LineTraceComponent Method

Christopher is right about the physics assets being used, and being a UE4 built in way to do the exact method you described ,

I have video proof of this that I specifically made to demonstrate this!

In the video I am using pretty much the exact method I am suggesting that Lewis Use

#Video, around 2:33
http://www…com/watch?v=725u770QM4Q&feature=youtu.be

Starting around 2:33

I walk a little skeleton up to a big skeleton who is playing an idle anim that causes his hand to be at times in range of just the very tip of the little skeleton’s sword

I have skeleton swing a bunch of times, well within the collision capsule, and it misses!

and then right when the idle anim is playing and the big skeleton’s hand comes juuuuuust in range of the sword tip, THEN the hand goes flying and the skeleton registers a hit!

The hand going flying is proof I accessed that exact bone and applied an impulse.

#Note the Big Skeleton Never Moves

The big skeleton neeever moves, it is just the idle animation and the bone movements that are determining when the skeleton is in range of the sword tip!

Yay!

This video is pretty much the code and method I mention in this UDN post.

#By the Way

I thoroughly enjoyed your additional explanation

and thanks for the pics and taking the time!

but I do feel that Christopher is right, and the Physics asset is being used with LineTraceComponent, and not just the whole-body mesh.


Great clarifications for the Community!

Thanks for the video, but I had already acknowledged my mistake in a reply to his comment, so it was a bit unnecessary. I was under the impression that it would trace the mesh directly, not the physic bodies. That turned out to be wrong.

It might be an idea to post in that comment chain that you put a video in a new answer, or just move it to the comment. It will make it a bit clearer for new readers.

I was not trying to point out a mistake,

I was just demonstrating how awesome UE4 was,

it was not a response only to you,

but a demo for all readers of this thread in the future.

UE4 is awesome!

My energy level in the post is due to my excitement about UE4, that’s all :slight_smile:

Hello, so sorry for brining back an old topic but could you guys direct me to a tutorial on how i can create my own hit boxes with blueprint?

Hi I Create Art!

This is a post from before the engine launched and a lot has changed. Please make a new post with your question. Thank you!