I want to get a Collide Vector of a Mesh using a Up-Vector.
I have a position and a Up Vector.. with these both I calculate the far vector
public Vector3 SetPlayerToGround(Matrix Object, Matrix Player, Mesh GroundObject)
{
Vector3 IntersectVector = new Vector3(0, 0, 0);
if (GroundObject != null)
{
Vector3 Player_UP = new Vector3(Player.M12, Player.M22, Player.M32);
Vector3 PlayerPos = new Vector3(Player.M14, Player.M24, Player.M34);
Vector3 PlayerPos_Far = PlayerPos - Player_UP ;
gameengine.m_Device.Transform.World = Object;
IntersectInformation closestIntersection;
if (GroundObject.Intersect(PlayerPos, PlayerPos_Far, out closestIntersection))
{
IntersectVector = Player_UP + (PlayerPos_Far * closestIntersection.Dist);
}
}
return IntersectVector;
}
Well if I do
Vector3 PlayerPos_Far = PlayerPos + Player_UP;
It will always intersect with nothing...
But the Object which I want to intersect is always under the "position - UpVector"
so I think
Vector3 PlayerPos_Far = PlayerPos - Player_UP ;
is right
why I cant intersect?
Here is a better Description:
Here is the Player and he is into a Ship. the Player is always at 0,0,0 because I move the world around the player. if I Move the Player forward I Chance the playerposition vector which chance only the positions of all other objects.
But I think the player has nothing to do with the Intersect.. but the ship itself.
I use the Position 0,0,0 and the upvector as direction to get the intersectvector of the ground from the ship. the Matrix of the Ship is (Matrix Object):
Vector3 com = ship.position - gamemanager.player.position;
Matrix world;
world = Matrix.Identity * Matrix.Scaling(0.001f, 0.001f, 0.001f) * Matrix.Translation(com);
m_Device.Transform.World = world;
I tried something and I think he wont use my translated Matrix of the ship...
You have to provide a ray defined by a position and a direction. You do not have to specify two points. So pass -PLAYER_UP instead of PlayerPos_Far.
Furthermore, the Intersect method will not care about transformations. You have to pretransform the ray. Transform both the ray position and the direction with the inverse world matrix (transform from world space to model's space) and you should be fine.
Vector3 rayStart = PlayerPos;
Vector3 rayDir = -PLAYER_UP;
Matrix world; //the ship's world matrix
world = Matrix.Invert(matrix);
rayStart = Vector3.TransformCoordinate(rayStart, world); //you may need to add an out parameter
rayDir = Vector3.TransformNormal(rayDir, world);
GroundObject.Intersect(rayStart, rayDir, ...
Related
I'm making a Unity game where you can use your imagination to summon things. The first thing you get is a cannon, but I'm having trouble making the cannon look at where the player is looking. I just need to change the z rotation to match the players but for some reason when I do this it changes the x rotation to be 180. Here's my code
if (Input.GetKeyDown("k"))
{
Vector3 playerPos = transform.position;
Vector3 playerDirection = transform.forward;
Quaternion playerRotation = transform.rotation;
float spawnDistance = 10;
smoke.transform.position = playerPos + playerDirection * spawnDistance;
smoke.Play();
StartCoroutine(SpawnCannon(1));
IEnumerator SpawnCannon(float waitTime)
{
yield return new WaitForSeconds(waitTime);
cannon.transform.position = smoke.transform.position;
cannon.transform.rotation = new Quaternion(-90,0,playerDirection.z,0);
}
}
does the cannon have a rigidbody? If it does then freeze the rotation of the canon on the x axis. But if it doesn't have a rigidbody, add one and freeze the rotation of the canon on the x axis. and this line of code here: Quaternion playerRotation = transform.rotation;, you can replace it with this : Quaternion playerRotation = transform.rotation.[AXIS HERE];. Replace the [AXIS HERE] with the axis you want the canon to rotate in, if you want the canon to be rotating in the z axis, you would replace [AXIS HERE] with z. Hope this helps a little! :D
I crafted a model to illustrate what I am trying to calculate. Given a line (vector) between two anchor points, I want to place one or more game objects a certain distance tangential to the midpoint of that vector and at designated angles (radians?) along a circle that is perpendicular to the vector.
In this illustration, an imaginary circle is placed at midpoint and perpendicular to the line between Anchor 1 and Anchor 2. I want to calculate the Vector3 positions of three points (P1, P2, and P3). The intent is to place objects at each of those points. The entire assembly will a gameobject that can rotate in space. (There will be a single game object with each object a child.)
I have scoured StackOverflow and the Unity communities and cannot find examples that help me make those three placements.
Any ideas?
Instead of trig, consider vector math and quaternions. Use cross products to find the 0 angle offset and quaternions to rotate it according to the angle. See comments for explanation.
public void PlaceObjects(Transform anchor1, Transform anchor2, float r,
List<Transform> objs, List<float> angles)
{
// lists must be non-null and same size
Debug.Assert(objs != null);
Debug.Assert(angles != null);
Debug.Assert(objs.Count == angles.Count);
// Find midpoint and axis of rotation
Vector3 midpoint = 0.5f * (anchor1.position + anchor2.position);
Vector3 axis = (anchor2.position - anchor1.position).normalized;
// What direction should the the "zero" offset be based on?
// Base it on the local up of the "assembly parent" this script is attached to?
// or Vector3.up if "0 angle" should approximate world up?
Vector3 upDirection = transform.up;
// Of directions perpendicular to the axis find the closest to upDirection
// See https://stackoverflow.com/a/57698547/1092820 for more information
Vector3 axisRight = Vector3.Cross(upDirection, axis);
if (axisRight == Vector3.zero)
{
// upDirection & axis are colinear, no unique "up-ish" exists.
// Just give up and don't move anything.
return;
}
Vector3 zeroOffsetDir = Vector3.Cross(axis, axisRight);
for (int i = 0 ; i < objs.Count ; i++)
{
Transform obj = objs[i];
float angle = angles[i];
// Find a rotation that describes how to rotate a "0 angle" offset into the one
// the current object needs
Quaternion rot = Quaternion.AngleAxis(angle, axis);
// Find the offset by rotating the "zero" offset, then extending it by the radius
Vector3 offset = r * (rot * zeroOffsetDir);
// Set the object's position based on its offset and the location of the midpoint
obj.position = midpoint + offset;
// Optionally, set the object's rotation based on its current forward and the new up:
// obj.rotation = Quaternion.LookRotation(obj.forward, offset);
}
}
For those interested, here's my Component adaptation of #Ruzihm's solution. The PlaceObjectsOnCirclePerpendicularToVectorLine component is placed on an empty game object.
using System.Collections.Generic;
using UnityEngine;
public class PlaceObjectsOnCirclePerpendicularToVectorLine : MonoBehaviour
{
// Adapted from https://stackoverflow.com/a/63308834/13052746, by Ruzihm.
public Transform anchor1;
public Transform anchor2;
public float radius;
public List<Transform> objs;
public List<float> angles;
private Vector3 anchor1PriorPosition;
private Vector3 anchor2PriorPosition;
// Start is called before the first frame update
void Start()
{
PlaceObjects(
anchor1,
anchor2,
radius,
objs,
angles);
}
// Update is called once per frame
void Update()
{
PlaceObjects(
anchor1,
anchor2,
radius,
objs,
angles);
}
public void PlaceObjects(
Transform anchor1,
Transform anchor2,
float radius,
List<Transform> objs,
List<float> angles)
{
if (anchor1PriorPosition == anchor1.position &&
anchor2PriorPosition == anchor2.position)
{
// The anchors haven't moved.
return;
} else
{
anchor1PriorPosition = anchor1.position;
anchor2PriorPosition = anchor2.position;
}
// lists must be non-null and same size
Debug.Assert(objs != null);
Debug.Assert(angles != null);
Debug.Assert(objs.Count == angles.Count);
// Find midpoint and axis of rotation
Vector3 midpoint = 0.5f * (anchor1.position + anchor2.position);
Vector3 axis = (anchor2.position - anchor1.position).normalized;
// What direction should the the "zero" offset be based on?
// Base it on the local up of the "assembly parent" this script is attached to?
// or Vector3.up if "0 angle" should approximate world up?
Vector3 upDirection = transform.up;
// Of directions perpendicular to the axis find the closest to upDirection
// See https://stackoverflow.com/a/57698547/1092820 for more information
Vector3 axisRight = Vector3.Cross(upDirection, axis);
//if (axisRight == Vector3.zero)
//{
// // upDirection & axis are colinear, no unique "up-ish" exists.
// // Just give up and don't move anything.
// return;
//}
Vector3 zeroOffsetDir = Vector3.Cross(axis, axisRight);
for (int i = 0; i < objs.Count; i++)
{
Transform obj = objs[i];
float angle = angles[i];
// Find a rotation that describes how to rotate a "0 angle" offset into the one
// the current object needs
Quaternion rot = Quaternion.AngleAxis(angle, axis);
// Find the offset by rotating the "zero" offset, then extending it by the radius
Vector3 offset = radius * (rot * zeroOffsetDir);
// Set the object's position based on its offset and the location of the midpoint
obj.position = midpoint + offset;
}
}
}
Here's what it looks like in the Scene view:
And here's what the component looks like in the inspector:
Again, brilliant, #Ruzihm! Exactly what I wanted!
I have achieved Globe rotating on mouse click on any particular panel on the Globe and the panel position gets in the Center of the Camera on click but the problem is Globe travels the shortest distance between the two points (Camera Center and Next Position on Globe).
As per the image currently Globe jumps to next position and tilts like this
As per this Image I need Globe to result in this rotation where NorthPole and SouthPole remains at their side looking through the camera.
public List<GameObject> characters = new List<GameObject>();
private Quaternion targetRotation = Quaternion.identity;
public void CharacterPosition(int charNum)
{
Quaternion diff = Quaternion.FromToRotation(characters[charNum].transform.up, camera.transform.position - transform.position);
targetRotation = diff * transform.rotation;
transform.DORotateQuaternion(targetRotation, 1f);
hitAgainNumber = charNum;
}
"characters" List conists of the panels on the globe on multiple positions.
DoTween Plugin is used for the Rotation.
I will be very thankful if someone helps me with that.
Explanations are in the comments:
public List<GameObject> characters = new List<GameObject>();
private Quaternion targetRotation = Quaternion.identity;
public void CharacterPosition(int charNum)
{
// Use cross products to find the closest vector to Vector3.up which is orthogonal
// to the direction from the sphere to the camera.
// This direction is to be the sprite's forward after we rotate the sphere
Vector3 charGoalUp = camera.transform.position - transform.position;
Vector3 charGoalRight = Vector3.Cross(charGoalUp, Vector3.up);
Vector3 charGoalForward = Vector3.Cross(charGoalRight, charGoalUp);
// Get the goal rotation for the character using `LookRotation`:
Quaternion charGoalRotation = Quaternion.LookRotation(charGoalForward, charGoalUp);
// Determine the world rotation that needs to apply to the character:
// delta * char_start = char_end -> delta = char_end * inv(char_start)
Quaternion worldCharDelta = charGoalRotation
* Quaternion.Inverse(characters[charNum].transform.rotation);
// Apply that same world rotation to the globe:
targetRotation = worldCharDelta * transform.rotation;
transform.DORotateQuaternion(targetRotation, 1f);
hitAgainNumber = charNum;
}
I'm trying to make a simple car simulator, and when I use the transform.Rotate() to rotate the wheels foreword (x axis), and the transform.localEulerAngles() to rotate in the turning direction (y axis), only the localEulerAngles() works. when I use only one method, the wheel foreword rotation (x axis) works, but I can't manage to make them both work. Do you have any ideas how to make them work together?
float ro = 20f; // 20 degrees turn
//to preserve the x and z values of rotation
Vector3 rot = wheel.gameObject.transform.rotation.eulerAngles;
//rotates the wheels angle
wheel.gameObject.transform.localEulerAngles = new Vector3(rot.x, ro, rot.z);
float vel = wheel.rpm * 2 * Mathf.PI / 60 * Time.deltaTime * Mathf.Rad2Deg;
//rotates the wheels forward
wheel.gameObject.transform.Rotate(vel, 0, 0);
You should not be using localEulerAngles when you are having two different rotations, because when you have 2 movements if you use localEulerAngles you change the local angles with the movements you are providing themselves so you loose the reference of where the angular position of your axis is at.
You can indicate to the rotate method to rotate respect to the world, transform.rotate rotates the transform of your object relative to the world so you can handle simultaneus rotations together because world axis do not change.
Find below the code snippet that I tried, and the picture of my axis orientation which is not exactly the same as yours.
public class WheelTurning : MonoBehaviour
{
float rpm=10f;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.A))
{
turn(direction.left);
}
if (Input.GetKeyDown(KeyCode.D))
{
turn(direction.right);
}
float vel = this.rpm * 2 * Mathf.PI / 60 * Time.deltaTime * Mathf.Rad2Deg;
rotate(vel);
}
enum direction
{
left,
right
}
void turn(direction dir)
{
Vector3 rot = this.gameObject.transform.rotation.eulerAngles;
//rotates the wheels angle
float rotation = dir == direction.left ? 20f : -20f;
gameObject.transform.Rotate(new Vector3(0, rotation, 0), Space.World);
}
void rotate (float speed)
{
gameObject.transform.Rotate(0, speed, 0);
}
}
However it is much more operative to use quaternions, try to check that out.
Hope that helps!
I do not get your point. If you want to turn a wheel it will alwiys be respect to its previous rotational postion. With that reference you can choose the value you like in the rotation vector Vector3(0, rotation, 0). If you want an absolute reference you can make a parent object and rotate this. Objects have the same world axis and when rotated or transformed, the children "suffer" the same transformation. You have to meke sure that the posistion in the childre is 0,0,0 as this is the distance respect to the parent position that will be the rotation pivot.
void setRotation()
{
Vector3 rot = this.gameObject.transform.rotation.eulerAngles;
GameObject wheelParent = gameObject.transform.parent.gameObject;
Vector3 rotationVector = new Vector3(0, 30, 0);//absolute turn set
Quaternion rotation = Quaternion.Euler(rotationVector);
wheelParent.transform.localRotation = rotation;
}
Hope that helps.
I want to move an instance of a gameObject along the outline of another gameobject. Its a 2D Project in Unity.
My current Code:
Vector3 mousePosition = m_camera.ScreenToWorldPoint(Input.mousePosition);
RaycastHit2D hit = Physics2D.Raycast(new Vector2(mousePosition.x, mousePosition.y), new Vector2(player.transform.position.x, player.transform.position.y));
if (hit.collider != null && hit.collider.gameObject.tag == "Player") {
if (!pointerInstance) {
pointerInstance = Instantiate(ghostPointer, new Vector3(hit.point.x, hit.point.y, -1.1f), Quaternion.identity);
} else if(pointerInstance) {
pointerInstance.gameObject.transform.position = new Vector3(hit.point.x, hit.point.y, -1.1f);
pointerInstance.gameObject.transform.eulerAngles = new Vector3(0f, 0f, hit.normal.x);
}
}
Unfortunately, the gameObject doesn't rotate towards the mouse and the position on the left side of the playerObject is also sometimes off. I tried to use Instantiate() with Quaternion.LookRotation(hit.normal), but no luck either.
Here a rough sketch of what I want to achieve:
Any help is appreciated. Thanks!
it's better to use Mathematical way instead of physical way(Raycasting),because in raycasting you have to throw ray several time for checking hit point and rotate your object,it makes lag in your game.
Attach this script to your instantiated object:
using UnityEngine;
using System.Collections;
public class Example : MonoBehaviour
{
public Transform Player;
void Update()
{
//Rotating Around Circle(circular movement depend on mouse position)
Vector3 targetScreenPos = Camera.main.WorldToScreenPoint(Player.position);
targetScreenPos.z = 0;//filtering target axis
Vector3 targetToMouseDir = Input.mousePosition - targetScreenPos;
Vector3 targetToMe = transform.position - Player.position;
targetToMe.z = 0;//filtering targetToMe axis
Vector3 newTargetToMe = Vector3.RotateTowards(targetToMe, targetToMouseDir, /* max radians to turn this frame */ 2, 0);
transform.position = Player.position + /*distance from target center to stay at*/newTargetToMe.normalized;
//Look At Mouse position
var objectPos = Camera.main.WorldToScreenPoint(transform.position);
var dir = Input.mousePosition - objectPos;
transform.rotation = Quaternion.Euler(0, 0, Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg);
}
}
Useful explanations
Atan2:
atan2(y,x) gives you the angle between the x-axis and the vector (x,y), usually in radians and signed such that for positive y you get an angle between 0 and π, and for negative y the result is between −π and 0.
https://math.stackexchange.com/questions/67026/how-to-use-atan2
Returns the angle in radians whose Tan is y/x.
Return value is the angle between the x-axis and a 2D vector starting at zero and terminating at (x,y).
https://docs.unity3d.com/ScriptReference/Mathf.Atan2.html
Mathf.Rad2Deg:
Radians-to-degrees conversion constant (Read Only).
This is equal to 360 / (PI * 2).