Quaternion based rotation and pivot position - math

I can't figure out how to perform matrix rotation using Quaternion while taking into account pivot position in OpenGL.What I am currently getting is rotation of the object around some point in the space and not a local pivot which is what I want.
Here is the code [Using Java]
Quaternion rotation method:
public void rotateTo3(float xr, float yr, float zr) {
_rotation.x = xr;
_rotation.y = yr;
_rotation.z = zr;
Quaternion xrotQ = Glm.angleAxis((xr), Vec3.X_AXIS);
Quaternion yrotQ = Glm.angleAxis((yr), Vec3.Y_AXIS);
Quaternion zrotQ = Glm.angleAxis((zr), Vec3.Z_AXIS);
xrotQ = Glm.normalize(xrotQ);
yrotQ = Glm.normalize(yrotQ);
zrotQ = Glm.normalize(zrotQ);
Quaternion acumQuat;
acumQuat = Quaternion.mul(xrotQ, yrotQ);
acumQuat = Quaternion.mul(acumQuat, zrotQ);
Mat4 rotMat = Glm.matCast(acumQuat);
_model = new Mat4(1);
scaleTo(_scaleX, _scaleY, _scaleZ);
_model = Glm.translate(_model, new Vec3(_pivot.x, _pivot.y, 0));
_model =rotMat.mul(_model);//_model.mul(rotMat); //rotMat.mul(_model);
_model = Glm.translate(_model, new Vec3(-_pivot.x, -_pivot.y, 0));
translateTo(_x, _y, _z);
notifyTranformChange();
}
Model matrix scale method:
public void scaleTo(float x, float y, float z) {
_model.set(0, x);
_model.set(5, y);
_model.set(10, z);
_scaleX = x;
_scaleY = y;
_scaleZ = z;
notifyTranformChange();
}
Translate method:
public void translateTo(float x, float y, float z) {
_x = x - _pivot.x;
_y = y - _pivot.y;
_z = z;
_position.x = _x;
_position.y = _y;
_position.z = _z;
_model.set(12, _x);
_model.set(13, _y);
_model.set(14, _z);
notifyTranformChange();
}
But this method in which I don't use Quaternion works fine:
public void rotate(Vec3 axis, float angleDegr) {
_rotation.add(axis.scale(angleDegr));
// change to GLM:
Mat4 backTr = new Mat4(1.0f);
backTr = Glm.translate(backTr, new Vec3(_pivot.x, _pivot.y, 0));
backTr = Glm.rotate(backTr, angleDegr, axis);
backTr = Glm.translate(backTr, new Vec3(-_pivot.x, -_pivot.y, 0));
_model =_model.mul(backTr);///backTr.mul(_model);
notifyTranformChange();
}

It seems to me you take into account the back and forth translation before and after the rotation already. Why that final call of translateTo?
Besides, when you rotate, a pure rotation is always meant around the origin. So if you want a rotation around your pivot point. I'd exptect to translate your pivot point to the origin, then rotate, then translate back to the pivot would be the right thing to do. Therefore, I'd expect your code to look like this:
_model = Glm.translate(_model, new Vec3(-_pivot.x, -_pivot.y, 0));
_model =rotMat.mul(_model);//_model.mul(rotMat); //rotMat.mul(_model);
_model = Glm.translate(_model, new Vec3(_pivot.x, _pivot.y, 0));
and without the call translateTo(_x, _y, _z);. Also, can you confirm that the rotation part already does what it supposed to? You can check this by comparing rotMat with Glm.rotate(new Mat4(1.0f), angleDegr, axis). They should be the same for the same rotation.

A quaternion describes only a rotation. As a result how do you want to rotate something around a pivot point with only a quaternion?
The minimum that you need is a R3 vector and a quaternion. With only one level of transformation you first roatate the object and then move it there.
If you want to create a matrix you first create the ration matrix and then add the translation unaltered.
If you want to just call glTranslate and glRotate (or glMultMatrix) you would first call glTranslate and then glRoatate.
Edit:
If you are not rendering and just want to know where each vertex is:
Vector3 newVertex = quat.transform(oldVertex) + translation;

Related

Draw an ellipse arc between two points in Three.js

I've been trying to draw an ellipse arc between two arbitrary points but my implementation is not working in some situations.
Because a part of this is involves mathematics, I started by asking this question.
Basically, given two points and the center, you can always get an ellipse if you allow rotation, except for cases where the points are collinear.
The solution proposed to that question is to:
Translate the center to the origin, translating both points by the same vector.
Rotate both points by the angle -alpha which is the simetric of the angle of the largest vector with the positive x-semiaxis.
Solve the ellipse equation to find its radiuses (system of two equations with two unknowns).
Define the ellipse
Rotate back the ellipse with the angle alpha and translate back to its center.
However, I'm having trouble implementing this in Three.js.
The documentation for the EllipseCurve lists the expected parameters. I assume the starting angle to always be zero and then set the end angle to either the angle between the two vectors or its simetric. I also want the arc to always be the smallest (i.e., if the angle is bigger than 180º, I'd use the complementary arc). I assume the center of the ellipse to be the middle point between the centers of the shape's bounding boxes.
This is my example code:
https://jsfiddle.net/at5dc7yk/1/
This example tries to create an arc from a vertex in the original shape and the same vertex in the modified shape.
Code regarding the ellipse arc is under the class EllipseArc and you can mess with the transformation applied to the object in line 190.
It works for some cases:
But not all:
Just an idea from scratch, not the ultimate solution.
When you clone and translate object, to build an arc between two respective points you'll need their coordinates in world coordinate system, and a coordinate of the middle point between centroids of objects.
Find the mid point between points in world space (between start and end vectors).
Find its projection on the vector of translation (this is the center of an arc).
Find the angle between vectors that you get by subtraction the result center vector from each of them.
Divide an angle by amount of divisions - you'll get the step value.
Get the end vector as the base and rotate it around an axis (which is the normal of a triangle, built with start, center, end vectors) in a loop, multiplying that step angle value with the number of the current iteration.
Code example:
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 1, 10000);
camera.position.set(0, 0, 150);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
var shapeGeom = new THREE.ShapeBufferGeometry(new THREE.Shape(californiaPts));
shapeGeom.center();
shapeGeom.scale(0.1, 0.1, 0.1);
var shapeMat = new THREE.MeshBasicMaterial({
color: "orange"
});
var shape = new THREE.Mesh(shapeGeom, shapeMat);
shape.updateMatrixWorld();
scene.add(shape);
var shapeClone = shape.clone();
shapeClone.position.set(25, 25, 0);
shapeClone.updateMatrixWorld();
scene.add(shapeClone);
var center = new THREE.Vector3().lerpVectors(shapeClone.position, shape.position, 0.5);
var vecStart = new THREE.Vector3();
var vecEnd = new THREE.Vector3();
var pos = shapeGeom.getAttribute("position");
for (let i = 0; i < pos.count; i++) {
vecStart.fromBufferAttribute(pos, i);
shape.localToWorld(vecStart);
vecEnd.fromBufferAttribute(pos, i);
shapeClone.localToWorld(vecEnd);
makeArc(center, vecStart, vecEnd);
}
function makeArc(center, start, end) {
console.log(center, start, end);
let vM = new THREE.Vector3().addVectors(start, end).multiplyScalar(0.5);
let dir = new THREE.Vector3().subVectors(end, start).normalize();
let c = new THREE.Vector3().subVectors(vM, center);
let d = c.dot(dir);
c.copy(dir).multiplyScalar(d).add(center); // get a center of an arc
let vS = new THREE.Vector3().subVectors(start, c);
let vE = new THREE.Vector3().subVectors(end, c);
let a = vS.angleTo(vE); // andgle between start and end, relatively to the new center
let divisions = 100;
let aStep = a / divisions;
let pts = [];
let vecTemp = new THREE.Vector3();
let tri = new THREE.Triangle(start, c, end);
let axis = new THREE.Vector3();
tri.getNormal(axis); // get the axis to rotate around
for (let i = 0; i <= divisions; i++) {
vecTemp.copy(vE);
vecTemp.applyAxisAngle(axis, aStep * i);
pts.push(vecTemp.clone());
}
let g = new THREE.BufferGeometry().setFromPoints(pts);
let m = new THREE.LineDashedMaterial({
color: 0xff0000,
dashSize: 1,
gapSize: 1
});
let l = new THREE.Line(g, m);
l.computeLineDistances();
l.position.copy(c);
scene.add(l);
}
renderer.setAnimationLoop(() => {
renderer.render(scene, camera);
});
body {
overflow: hidden;
margin: 0;
}
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
<script>
var californiaPts = [
new THREE.Vector2(610, 320),
new THREE.Vector2(450, 300),
new THREE.Vector2(392, 392),
new THREE.Vector2(266, 438),
new THREE.Vector2(190, 570),
new THREE.Vector2(190, 600),
new THREE.Vector2(160, 620),
new THREE.Vector2(160, 650),
new THREE.Vector2(180, 640),
new THREE.Vector2(165, 680),
new THREE.Vector2(150, 670),
new THREE.Vector2(90, 737),
new THREE.Vector2(80, 795),
new THREE.Vector2(50, 835),
new THREE.Vector2(64, 870),
new THREE.Vector2(60, 945),
new THREE.Vector2(300, 945),
new THREE.Vector2(300, 743),
new THREE.Vector2(600, 473),
new THREE.Vector2(626, 425),
new THREE.Vector2(600, 370),
new THREE.Vector2(610, 320)
];
</script>
If you don't translate, and just rotate an object, in this case you don't need to compute a new center for each arc, just omit that step, as all the centers are equal to the centroid of the object.
I hope I explained it in more or less understandable way ^^

Projection of a vector in processing using jama

I want to project A vector onto vector a and vector c, in Processing.
In my sketch vector a is red and c is blue, I wanted c to be perpendicular to b but this is where i'm having alot of trouble. I'm using the JAMA library to try and make this easier. Any help with this is much appreciated as I have been stumped for about a week now.
float X=200; // Origin : Note we have now centred the origin in the
X-direction float Y=350; float ax=150; // Vector a resolved into
components float ay=-50; float bx=0; // Vector b resolved into
components float by=-150; float cx=150; float cy=200;
Matrix a; Matrix b; Matrix c;
void setup() {
size(400,400); // Create a drawing window
strokeWeight(3); // Make pen 3 pixels wide for all lines
double [][] anums = {{ax},
{ay}};
double [][] bnums = {{bx},
{by}};
double [][] cnums = {{-cy},
{cx}};
a = new Matrix(anums);
b = new Matrix(bnums);
c = new Matrix(cnums); }
void draw() {
background(255); // Clear screen
// Evaluate equation (1.5)
// STEP1: Insert code here that computes a_unit (i.e. the unit vector in the
// direction of a
double length = a.norm2();
Matrix a_unit= a.times(1/length);
// STEP2: Insert code here to compute the dot product of b and a_unit
Matrix a_unit_T = a_unit.transpose();
Matrix projection = a_unit_T.times(b);
double lp = projection.get(0,0);
// STEP3 Insert code here to compute the vector p using equation 1.5 above Matrix p = a_unit.times(lp);
float px = (float)p.get(0,0);
float py = (float)p.get(1,0);
float ax = (float)a.get(0,0);
float ay = (float)a.get(1,0);
float bx = (float)b.get(0,0);
float by = (float)b.get(1,0);
float cx = (float)c.get(0,0);
float cy = (float)c.get(1,0);
// Draw the projection of b onto a
stroke(0,0,0); // Use a black pen
ellipse(X+px,Y+py,10,10); // point where b projects onto a
line(X+px,Y+py,X+bx,Y+by); // line from a to point of projection on b
stroke(255,0,0); // Make pen red
arrow(X,Y,X+ax,Y+ay); // Draw vector a starting at (X,Y)
//stroke(0,0,255);
//arrow(X,Y,X-ax,Y+ay);
stroke(0,255,0); // Make pen green
arrow(X,Y,X+bx,Y+by); // Draw vector b starting at (X,Y)
// STEP 4. Insert code here to add a new vector at 90 degrees to the vector a
stroke(0,0,255);
arrow(X,Y,X+cx,Y+cy);
// STEP 5. Insert code here to compute and draw the projection of b onto c
double length1 = c.norm2();
Matrix c_unit= c.times(1/length1);
// STEP2: Insert code here to compute the dot product of b and a_unit
Matrix c_unit_T = c_unit.transpose();
Matrix projection1 = c_unit_T.times(b);
double lp1 = projection.get(0,0);
// STEP3 Insert code here to compute the vector p using equation 1.5 above
Matrix r = c_unit.times(lp1);
float rx = (float)r.get(0,0);
float ry = (float)r.get(1,0);
stroke(0,0,0); // Use a black pen
ellipse(X+rx,Y+ry,10,10); // point where b projects onto a
line(X+rx,Y+ry,X+bx,Y+by); // line from a to point of projection on b
if (mouseButton == RIGHT)
{
a.set(0,0,(double)mouseX-X);
a.set(1,0,(double)mouseY-Y);
}
if (mouseButton == LEFT)
{
b.set(0,0,(double)mouseX-X);
b.set(1,0,(double)mouseY-Y);
} } // Draw an arrow from (x1,y1) to (x2,y2) void arrow(float x1, float y1, float x2, float y2) { line(x1, y1, x2, y2);
pushMatrix(); translate(x2, y2); float a = atan2(x1-x2, y2-y1);
rotate(a); line(0, 0, -8, -8); line(0, 0, 8, -8); popMatrix(); }
Here is the code mate,
float X=200; // Origin : Note we have now centred the origin in the X-direction
float Y=350;
float ax=300; // Vector a resolved into components
float ay=-100;
float bx=0; // Vector b resolved into components
float by=-300;
Matrix a;
Matrix b;
void setup()
{
size(400,400); // Create a drawing window
strokeWeight(3); // Make pen 3 pixels wide for all lines
double [][] anums = {{ax},
{ay}};
double [][] bnums = {{bx},
{by}};
a = new Matrix(anums);
b = new Matrix(bnums);
}
void draw()
{
background(255); // Clear screen
// Evaluate equation (1.5)
// STEP1: Insert code here that computes a_unit (i.e. the unit vector in the
// direction of a
double length = a.norm2();
Matrix a_unit = a.times(1/length);
// STEP2: Insert code here to compute the dot product of b and a_unit
Matrix a_unit_T = a_unit.transpose();
Matrix projection = a_unit_T.times(b);
double lp = projection.get(0,0);
// STEP3: Insert code here to compute the vector p using equation 1.5 above
Matrix p = a_unit.times(lp);
float px = (float)p.get(0,0);
float py = (float)p.get(1,0);
float ax = (float)a.get(0,0);
float ay = (float)a.get(1,0);
float bx = (float)b.get(0,0);
float by = (float)b.get(1,0);
// Draw the projection of b onto a
stroke(0,0,0); // Use a black pen
ellipse(X+px,Y+py,10,10); // point where b projects onto a
line(X+px,Y+py,X+bx,Y+by); // line from a to point of projection on b
stroke(255,0,0); // Make pen red
arrow(X,Y,X+ax,Y+ay); // Draw vector a starting at (X,Y)
stroke(0,255,0); // Make pen green
arrow(X,Y,X+bx,Y+by); // Draw vector b starting at (X,Y)
// STEP 4. Insert code here to add a new vector at 90 degrees to the vector a
double [][] cnums = {{ay},
{-ax}};
Matrix c = new Matrix(cnums);
float cx = (float)c.get(0,0);
float cy = (float)c.get(1,0);
stroke(0,0,255);
arrow(X,Y,X+cx,Y+cy);
// STEP 5. Insert code here to compute and draw the projection of b onto c
double length1 = c.norm2();
Matrix c_unit= c.times(1/length1);
Matrix c_unit_T = c_unit.transpose();
Matrix projection1 = c_unit_T.times(b);
double lp1 = projection1.get(0,0);
Matrix r = c_unit.times(lp1);
float rx = (float)r.get(0,0);
float ry = (float)r.get(1,0);
stroke(0,0,0); // Use a black pen
ellipse(X+rx,Y+ry,10,10); // point where b projects onto a
line(X+rx,Y+ry,X+bx,Y+by); // line from a to point of projection on b
if (mouseButton == RIGHT)
{
a.set(0,0,(double)mouseX-X);
a.set(1,0,(double)mouseY-Y);
}
if (mouseButton == LEFT)
{
b.set(0,0,(double)mouseX-X);
b.set(1,0,(double)mouseY-Y);
}
}
// Draw an arrow from (x1,y1) to (x2,y2)
void arrow(float x1, float y1, float x2, float y2)
{
line(x1, y1, x2, y2);
pushMatrix();
translate(x2, y2);
float a = atan2(x1-x2, y2-y1);
rotate(a);
line(0, 0, -8, -8);
line(0, 0, 8, -8);
popMatrix();
}

XNA - Bounding Box Rotation Nightmare

I'm currently going throught kind of a nightmare right now by trying to find the right formula to obtain a bounding box that correspond to my sprite orientation.
I KNOW ! There is a bunch of examples, solution, explanations on the internet, including here, on this site. But trust me, I've tried them all. I tried to just apply solutions, I tried to understand explanations, but every post gives a different solution and none of them work.
I'm obviously missing something important here...
So, basically, I have a sprite which texture is natively (20 width * 40 height) and located at (200,200) when starting the app. The sprite origin is a classic
_origin = new Vector2((float)_texture.Width / 2, (float)_texture.Height / 2);
So origin would return a (5.5;8) vector 2
By keyboard input, I can rotate this sprite. Default rotation is 0 or Key.Up. Then rotation 90 corresponds to Key.Right, 180 to Key.Down, and so on...
For the moment, there is no move involved, just rotation.
So here is my code to calculate the bounding rectangle:
public partial class Character : ICollide
{
private const int InternalRunSpeedBonus = 80;
private const int InternalSpeed = 80;
private Vector2 _origin;
private Texture2D _texture;
private Texture2D _axisBase;
private Texture2D _axisOrig;
public Character()
{
MoveData = new MoveWrapper { Rotation = 0f, Position = new Vector2(200, 200), Speed = new Vector2(InternalSpeed) };
}
public MoveWrapper MoveData { get; set; }
#region ICollide Members
public Rectangle Bounds
{
get { return MoveData.Bounds; }
}
public Texture2D Texture
{
get { return _texture; }
}
#endregion ICollide Members
public void Draw(SpriteBatch theSpriteBatch)
{
theSpriteBatch.Draw(_texture, MoveData.Position, null, Color.White, MoveData.Rotation, _origin, 1f, SpriteEffects.None, 0);//main sprite
theSpriteBatch.Draw(_axisOrig, MoveData.Position, null, Color.White, 0f, _origin, 1f, SpriteEffects.None, 0);//green
theSpriteBatch.Draw(_axisBase, MoveData.Position, null, Color.White, 0f, Vector2.Zero, 1f, SpriteEffects.None, 0);//red
}
public void Load(ContentManager theContentManager)
{
_texture = theContentManager.Load<Texture2D>("man");
_axisBase = theContentManager.Load<Texture2D>("axis");
_axisOrig = theContentManager.Load<Texture2D>("axisOrig");
_origin = new Vector2((float)_texture.Width / 2, (float)_texture.Height / 2);
}
public void MoveForward(GameTime theGameTime, KeyboardState aCurrentKeyboardState)
{
InternalMove(theGameTime, aCurrentKeyboardState);
}
private void InternalMove(GameTime theGameTime, KeyboardState aCurrentKeyboardState, bool forward = true)
{
//stuff to get the move wrapper data valorized (new position, speed, rotation, etc.)
MoveWrapper pm = MovementsHelper.Move(MoveData.Position, MoveData.Rotation, aCurrentKeyboardState, InternalSpeed,
InternalRunSpeedBonus, theGameTime, forward);
pm.Bounds = GetBounds(pm);
MoveData = pm;
}
public void MoveBackward(GameTime theGameTime, KeyboardState aCurrentKeyboardState)
{
InternalMove(theGameTime, aCurrentKeyboardState, false);
}
private Rectangle GetBounds(MoveWrapper pm)
{
return GetBoundingBox(pm, _texture.Width, _texture.Height);
}
public Rectangle GetBoundingBox(MoveWrapper w, int tWidth, int tHeight)
{
//1) get original bounding vectors
//upper left => same as position
Vector2 p1 = w.Position;
//upper right x = x0+width, y = same as position
Vector2 p2 = new Vector2(w.Position.X + tWidth, w.Position.Y);
//lower right x = x0+width, y = y0+height
Vector2 p3 = new Vector2(w.Position.X + tWidth, w.Position.Y + tHeight);
//lower left x = same as position,y = y0+height
Vector2 p4 = new Vector2(w.Position.X, w.Position.Y + tHeight);
//2) rotate all points given rotation and origin
Vector2 p1r = RotatePoint(p1, w);
Vector2 p2r = RotatePoint(p2, w);
Vector2 p3r = RotatePoint(p3, w);
Vector2 p4r = RotatePoint(p4, w);
//3) get vector2 bouding rectancle location
var minX = Math.Min(p1r.X, Math.Min(p2r.X, Math.Min(p3r.X, p4r.X)));
var maxX = Math.Max(p1r.X, Math.Max(p2r.X, Math.Max(p3r.X, p4r.X)));
//4) get bounding rectangle width and height
var minY = Math.Min(p1r.Y, Math.Min(p2r.Y, Math.Min(p3r.Y, p4r.Y)));
var maxY = Math.Max(p1r.Y, Math.Max(p2r.Y, Math.Max(p3r.Y, p4r.Y)));
var width = maxX - minX;
var height = maxY - minY;
// --> begin hack to get it work for 0,90,180,270 degrees
var origMod = new Vector2((float)tWidth / 2, (float)tHeight / 2);
var degree = (int)MathHelper.ToDegrees(w.Rotation);
if (degree == 0)
{
minX -= origMod.X;
minY -= origMod.Y;
}
else if (degree == 90)
{
minX += origMod.Y;
minY -= origMod.X;
}
else if (degree == 180)
{
minX += origMod.X;
minY += origMod.Y;
}
else if (degree == 270)
{
minX -= origMod.Y;
minY += origMod.X;
}
// end hack <--
return new Rectangle((int)minX, (int)minY, (int)width, (int)height);
}
public Vector2 RotatePoint(Vector2 p, MoveWrapper a)
{
var m = Matrix.CreateRotationZ(a.Rotation);
var refToWorldOrig = p - a.Position;
Vector2 rotatedVector = Vector2.Transform(refToWorldOrig, m);
var backToSpriteOrig = rotatedVector + a.Position;
return backToSpriteOrig;
//does not work
//var Origin = new Vector3(_origin, 0);
//var Position = new Vector3(p, 0);
//var m = Matrix.CreateTranslation(-Origin)
// * Matrix.CreateRotationZ(a.Rotation)
// * Matrix.CreateTranslation(Position);
//return Vector2.Transform(p, m);
}
}
The rotation paramter is MathHelper degree to radians result.
I have a function to draw a rectangle corresponding to the bounding box and I expect that bounding box to overlap exactly with my sprite, at least for 0,90,180 and 270 degrees angle rotations.
Instead I have strange coordinates after rotation calculation:
- when rotation to 90°, bounding box X is negative (so the box is not visible)
- when rotation to 180°, bounding box X and Y are negative (so the box is not visible)
- when rotation to 270°, bounding box Y is negative (so the box is not visible)
Can someone explain to me what I'm doing wrong, and do it like is was explaining to 3 year old child, because regarding Maths, this is what I am !!!
:)
EDIT : I have found a hack to make it work for 0, 90, 180, 270 degrees but now i'm stuck for intermediate positions (45,135,215, 325 degrees) which make me thinks that THERE MUST BE a way to compute all that stuff in one single formula that would work for any angle...
Finally found the way to make it work without the hack !!!!!!!!!!!!!!!!
public Vector2 RotatePoint(Vector2 p, MoveWrapper a)
{
var wm = Matrix.CreateTranslation(-a.Position.X - _origin.X, -a.Position.Y - _origin.Y, 0)//set the reference point to world reference taking origin into account
* Matrix.CreateRotationZ(a.Rotation) //rotate
* Matrix.CreateTranslation(a.Position.X, a.Position.Y, 0); //translate back
var rp = Vector2.Transform(p, wm);
return rp;
}
Bonus effect, this is even more precise (as my drawn guides seems to show) than my previous "hacky" method
I juste realized that this is pretty close as what Blau proposed except that my first translation set the reference back to world 0,0,0 minus the sprite origin. I Guess id did not understand the hint at that time...
You can rotate positions using the matrix struct.
Vector2 p1 = MoveData.Position;
var m = Matrix.CreateRotationZ(angleInRadians);
p1 = Vector2.Transform(p1, m);
if you want to rotate about an origin it should be:
var Origin = new Vector3(Origin2D, 0);
var Position = new Vector3(Position2D, 0);
var m = Matrix.CreateTranslation(-Origin)
* Matrix.CreateRotationZ(angleInRadians)
* Matrix.CreateTranslation(Position);

Entity look at for cameras and objects

I'm currently extending my 3D-engine for a better entity system which includes cameras. This allows me to put cameras into parent entities which may also be in another entity ( and so on... ).
--Entity
----Entity
------Camera
Now i want to set the cameras look direction, i'm doing this with the following method which is also used to set the look at of a entity:
public void LookAt(Vector3 target, Vector3 up)
{
Matrix4x4 oldValue = _Matrix;
_Matrix = Matrix4x4.LookAt(_Position, target, up) * Matrix4x4.Scale(_Scale);
Vector3 p, s;
Quaternion r;
Quaternion oldRotation = _Rotation;
_Matrix.Decompose(out p, out s, out r);
_Rotation = r;
// Update dependency properties
ForceUpdate(RotationDeclaration, _Rotation, oldRotation);
ForceUpdate(MatrixDeclaration, _Matrix, oldValue);
}
But the code is only working for cameras and not for other entities, when using this method for other entities the object is rotating at it's position ( The entity is at a root node, so it has no parent ). The matrix's look at method looks like this:
public static Matrix4x4 LookAt(Vector3 position, Vector3 target, Vector3 up)
{
// Calculate and normalize forward vector
Vector3 forward = position - target;
forward.Normalize();
// Calculate and normalie side vector ( side = forward x up )
Vector3 side = Vector3.Cross(up, forward);
side.Normalize();
// Recompute up as: up = side x forward
up = Vector3.Cross(forward, side);
up.Normalize();
//------------------
Matrix4x4 result = new Matrix4x4(false)
{
M11 = side.X,
M21 = side.Y,
M31 = side.Z,
M41 = 0,
M12 = up.X,
M22 = up.Y,
M32 = up.Z,
M42 = 0,
M13 = forward.X,
M23 = forward.Y,
M33 = forward.Z,
M43 = 0,
M14 = 0,
M24 = 0,
M34 = 0,
M44 = 1
};
result.Multiply(Matrix4x4.Translation(-position.X, -position.Y, -position.Z));
return result;
}
The decompose method also returns the wrong value for the position variable p. So why is the camera working and the entity not?
I had a similar problem a while ago.The problem is that camera transformations are different from others as those are negated.What I did was first to transform camera eye, center and up into world space (transforming those vectors by its parent model matrix )and then calculating the lookAt() .That is how it worked for me.

Bounding Spheres move farther than sphere object

I have a program that I'm making with others and I ran into a problem. I'm working on adding in polygon models into our scene in an XNA window. I have that part complete. I also have bounding spheres(I know I tagged as bounding-box but there is no bounding sphere tag) drawing around each polygon. My problem is when I move the polygons around the 3D space the bounding spheres move twice as much as the polygons. I imagine its something within my polygon matrices that I use to create the bounding sphere that makes it move twice as much but that is only speculation.
So just to clarify I'll give you an example of my problem. If I hold down D to move a polygon along the X axis. (model.position.X--;) The polygon moves as expected to but the bounding sphere around the polygon moves twice as much. Thanks for the help guys!
Here is how I draw the models and the bounding spheres:
public void Draw(Matrix view, Matrix projection, bool drawBoundingSphere)
{
Matrix translateMatrix = Matrix.CreateTranslation(position);
Matrix worldMatrix = translateMatrix * Matrix.CreateScale(scaleRatio);
foreach (ModelMesh mesh in model.Meshes)
{
foreach (BasicEffect effect in mesh.Effects)
{
effect.World = worldMatrix * modelAbsoluteBoneTransforms[mesh.ParentBone.Index];
effect.View = view;
effect.Projection = projection;
effect.EnableDefaultLighting();
effect.PreferPerPixelLighting = true;
}
mesh.Draw();
if (drawBoundingSphere)
{
// the mesh's BoundingSphere is stored relative to the mesh itself.
// (Mesh space). We want to get this BoundingSphere in terms of world
// coordinates. To do this, we calculate a matrix that will transform
// from coordinates from mesh space into world space....
Matrix world = modelAbsoluteBoneTransforms[mesh.ParentBone.Index] * worldMatrix;
// ... and then transform the BoundingSphere using that matrix.
BoundingSphere sphere = BoundingSphereRenderer.TransformBoundingSphere(mesh.BoundingSphere, world);
// now draw the sphere with our renderer
BoundingSphereRenderer.Draw(sphere, view, projection);
}
}
And here is the BoundingSphereRenderer Code:
private static VertexBuffer vertexBuffer;
private static BasicEffect effect;
private static int lineCount;
public static void Initialize(GraphicsDevice graphicsDevice, int sphereResolution)
{
// create our effect
effect = new BasicEffect(graphicsDevice);
effect.LightingEnabled = false;
effect.VertexColorEnabled = true;
// calculate the number of lines to draw for all circles
lineCount = (sphereResolution + 1) * 3;
// we need two vertices per line, so we can allocate our vertices
VertexPositionColor[] vertices = new VertexPositionColor[lineCount * 2];
// compute our step around each circle
float step = MathHelper.TwoPi / sphereResolution;
// used to track the index into our vertex array
int index = 0;
//create the loop on the XY plane first
for (float angle = 0f; angle < MathHelper.TwoPi; angle += step)
{
vertices[index++] = new VertexPositionColor(new Vector3((float)Math.Cos(angle), (float)Math.Sin(angle), 0f), Color.Blue);
vertices[index++] = new VertexPositionColor(new Vector3((float)Math.Cos(angle + step), (float)Math.Sin(angle + step), 0f), Color.Blue);
}
//next on the XZ plane
for (float angle = 0f; angle < MathHelper.TwoPi; angle += step)
{
vertices[index++] = new VertexPositionColor(new Vector3((float)Math.Cos(angle), 0f, (float)Math.Sin(angle)), Color.Red);
vertices[index++] = new VertexPositionColor(new Vector3((float)Math.Cos(angle + step), 0f, (float)Math.Sin(angle + step)), Color.Red);
}
//finally on the YZ plane
for (float angle = 0f; angle < MathHelper.TwoPi; angle += step)
{
vertices[index++] = new VertexPositionColor(new Vector3(0f, (float)Math.Cos(angle), (float)Math.Sin(angle)), Color.Green);
vertices[index++] = new VertexPositionColor(new Vector3(0f, (float)Math.Cos(angle + step), (float)Math.Sin(angle + step)), Color.Green);
}
// now we create the vertex buffer and put the vertices in it
vertexBuffer = new VertexBuffer(graphicsDevice, typeof(VertexPositionColor), vertices.Length, BufferUsage.WriteOnly);
vertexBuffer.SetData(vertices);
}
public static void Draw(this BoundingSphere sphere, Matrix view, Matrix projection)
{
if (effect == null)
throw new InvalidOperationException("You must call Initialize before you can render any spheres.");
// set the vertex buffer
effect.GraphicsDevice.SetVertexBuffer(vertexBuffer);
// update our effect matrices
effect.World = Matrix.CreateScale(sphere.Radius) * Matrix.CreateTranslation(sphere.Center);
effect.View = view;
effect.Projection = projection;
// draw the primitives with our effect
effect.CurrentTechnique.Passes[0].Apply();
effect.GraphicsDevice.DrawPrimitives(PrimitiveType.LineList, 0, lineCount);
}
public static BoundingSphere TransformBoundingSphere(BoundingSphere sphere, Matrix transform)
{
BoundingSphere transformedSphere;
// the transform can contain different scales on the x, y, and z components.
// this has the effect of stretching and squishing our bounding sphere along
// different axes. Obviously, this is no good: a bounding sphere has to be a
// SPHERE. so, the transformed sphere's radius must be the maximum of the
// scaled x, y, and z radii.
// to calculate how the transform matrix will affect the x, y, and z
// components of the sphere, we'll create a vector3 with x y and z equal
// to the sphere's radius...
Vector3 scale3 = new Vector3(sphere.Radius, sphere.Radius, sphere.Radius);
// then transform that vector using the transform matrix. we use
// TransformNormal because we don't want to take translation into account.
scale3 = Vector3.TransformNormal(scale3, transform);
// scale3 contains the x, y, and z radii of a squished and stretched sphere.
// we'll set the finished sphere's radius to the maximum of the x y and z
// radii, creating a sphere that is large enough to contain the original
// squished sphere.
transformedSphere.Radius = Math.Max(scale3.X, Math.Max(scale3.Y, scale3.Z));
// transforming the center of the sphere is much easier. we can just use
// Vector3.Transform to transform the center vector. notice that we're using
// Transform instead of TransformNormal because in this case we DO want to
// take translation into account.
transformedSphere.Center = Vector3.Transform(sphere.Center, transform);
return transformedSphere;
}

Resources