Trying to do skeletal visualization in bind pose similar to blender with octahedral mode

Started by
-1 comments, last by Breyer 8 years, 3 months ago

I already achieved drawing octahedral by just porting blender code to c#+opentk. Here ported code:


static float[][] bone_octahedral_verts =new float[6][] {
	new []{ 0.0f, 0.0f,  0.0f},
	new []{ 0.1f, 0.1f,  0.1f},
	new []{ 0.1f, 0.1f, -0.1f},
	new []{-0.1f, 0.1f, -0.1f},
	new []{-0.1f, 0.1f,  0.1f},
	new []{ 0.0f, 1.0f,  0.0f}
		};

		static int[][] bone_octahedral_solid_tris =new int[8][] {
	new []{2, 1, 0}, /* bottom */
	new []{3, 2, 0},
	new []{4, 3, 0},
	new []{1, 4, 0},

	new []{5, 1, 2}, /* top */
	new []{5, 2, 3},
	new []{5, 3, 4},
	new []{5, 4, 1}
		};
		static float M_SQRT1_2=0.707106781186547524401f;
		/* aligned with bone_octahedral_solid_tris */
		static float[][] bone_octahedral_solid_normals =new float[8][] {
	new []{ M_SQRT1_2,   -M_SQRT1_2,    0.00000000f},
	new []{-0.00000000f, -M_SQRT1_2,   -M_SQRT1_2},
	new []{-M_SQRT1_2,   -M_SQRT1_2,    0.00000000f},
	new []{ 0.00000000f, -M_SQRT1_2,    M_SQRT1_2},
	new []{ 0.99388373f,  0.11043154f, -0.00000000f},
	new []{ 0.00000000f,  0.11043154f, -0.99388373f},
	new []{-0.99388373f,  0.11043154f,  0.00000000f},
	new []{ 0.00000000f,  0.11043154f,  0.99388373f}
		};


		static void draw_bone_solid_octahedral(ref Matrix4 mat,float length)
		{

	GL.PushMatrix();

	GL.MultTransposeMatrix(ref mat);
			GL.Scale(length,length,length);
		GL.Begin(PrimitiveType.Triangles);
				for (var i = 0; i < 8; i++) {
					GL.Normal3(bone_octahedral_solid_normals[i]);
					GL.Vertex3(bone_octahedral_verts[bone_octahedral_solid_tris[i][0]]);
					GL.Vertex3(bone_octahedral_verts[bone_octahedral_solid_tris[i][1]]);
					GL.Vertex3(bone_octahedral_verts[bone_octahedral_solid_tris[i][2]]);
				}

				GL.End();
				GL.PopMatrix ();
		}

Originally blender used displayList+fixed pipeline but i removed displayList. As you see octahedron is normalized along Y axis (head is in {0,0,0} and tail is in {0,1,0}). This mean you have to multiply vertex with skeletal MVP matrix (matrix is loaded once before draw) and then is multiplied by inverted offset matrix for each bone - last thing is scale octa by length.

This gain me correct position and rotation. But i have serious trouble with length. I already spent 3 days for just trying fix length of octa for myself. I read multiple articles and posts including those in gamedev.net forum. Prolly most useful was this discussion: http://gamedev.stackexchange.com/questions/31959/getting-bone-base-and-tip-positions-from-a-transform-matrix

@Matt Kemp pointed out that i could find head and tail by multiplying {0,0,0} and {0,1,0} (i chose Y axis since octa is normalized along Y axis) positions by one matrix from bone (local/global/offset?) then find length by subtracting these positions. I tried multiple variants of matrix calculations but always got no effect or too big effect (too small bone or too big).

I belive problem lie in matrix calculation or in their order. Here is my rest code for skeletal visualisation:

Loading skeleton (i use assimp.net):


using System;
using Assimp;
using Assimp.Configs;
using OpenTK;
using System.Linq;
using System.Collections.Generic;

namespace SharpAsset.Pipeline
{
	public class SkeletonPipeline: Pipeline
	{
		public static readonly SkeletonPipeline singleton=new SkeletonPipeline();
		public Scene scene;
		private Dictionary<string,Assimp.Bone> boneNames;
		private List<Assimp.Node> rootBones;

		public override IAsset Import (string pathToFile)
		{
			
			boneNames = new Dictionary<string, Assimp.Bone>();
			//rootBones = new List<Node> ();
			Assimp.Node rootBone=null;
			foreach (var mesh in scene.Meshes)
				foreach (var bone in mesh.Bones)
					boneNames.Add (bone.Name,bone);
			
			foreach(var boneName in boneNames.Keys){
				var boneNode=scene.RootNode.FindNode (boneName);
				if (boneNode.Parent == null || !boneNames.ContainsKey (boneNode.Parent.Name)) {
					rootBone = boneNode.Parent;
					break;
				}
			}
			var skele = new Skeleton ();
			skele.Name = "_Skeleton";
			skele[rootBone.Name]=CreateBoneTree (ref skele, rootBone,null);
			//bvh_to_vertices (skele[rootBone.Name],);
			Console.WriteLine ("/n Start bone list: /n"+rootBone.Name);
		
			return skele;
		}
	
		void PrintBones(Bone n){
			Console.WriteLine (n.Name);
			foreach(var node in n.Children)
				PrintBones (node);
		}
		private int _i;
		private Bone CreateBoneTree(ref Skeleton skele, Node node, Bone parent) {

			var internalNode = new Bone {
				Name = node.Name, Parent = parent,
			};
			if (boneNames.ContainsKey (node.Name)) {
				boneNames [node.Name].OffsetMatrix.Transpose ();
				internalNode.Offset = FromMatrix (boneNames [node.Name].OffsetMatrix);

			}if (internalNode.Name == "") {
				internalNode.Name = "bone_" + _i++;
			}
			//skele[internalNode.Name] = internalNode;
			var trans = node.Transform;
			trans.Transpose(); //drectx stuff
			internalNode.LocalTransform =FromMatrix(trans);
			internalNode.OriginalLocalTransform = internalNode.LocalTransform;
			CalculateBoneToWorldTransform(internalNode);
			internalNode.Children = new List<Bone> ();
			for (var i = 0; i < node.ChildCount; i++) {
				var child = CreateBoneTree(ref skele,node.Children[i], internalNode);
				if (child != null) {
					internalNode.Children.Add(child);
				}
			}

			return internalNode;
		}

		private static void CalculateBoneToWorldTransform(Bone child) {
			child.GlobalTransform = child.LocalTransform;
			var parent = child.Parent;
			while (parent != null) {
				child.GlobalTransform *= parent.LocalTransform;
				parent = parent.Parent;
			}
		}
		public override void Export (string pathToExport, string format)
		{
			throw new NotImplementedException ();
		}
		private Matrix4 FromMatrix(Matrix4x4 mat)
		{
			Matrix4 m = new Matrix4();
			m.M11 = mat.A1;
			m.M12 = mat.A2;
			m.M13 = mat.A3;
			m.M14 = mat.A4;
			m.M21 = mat.B1;
			m.M22 = mat.B2;
			m.M23 = mat.B3;
			m.M24 = mat.B4;
			m.M31 = mat.C1;
			m.M32 = mat.C2;
			m.M33 = mat.C3;
			m.M34 = mat.C4;
			m.M41 = mat.D1;
			m.M42 = mat.D2;
			m.M43 = mat.D3;
			m.M44 = mat.D4;
			return m;
		}
	}
}

show skeleton code (highest level method in opengl renderer)


GL.LoadMatrix(ref skele.MVP);
//foreach (var childBone in skele.bones[0].Children)
var noscale=skele.bones[0].GlobalTransform.Inverted();
DisplayOcta (skele.bones[0],ref noscale);

DisplayOcta method:


void DisplayOcta(Bone bone, ref Matrix4 mvp){
            var mat =bone.Offset.Inverted();
            var copyMat =bone.Offset.Inverted()*bone.GlobalTransform;
            //copyMat.Transpose ();
            var final =copyMat;
            var head = Vector3.Transform (Vector3.Zero,final);
            var tail = Vector3.Transform (Vector3.UnitY,final);
            Console.WriteLine ((tail-head).Length);
            draw_bone_solid_octahedral (ref mat,(tail-head).Length);
            foreach (var childBone in bone.Children) 
                DisplayOcta (childBone,ref mvp);
            
        }

draw_bone_solid_octahedral is already mentioned on the begining of post. These weird matrix multiplications are result of trying very hard to fix problem one way or another

here are pics to show the problem, first, see how it look in blender:

[attachment=30350:blenderrig.png]

here is my scene view with exactly same sekeleton

[attachment=30351:myrig.png]

as you see position and rotation of bone itself are same as in blender but length of bones are different

This topic is closed to new replies.

Advertisement