# Distance to box represented by a Matrix4x4

So I have some boxes represented by a Matrix4x4 (position is center, scale is extends and rotation is rotation) and I need to find out the distance an arbitrary point is of any of the planes of the box. I get that I could just “Plane.GetDistanceToPoint”, yet I am having way too much trouble figuring out how to make the Matrix4x4 in 6 planes.

Context: The boxes represent a ‘grass changer’, where blades of grass on it will be generated as another type, in this case, small white flowers. The idea is that grass in the inner box is 100% flowers, and as they get further from it, up to the outer box, they will smoothly transform or not in flowers, creating a smooth effect where it’s not a hard line like currently. The outer outer box is the bounds.

Don’t ask me how I can make a grass shader that lets you bend and cut individual blades of grass but can’t convert a code that draws a box outline to 6 planes.

That is an … interesting data storage technique! I’ll take it for granted it works for you.

I believe your problem is you have a point in space and you want to decide “what are my chances of being grass versus flower,” and you want that to smoothly go from 0 chance to 1 chance at the edge of your extents.

I think you can accomplish that by getting the Quaternion.Inverse() of the rotation for that box, multiplying the point in question by that inverted quaternion, then it simply becomes an axis-aligned box check: check X, check Y, check Z separately: if they are outside, then grass. If they are inside, then take the smallest (minimum) of the distances they are inside each axis extent, and use that as your lookup on the probability.

1 Like

Most of the techniques to figuring out if a point is inside an arbitrary box ended up using a matrix at one point anyways, so I decided to store the box as the matrix ready to be used, not to mention, I can just transform.localToWorld to get it.

Using the box center as a pivot, right? I will try that tomorrow.

Yes, I’d have to actually try it, but it SEEMS all the information is present in one way or another, just need to do the transform, possibly an offset, then a compare. Personally I would set up a single super-simplified script to use it in sort of a test context to make sure it is doing what you think it is.

Turns out all I needed was to stop to think of the box as a box, and instead think of it as 3 lines, one for each axis.
Project the grass to each of the 3 lines, and check the projected point distance to the box center, then check if the distance is within the extents and it works just fine. Seems I was too stuck up in attempting to make the planes to figure out there was this much simpler solution, I only figured out I could solve like this after I started to think how to do the rotation thing you proposed.

Code if anyone cares:
Will return 1 if it’s inside the ‘full’ part of the box, 1-0 as it gets closer to the limit and 0 if it’s outside the box.

``````//planes  = new float3x3(1, 0, 0, 0, 1, 0, 0, 0, 1); couldn't make a constant out of it
public static float ProportionInside(Matrix4x4 blocker, float3x3 planes, float3 position, float cutout) {
Vector3 ccenter = blocker.ExtractPosition();
float3 scale = blocker.ExtractScale();
float least = 1;
float min = math.min(scale.x, math.min(scale.y, scale.z))/2;
min *= cutout;

for (int j = 0; j < 3; j++) {
Vector3 lineVec = blocker.MultiplyVector(planes[j]).normalized;
Vector3 proj = Math3d.ProjectPointOnLine(ccenter, lineVec, position);
float dist = Vector3.Distance(proj, ccenter);
float extent = scale[j] / 2;
if (dist <= extent) {
if (cutout != 0 && dist >= (extent -= min)) {
least = math.min(least, 1 - (dist - extent) / min);
}
} else {
return 0;
}
}
return least;
}
//snippet from Math3d
//probably taken from [URL]https://gist.github.com/jankolkmeier/8543156[/URL], I have this class for so long I don't remember where it is from
//This function returns a point which is a projection from a point to a line.
//The line is regarded infinite. If the line is finite, use ProjectPointOnLineSegment() instead.
public static Vector3 ProjectPointOnLine(Vector3 linePoint, Vector3 lineVec, Vector3 point) {
Vector3 linePointToPoint = point - linePoint;
float t = Vector3.Dot(linePointToPoint, lineVec);
return linePoint + lineVec * t;
}
``````
1 Like