Set collision settings for Brushes

Hello!

I am investigating a possibility to set for a given geometry brush my own collision settings.

In fact, I am using a collision channel to track the cursor so that my character is looking at it (Diablo like, TopDown camera, getting the result with help of GetHitResultUnderCursor). Well, it works fine, except that I want that the actual collision data doesn’t affect different objects except the floor (elsewhere the character is rotating when howering a cursor over another element because of height differences etc).

For that I created my own collision channel. And set it as default response to ignore, planning to change for needed actors to “block” - like the floor (and not changing for other objects, like walls). And… The problem is… The floor is a brush, so I can’t override the collision settings.

Of course I can convert it to a static brush, but I don’t like that idea at all. Because it renders the lights etc totally differently than for a brush, and changing all floors while prototyping to static meshes… Well… Seems to be a bit of overhead.

I analyzed the source code and saw, that the brush sets it’s collisions settings somewhat by the help of a UBodySetup object (which is absent in nearly all other Object Components, including the MeshComponent). The problem is that I don’t understand how this UBodySetup BrushBodySetup works - and how to set my own setting for my own channel.

Or maybe there is another way to make what I want?

Desesperatly I was even trying to set the collision channel properties from C++ - they were setting how they whould, but they didn;t get applied. I even rebuilt UE4 with removing the Collision entry in HideCategories in Brush.h - and showing the collision parameters for brushes - but they still weren’t applied…

Well, I ended up by giving up the collision thing and using math instead (it seems to be a more correct approach).
I created a “virtual plane” instead of sticking to the floors, and raytraced by myself the cursor location (which I got by using DeprojectMousePositionToWorld function) to that plane - pure mathematics, plane and line formulas. My own implementation of the Ray Plane Intersection Point Function in C++.

Something like this:

APawn* Pawn = GetPawn();
FVector PlaneNormal; // Here we set the "normal" vector, which must be perpendicular to the plane we are creating.
PlaneNormal.X = 0.f;
PlaneNormal.Y = 0.f;
PlaneNormal.Z = 1.f;
FVector PlanePoint = Pawn->GetActorLocation(); // We are using the pawn as a reference point - a plane requires a vector (a "Direction" in UE terms) and a point to be defined - pure maths!
//Plane Formula:
//PlaneNormal.X(x - PlanePoint.X) + PlaneNormal.Y(y - PlanePoint.Y) + PlaneNormal.Z(z - PlanePoint.Z) = 0
// D = -1 * (PlaneNormal.X * PlanePoint.X + PlaneNormal.Y * PlanePoint.Y + PlaneNormal.Z * PlanePoint.Z)
float PlaneFormulaD = -1 * (PlaneNormal.X * PlanePoint.X + PlaneNormal.Y * PlanePoint.Y + PlaneNormal.Z * PlanePoint.Z);
// A = PlaneNormal.X
// B = PlaneNormal.Y
// C = PlaneNormal.Z
// Standart Plane Formula:
// PlaneNormal.X*x + PlaneNormal.Y*y + PlaneNormal.Z*z + PlaneFormulaD = 0

FVector WorldLocation;
FVector WorldDirection;
DeprojectMousePositionToWorld(WorldLocation, WorldDirection);
// Line Formulas:
// (x - WorldLocation.X) / WorldDirection.X = t -> x = t * WorldDirection.X + WorldLocation.X
// (y - WorldLocation.Y) / WorldDirection.Y = t -> y = t * WorldDirection.Y + WorldLocation.Y
// (z - WorldLocation.Z) / WorldDirection.Z = t -> z = t * WorldDirection.Z + WorldLocation.Z

// Calculate our t to calculate coordinates:
//PlaneNormal.X*(t * WorldDirection.X + WorldLocation.X) + PlaneNormal.Y*(t * WorldDirection.Y + WorldLocation.Y) + PlaneNormal.Z*(t * WorldDirection.Z + WorldLocation.Z) + PlaneFormulaD = 0
//PlaneNormal.X*t*WorldDirection.X + PlaneNormal.Y*t*WorldDirection.Y+PlaneNormal.Z*t*WorldDirection.Z = -1*(PlaneFormulaD + PlaneNormal.X*WorldLocation.X + PlaneNormal.Y*WorldLocation.Y + PlaneNormal.Z*WorldLocation.Z)

float tLeftSide = PlaneNormal.X*WorldDirection.X + PlaneNormal.Y*WorldDirection.Y + PlaneNormal.Z*WorldDirection.Z;
float tRightSide = -1 * (PlaneFormulaD + PlaneNormal.X*WorldLocation.X + PlaneNormal.Y*WorldLocation.Y + PlaneNormal.Z*WorldLocation.Z);
float t = tRightSide / tLeftSide;
FVector IntersectionPoint; // The result point where the mouse cursor is "projected". This is the point at which the pawn will be looking at.
IntersectionPoint.X = t * WorldDirection.X + WorldLocation.X;
IntersectionPoint.Y = t * WorldDirection.Y + WorldLocation.Y;
IntersectionPoint.Z = t * WorldDirection.Z + WorldLocation.Z;


FVector Direction = IntersectionPoint - PlanePoint;
FRotator NewControlRotation = Direction.Rotation();
NewControlRotation.Pitch = 0.f;
NewControlRotation.Yaw = FRotator::ClampAxis(NewControlRotation.Yaw); // We aren't interesting in anything than the Yaw, so all the rest rotations we are zeroing - just to be sure.
NewControlRotation.Roll = 0.f;
SetControlRotation(NewControlRotation);

So math rulez! :slight_smile:

By the way setting the plane normal vector to the camera direction seems to be more appropriate for the cursor. For example the distance between the cursor and the character calculations are more accurate.

Thank you for this. It gave the exact results I wanted with mouse to pawn rotation. I was wondering, if it was not much to ask, would you ever be interested in making a video tutorial with step by step explanations? I know that not only I but countless others will benefit from a deep explanation of what is going on when you transform the formulas to get you the desired results.

Sorry for the question. I’m completely new to UE (not C++) and I’m little stuck here. How / where do I implement this? I already tried creating a new class derived from APlayerController overriding PlayerTick() or UpdateRotation(), assigned it to the project’s Player Controller Class. The code is executed, I can set breakpoints and step through but in the end NewControlRotation.Yaw is always -nan.