- Home /
Rounding a position against the surface of an object.
Hello, I am making a block-based building system.
It is supposed to be able to place a block against any surface, aligned to a grid, regardless of the surface's orientation. (For a space-themed ship building game)
I have already implemented the entire placement system, except that I cannot figure out how to place a block where it is supposed to be regardless of the orientation of the thing to be placed against.
My problem, specifically, is that when the surface is at a 45 degree angle, the block's position is not rounded against the surface in one direction. (In this case, the axis around which the object was rotated.)
Here is my current code:
Vector3 RoundAgainstSurface(Vector3 v3, RaycastHit hit)
{
Vector3 vtemp;
// if this direction isn't directly away or towards the surface (so that it doesn't round away or towards it)
if(Mathf.Abs(hit.normal.x) < 0.5f)
{
// round relative distance to the center of the object we're placing on.
vtemp.x = hit.collider.gameObject.transform.position.x + (float) System.Math.Round(hit.point.x - hit.collider.gameObject.transform.position.x, System.MidpointRounding.AwayFromZero);
}
else
{
vtemp.x = v3.x;
}
if(Mathf.Abs(hit.normal.y) < 0.5f)
{
vtemp.y = hit.collider.gameObject.transform.position.y + (float) System.Math.Round(hit.point.y - hit.collider.gameObject.transform.position.y, System.MidpointRounding.AwayFromZero);
}
else
{
vtemp.y = v3.y;
}
if(Mathf.Abs(hit.normal.z) < 0.5f)
{
vtemp.z = hit.collider.gameObject.transform.position.z + (float) System.Math.Round(hit.point.z - hit.collider.gameObject.transform.position.z, System.MidpointRounding.AwayFromZero);
}
else
{
vtemp.z = v3.z;
}
// v make it so the object's center isn't directly at the point of intersection
return vtemp + (hit.normal/2);
}
Any help at all would be appreciated. Thanks in advance!
Answer by b1gry4n · Aug 30, 2016 at 11:50 PM
It seems like youre doing more work than what you need for what you want.
If you want the block to be its default rotation, you wouldnt use the surface normal to calculate any sort of rotation. If you want the block to align to the surface, thats when you want the normal information. After you do your check to see if the clicked point is a suitable spot, simply place the block at the hit.point and set its rotation to Quaternion.identity
If youre trying to snap these objects to a grid you could use
Vector3 pos= hit.point;
float gridSize = 1;
block.position = Vector3(Mathf.Round(pos.x / gridSize ) * gridSize,
Mathf.Round(pos.y / gridSize ) * gridSize,
Mathf.Round(pos.z / gridSize ) * gridSize);
Yes, that's the problem I'm running into. I do want the block to align to the surface, since it's going to be a space game in which the surface could be at any angle at all, in any position including non-rounded positions. (In global space)
What I'm looking for is some way to round the position in local space and align it to a 'grid' which could be in any position in global space.
Then you would need to translate from world space of the hit.point to local space of the object you wish to snap to (that could be at any rotation) and offset the blocks position/rotation to local space.
http://answers.unity3d.com/questions/181741/how-to-convert-between-local-world-coordinates.html
You can use what I posted above with a $$anonymous$$or tweak as well as a step prior and after.
If I understand correctly and for the purposes of demonstration... say you have an asteroid belt and all the asteroids are rotated differently. retrieving the hit.point on any given asteroid is the first step. The next would be to translate from world position to local position against the hit asteroid's transform. rotate the block to the asteroids rotation and then apply the code above, but ins$$anonymous$$d of using the "hit.point" use your converted "worldtolocal" position. After you have the new localposition you can translate from local back to world space and position your block.
An easier way(i think) would be to make this block you are placing a child of the asteroid. Set its localEulerAngles to 0,0,0 and snap it to the local grid (converting world position to local) and then updating the blocks position with block.localPosition = yournewposition
That's actually a much simpler and more efficient solution that what I had in $$anonymous$$d. I knew about the world space to local space conversion methods, but I didn't quite know how to use them. Thanks a lot!
Your answer
![](https://koobas.hobune.stream/wayback/20220612091900im_/https://answers.unity.com/themes/thub/images/avi.jpg)
Follow this Question
Related Questions
Make Gameobject Stand On Surface Facing Certain Direction 0 Answers
Transform rapidly spins when flipped upside down. 2 Answers
How to get rotation relative to the ground normal? 0 Answers
How do you perform multiple rotations on the same object? - (in a single frame) 0 Answers
Rotate Vector3 array around a point 1 Answer