Local Position of Bone wrt Model - c#

I have a requirement to get either position matrix or position vector of a bone (say wheel) with respect to my model (car).
What I have tried -
Vector3.Transform(mesh.BoundingSphere.Center , transforms[mesh.ParentBone.Index]*Matrix.CreateScale(o.Scaling )))
Above doesn't give accurate result.

What you want is to calculate the absolute transforms for each bone. The CopyAbsoluteBoneTransformsTo method can do it for you.
It is equivalent to the following code:
/// <summary>Calculates the absolute bone transformation matrices in model space</summary>
private void calculateAbsoluteBoneTransforms() {
// Obtain the local transform for the bind pose of all bones
this.model.CopyBoneTransformsTo(this.absoluteBoneTransforms);
// Convert the relative bone transforms into absolute transforms
ModelBoneCollection bones = this.model.Bones;
for (int index = 0; index < bones.Count; ++index) {
// Take over the bone transform and apply its user-specified transformation
this.absoluteBoneTransforms[index] =
this.boneTransforms[index] * bones[index].Transform;
// Calculate the absolute transform of the bone in model space.
// Content processors sort bones so that parent bones always appear
// before their children, thus this works like a matrix stack,
// resolving the full bone hierarchy in minimal steps.
ModelBone bone = bones[index];
if (bone.Parent != null) {
int parentIndex = bone.Parent.Index;
this.absoluteBoneTransforms[index] *= this.absoluteBoneTransforms[parentIndex];
}
}
}
Taken from here.

Related

Skeletal skinning algorithm bunches up everything at the model's feet

I'm trying to implement skinning using skeletal animations stored in a Collada file, and while I managed to load it and render the model without skinning correctly, I can't figure out why when I apply my skinning algorithm all the parts get bunched up at the model's feet, or extremely deformed. The entire project is stored on GitHub for reference (the skinning branch).
I believe the vertex shader is correct since if I pass identity transforms to the bones I get my default pose model, it's calculating the bone transforms based on the skeletal animation in the .dae file that's somehow broken. This is what my problem looks like, versus how the model looks like in the default pose:
I believe my problem is somewhere while applying the recursive bone transforms:
public void Update(double deltaSec)
{
if (CurrentAnimationName is null) return;
var anim = animations[CurrentAnimationName];
currentAnimationSec = (currentAnimationSec + deltaSec) % anim.Duration.TotalSeconds;
void calculateBoneTransforms(BoneNode boneNode, Matrix4x4 parentTransform)
{
var bone = anim.Bones.FirstOrDefault(b => b.Id == boneNode.Id);
var nodeTransform = bone?[TimeSpan.FromSeconds(currentAnimationSec)] ?? boneNode.Transform;
var globalTransform = parentTransform * nodeTransform;
if (boneNode.Id >= 0)
for (int meshIdx = 0; meshIdx < perMeshData.Length; ++meshIdx)
perMeshData[meshIdx].FinalBoneMatrices[boneNode.Id] = globalTransform * perMeshData[meshIdx].boneOffsetMatrices[boneNode.Id];
foreach (var child in boneNode.Children)
calculateBoneTransforms(child, globalTransform);
}
calculateBoneTransforms(rootBoneNode, Matrix4x4.Identity);
}
Or when building the recursive structure of bone data with their transforms:
BoneNode visitTransforms(Node node, Matrix4x4 mat)
{
var boneNode = new BoneNode
{
Children = new BoneNode[node.ChildCount],
Id = boneIds.TryGetValue(node.Name, out var id) ? id : -1,
Transform = Matrix4x4.Transpose(node.Transform.ToNumerics()),
};
mat = node.Transform.ToNumerics() * mat;
foreach (var meshIndex in node.MeshIndices)
transformsDictionary[scene.Meshes[meshIndex]] = mat;
int childIdx = 0;
foreach (var child in node.Children)
boneNode.Children[childIdx++] = visitTransforms(child, mat);
return boneNode;
}
rootBoneNode = visitTransforms(scene.RootNode, Matrix4x4.Identity);
I believe the bone to vertex weights are gathered and uploaded to the shader correctly, and that the final bone array uniform is uploaded correctly (but maybe not calculated correctly). I'm also not sure of the order of matrix multiplications and whether or not to transpose anything when uploading to the shader, though I've tried it both ways every attempt.
If anyone runs into a similar issue, my problem was that my keyframe bone transforms were being transposed compared to how the rest of the chain of transforms were calculated, so when I multiplied them everything went crazy. So, keep track of what matrices are left-handed and which are right-handed!

Move each UV vertex by offset/vector

I want to create second UV set, and then move each UV vertex in an object by vector u=0, v=1.0/number of vertices. The new UV vertex coordinates created for 4 vertices plane should go like this: for vertex 0 (u=0,v=0), for vertex 1 (u=0,v=0.25), for vertex 2 (u=0,v=0.5), for vertex 3 (u=0,v=0.75), etc.
I have a source code in C# :
Vector2[] UV2 = new Vector2[m.vertexCount];
float HalfTexelSize = (1f/ (float)m.vertexCount)/2f;
for (int i = 0; i < m.vertexCount; i++) {
UV2[i] = new Vector2(0f, (float)i / (float)m.vertexCount) + new Vector2(0f, HalfTexelSize);
}
m.uv2 = UV2;
meshFilter.mesh = m;
As far as my research goes there is no vectors in Python, and now I'm stuck with the solution. So far I came up this:
import maya.cmds as cmds
cmds.polyUVSet(create=True, uvSet='map2')
vertexCount = cmds.polyEvaluate(v=True)
vertexCount_float = float(vertexCount)
HalfTextureSize = (1.0/vertexCount/2.0)
x = 1.0/vertexCount
sel = cmds.ls(sl=1, fl=1)
for i in sel:
i=0, i<sel
cmds.polyEditUV(uValue=0.0, vValue=x)
But the output I get is the second UV set with every vertex in (0,0) UV coordinates. Can anyone help me? Any MEL/Python solution would be appreciated.
There's no vectors in default maya pyhon.
If you want a vanilla python-only solution this project is a single-file vector library.
You can also get 3-vectors from maya directly using the API:
from maya.api.OpenMaya import MVector
v1 = MVector(1,2,3)
v2 = MVector(3,4,5)
print v1 + v2
These are 3d vectors but you can just ignore the 3d component
For actually creating and editing the UV set, there are a couple of complexities to consider
Just creating a new UV set gives you an empty set; the set exists but it won't contain any UVs. The relationship between verts and UVs is not always 1:1, you can have more than one UVs for a physical vert and you can have un-mapped vertices. To create a 1-uv-per-vertex mapping it's easiest to just apply a simple planar or sphere map.
You'll need to set the 'current uv set' so maya knows which set you want to work on. Unfortunately when you ask maya for UV set names, it gives you unicode, but when you set them it expects strings (at least in 2016 - I think this is a bug)
You don't really need a vector to set this if your current code is an indication.
The final solution will look something like this:
import maya.cmds as cmds
# work on only one selected object at a time
selected_object = cmds.ls(sl=1, fl=1)[0]
vertexCount = cmds.polyEvaluate(selected_object, v=True)
# add a projection so you have 1-1 vert:uv mapping
cmds.polyPlanarProjection(selected_object, cm=True)
# get the name of the current uv set
latest_uvs = cmds.polyUVSet(selected_object, q=True, auv=True)
# it's a unioode by default, has to be a string
new_uv = str(latest_uvs[-1])
# set the current uv set to the newly created one
cmds.polyUVSet(selected_object, e=True, cuv = True, uvs=new_uv)
vert_interval = 1.0 / vertexCount
for vert in range (vertexCount):
uv_vert = "{}.map[{}]".format (selected_object, vert)
cmds.polyEditUV( uv_vert, u= 0, v = vert * vert_interval, relative=False, uvs=new_uv)

Collision detection in XNA 3.1

I'm currently making a 3D car game using XNA 3.1. It is a taxi game. So my main vehicle encounters traffic vehicles during the game. I'm having problems with coding the collision detection among traffic vehicles and the main vehicle. I used the bounding box method instead of bounding sphere method because bounding spheres don't cover the vehicles properly.
Below is the code i used to achieve collision. Problem with it is when the vehicle turns left or right bounding box doesn't change according to that.
I wrote this code in the update method.
carWorld = Matrix.CreateScale(1f) * Matrix.CreateTranslation(vehicalClassObs[0].Position);
trafficWorld = Matrix.CreateScale(1f) * Matrix.CreateTranslation(carObject.Position);
BoundingBox b=CalculateBoundingBox(carO);
BoundingBox c=CalculateBoundingBox(car);
Vector3[] obb = new Vector3[8];
b.GetCorners(obb);
Vector3.Transform(obb, ref carWorld, obb);
BoundingBox worldAABB = BoundingBox.CreateFromPoints(obb);
Vector3[] occ=new Vector3[8];
c.GetCorners(occ);
Vector3.Transform(occ, ref trafficWorld, occ);
BoundingBox worldAACC = BoundingBox.CreateFromPoints(occ);
if (worldAABB.Intersects(worldAACC))
col = true;
else col = false;
Below is the CalculateBoundingBox method
public BoundingBox CalculateBoundingBox(Model m_model)
{
// Create variables to hold min and max xyz values for the model. Initialise them to extremes
Vector3 modelMax = new Vector3(float.MinValue, float.MinValue, float.MinValue);
Vector3 modelMin = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
foreach (ModelMesh mesh in m_model.Meshes)
{
Matrix[] m_transforms = new Matrix[m_model.Bones.Count];
m_model.CopyAbsoluteBoneTransformsTo(m_transforms);
//Create variables to hold min and max xyz values for the mesh. Initialise them to extremes
Vector3 meshMax = new Vector3(float.MinValue, float.MinValue, float.MinValue);
Vector3 meshMin = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
// There may be multiple parts in a mesh (different materials etc.) so loop through each
foreach (ModelMeshPart part in mesh.MeshParts)
{
// The stride is how big, in bytes, one vertex is in the vertex buffer
// We have to use this as we do not know the make up of the vertex
int stride = part.VertexDeclaration.GetVertexStrideSize(0);
byte[] vertexData = new byte[stride * part.NumVertices];
mesh.VertexBuffer.GetData(part.BaseVertex * stride, vertexData, 0, part.NumVertices, 1); // fixed 13/4/11
// Find minimum and maximum xyz values for this mesh part
// We know the position will always be the first 3 float values of the vertex data
Vector3 vertPosition=new Vector3();
for (int ndx = 0; ndx < vertexData.Length; ndx += stride)
{
vertPosition.X= BitConverter.ToSingle(vertexData, ndx);
vertPosition.Y = BitConverter.ToSingle(vertexData, ndx + sizeof(float));
vertPosition.Z= BitConverter.ToSingle(vertexData, ndx + sizeof(float)*2);
// update our running values from this vertex
meshMin = Vector3.Min(meshMin, vertPosition);
meshMax = Vector3.Max(meshMax, vertPosition);
}
}
// transform by mesh bone transforms
meshMin = Vector3.Transform(meshMin, m_transforms[mesh.ParentBone.Index]);
meshMax = Vector3.Transform(meshMax, m_transforms[mesh.ParentBone.Index]);
// Expand model extents by the ones from this mesh
modelMin = Vector3.Min(modelMin, meshMin);
modelMax = Vector3.Max(modelMax, meshMax);
}
// Create and return the model bounding box
return new BoundingBox(modelMin, modelMax);
}
If someone can help me to solve this problem it wil be very helpful. If there is a better way to achieve collision other than the way i used please let me know about that method.
You have a couple of options here. The easiest is to transform the vehicle's bounding box according to the vehicle's world transforms (no projection or view required here since you're not concerned about camera position when checking for collisions.)
Assuming you already have the vehicle's original bounding box,
/// <summary>
/// Transforms a bounding box for collision detection
/// </summary>
/// <param name="vehicleBounds">Original, object-centered bounding box that contains a car model</param>
/// <param name="vehicleWorldMatrix">Vehicle's world transformation matrix (does not include projection or view)</param>
/// <returns>An axis-aligned bounding box (AABB) that will com </returns>
protected BoundingBox TransformBoundingBox(BoundingBox vehicleBounds, Matrix vehicleWorldMatrix)
{
var vertices = vehicleBounds.GetCorners();
/// get a couple of vertices to hold the outer bounds of the transformed bounding box.
var minVertex = new Vector3(float.MaxValue);
var maxVertex = new Vector3(float.MinValue);
for(int i=0;i<vertices.Length;i++)
{
var transformedVertex = Vector3.Transform(vertices[i],vehicleWorldMatrix);
/// update min and max with the component-wise minimum of each transformed vertex
/// to find the outer limits fo teh transformed bounding box
minVertex = Vector3.Min(minVertex, transformedVertex);
maxVertex = Vector3.Max(maxVertex, transformedVertex);
}
var result = new BoundingBox(minVertex, maxVertex);
return result;
}
For each vehicle, use that method to create a temporary bounding box to use for collisions. Only test transformed bounding boxes against each other, and do not overwrite you're original bounding box as you'll need to recalculate this box from your source any time the vehicle moves.
If you're using a multi-mesh model, use BoundingBox.CreateMerged() to combine them to get a box that contains the entire model, or perform your collisions for each sub-mesh bounding box (though this can get expensive without using some sort of acceleration structure).
What I have been using is a very simple method which can fit almost any situation. Here it is:
//Create one of the matricies
//Vector3 loc = new Vector3(0, 0, 0); //Wherever the model is.
//Matrix world1 = Matrix.CreateTransform(loc);
private bool IsCollision(Model model1, Matrix world1, Model model2, Matrix world2)
{
for (int meshIndex1 = 0; meshIndex1 < model1.Meshes.Count; meshIndex1++)
{
BoundingSphere sphere1 = model1.Meshes[meshIndex1].BoundingSphere;
sphere1 = sphere1.Transform(world1);
for (int meshIndex2 = 0; meshIndex2 < model2.Meshes.Count; meshIndex2++)
{
BoundingSphere sphere2 = model2.Meshes[meshIndex2].BoundingSphere;
sphere2 = sphere2.Transform(world2);
if (sphere1.Intersects(sphere2))
return true;
}
}
return false;
}
You can change all the spheres to boxes, but this might work. Additionally, what I do is move the location one axis at a time (X axis then Y axis then Z axis). This creates smoother collision.

XNA Find nearest Vector from player

I have a List of vectors and a PlayerVector I just want to know how I can find the nearest Vector to my PlayerVector in my List.
Here are my variables:
List<Vector2> Positions;
Vector2 Player;
The variables are already declared and all, I just need a simple code that will search for the nearest position to my player. Isn't there a simple way?
Since you don't need the exact distance (just a relative comparison), you can skip the square-root step in the Pythagorean distance formula:
Vector2? closest = null;
var closestDistance = float.MaxValue;
foreach (var position in Positions) {
var distance = Vector2.DistanceSquared(position, Player);
if (!closest.HasValue || distance < closestDistance) {
closest = position;
closestDistance = distance;
}
}
// closest.Value now contains the closest vector to the player
Create a int called distanceToPlayer, set it to 0.
Create a int called nearestObject set it to 0.
Loop through all the objects with a for loop. It is slightly faster than a foreach loop, and is more useful in this situation.
In the loop:
Get the distance with Vector2.Distance, and check it against distanceToPlayer, if less, then store the index number of the object in nearestObject, and store the new distance in distanceToPlayer.
After the loop is done, you will have the distance in whole pixels, and the index of the item in the list stored. You can access the item using Positions[index].
I'm writing it from memory, because I don't have access to XNA now:
Vector2 nerrest = Positions.Select(vect => new { distance= vect.Distance(Player), vect})
.OrderBy(x => x.distance)
.First().vect;
Little tips:
In this solution you probably can use PLINQ to gain little speedup on distance computing.

Distance between Matrix Objects, relative to parents orientation, using XNA?

I would like to understand how to measure the distance between two 3D objects, let's call them a parent object and a child object. Think of the parent as the body of a car and the child being a wheel of the car.
I understand how to get the difference based on the objects position in world space but I would like to get the difference as a measurement based on the parents relative object space. 
E.g if the parent is facing East and the child is 2X, 3Y from the parent, measured in a relative sense. Such that if the parent rotated 60 degrees, the relative location of the child remains at a distance of 2x, 3y in the object space. Where as in a world space sense the child objects measurement as a Vector3 would be quite different. 
Basically I just want a predictable way to get the difference so that a child object which is on the right of the patent can always stay right of the parent object. 
This is the parent component, this update is run every frame:
[Serializable]
public class Component_Parent : BaseComponentAutoSerialization<ISceneEntity>
{
public override void OnUpdate(GameTime gameTime)
{
PassThrough.ParentMatrix = ParentObject.World;
PassThrough.ParentTranslation = ParentObject.World.Translation;
}
}
This next part is the child component:
[Serializable]
public class Component_Child : BaseComponentAutoSerialization<ISceneEntity>
{
Vector3 _parentOffset;
Quaternion _parentQuaternionOffset;
public override void OnUpdate(GameTime gameTime)
{
// Get a sceneobject from the ParentObject
SceneObject sceneobject = (SceneObject)ParentObject;
// This relies on the position never being at 0,0,0 for setup, so please don't do that
// or change it with more look ups so that you don't need to rely on a Zero Vector3 :-)
if (PassThrough.GroupSetupMode || _parentOffset == Vector3.Zero)
{
if (PassThrough.ParentTranslation != Vector3.Zero)
{
_parentOffset = sceneobject.World.Translation - PassThrough.ParentTranslation;
// Decompose World Matrix (Parent)
Quaternion parentQ = new Quaternion();
Vector3 parentSpot = new Vector3();
Vector3 parentScale = new Vector3();
PassThrough.ParentMatrix.Decompose(out parentScale, out parentQ, out parentSpot);
Matrix identity = Matrix.Identity;
// Decompose Identity Matrix (Parent)
Quaternion identityQ = new Quaternion();
Vector3 identitySpot = new Vector3();
Vector3 identityScale = new Vector3();
identity.Decompose(out identityScale, out identityQ, out identitySpot);
_parentQuaternionOffset = identityQ - parentQ;
}
}
else
{
if (_parentOffset != Vector3.Zero)
{
// Decompose World Matrix (Child)
Quaternion rotationQ = new Quaternion();
Vector3 spot = new Vector3();
Vector3 scale = new Vector3();
sceneobject.World.Decompose(out scale, out rotationQ, out spot);
// Decompose World Matrix (Parent)
Quaternion parentQ = new Quaternion();
Vector3 parentSpot = new Vector3();
Vector3 parentScale = new Vector3();
PassThrough.ParentMatrix.Decompose(out parentScale, out parentQ, out parentSpot);
Matrix location = Matrix.CreateTranslation(PassThrough.ParentTranslation);
Matrix rotation = Matrix.CreateFromQuaternion(parentQ);
Matrix rotation2 = Matrix.CreateFromQuaternion(_parentQuaternionOffset);
Matrix newWorld = rotation * location;
Vector3 testTranslation = newWorld.Translation + ((newWorld.Left * _parentOffset.X) + (newWorld.Up * _parentOffset.Y) + (newWorld.Forward * _parentOffset.Z));
Matrix scaleM = Matrix.CreateScale(scale);
//sceneobject.World = scaleM * (rotation * (Matrix.CreateTranslation(testTranslation)));
sceneobject.World = (Matrix.CreateTranslation(testTranslation));
}
}
}
}
I think it has something to do with keeping track of an offset rotation, from the identity matrix and I have started trying to add some code to that effect but really unsure of what next now.
Additional:
If I have the parent object facing the direction of the world space it all works, if it's facing a different direction then it's an issue and the child seems to rotate by the same amount when they are grouped together.
I've uploaded a demo video to try and explain:
http://www.youtube.com/watch?v=BzAKW4WBWYs
I've also pasted up the complete code for the components, the static pass through and the scene entity.
http://pastebin.com/5hEmiVx9
Thanks
Think wheels on a car. I want the right wheel to always be in the same
spot relative to the body of the car.
It sounds like you want to be able to locate the position of the wheel for any given orientation or position of the car. One built in method that XNA has to help here is Model.CopyAbsoluteBoneTransformsTo(Matrix[]); However, your code looks like you want to handle parent child relationship manually. So here is a way to do it without using the built in method. It assumes you do have offset information at load time:
Before the game loops starts (say, in the LoadContent method), after loading the car & wheel and assuming they load into the proper positions, you can then create your offset vector ( _parentOffset )
Vector3 _parentOffset = wheel.meshes[?].ParentBone.Transform.Translation - car.meshes[?].ParentBone.Transform.Translation;//where ? is the mesh index of the mesh you are setting up.
Save that vector and don't modify it.
Later, after the car's matrix has been rotationally and or positionally displaced, set the wheel's matrix like this:
Matrix wheelMatrix = carMatrix;
wheelMatrix.Translation += (wheelMatrix.Right * _parentOffset.X) +
(wheelMatrix.Up * _parentOffset.Y) +
(wheelMatrix.Backward * _parentOffset.Z);
This allows that the wheel matrix will inherit any rotational and translational information from the car but will displace the wheel's position appropriately regardless of car's orientation/position.
The distance between two objects is NOT a function of either orientations.
What you basically want is the distance of the child object to the orientation line of the parent object. Assuming you have a global cartesian coordinate system this can be simply calculated as h=sqrt(x^2+y^2)*sin(Theta), x and y being the relative coordinates of the child with respect to the parent and Theta the orientation of the parent measured from x axis.
But still the question is a little bit confusing to me. If you only want to make sure that the child is on the right side of the parent why don't you simply check the relative x? If it's positive it's on the right and if it's negative it's on the left?
The issue was the way I was trying to use the offset of the world space.
Thanks to flashed from #XNA on EFnet, this code works perfectly:
[Serializable]
public class Component_Child_fromxna : BaseComponentAutoSerialization<ISceneEntity>
{
Vector3 _parentOffset;
Matrix _ParentMatrixOffset;
public override void OnUpdate(GameTime gameTime)
{
// Get a sceneobject from the ParentObject
SceneObject sceneObject = (SceneObject)ParentObject;
// This relies on the position never being at 0,0,0 for setup, so please don't do that
// or change it with more look ups so that you don't need to rely on a Zero Vector3 :-)
if (PassThrough.GroupSetupMode || _parentOffset == Vector3.Zero)
{
if (PassThrough.ParentTranslation != Vector3.Zero)
{
// The old offset - This is just in world space though...
_parentOffset = sceneObject.World.Translation - PassThrough.ParentTranslation;
// Get the distance between the child and the parent which we keep as the offset
// Inversing the ParentMatrix and multiplying it by the childs matrix gives an offset
// The offset is stored as a relative xyz, based on the parents object space
_ParentMatrixOffset = sceneObject.World * Matrix.Invert(PassThrough.ParentMatrix);
}
}
else
{
if (_parentOffset != Vector3.Zero)
{
//Matrix pLocation = Matrix.CreateTranslation(_parentOffset);
//sceneObject.World = Matrix.Multiply(pLocation, PassThrough.ParentMatrix);
sceneObject.World = Matrix.Multiply(_ParentMatrixOffset, PassThrough.ParentMatrix);
}
}
}
}

Categories

Resources