[Question] Aligning to rotated actor Normal

Hi folks!

I’m having some trouble getting my spawned actor to align to another actor’s normal correctly. I’m using a snapping system so it aligns 200x200, without the snap system the alignment is fine, but I really want this snap system :smiley:.

Most of the time it aligns perfect on flat surfaces but when it comes to rotated actors at for example 45 degrees then it has trouble aligning correctly.

Here is an image of the alignment working correctly on flat surfaces:

Here is an image of what is happening on rotated actor’s:

There is another small issue I’m having that happens on some surfaces, not sure why as the actors on these following images are the same but just placed next to eachother:

Here is another image of the alignment working correctly:

And not working correctly:

As far as I can tell the Normals of each actor are exactly the same. so I’m not entirely sure what the issue is on that last one but any help would be much appreciated!

Here’s my code:

void AQUBECharacterPlayer::CharacterTrace(FVector& CameraLocation, FRotator& CameraRotation, FHitResult& HitResult)
{
	if(Controller)
	{
		Controller->GetPlayerViewPoint(CameraLocation, CameraRotation); 

		FCollisionQueryParams CollisionQuery(NAME_None, false, this);

		if (GetWorld()->LineTraceSingle(HitResult, CameraLocation, CameraLocation + CameraRotation.Vector() * 10000, ECC_WorldStatic, CollisionQuery))
		{
			if(HitResult.GetActor())
			{
				if(HitResult.GetActor()->HasTag(TEXT("Interact")) || HitResult.GetActor()->HasTag(TEXT("PhysicsActor")) || HitResult.GetActor()->HasTag(TEXT("CanMove")))
				{
					return;
				}

				BuildLocation = HitResult.ImpactPoint;

				BuildLocation.X = BuildLocation.X + 200.0 / 2.0 * HitResult.ImpactNormal.X;
				BuildLocation.X = FMath::Round(BuildLocation.X / 200.0) * 200.0;

				BuildLocation.Y = BuildLocation.Y + 200.0 / 2.0 * HitResult.ImpactNormal.Y;
				BuildLocation.Y = FMath::Round(BuildLocation.Y / 200.0) * 200.0;

				BuildLocation.Z = BuildLocation.Z + 200.0 / 2.0 * HitResult.ImpactNormal.Z;
				BuildLocation.Z = FMath::Round(BuildLocation.Z / 200.0) * 200.0;
			}
		}
	}
}

In Tick:

FVector CamLoc;
		FRotator CamRot;
		FHitResult HitResult;		


		/*
		 *	Start of ***BLUE*** cube mini spawnable code
		*/
		if(bPreThrowBlue)
		{
			CharacterTrace(CamLoc, CamRot, HitResult);

			if(HitResult.GetActor() == SpawnedRedCube || HitResult.GetActor() == SpawnedGreenCube)
			{
				return;
			}

			if(SpawnedBlueCubeGhost)
			{
				SpawnedBlueCubeGhost->SetActorLocation(BuildLocation);
				SpawnedBlueCubeGhost->SetActorRotation(HitResult.ImpactNormal.Rotation() + FRotator(-90,0,0));
			}
		}
		/*
		 *	End of BLUE cube mini spawnable code
		*/

...
...

THANKS!! :slight_smile:

The first thing that I would do here, is make use of DrawDebugLine and DrawDebugSphere, or something similar to those over in AHUD, and use them to get a visualization on all your vectors and rotations. I don’t see an obvious error, but I feel like there’s something fundamentally wrong with the way it’s being done, and personally, I can conceive of what’s wrong with my 3D space code when I can actually see all of the variables as real points and lines in space.

I am presuming the issue must be here since you said that without vertex snapping, all is well

   BuildLocation = HitResult.ImpactPoint;

      BuildLocation.X = BuildLocation.X + 200.0 / 2.0 * HitResult.ImpactNormal.X;
      BuildLocation.X = FMath::Round(BuildLocation.X / 200.0) * 200.0;

      BuildLocation.Y = BuildLocation.Y + 200.0 / 2.0 * HitResult.ImpactNormal.Y;
      BuildLocation.Y = FMath::Round(BuildLocation.Y / 200.0) * 200.0;

      BuildLocation.Z = BuildLocation.Z + 200.0 / 2.0 * HitResult.ImpactNormal.Z;
      BuildLocation.Z = FMath::Round(BuildLocation.Z / 200.0) * 200.0;
     }
   }
}

}

#Order of Operations

just cause im not sure about order of operations

can you try this instead

       BuildLocation = HitResult.ImpactPoint;
 
          BuildLocation.X = (BuildLocation.X + (200.0 / 2.0)) * HitResult.ImpactNormal.X;
          BuildLocation.X = FMath::Round(BuildLocation.X / 200.0) * 200.0;
 
          BuildLocation.Y = (BuildLocation.Y + (200.0 / 2.0)) * HitResult.ImpactNormal.Y;
          BuildLocation.Y = FMath::Round(BuildLocation.Y / 200.0) * 200.0;
 
          BuildLocation.Z = (BuildLocation.Z + (200.0 / 2.0)) * HitResult.ImpactNormal.Z;
          BuildLocation.Z = FMath::Round(BuildLocation.Z / 200.0) * 200.0;
         }
       }
    }
}

Let me know how that goes!

Hey Rama! It’s good to hear from you again! Thanks for the response!

Yes it’s got something to do with this area but I’m not sure how to correct it.

Unfortunately those changes cause the actor to not spawn, well it’s either that or it spawns somewhere off screen that I am unable to reach.

Cheers,
Jon

#Changing Your Algorithm

This is more of a conceptual issue than actual implementaiton

You have to find way to do two things and get desired end result

  1. move your ghost mesh to right location
  2. rotate it to match target mesh’s surface normal rotation

So there’s two main operations, a translation and a rotation

I’d recommend trying this

#Translate/Rotation via Transform

  1. Translate the ghostoutline to exactly the same location and rotation of its target

you can use

Ghost->SetActorTransform(Target->GetTransform());

then

to make the ghost visible on top of the Target, you need to move it along the surface normal a certain distance.

to get you started, just try moving for the amount of however thick your target tile is (not sure what your unit scaling is like, and how thick the tile is)

Translate along surface normal

Loc = Ghost->GetActorLocation();
Loc += SurfaceNormal * TileWidth;
Ghost->SetActorLocation(Loc);

so if this gets you some new results :slight_smile:

you need to start with an algorithm / overall plan well understood in your mind and then do the programming :slight_smile:

Rama

Hey Rama :smiley:

Thanks for the reply!!

With those changes I’m getting a free aim with no snap (tile width is 200 but had no effect).

I’m really just trying to achieve a basic snapping system to and from each tile which are combined static meshes of cubes which are 200x200x200, although some combined walls do become very big. I feel that I’m almost there but having trouble just on this one rotation issue. I find it odd how a 90 degree rotation is completely fine but anything inbetween doesn’t seem to act correctly.

Jon

Hi Jon,

We are glad to address issues and questions explicitly concerning the functionality of the UE4 engine and editor, however it appears that your issue is more related to general game development and is beyond the scope of our support staff to address. We wish you success as you develop your game, and urge you to reach out to the community and review available documentation if you find yourself struggling.

If you do determine that there is an issue with UE4 that is preventing you from obtaining your development goals, or if you have a focused question regarding the tools, then please do not hesitate to contact us and we will offer all available support.

Thank you.

Hi Stephen, no worries!

I was unsure as to what questions we could post here, thanks for clearing that up. I’ll put my question across to the Rocket forum community.

Thanks!
Jon

Hey Rama I tried your solution again and it worked :slight_smile: Thanks!