# Determine Point on Mesh Collider along specified direction?

I’ve been working on an object placement/base building system, and I’ve hit a snag that I’ve been struggling with the past few days, and I can’t seem to figure it out. I’m trying to figure out the first point on a mesh collider in the opposite direction from a Raycast hit normal so that I can offset object placement to avoid clipping like in the first image.

(Above image is what I have)

What I’m looking to do is move Object B along the hit normal so that the face furthest from the hit point direction lines up or “snaps” to the point on Object A.

(Above image is what I want)

What’s making this a real challenge is that the player can rotate Object B along the Y-axis and some object meshes aren’t rectangular so I can’t simply use the collider bounds/size.x/y/z.

Basically asking, “Hey, if I move along this direction what is the first Vector3 point on a mesh collider do I come across regardless of the mesh’s normal?” Sort of like a Raycast or Collider.ClosestPoint “in that direction”.

Any thoughts or suggestions on how to tackle this?

Thanks

Use B’s boudning box?

So if you can rotate B, but A doesn’t rotate, you could take the point where the mouse has hit A and move along it’s normal by half object B’s bounds.

It would look something like this…

``````ObjectB.position = hit.point + (ObjectB.collider.bounds.extends * hit.normal)
``````

I think this will only work if A is always a rectable and isn’t rotated, so that the hit.normla is always pointing cleanly along a world axis.

ps. don’t tell Kurt how many periods I used in that example…

I was trying something similar originally but the problem is that the X, Y, and Z extents differ. Object A’s size is x2, y1, z2 while Object B’s is x2, y0.5, z0.5, other pieces such as walls could be x2, 2y, z0.15. So while one angle might meet flush at one rotation, Object B might either clip complete inside Object A or have a large gap between A and B at another rotation. It’s even more problematic when the Object A or B is a mesh at an angle such as below.

One thing I did try was ticking “Queried Hit Backfaces” in the Physics manager and doing a ray cast from (hit.point + -hit.normal) but because the origin of the ray started within Object B’s collider it didn’t detect any hits as I was hoping for.

Ok just throwing it out there, what if we move ObjectB to the hit.point, and then move it an arbitrary distance away from hit.point along hit.normal, and then use the collider’s ClosestPoint() method to work out where along ObjectB’s collider is the closest point to hit.point, we then know the offset from hit.point to place ObjectB at.

That was hard to follow, here’s some psudo code

``````B.position = hit.point + (hit.normal * 100)
offset = B.collider.closestPoint(hit.position)
B.position = hit.point - offset
``````

We should hopfully end up with ObjectB being placed exactly along hit.normal far enough away to have it’s collider just touch edges with ObjectA regardless of the rotation, size and shape of both objects

1 Like

ZBerm, thank you! After a little finessing and a fair amount of debug stepping, it’s working. I don’t know why I just couldn’t wrap my head around this. One thing to note, however. The Mesh collider Convex property MUST be ticked for this to work. If the collider is not marked convex then the object position will be offset by the distance of (hit.normal * distance). I’ll have to investigate if there’s a way to do this with concave colliders. If not I could have a simplified convex collider and only have it enabled when Object B is being placed.

Here’s the final code. Stupid simple now that I look at it…

``````private Ray _cameraForward => new Ray(_playerCamera.transform.position, _playerCamera.transform.forward);

// Called from Update... for now
private void moveBuild()
{
if (_currentBuildObject == null) return;

if (Physics.Raycast(_cameraForward, out RaycastHit hit, _rayCastDistance, _placementLayers))
{
// Only enable the object if a hit is found and if the object isn't already enabled.
if (_currentBuildObject.selfActive == false)
_currentBuildObject.SetActive(true);

// Get a location a distance from the hit point in the direction of the hit normal
_currentBuildObject.position = hit.point + (hit.normal * 10);

// Get the closest point on the collider.
// NOTE: For a mesh collider CONVECT NEEDS TO BE CHECKED!
Vector3 closestColliderPoint = _currentBuildObject.collider.ClosestPoint(hit.point);

// The distance between the hit.point and the closest point is how much we need to move the build object back from it's temp position
_currentBuildObject.position = _currentBuildObject.position + hit.point - closestColliderPoint;
}
else
{
if (_currentBuildObject.selfActive)
_currentBuildObject.SetActive(false);
}
}
``````

EDIT: Trying to format the code… message keeps saying it looks like spam or is inappropriate…

1 Like