A hinge's hingeAngle can be retrieved as a singular float but not be set explicit. I am simulating a door using hinges and need to be able to instantly set the angle to open or closed at will. How can this be achieved?
The hinge is created with:
const float mass = 10.0f;
BoxShape boxShape = new BoxShape(Door.CollisionShape);
Vector3 pivotA = new Vector3(-Door.CollisionShape.X, Door.CollisionShape.Y, Door.CollisionShape.Z);
door.rigidBody = physics.LocalCreateRigidBody(mass, door.getRotationMatrix() * Matrix4.CreateTranslation(position), boxShape);
door.rigidBody.ActivationState = ActivationState.DisableDeactivation;
door.rigidBody.UserObject = "Door";
var axisA = Vector3.UnitY; // pointing upwards, aka Y-axis
var hinge = new HingeConstraint(door.rigidBody, pivotA, axisA);
hinge.SetLimit(-(float)Math.PI * 0.25f, 0);
physics.World.AddConstraint(hinge);
and I am moving it with:
float targetVelocity = Door.OpenSpeed;
float maxMotorImpulse = 1.0f;
door.hinge.EnableAngularMotor(true, targetVelocity, maxMotorImpulse);
On each step BulletPhysics increases the hingeangle based on the targetVelocity. I'm looking to set this value directly, as opposed to indirectly by applying forces.
Did you try setMotorTarget() function?
void btHingeConstraint::setMotorTarget
(
btScalar targetAngle,
btScalar dt
);
Is your desired behaviour that the door changes from open to close, in a single simulation step?
If so, that seems a dangerous thing to do, because there may be something blocking the door, and by hard-setting the door rigid body, it may be intersection other shapes.
Related
I'd like to programmatically modify the Scale parameter (specifically the x Scale) of the Rect Transform component attached to my 'damage pop-up' game object, as shown in the attached image; however, I just can't seem to modify this value. I've tried several methods (code shown below) and nothing seems to work.
Any help or guidance is much appreciated!
Rect Transform component in Unity (image):
Vector3 rectScale;
RectTransform rectTransform;
float xScale;
// Start is called before the first frame update
void Start()
{
rectTransform = GetComponent<RectTransform>();
rectScale = rectTransform.localScale;
rectScale = new Vector3(3f, transform.localScale.y, transform.localScale.z); //this doesn't work
xScale = rectTransform.localScale.x;
xScale = *any number*; // this doesn't work
}
void Update()
{
rectScale = new Vector3(3f, transform.localScale.y, transform.localScale.z); //this doesn't work
xScale = *any number* //this doesn't work
}
The issue here seems to be more a misunderstanding how c# works in general!
The
xScale = 3f;
assigns a new value to the field xScale. Whatever value it had before is now forgotten and it is 3f now. The same as
rectScale = new Vector3(3f, transform.localScale.y, transform.localScale.z);
assigns a new value to the field rectScale. Whatever vector value it had before is forgotten and it now has the value (3f, transform.localScale.y, transform.localScale.z)
Both do NOT change the value of rectTransform.localScale or rectTransform.localScale.x!
You rather want to assign a new value to rectTransform.localScale like e.g.
recTransform.localScale = new Vevtor3 (3f, rectTransform.localScale.y, rectTransform.localScale.z);
Or a bit more efficient without accessing the same property multiple times
var scale = rectTransform.localScale;
scale.x = 3f;
recTransform.localScale = scale;
Btw specifically for RectTransform you might rather want to use sizeDelta which scales the actual rect. Using localScale will cause the content and any children to look stretched!
var scale = rectTransform.sizeDelta:
scale.x = 3f;
recTransform.sizeDelta = scale;
I was looking for a way to set the Quaternions (x, y, z, w) through the inspector window. We get all these variables when we click on "Debug" mode in Unity. Through Unity docs, I got to know that these values are between 0-1. So how do we set for angles such as 90,-90,180,-180,270,.... MAIN THING here is that I want to set the target rotations in the script of this game object so that the gameObject moves from initial rotation to target rotation.
For example in "Normal" window, if I set the target rotation of x as 180 (shown as -5.008956e-06 in the inspector window), the gameObject moves from 0 to -180, instead of +180. That is the reason I moved to "Debug" window thinking it helps here to set it. But the values here range between 0-1, so does anyone have an idea of how to calculate this?
Moreover, for rotation I am using this one line:
transform.localRotation = Quaternion.Slerp(transform.localRotation, targetRotation, Time.deltaTime * RotationSpeed);
It sounds like you want to be able to adjust it via a Vector3 just how Unity does it in the Transform Inspector. You could do something like
public Vector3 targetRotationV3;
private Quaternion targetRotation;
private void Start()
{
targetRotation = Quaternion.Euler(targetRotationV3);
}
or if you need to be more flexible
private void Update()
{
targetRotation = Quaternion.Euler(targetRotationV3);
...
}
Then for my comment what I mean is that Slerp interpolates a value between the first and the second argument using the factor between 0 and 1.
Since you every frame use a new value as start point, namely the current rotation, this will get slower and slower to the end and depending on your given speed never reach the target rotation.
It makes little sense to use Time.deltaTime here which just divides your speed by about 60 (for 60 FPS). Usually you rather want a constant interpolation factor between 0 and 1. If the frame-rate goes up it might even rotate back since in this case the Time.deltaTime would get smaller!
So you either rather want a constant interpolation factor
[Range(0f,1f)] private float slerpFactor = 0.5f;
private void Update()
{
targetRotation = Quaternion.Euler(targetRotationV3);
transform.localRotation = Quaternion.Slerp(transform.localRotation, targetRotation, slerpFactor);
}
or if you want to rotate with a constant speed instead use Quaternion.RotateTowards
private void Update()
{
targetRotation = Quaternion.Euler(targetRotationV3);
transform.localRotation = Quaternion.RotateTowards(transform.localRotation, targetRotation, Time.deltaTime * RotationSpeed);
}
where your RotationSpeed is now in ° / second
As I said in my comment, don't set Quaternion directly ever, unless you are really confident in your understanding of them, as pointed out in the unity docs (emphasis mine).
They are based on complex numbers and are not easy to understand intuitively. You almost never access or modify individual Quaternion components (x,y,z,w); most often you would just take existing rotations (e.g. from the Transform) and use them to construct new rotations (e.g. to smoothly interpolate between two rotations). The Quaternion functions that you use 99% of the time are: Quaternion.LookRotation, Quaternion.Angle, Quaternion.Euler, Quaternion.Slerp, Quaternion.FromToRotation, and Quaternion.identity. (The other functions are only for exotic uses.)
Rather what you want to do is set the initial and target rotations as Vector3 (Eulerangles) from the inspector and use the build in Quaternion.Euler(); method to let Unity figure out the transformation from Eulerangles to Quaternions.
This would look something like this (Note that I am doing this in an update for the example, and using a float time that I update from the inspector to change the rotation, this is just done for ease of example and not the best way to do implement the t parameter of Quaternion.Slerp):
public Vector3 initialrotation;
public Vector3 targetRotation;
public float time;
void Update()
{
// Let Unity figure out what the appropriate Quaternions are for the given Eulerangles
// Note that this can better be done in Start if initialRotation and targetRotation never change. Just put it here for simplicity
var initialQuaternion = Quaternion.Euler(initialrotation);
var targetQuaternion = Quaternion.Euler(targetRotation);
var slerp = Quaternion.Slerp(initialQuaternion, targetQuaternion, time);
transform.rotation = slerp;
}
I am trying to simulate a door in BulletPhysics using a HingeConstraint. The following code works as intended, in that the cube pivots on its corner around the Y-axis, effectively swinging open like a door, but as soon as I place the object on the ground it begins flying around uncontrollably.
RigidBody body = physics.LocalCreateRigidBody(mass, Matrix4.CreateTranslation(new Vector3(0, 0.5f, 0)), new BoxShape(1, 1, 1));
body.UserObject = "Door";
Vector3 pivotInA = new Vector3(1, 1, 1);
Vector3 axisInA = new Vector3(0, 1, 0);
var hinge = new HingeConstraint(body, pivotInA, axisInA);
const float targetVelocity = 1.0f;
const float maxMotorImpulse = 1.0f;
hinge.EnableAngularMotor(true, targetVelocity, maxMotorImpulse);
physics.World.AddConstraint(hinge);
Disabling collisions between the door and ground would solve the problem but I am struggling to achieve this also. The documentation says you can set a collision type and mask for a body but only the World.AddRigidBody() constructor appears
to take such parameters and as far as I can tell my door is added to the world as a Hinge and the ground is added automagically when calling LocalCreateRigidBody(), shown below.
CollisionShape groundShape = new BoxShape(10, 1, 10);
CollisionObject ground = LocalCreateRigidBody(0, Matrix4.CreateTranslation(0, -1, 0), groundShape);
ground.UserObject = "Ground";
How can I stop the door spinning out when it sits atop the ground?
You can write your own version of LocalCreateRigidBody that sets up the collision mask. LocalCreateRigidBody is a helper function in the BulletSharp demos and not a built-in function in Bullet.
Here is one way to set up the collision filter:
const CollisionFilterGroups groundGroup = (CollisionFilterGroups)0x40000000;
var groundMask = CollisionFilterGroups.AllFilter ^ CollisionFilterGroups.StaticFilter;
World.AddRigidBody(ground, groundGroup, groundMask);
var doorMask = CollisionFilterGroups.AllFilter ^ groundGroup;
World.AddRigidBody(door, CollisionFilterGroups.DefaultFilter, doorMask);
Another way to solve this is to make the door shorter so it's not close enough to the ground to generate collisions. Then render a larger graphics object in place of the smaller physics object. If you are using the BulletSharp demo framework, then you will have to modify the framework to support this.
I have been working on programming a graph in Unity that rotates based on head movement. I have been having multiple issues with the rotation aspect of it.
A sample of the Autowalk class, which I am using to find the angle that the graph needs to rotate based on where the user is facing:
public class AutoWalk : MonoBehaviour {
//VR head
private Transform vrHead;
//angular displacement from normal
public float xAng, yAng, zAng;
//previous values
public float xOrig, yOrig, zOrig;
// Use this for initialization
void Start () {
//Find the VR head
vrHead = Camera.main.transform;
//finding the initial direction
Vector3 orig = vrHead.TransformDirection(Vector3.forward);
xOrig = orig.x;
yOrig = orig.y;
zOrig = orig.z;
}
// Update is called once per frame
void Update () {
//find the forward direction
Vector3 forward = vrHead.TransformDirection(Vector3.forward);
float xForward = forward.x;
float yForward = forward.y;
float zForward = forward.z;
//find the angle between the initial and current direction
xAng = Vector3.Angle(new Vector3(xOrig, 0, 0), new Vector3(xForward, 0, 0));
yAng = Vector3.Angle(new Vector3(0, yOrig, 0), new Vector3(0, yForward, 0));
zAng = Vector3.Angle(new Vector3(0, 0, zOrig), new Vector3(0, 0, zForward));
//set new original angle
xOrig = xAng;
yOrig = yAng;
zOrig = zAng;
}
From there I go to the ReadingPoints class, which contains all of the points on the graphs (spheres) and axes (stretched out cubes):
public class ReadingPoints : MonoBehaviour {
// Update is called once per frame
void Update () {
float xAngl = GameObject.Find("GvrMain").GetComponent<AutoWalk>().xAng;
float yAngl = GameObject.Find("GvrMain").GetComponent<AutoWalk>().yAng;
float zAngl = GameObject.Find("GvrMain").GetComponent<AutoWalk>().zAng;
if ((xAngl != prevXAngl) || (yAngl!=prevYAngl) || (zAngl!=prevZAngl))
{
//rotate depending on the angle from normal
foreach (GameObject o in allObjects)
{
o.transform.Rotate(new Vector3(xAngl, yAngl, zAngl), Space.World);
prevXAngl = xAngl;
prevYAngl = yAngl;
prevZAngl = zAngl;
}
}
allObjects, as the name implies, contains the points and the axes.
Anyway, the first issue that is upon running the program is that the graph appears to be torn apart.
How the graph is supposed to look (this is what it looks like when o.transform.Rotate(...) is commented out)
Here is how it actually looks :( Also, the graph does not rotate when I move, and I have no idea why (I thought I might be using the Rotate function improperly but perhaps I also didn't find the correct angles?). Any ideas of what went wrong are much appreciated, thank you!
First of all I think you should start using Quaternions (https://docs.unity3d.com/ScriptReference/Quaternion.html)
Secondly; while you rotate a object with a Camera attached its line of view will change and eventually the object(Graph) will be out of view. If you want as much of the full graph as possible to remain in view of camera as long as possible. You should give the Quaternion of the graph the opposite rotation of that applied to your Camera or the object it is attached to.
Make sure your all elements of your graph are children of a central gameobject in your graph, and only manipulate that point.
I'm programming a game in C# using the XNA3.1 engine. However I'm having a small issue with my camera, basically my camera tends to "flip" when it rotates more than 180 degrees on its roll (when the camera reaches 180 degrees, it seems to flip back to 0 degrees). The code for obtaining the view matrix is as follows:
Globals.g_GameProcessingInfo.camera.viewMat = Matrix.CreateLookAt(Globals.g_GameProcessingInfo.camera.target.pos, Globals.g_GameProcessingInfo.camera.LookAt, up); //Calculate the view matrix
The Globals.g_GameProcessingInfo.camera.LookAt variable the position 1 unit directly in front of the camera, relative to the rotation of the camera, and the "up" variable is obtained with the following function:
static Vector3 GetUp() //Get the up Vector of the camera
{
Vector3 up = Vector3.Zero;
Quaternion quat = Quaternion.Identity;
Quaternion.CreateFromYawPitchRoll(Globals.g_GameProcessingInfo.camera.target.rot.Y, Globals.g_GameProcessingInfo.camera.target.rot.X, Globals.g_GameProcessingInfo.camera.target.rot.Z, out quat);
up.X = 2 * quat.X * quat.Y - 2 * quat.W * quat.Z; //Set the up x-value based on the orientation of the camera
up.Y = 1 - 2 * quat.X * quat.Z - 2 * quat.Z * quat.Z; //Set the up y-value based on the orientation of the camera
up.Z = 2 * quat.Z * quat.Y + 2 * quat.W * quat.X; //Set the up z-value based on the orientation of the camera
return up; //Return the up Vector3
}
I got same problems in OpenGL with gluLookAt. I fixed that problem with my own camera class:
void Camera::ComputeVectors()
{
Matrix4x4 rotX, rotZ;
Quaternion q_x, q_y, q_z;
Quaternion q_yx, q_yz;
q_x.FromAngleAxis(radians.x, startAxisX);
q_y.FromAngleAxis(radians.y, startAxisY);
q_z.FromAngleAxis(radians.z, startAxisZ);
q_yx = q_y * q_x;
q_yx.ToMatrix(rotZ);
q_yz = q_y * q_z;
q_yz.ToMatrix(rotX);
axisX = startAxisX;
axisZ = startAxisZ;
axisX.Transform(rotX);
axisZ.Transform(rotZ);
axisY = axisX.Cross(axisZ);
position = startPosition;
position -= center;
position.Transform(q_yx);
position += center;
}
It is maybe overcomplicated, but working. axisY is your up vector.
Full code listing is at:
http://github.com/filipkunc/opengl-editor-cocoa/blob/master/PureCpp/MathCore/Camera.cpp
Hope it helps.
This is probably slower but the only way I know to do with would be the with the rotation matrix for 3D. Wikipedia Link
Where
and U = (Camera.position - Camera.lookat).norm
... Now, I believe that would give you the rotation part of the view matrix. However, I'm not 100% on it. I'm still looking into this though.
meh was hoping to see a tan in there somewhere.
can you link to where you got your equation from please?
(am at work and really don;t want to sit down myself and derive it)
how are you setting your camera rotation? are you sure nothing is going on there?
I'm a bit unsure about the math in your GetUp method. Could you elaborate on the math behind it?
In my lookat camera I initialize my up-vector once and then rotate that vector using a quaternion. This removes the possibility of trying to do a cross-product on parallel vectors in order to calculate the up vector.
Some semicode to clarify perhaps:
var up = Vector3.Up;
var target = <some point in space>;
var rotation = <current rotation quaternion>;
var forward = target - position;
forward = Vector3.Transform(forward, rotation);
var updatedPosition = target - forward;
var updatedUp = Vector3.Transform(up, rotation);
var view = Matrix.CreateLookAt(updatedPosition, target, updatedUp);
Since I wasn't satisfied with the answers here already, I had to figure this out myself.
What I discovered is it's actually quite simple. Just do this:
Matrix ypr = Matrix.CreateFromYawPitchRoll(yaw, pitch, roll);
Vector3 up = Vector3.Transform(Vector3.Up, ypr);
"up" is the direction you want.