How to position and scale a triangular model by knowing its vertices in Unity3d - unity3d

I want to position different equilateral triangular models, in a 3d space in unity. The problem is that the 3 known vertices aren't equilateral triangular, some of them aren't even isosceles so I need to wrap my model to match it's corners to the given vertices.
I would like to model those triangles different from each other that's why want to use pre-created models.
Currently I do the following calculation to position and scale the triangles onto a isosceles triangle:
Middle-point of the given 3 vertices
Vector3 middlepoint = (points[0]+points[1]+points[2])/3;
Distance from Middle-point
pointdistance[i] = Vector3.Distance(points[i],middlepoint);
The closest point is the one I will rotate the triangle to, so I know the triangles height (y-Axis), let's say the corner point is points[0] so float height = Vector3.Distance(points[0],middlepoint);
(I'm certain this step is wrong for a non isosceles triangle) I calculate it's width by determining the circumscribed circle radius, with the help of the remaining points
float width = (float)(Vector3.Distance(points[1] , points[2])*Math.Sqrt(3)/3);
Apply the scale to the model
float scale = new Vector3(height,width,1);
I calculate the normal normalVec of those 3 points to get the x and y orientation right, this works well so i think I don't need to change it
Instantiate the triangle
this.Triangle = (GameObject)Instantiate(standardTriangleModel,middlepoint, Quaternion.LookRotation(normalVec,points[0]));
The result looks pretty good until the triangles are not isosceles anymore
(Blue line = middlepoint to closest point, Green lines = connection between the given vertices)
So does anyone have a clue how i could position and resize my triangular models to match those points?

No code as I don't have unity handy at the moment. This answer is based on how to shear using unity gameobject transforms by trejkaz on the Unity Q&A site.
Start with gameobjects that are a right triangle of height and width 1:
Then for Triangle ABC, Set the X scale of the right triangle gameobject (which we can call mainObject) to be the length of AB, and set the Y scale to be the shortest distance between C and the line that travels through AB (the height of the triangle measured from the base AB).
Consider the angle CAB = θ.
Then, put mainObject inside of a parent gameobject called Outer1. Scale Outer1 with Y=sqrt(2)/sin(90-θ), X=sqrt(2).
Then, put Outer1 inside of a parent gameobject called Outer2. Rotate Outer2 around mainObject.forward by (θ-90) (which should be a clockwise rotation of 90-θ).
Then, put Outer2 inside of a parent gameobject called Outer3. Scale Outer3 with Y=sin((90-θ)/2), X=cos((90-θ)/2).
At this point, mainObject should be sheared and scaled into the correct shape. You will just need to position and rotate Outer3 so that the (pre-shearing) right angle corner of mainObject is at A,mainObject.right points from A to B, and mainObject.forward points normal to the triangle.

Related

Unity Rotate Sphere To Point Directly Upwards Based On Child Point

I've got a 3d sphere which I've been able to plot a point on using longitude and latitude thanks to some work of another developer I've found online. I think I understand what its doing.
What I need to do now is rotate my planet so the point is always at the top most point (ie the north pole) but I'm not sure how to do this. I'm probably missing some important fundamentals here so I'm hoping the answer can assist in my future learning.
Here's an image showing what I have - The blue line is a line coming from the longitude and latitude I have plotted and I need to rotate the planet so that line is basically pointing directly upwards.
https://ibb.co/2y24FxS
If anyone is able to advise it'd be very much appreciated.
If I'm not mistaken, Unity uses a coordinate system where the y-axis points up.
If the point on your sphere was in the xy-plane, you'd just have to determine the angle between the radius-vector (starts in the center of the sphere, ends on the point in question) and the y-axis, and than rotate by that amount around the z-axis, so that the radius vector becomes vertical. But your point is at an arbitrary location in 3D space - see the image below. So one way to go about it is to first bring the point to the xy-plane, then continue from there.
Calculate the radius vector, which is just r = x-sphereCenter. Make a copy of it, set y to zero, so that you have (x, 0, z) - which is just the projection of the vector r on the horizontal xz-plane - let's call the copy rXZ.
Determine the signed angle between the x-axis and rXZ (use Vector3.SignedAngle(xAxis, rXZ, yAxis), see docs), and create a rotation matrix M1 that rotates the sphere in the opposite direction around the vertical (negate the angle). This should place your point in the xy-plane.
Now determine the angle between r and the y-axis (Vector3.SignedAngle(r, yAxis, zAxis)), and create a new rotation matrix M2 that rotates by that angle around the zAxis. (I think for this second one, the simpler Vector3.Angle will work as well.)
So, what you want now is to combine the two matrices (by multiplying them) into a single transform (I'm assuming this is a transformation in the local coordinate system of the sphere, where (0, 0, 0) is the sphere's center). If I'm not mistaken, Unity uses column-major matrices, so the multiplication order should be M = M2 * M1 (the rightmost matrix is applied first).
Reorient your globe using M as a local transform, and it should bring your point to the top. You can also create M3 = M1.inverse, and then do M = M3 * M2 * M1, to preserve the original angular offset from the xy-plane.
Check for edge cases, such as r already being vertical (pointing straight up, or straight down).

Visio custom circle where diameter is calculated from control distance

I'm trying to figure out how to create a custom circle shape in Visio using the ShapeSheet to dynamically calculate the diameter of the circle relative to a control point.
The control point is essentially the vertex of an isosceles triangle and the diameter of the circle is calculated as the base of the isosceles triangle using a user variable for the angle of the vertex of that isosceles triangle.
The effect is the further you drag the control point away from the circle, the larger the circle gets, but the constant 'angle' of the vertex affects the rate that the circle would grow.
I know the trig for this diameter=2*control_distance*tan(vertex_angle/2) but since a circle isn't a fundamental shape in Visio (rather an ellipse is), I don't know how to accomplish calculating a circle with a shape sheet.

Want to find intersecting angle (3D position) of two 3D points or Y distance

I have point A (x,y,z) and point B (x, y, z) in ARWorld. I want to keep point A horizontally parallel to B or let's say both should be on the surface.
See the image to get a better idea.
I am planning to get Y direction height or vertical height from A to B and then I will push down A by height. But how to find the height.
I want to keep A's x and z the same as it is.
Not sure how to articulate the issue, But aY - By does not work.
NOTE: A and B both are different Anchor in ARKit. Box/Mesh is on the anchor. Seems like I need global absolute world positions.
Is there any other way to get a rounded position in the image?
You say you want to get the positionA mapped down to the same "height" (Y axis) level as positionB
positionA.y = positionB.y;
it is simple as that.
Be aware that I am talking about absolute world space positions ... the values will of course be different in the Inspector since there you see only the local positions relative to the parent.
So when we are talking about GameObjects what you want to do is
var positionA = objectA.transform.position;
var positionB = objectB.transform.position;
positionA.y = positionB.y;
objectA.transform.position = positionA;
I would make an horizontal plane in B find the closest point in that plane to A and move A to that point.
Create horizontal plane:
Taking the constructor into account Plane(Vector3 inNormal, Vector3 inPoint);.
Plane myPlane = new Plane(Vector3.up, <Bpositon>)
Then with Plane.ClosestPointOnPlane you can find the closest point to A in your horizontal plane.
Vector3 closestPoint = myPlane.ClosestPointOnPlane(<APosition>);
Then you can move A to that point.
APosition = closesPoint;
Conviniently the closest point in the plane to one point is the one perpendicular to the plane, so the one "horizontally parallel" I believe you are after.

Find angle between 2 points ignoring origin.forward in Unity

Background: I am creating an AR treasure hunt app. It is simple, it has a locator that tells you where the treasure is relative to you. I have the camera being the origin and the treasure being an object in AR world.
Question: I would like to rotate my arrow according to where in space the treasure is at. but in 2d. Basically, I would ignore the relative forward plane that is camera.forward.
Example: If the camera rotation is default, the angle can be calculated as atan2(dy,dx). If the camera is looking straight down, the angle is atan2(dz,dx).
What I have tried:
Quaternion lookRot = Quaternion.LookRotation(target.transform.position - origin.transform.position);
Quaternion relativeRot = Quaternion.Inverse(origin.transform.rotation) * lookRot;
Relative rotation is correct in 3d space but I would like to convert that into 2d ignoring the camera.forward plane. So even if the treasure is in front or behind the camera, it should not change the angle.
Okay so I’m hoping this makes sense. You’re going to need some sort of if statement to determine if your character is looking along the x, y or z plane. Hopefully the diagram is clear as to what those parameters are but if not. To be looking in the “x” plane for example, the y rotation would have to be between 45° and -45° or 135° and -135° AND the z rotation would have to be between 45° and -45° or between 135° and -135°.
Essentially what you’ve got is a sphere split into six parts, two parts for each plane along which the character could look. Once you’ve determined which plane the character is looking in you can determine the direction by finding the difference in position between the character and the treasure along the two planes the character isn’t looking along. Then use trig to calculate the angle
Replying to an old thread, but I was struggling with the same problem and found a relatively simple solution:
Project the position of the target (relative to the origin) on a plane defined by the forward vector of the camera. Then just rotate towards the projected point:
Vector3 diff = target.transform.position - origin.transform.position;
Vector3 projected = Vector3.ProjectOnPlane(diff, Camera.main.transform.forward);
origin.transform.rotation = Quaternion.LookRotation(projected);
Calculate the difference in x and y coordinates simply by subtracting transform.x for one object by transform.x of another object and the same process for y coordinates and then use Mathf.atan(difference in y/difference in x) to calculate the angle. Then put the z rotation to this angle and assign the x and y rotation to what they already were.
Turns out there is a very simple way to get relative X and Y of the target.
Vector2 ExtractRelativeXY(Transform origin, Transform target) {
// Get the absolute look rotation from origin to target.
Quaternion lookRot = Quaternion.LookRotation(target.transform.position - origin.transform.position);
// Create a relative look rotation with respect to origin's forward.
Quaternion relativeRot = Quaternion.Inverse(origin.transform.rotation) * lookRot;
// Obtain Matrix 4x4 from the rotation.
Matrix4x4 m = Matrix4x4.Rotate(relativeRot);
// Get the 3rd column (which is the forward vector of the rotation).
Vector4 mForward = m.GetColumn(2);
// Simply extract the x and y.
return new Vector2(mForward.x, mForward.y);
}
Once obtained x and y, turn it into angle using angle = atan2(y,x) as suggested by both MBo and Tom.
This works because of the matrix components of the quaternion can be demonstrated in multiple vectors. Better illustration is found here https://stackoverflow.com/a/26724912.

compute pitch, roll and yaw movement of an object in Matlab

I am currently working, with Matlab, on a 3D simulator whose aim is to move an object (currently it's just a simple circle) in space (using plot3).
Although it's easy to compute a trajectory without any rotation of my object, I do not manage to rotate my object around its own axis. Indeed, I have computed the 3 well-known rotation matrix but it (of course) rotate my object (represented by a set of points) around the axis of my figure (in the "world" system).
For example, the center of inertia of my object (currently the center of my circle) is I whose coordinates are (Xi,Yi,Zi). Thus, I suppose that I need to define an additional system for my object to be able to rotate my object about these 3 new axis composing such a system...
I would like something like:
[X2,Y2,Z2]=Mat*[X1,Y1,Z1] where [X1,Y1,Z1] is the coordinates of a point of my object before the rotation, [X2,Y2,Z2] the coordinates after the rotation and Mat the matrix I am looking for. Of course, the center of inertia must be unchanged whichever the rotation (yaw and/or pitch or/and roll)
However I have no idea about the way to compute such a matrix. The link below summarizes my wish.
Drawing of my problem