How to figure out which vector has a closer dot product to world up

Greetings.

Im trying to right a function that will return which face of an object is closest to facing up.

In the example the shape has 6 sides (a cube). But there is cases where i will need to do different amounts of uniform sides.

I have the following code.

const int SidesOfDie = 6;
const FVector BaseUp = FVector(1.0f, 0.0f, 0.0f);
float Angle;
int32 LowestInt;
float LowestAngle;

FRotator ActorRotation = this->GetActorRotation();

FVector vectors[SidesOfDie] = {
    ActorRotation.RotateVector(FVector(1.0f, 0.0f, 0.0f)),
    ActorRotation.RotateVector(FVector(-1.0f, 0.0f, 0.0f)),
    ActorRotation.RotateVector(FVector(0.0f, 1.0f, 0.0f)),
    ActorRotation.RotateVector(FVector(0.0f, -1.0f, 0.0f)),
    ActorRotation.RotateVector(FVector(0.0f, 0.0f, 1.0f)),
    ActorRotation.RotateVector(FVector(0.0f, 0.0f, -1.0f))
};


for (size_t i = 0; i < SidesOfDie; i++)
{
    Angle = FVector::DotProduct(BaseUp, vectors[i]);
    if (i == 0) {
        LowestInt = i;
        LowestAngle = Angle;
    }
    else if (Angle < LowestAngle) {
        LowestInt = i;
        LowestAngle = Angle;
    }
}

return LowestInt;

So we start of by defining the base up vector which is 1,0,0

Then I make a vector from the center of the object to the middle of each face.

Then I rotate each vector by the objects current rotation.

Then I calculate the dot product.

Now if i remember my maths right that should return the angle between the vectors. Meaning the smallest one is the vector correlating to the side facing.

But its not working i rotate my cube and get the same value.

Can anyone see what im doing wrong :)?

Not to state the obvious, but your line that’s supposed to rotate the vectors by the Actor’s rotation is commented out, so you would get the same result every time.

The dot product doesn’t return the angle between the vectors - it returns the cosine of the angle between the vectors (given that the input vectors are normalized). You don’t want the closest to zero as you have there (that would give you the most perpendicular to your BaseUp), you want the closest dot product to 1.0f.

In your code, this should fix it:

if(Angle > 0.0f && FMath::Abs(1.0f-Angle) < LowestAngle) {

I’m checking that ‘Angle’ is > 0.0f because if it’s negative the angle is pointing the opposite way, but if you have a cube you won’t need it because at least one of the sides will yield a better result. If it’s an arbitrary set of polys, then you need it.

I do the rotation in the vector array initialization. Ignore the commented line in fact ill remove it.

But the rest of what you say is making sense i will test it when i get home tonight and report back :slight_smile: cheers.

@rantrod this has not fixed my problem.

I get vector one as the result of 0deg rotation
I get vector 4 as the result of 180deg ,180deg, 0 rotation where i would expect the same result :frowning:

I needed the greatest result from the dot product :smiley:

The following works.

const int SidesOfDie = 6;
const FVector BaseUp = FVector(0.0f, 0.0f, 1.0f);
float Angle;
int32 LowestInt;
float LargestAngle;

FRotator ActorRotation = this->GetActorRotation();

FVector vectors[SidesOfDie] = {
	ActorRotation.RotateVector(FVector(1.0f, 0.0f, 0.0f)),
	ActorRotation.RotateVector(FVector(-1.0f, 0.0f, 0.0f)),
	ActorRotation.RotateVector(FVector(0.0f, 1.0f, 0.0f)),
	ActorRotation.RotateVector(FVector(0.0f, -1.0f, 0.0f)),
	ActorRotation.RotateVector(FVector(0.0f, 0.0f, 1.0f)),
	ActorRotation.RotateVector(FVector(0.0f, 0.0f, -1.0f))
};


for (size_t i = 0; i < SidesOfDie; i++)
{

	Angle = FVector::DotProduct(BaseUp, vectors[i]);
	if (i == 0) {
		LowestInt = i;
		LargestAngle = Angle;
	}
	else if (Angle > LargestAngle) {
		LowestInt = i;
		LargestAngle = Angle;
	}
}

return LowestInt;