Unity3D - Get Mathematical Plane from Primitive Plane in same world position - unity3d

I have a GameObject.Plane in a given position for visual purposes.
From that, given the plane's rotation and position in world space, I have to make a mathematical plane to use in the next calculations, but something's off.
I've tried doing
new Plane(go.transform.InverseTransformDirection(-go.transform.right), go.transform.InverseTransformPoint(go.transform.position));
where go is the primitive plane object.
Its position in world space seems fine, judging from the later results, but the rotation is not.
The Primitive plane(go) is rotated 90 degrees so instead of facing upwards it's facing the side.
What's going wrong here?
Edit: Current setup is
go.transform.InverseTransformDirection(-go.transform.right);
return new Plane(go.transform.up, go.transform.position);
void OnDrawGizmos()
{
Gizmos.color = Color.magenta;
Gizmos.DrawLine(planePrimitive.transform.position, planePrimitive.transform.position + plane.normal * 3f);
}

This
go.transform.InverseTransformDirection(-go.transform.right)
returns a vector facing to the side and you are using it as the Plane's normal.
A primitive Plane object's normal is simply it's local transform.up vector.
Then note that a Plane takes world space coordinates so it makes no sense to use InverseTransformDirection and InverseTransformPoint since transform.up and transform.position already are in world space.
new Plane(go.transform.up, go.transform.position);
If you are rather talking about a primitive Quad object then the vector you want is -transform.forward instead.
new Plane(-go.transform.forward, go.transform.position);
To your Gizmos:
You are using the testPlane.normal like it was a position. It is not! The normal is a direction and doesn't tell anything about the position.
What you want to do would be e.g. (without using local space gizmos)
Gizmos.DrawLine(go.transform.position, go.transform.position + testPlane.normal * 3f);
or if you can depend only on the plane itself use
Gizmos.DrawLine(plane.distance, plane.distance + testPlane.normal * 3f);
In this second plane the plane.distance is the vector from 0,0,0 to the closest point on the plane. It will therefore still not be exactly in the position of the given plane object.

Related

How to make object pull another in Unity 2D

So I'm trying to simulate orbital mechanics in Unity 2D. I have a ship and Moon model in scene. I calculated the sphere of influence, and if the distance between the Moon and ship is smaller than sphere of influence, the gravity will effect. Problem is;
I can't get gravity affect working.
I've tried using AddForce method, but since it requires Vector2 elements and I calculate my force as float (I use Newton's law of gravitation formula and I get a float), I don't know how to include my float force in Vector2 force.
force = (GravitationalConstant * ((planetMass * ship.GetComponent<Rigidbody2D>().mass)/Mathf.Pow(Vector3.Distance(ship.transform.position,transform.position),2)))/(realityConstant * forceReducer);
if (Vector3.Distance(transform.position,ship.transform.position) < SOI/realityConstant){
ship.GetComponent<Rigidbody2D>().AddForce(new Vector2((float)force,0f));
}
This code makes Moon pull the ship to itself only from left side. When ship passes Moon, it keeps pushing it to right. Not to itself.
I need a fix, that makes Moon pull the ship to itself everytime, with a specific force. How do i make this happen?
Any idea would be helpful.
Thanks a lot!
Force is applied using a vector. You have the magnitude of your vector but not its direction. You can calculate a direction by subtracting moon position from the ship position:
ship.GetComponent<Rigidbody2D>().AddForce((Moon.transform.position -
ship.transform.position).normalize * force);

Questions related to transform.rotate() in Unity Scripting

I have four rectangular platforms put around a square platform. All other three rectangular platforms were rotated from the '0' platform. On the end of each rectangular platforms, I set up some spawn points to generate cubes with arrows sign on its face(the image of this cube is shown in the second link). I hope to rotate the cube to change the orientation of the arrow on it. But my original codes that rotating the cube do not work for platform 1 & 3, but work for platform 0&2.
Although I have found how to change it to make it works, I still cannot understand why my original codes failed. The version I used is 2019.4.18f1.
The top view of these platforms are shown below.
enter image description here
Unworkable way
dirCubeTypes is an array that stores all my different kinds of cube objects.
dirCubePoints is an array that stores all my spawn points.
The first statement works well. The problem is in the second statement.
GameObject cube = Instantiate(dirCubeTypes[Random.Range(0, 6)], dirCubePoints[Random.Range(0, 4)]);
cube.transform.Rotate(transform.forward, 90 * Random.Range(0, 4));
The figure below shows the cube generated on the platfrom 3. I want it to rotate around z-axis, but the codes above make it rotate around its x-axis instead of z-aixs. I know the third parameter is relativeTo, and the default value is Space.self. Why doesn't the codes above make it rotate along the z-axis in its own local coordinate system?
enter image description here
Workable ways
I have tried out three workable ways, but for two of them, I still don't know why it works.
This one works well. If I use Vector3.forward in Space.self, I think it should rotate around the x-axis of the cube itself, but it rotate around its z-axis.
GameObject cube = Instantiate(dirCubeTypes[Random.Range(0, 6)], dirCubePoints[Random.Range(0, 4)]);
cube.transform.Rotate(Vector3.forward, 90 * Random.Range(0, 4));
This one also works well. But I am confused either.
GameObject cube = Instantiate(dirCubeTypes[Random.Range(0, 6)], dirCubePoints[Random.Range(0, 4)]);
cube.transform.Rotate(transform.forward, 90 * Random.Range(0, 4), Space.World
);
The last one is the only one that works as I think.
GameObject cube = Instantiate(dirCubeTypes[Random.Range(0, 6)], dirCubePoints[Random.Range(0, 4)]);
cube.transform.RotateAround(transform.position, transform.forward, 90*Random.Range(0,4));
First of all
Vector3.forward just equals new Vector3(0,0,1) so it is just a generic Z axis vector (either in the world or local depending on how it is used)
transform.forward rather is the local Z axis of your object in world space
And Rotate can either be used in world space or in local space (this is the default since the space parameter is optional and defaults to Space.Self).
When you passed in
cube.transform.Rotate(transform.forward * 90 * Random.Range(0,4));
it of course behaves strange since you treat the world space vector transform.forward like a local space one. So as soon as your object is somehow rotated in the world it breaks.
So either you want the world space then do
// Using the world space transform.forward and passing in Space.World
cube.transform.Rotate(transform.forward * 90 * Random.Range(0,4), Space.World);
or the same in local space
// Using the local space Vector3.right
// in this case - since it will use Space.Self if nothing is passed in -
// the Vector3.forward is treated as relative to the local space
cube.transform.Rotate(Vector3.forward * 90 * Random.Range(0,4));
I just saw your question update. I believe your misunderstanding stems from not knowing what Vector3.forward and Transform.forward are and their core difference. Vector3.forward is the unit vector defined by (0, 0, 1). The Transform.forward is a relative direction based on the orientation of your object.
Your first example works in some cases as it just so happens that the Transform.forward and Vector3.forward happen to be the same direction.
Your second example works as you are using Vector3.forward not the relative Transform.forward
Your third example works as you provide the Space.World, so instead of using local orientations, it is rotating the object in world space relative to the scene.
Your fourth example works as you are using RotateAround. RotateAround is different than Rotate in that it will rotate the transform about your inputted axis (transform.forward), which pass through the point (transform.position) in world coordinates by the angle (90*Random.Range(0,4)) degrees. Effectively moving the local rotation around an axis back to world space.
I hope this clears up why the first example does not work while the last three do.

Why am I getting an incorrect vector when trying to find HingeJoint2D.anchor in world space?

In the scene, I have a long chain of children that are connected via hinge to their parent. For my code, I need the position of the hinge anchors in world space, so I use:
public Vector2 hingeVector => hinge.anchor + (Vector2)gameObject.transform.position;
For the first hinge, that code gives the correct position. But for the second hinge this happens:
The red point is the vector I get, the blue point is the actual position. As you can see, it's a somewhat small but still problematic difference.
Is there any way I can fix this? I couldn't find anything like this online.
You need to add the object's rotation
The anchor values are axis aligned and aren't affected by rotation, but in order to calculate the anchor point in world space, knowing the transform's position, you need to rotate the anchor point values by the object's rotation then add it to the position:
Vector2 p = hinge.anchor.Rotate(gameObject.transform.rotation.eulerAngles.z)
+ (Vector2)gameObject.transform.position;

Which side of my cube is hitting the plane below the cube

Im working in Unity and I have a simple scene. It consists of a cube which has a box collider on it. Below this cube is a plane
I want to know which side of the cube is hitting the plane at any given instant
One way to do this is to cast a ray from each side of the cube and determine which ray is colliding with the plane
But i fear that it may be performance heavy. Is there a way to do this in an efficient manner?
I used for same need:
1) Place plane for each side of cude;
2) Set clear color for planes;
3) Write script that check plane position (in your option need loop that search plane with lower position.
If you're just looking for a way other than just ray casting then you could create a method that takes in your cube's position and your plane's position and then do some calculations.
Vector3 heading = plane.transform.position - cube.transform.position;
float distance = heading.magnitude;
Vector3 direction = heading / distance;
From here you would just have to check what that direction is.

Placing objects right in front of camera

I am trying to figure out how to modify HelloARController.cs from the example ARCore scene to place objects directly in front of the camera. My thinking is that we are raycasting from the camera to a Vector3 on an anchor or tracked plane, so can't we get the Vector3 of the start of that ray and place an object at or near that point?
I have tried lots, and although I am somewhat a beginner, I have come up with this
From my understanding, ScreenToWorldPoint should output a vector3 of the screen position corresponding to the world, but it is not working correctly. I have tried other options instead of ScreenToWorldPoint, but nothing has presented the desired effect. Does anyone have any tips?
To place the object right at the middle of the camera's view, you would have to change the target gameObject's transform.position (as AlmightyR has said).
The ready code would look something like this:
GameObject camera;
GameObject object;
float distance = 1;
object.transform.position = camera.transform.position + camera.transform.forward * distance;
Since camera's forward component (Z axis) is always poiting at the direction where Camera is looking to, you take that vector's direction and multiply it by a distance you want your object to be placed on. If you want your object to always stay at that position no matter how camera moves, you can make it a child of camera's transform.
object.transform.SetParent(camera.transform);
object.transform.localPosition = Vector3.forward * distance;
Arman's suggestion works. Also giving credit to AlmightyR since they got me started in the right direction. Here's what I have now:
// Set a position in front of the camera
float distance = 1;
Vector3 cameraPoint = m_firstPersonCamera.transform.position + m_firstPersonCamera.transform.forward * distance;
// Intanstiate an Andy Android object as a child of the anchor; it's transform will now benefit
// from the anchor's tracking.
var andyObject = Instantiate(m_andyAndroidPrefab, cameraPoint, Quaternion.identity,anchor.transform);
The only problem with this is that because of the existing HelloAR example code, an object is only placed if you click on a point in the point cloud in my case (or a point on a plane by default). I would like it to behave so that you click anywhere on screen, and it places an object anchored to a nearby point in the point cloud, not necessarily one that you clicked. Any thoughts for how to do that?
Side tip for those who don't know: If you want to place something anchored to a point in the cloud, instead of on a plane, change
TrackableHitFlag raycastFilter = TrackableHitFlag.PlaneWithinBounds | TrackableHitFlag.PlaneWithinPolygon;
to
TrackableHitFlag raycastFilter = TrackableHitFlag.PointCloud;