I have successfully implemented the floor clip plane to measure the distance of left foot to the floor, which is fairly accurate. The problem I have is that as I move away from the camera (i.e. left foot Z axis is increased), the foot distance to the floor changes (increases).
Note: The floor itself is not tilted nor the Kinect stand.
I tested it with Kinect 1 and had the same result. The subject's head height (Y axis) also changes value as I move away or get closer to the camera. It does not matter of the camera is tilted or line of sight. the D value in the FloorClipPlane equation shows a constant number during the test.
A = bodyFrame.FloorClipPlane.X;
B = bodyFrame.FloorClipPlane.Y;
C = bodyFrame.FloorClipPlane.Z;
D = bodyFrame.FloorClipPlane.W;
distanceLeftFoot = A * leftFootPosX + B * leftFootPosY + C * leftFootPosZ + D;
Just to let you know, I have coordinate mapping between depth and colour. Not sure if that has anything to do with the issue.
The FloorClipPlane is expressed in hessian normal form - as explained in the docs. Specifically, your A, B, and C values compromise the unit vector from camera origin (center of the Kinect) to floor plane such that it produces a perpendicular intersection with the floor plane. D is the magnitude of that vector (distance from camera origin to floor plane).
Even if you think the floor is flat and the Kinect is parallel to the ground, you have a perspective warping problem which means the body location (measured in depth space) is going to change as you come closer and further.
To fix this you need to provide as input both your 3D coordinate values and the floor plane, which will then give you back what you want, a measured distance from floor plane to joint:
// j is your joint - left foot or any other joint
float x = j.Position.X;
float y = j.Position.Y;
float z = j.Position.Z;
float distance = (Math.Abs((x * floorPlane.X) + (y * floorPlane.Y) + (z * floorPlane.Z) + floorPlane.W))/((float)Math.Sqrt((Math.Pow(floorPlane.X,2)) + (Math.Pow(floorPlane.Y, 2)) + (Math.Pow(floorPlane.Z, 2))));
I hope this helps you. Can't elaborate further what influence your mapping from depth to color might be doing here without seeing what you are specifically doing
Related
May I ask you for piece of advice writing my raytracer in c#. Here's the rpoblem:
I've got a problem detecting hits of the rays and geometry in my raytracer. I've implemented several functions based on this articles: https://www.scratchapixel.com/lessons/3d-basic-rendering/ray-tracing-rendering-a-triangle/ray-triangle-intersection-geometric-solution
Here's the code of calculating hitpoint:
public Vector3 GetHitPoint(Vector3 origin, Vector3 ray)
{
float D = Vector3.Dot(this.GetNormal(), vertices[0]);
float up = Vector3.Dot(this.GetNormal(), origin);
up = -1 * (up + D); //50
float down =Vector3.Dot(this.GetNormal(), ray); //0.999975
float t = up / -1* down; //50,00125003125078
Console.WriteLine(origin + Vector3.Multiply(t, ray));
return origin + Vector3.Multiply(t, ray);
}
Not very elegant, but shall work. I've got the problem with precision. I've prepared test triangle that is located perpendicular to camera (center -> 0,0,50). The code calculates the point of intersection between triangle and ray.
Origin stands for camera position, ray is the normalized vector that comes from camera to geometry, vertices[0] is the position of vertex and GetNormal() function gives correct normal vector of triangle. The problem in this case is the precision of calculation. After doing all these calculation, my hitpoint has the z coordinate of 49.99975 instead of 50.0.
This is a problem, because I use another algorithm (based on baricentric coordinates) in order to check if hitpoint is inside the triangle.
public bool CheckHitPoint(Vector3 P)
{
Vector3 v0 = vertices[1] - vertices[0];
Vector3 v1 = vertices[2] - vertices[0];
Vector3 v2 = P - vertices[0];
float d00 = Vector3.Dot(v0, v0);
float d01 = Vector3.Dot(v0, v1);
float d11 = Vector3.Dot(v1, v1);
float d20 = Vector3.Dot(v2, v0);
float d21 = Vector3.Dot(v2, v1);
float denom = d00 * d11 - d01 * d01;
float v = (d11 * d20 - d01 * d21);
float w = (d00 * d21 - d01 * d20);
float u = 1.0f - v - w;
if (u < 0 || v < 0 || w < 0)
{
return false;
}
else if (u > 1 || v > 1 || w > 1)
{
return false;
}
else return true;
}
The conditions in algorithm and in the article is the same, but because of inaccurate result of previous function, u v w coefficients are completely wrong (since hitpoint is actually in front of the triangle).
Can I ask you to help me fixing the precision issue in the first algorithm, or introduce some kind of bias into the second algorithm, so I can get the precise hitpoint and successfully detect it inside triangle?
EDIT: Sorry, I thought that problem is preety much clear. Let me explain it deeper. Let's see the triangle:
Vector3[] vertices =
{
new Vector3(-5,-5,50),
new Vector3(5,-5,50),
new Vector3(0,5,50)
};
Vector3[] normals =
{
new Vector3(0,0,-1),
new Vector3(0,0,-1),
new Vector3(0,0,-1)
};
It is clear that Normal Vector for this triangle is n(0,0,-1) and in combination with any point on it's surface, it may describe mathematically the surface.
D is the distance between between (0,0,0) and point on surface, that the triangle lies on. Since the surface may be described as a pair of parameters (normal vector and any point on surface), dot product of these parameter describes D.
Next four lines describes the equation:
t = N(A,B,C)⋅O + D/−N(A,B,C)⋅R
where
N(A,B,C) - normal vector of triangle
O - camera Position
D - Distance from (0,0,0) to surface
R - Normalized Ray Vector
Equation calculates the distance from camera position to point of intersection.
Following these equations, with triangle parameters I attached and camera position (0,0,0) poinitng at (0,0,50) the return value shall be the point with coordinates (x,y,50), no matter what is the pixel I create the ray for.
The problem is, vector methods in c# generally use floats for computations, and this is why the z coordinate is close, but not precisely 50.
Mathematically this is 100% correct, but the precision is poor.
This makes a problem, when I try to check, if the point lies inside triangle using transformation to baricentric coordinates.
The second method is ok mathematically too. Provided that Hitpoint is on the surface, if all coordinates are between 0 and 1 that means that point lies on the triangle. Details here: https://www.scratchapixel.com/lessons/3d-basic-rendering/ray-tracing-rendering-a-triangle/barycentric-coordinates
If only I could precisely count the coordinates from previous method, that would work. The problem is, because of lack of precision, the hitpoint is slightly on top or below the surface, and baricentric coordinates have crazy values.
The question is, how can I make the first method to be more precise, that means reproduce the t - distance between camera and hitpoint to be enough precise to be 50. What solution would be the best, rounding, creating custom methods for vectors replacing the built-in float-based methods or maybe some algorithm modification?
Would be grateful, if someone with experience with raytracers would gave me the piece of advice.
I found out an equation of a plane,from three vertices.
Now,if I have a bounding box(i.e. a large cube),How can I determine the grid positions(small cubes),where the plane cuts the large cube.
I am currently following this approach:
For each small cube center, say(Xp, Yp, Zp), calculate perpendicular distance to the plane i.e., (aXp + bYp + c*Zp + d)/ (SquareRoot Of (a^2 + b^2 + c^2)). This should be less than or equal to (length of smallCube * SquareRoot(3))/2.
If this criteria,gets satisfied,then I assume my plane to cut the large cube at this small cube position.
a,b,c,d are coefficients of the plane,of the form ax+by+cz+d = 0.
I would be really glad,if someone can let me know,if I am doing something wrong (or) also,any other simple approach.
Seems you want to get a list of small cubes (grid voxels) intersected by given plane.
The simplest approach:
Find intersection of the plane with any cube edge. For example, intersection with vertical edge of AAB (X0,Z0 are constant) might be calculated by solving this equation for unknown Y:
aX0 + bY + c*Z0 + d = 0
and checking that Y is in cube range. Get small cube coordinates (0, ky=Floor(Y/VoxelSize), 0) and then check neighbor voxels in order (account for plane coefficients to check only real candidates).
candidates:
0,ky,0
1,ky,0
0,ky-1,0
0,ky+1,0
0,ky,1
There are more advanced methods to generate voxel sequence for ray case (both 2d and 3d) like Amanatides/Woo algorithm. Perhaps something similar exists also for plane voxelization
Here is AABB-plane intersection test code from this page (contains some explanations)
// Test if AABB b intersects plane p
int TestAABBPlane(AABB b, Plane p) {
// Convert AABB to center-extents representation
Point c = (b.max + b.min) * 0.5f; // Compute AABB center
Point e = b.max - c; // Compute positive extents
// Compute the projection interval radius of b onto L(t) = b.c + t * p.n
float r = e[0]*Abs(p.n[0]) + e[1]*Abs(p.n[1]) + e[2]*Abs(p.n[2]);
// Compute distance of box center from plane
float s = Dot(p.n, c) - p.d;
// Intersection occurs when distance s falls within [-r,+r] interval
return Abs(s) <= r;
}
Note that e and r remain the same for all cubes, so calculate them once and use later.
I stumbled on a working concept for a fast rotation & orientation system today, based on a two-term quaternion that represents either a rotation about the X axis (1,0,0) in the form w + ix, a rotation about the Y axis (0,1,0) in the form w + jy, or a rotation about the Z axis (0,0,1) in the form w + kz.
They're similar to complex numbers, but a) are half-angled and double-sided like all quaternions (they're simply quaternions with two of three imaginary terms zeroed out), and b) represent rotations about one of three 3D axes specifically.
My problem and question is...I can't find any representation of such a system online and have no idea what to search for. What are these complex numbers called? Who else has done something like this before? Where can I find more information on the path I'm headed down? It seems too good to be true and I want to find the other shoe before it drops on me.
Practical example I worked out (an orientation quaternion from Tait-Bryan angles):
ZQuat Y, YQuat P, XQuat R; // yaw, pitch, roll
float w = Y.W * P.W;
float x = -Y.Z * P.Y;
float y = Y.W * P.Y;
float z = Y.Z * P.W;
Quaternion O; // orientation
O.W = x * R.W + w * R.X;
O.X = y * R.W + z * R.X;
O.Y = z * R.W - y * R.X;
O.Z = w * R.W - x * R.X;
Quaternions in 2D would degenerate to just being a single component being no diferrent than an rotation angle. That's propably why you do not find anything. With quaternions you do f.e. not have the problem of gimbal lock, appearing when two rotation axes align because of rotation order. In normal 2D space you do not have more than a single rotation axis, so it has neither order (how do you sort a single element) and there are no axes to align. The lack of rotation axes in 2D is because you get a rotation axis when being perpendicular to two other axes.
This gives 3 axes for 3D:
X&Y=>Z
X&Z=>Y
Y&Z=>X
But only one for 2D:
X&Y=>Z
So basically, I am doing my first xna game and it's an arkanoid game. My ball right now is a square that rotate.
Unfortunately, it's impossible to correctly detect the collision of a rotated rectangle in xna.
I found thing about scalars but I am only in computer science in college so I don't know about these big maths...
Can anyone direct me in the right way to detect these kind of collision ? or at least to be able to obtain a new rectangle in the right way so that I can detect the collision on this one?
EDIT
I just thought about making my rotating square in a still square and test the collision with the outer square would that be viable ?
If you want to detect a collision of the square ball with the outer rectangle, you need to know the coordinates of the four corners of the ball. Then simply compare these points with the outer rectangle.
If s is the length of the sides of the rectangle. The corners can be calculated like this:
double h = 0.707106781 * s; // Half diagonal
double angle = rotation_angle + 0.25 * Math.PI; // 0.25 * Math.PI = 45 degrees
// inclination of the diagonal.
double x = h * Math.Cos(angle);
double y = h * Math.Sin(angle);
// The four points are
p1x = +x + squareCenterX;
p1y = +y + squareCenterY;
p2x = -y + squareCenterX;
p2y = +x + squareCenterY;
p3x = -x + squareCenterX;
p3y = -y + squareCenterY;
p4x = +y + squareCenterX;
p4y = -x + squareCenterY;
Do you really want your ball to be a square?
Or a simple circle could do?
You could use a collision circle instead, the logic behind the collision is much more simple than rotated squares... (If you really want a square and a pixel-perfect collision, disregard this answer and see Terrance's comment)
if(circle.Center.X - circle.Radius < ScreenBounds.XMin ||
circle.Center.X + circle.Radius > ScreenBounds.XMax ||
circle.Center.Y - circle.Radius < ScreenBounds.YMin ||
circle.Center.Y + circle.Radius > ScreenBounds.YMax)
{
//Ball is partly or entirely outside of the screen
}
This is not really a direct answer to your question, but more of an alternative
Edit: This code assumes that the position of your ball is relative to its center.
Also, you can approximate your rotated square's collision with a collision circle (or a non-rotated square as a matter of fact). The collision won't be pixel perfect, but I think that'll be hardly noticeable. It will also be easier to implement (considering this is your first game).
I'm making an XNA game and have run into a small problem figuring out a bit of vector math.
I have a class representing a 2D object with X and Y integer coordinates and a Rotation float. What I need is to have a Vector2 property for Position that gets and sets X and Y as a Vector2 that has been transformed using the Rotation float. This way I can just do something like;
Position += new Vector2((thumbstick.X * scrollSpeed), -(thumbstick.Y * scrollSpeed));
and the object will move in it's own upward direction, rather than the View's upward direction.
So far this is what I have...I think the set is right, but for += changes it needs a get as well and the answer just isn't coming to me right now... >.>
public Vector2 Position
{
get
{
// What goes here? :S
}
set
{
X = value.X * (int)Math.Cos(this.Rotation);
Y = value.Y * (int)Math.Cos(this.Rotation);
}
}
No, both are incorrect.
A 2D vector transforms like this:
x' = x*cos(angle) - y*sin(angle)
y' = x*sin(angle) + y*cos(angle)
where the angle is measured in radians, zero angle is along the positive x-axis, and increases in the counterclockwise direction as you rotate around the z-axis out of plane. The center of rotation is at the end of the vector being transformed, so imagine the vector with origin at (0,0), end at (x,y) rotation through an angle until it becomes a vector with origin at (0,0) and end at (x', y').
You can also use the Matrix helper methods to create a Z rotation matrix then multiply your vector by this to rotate it. Something like this:
Vector v1;
Matrix rot = Matrix.CreateRotationZ(angle);
Vector v2 = v1 * rot;
I think this is a bad idea. Keep all of your objects' X and Y co-ordinates in the same planes instead of each having their own axes. By all means have a Position and Heading properties and consider having a Move method which takes your input vector and does the maths to update position and heading.