SurfaceHit.ImpactNormal.Rotation()

On the code

SurfaceHit.ImpactNormal.Rotation(); // SurfaceHit is a FHitResult variable

the result is wrong.

How to reproduce:

  1. Create a brand new ShooterDemo project.
  2. Build and Play. (No modifications to the code)
  3. Shoot on the ground.
  4. You will see that the bullet decal (ShooterImpactEffect and ShooterExplosionEffect) has a weird stretch to it.

Attached screenshot of the effect (check the bullet decal on the ground):

Did anything change in the “ImpactNormal” property, from UE4.10 to UE4.11?

Is there a temporary workaround I can use?

Thank you in advance!

Hey -

I have entered a bug report about the difference in appearance of the impact decal (UE-29076) for investigation. To help with narrowing down the cause of the issue, could you point out which file / function you’re referring to when you mention the the call to SurfaceHit.ImpactNormal.Rotation();?

Cheers

Hello ,

Apparently I screwed up my report. I apologize for not digging deeper on it.
However, I did now.

I compiled ShooterDemo for both 4.10 and 4.11 and compared the results.

The function I analyzed in question is AShooterImpactEffect::PostInitializeComponents(), line 34:
FRotator RandomDecalRotation = SurfaceHit.ImpactNormal.Rotation();

I tested pressing play and aiming down, and firing a single bullet. In both versions, the result returned was the same.

However, I dug further in UGameplayStatics::SpawnDecalAttached() and found why the spawned decal is odd.

Previously (4.10), the code for this function was (File: GameplayStatics.cpp) :

UDecalComponent* CreateDecalComponent(class UMaterialInterface* DecalMaterial, FVector DecalSize, UWorld* World, AActor* Actor, float LifeSpan)
{
	const FMatrix DecalInternalTransform = FRotationMatrix(FRotator(0.f, 90.0f, -90.0f));

	UDecalComponent* DecalComp = NewObject<UDecalComponent>((Actor ? Actor : (UObject*)World));
	DecalComp->bAllowAnyoneToDestroyMe = true;
	DecalComp->DecalMaterial = DecalMaterial;
	DecalComp->DecalSize = DecalInternalTransform.TransformVector(DecalSize);;
	DecalComp->bAbsoluteScale = true;
	DecalComp->RegisterComponentWithWorld(World);

	if (LifeSpan > 0.f)
	{
		DecalComp->SetLifeSpan(LifeSpan);
	}

	return DecalComp;
}

Now (4.11) it is:

UDecalComponent* CreateDecalComponent(class UMaterialInterface* DecalMaterial, FVector DecalSize, UWorld* World, AActor* Actor, float LifeSpan)
{
	UDecalComponent* DecalComp = NewObject<UDecalComponent>((Actor ? Actor : (UObject*)World));
	DecalComp->bAllowAnyoneToDestroyMe = true;
	DecalComp->DecalMaterial = DecalMaterial;
	DecalComp->DecalSize = DecalSize;
	DecalComp->bAbsoluteScale = true;
	DecalComp->RegisterComponentWithWorld(World);

	if (LifeSpan > 0.f)
	{
		DecalComp->SetLifeSpan(LifeSpan);
	}

	return DecalComp;
}

To test, since I can’t modify the source code on the 4.11 engine version (I can’t compile it), I did the transform in the void AShooterImpactEffect::PostInitializeComponents() function.

I changed from:

if (DefaultDecal.DecalMaterial)
{
	FRotator RandomDecalRotation = SurfaceHit.ImpactNormal.Rotation();
	RandomDecalRotation.Roll = FMath::FRandRange(-180.0f, 180.0f);

	UGameplayStatics::SpawnDecalAttached(DefaultDecal.DecalMaterial, FVector(DefaultDecal.DecalSize, DefaultDecal.DecalSize, 1.0f),
		SurfaceHit.Component.Get(), SurfaceHit.BoneName,
		SurfaceHit.ImpactPoint, RandomDecalRotation, EAttachLocation::KeepWorldPosition,
		DefaultDecal.LifeSpan);
}

To

if (DefaultDecal.DecalMaterial)
{
	FRotator RandomDecalRotation = SurfaceHit.ImpactNormal.Rotation();
	RandomDecalRotation.Roll = FMath::FRandRange(-180.0f, 180.0f);

	const FMatrix DecalInternalTransform = FRotationMatrix(FRotator(0.f, 90.0f, -90.0f));
	const FVector DecalSizeLocal = FVector(DefaultDecal.DecalSize, DefaultDecal.DecalSize, 1.0f);
	FVector DecalSizeCorrected = DecalInternalTransform.TransformVector(DecalSizeLocal);

	UGameplayStatics::SpawnDecalAttached(DefaultDecal.DecalMaterial, DecalSizeCorrected,
		SurfaceHit.Component.Get(), SurfaceHit.BoneName,
		SurfaceHit.ImpactPoint, RandomDecalRotation, EAttachLocation::KeepWorldPosition,
		DefaultDecal.LifeSpan);
}

and it works again.

I don’t understand why the CreateDecalComponent() function was changed… Apparently it used to make the decals always face the player - but I do understand it might make the function more flexible, if there are other uses.

Do you happen to have any idea why it changed and if it will stay that way (so I merge those changes with my code) ? :slight_smile:

Should I open another report concerning this, or can you edit and fix this topic for me?

Thank you in advance, and I apologize again for this rushed report.

Cheers!

Thank you for the detailed information. I will add this to the current report for the difference in appearance.

Thanks for changing that! :slight_smile:

This will be only updated on 4.12, right ?

How did you fix the code, for now, so I can apply the fix already ? :slight_smile:
My game code is heavily based on the ShooterDemo code, thus, that would be really helpful.

Thank you! :slight_smile:

Thank you! :slight_smile:

Thanks for you detailed report. I removed the rotation code as it was making C++ / blueprint calls inconsistent to the editor UI hwere x is the projection direction. I just fixed shooter game which was still calling it the old way. Going forward this should not change any more.

I changed

UGameplayStatics::SpawnDecalAttached(DefaultDecal.DecalMaterial, FVector(DefaultDecal.DecalSize, DefaultDecal.DecalSize, 1.0f),

to

UGameplayStatics::SpawnDecalAttached(DefaultDecal.DecalMaterial, FVector(1.0f, DefaultDecal.DecalSize, DefaultDecal.DecalSize),