浏览代码

skin support for h3d format in progress

Nicolas Cannasse 11 年之前
父节点
当前提交
1e7b12674d
共有 7 个文件被更改,包括 212 次插入37 次删除
  1. 8 4
      h3d/anim/Skin.hx
  2. 4 1
      h3d/scene/Skin.hx
  3. 3 2
      hxd/fmt/fbx/BaseLibrary.hx
  4. 123 21
      hxd/fmt/fbx/H3DOut.hx
  5. 19 0
      hxd/fmt/h3d/Data.hx
  6. 31 5
      hxd/fmt/h3d/Reader.hx
  7. 24 4
      hxd/fmt/h3d/Writer.hx

+ 8 - 4
h3d/anim/Skin.hx

@@ -29,6 +29,7 @@ private class Influence {
 
 class Skin {
 
+	public var name : String;
 	public var vertexCount(default, null) : Int;
 	public var bonesPerVertex(default,null) : Int;
 	public var vertexJoints : haxe.ds.Vector<Int>;
@@ -47,12 +48,15 @@ class Skin {
 
 	var envelop : Array<Array<Influence>>;
 
-	public function new( vertexCount, bonesPerVertex ) {
+	public function new( name, vertexCount, bonesPerVertex ) {
+		this.name = name;
 		this.vertexCount = vertexCount;
 		this.bonesPerVertex = bonesPerVertex;
-		vertexJoints = new haxe.ds.Vector(vertexCount * bonesPerVertex);
-		vertexWeights = new haxe.ds.Vector(vertexCount * bonesPerVertex);
-		envelop = [];
+		if( vertexCount > 0 ) {
+			vertexJoints = new haxe.ds.Vector(vertexCount * bonesPerVertex);
+			vertexWeights = new haxe.ds.Vector(vertexCount * bonesPerVertex);
+			envelop = [];
+		}
 	}
 
 	public function setJoints( joints : Array<Joint>, roots : Array<Joint> ) {

+ 4 - 1
h3d/scene/Skin.hx

@@ -99,7 +99,10 @@ class Skin extends MultiMaterial {
 		return b;
 	}
 
-	override function getObjectByName( name : String ) {
+	override function getObjectByName( name : String ) : h3d.scene.Object {
+		// we can reference the object by both its model name and skin name
+		if( skinData != null && skinData.name == name )
+			return this;
 		var o = super.getObjectByName(name);
 		if( o != null ) return o;
 		// create a fake object targeted at the bone, not persistant but matrixes are shared

+ 3 - 2
hxd/fmt/fbx/BaseLibrary.hx

@@ -12,8 +12,9 @@ class TmpObject {
 	public var childs : Array<TmpObject>;
 	#if !(dataOnly || macro)
 	public var obj : h3d.scene.Object;
-	public var joint : h3d.anim.Skin.Joint;
 	#end
+	public var joint : h3d.anim.Skin.Joint;
+	public var skin : TmpObject;
 	public function new() {
 		childs = [];
 	}
@@ -963,7 +964,7 @@ class BaseLibrary {
 				if( skin != null )
 					return skin;
 				var geom = hgeom.get(getParent(def, "Geometry").getId());
-				skin = new h3d.anim.Skin(geom.getVerticesCount(), bonesPerVertex);
+				skin = new h3d.anim.Skin(null, geom.getVerticesCount(), bonesPerVertex);
 				geom.setSkin(skin);
 				hskins.set(def.getId(), skin);
 			}

+ 123 - 21
hxd/fmt/fbx/H3DOut.hx

@@ -8,9 +8,14 @@ class H3DOut extends BaseLibrary {
 	var d : Data;
 	var dataOut : haxe.io.BytesOutput;
 	var filePath : String;
+	var tmp = haxe.io.Bytes.alloc(4);
 
 	function int32tof( v : Int ) : Float {
-		throw "TODO";
+		tmp.set(0, v & 0xFF);
+		tmp.set(1, (v >> 8) & 0xFF);
+		tmp.set(2, (v >> 16) & 0xFF);
+		tmp.set(3, v >>> 24);
+		return tmp.getFloat(0);
 	}
 
 	function buildGeom( geom : hxd.fmt.fbx.Geometry, skin : h3d.anim.Skin, dataOut : haxe.io.BytesOutput ) {
@@ -33,6 +38,12 @@ class H3DOut extends BaseLibrary {
 			g.vertexFormat.push(new GeometryFormat("color", DVec3));
 
 		var stride = 3 + (normals == null ? 0 : 3) + uvs.length * 2 + (colors == null ? 0 : 3);
+		if( skin != null ) {
+			if( bonesPerVertex <= 0 || bonesPerVertex > 4 ) throw "assert";
+			g.vertexFormat.push(new GeometryFormat("weights", [DFloat, DVec2, DVec3, DVec4][bonesPerVertex]));
+			g.vertexFormat.push(new GeometryFormat("indexes", DBytes4));
+			stride += 1 + bonesPerVertex;
+		}
 		g.vertexStride = stride;
 		g.vertexCount = 0;
 
@@ -89,11 +100,11 @@ class H3DOut extends BaseLibrary {
 				}
 
 				if( skin != null ) {
-					var p = vidx * skin.bonesPerVertex;
+					var k = vidx * skin.bonesPerVertex;
 					var idx = 0;
 					for( i in 0...skin.bonesPerVertex ) {
-						tmpBuf[p++] = skin.vertexWeights[p + i];
-						idx = (skin.vertexJoints[p + i] << (8*i)) | idx;
+						tmpBuf[p++] = skin.vertexWeights[k + i];
+						idx = (skin.vertexJoints[k + i] << (8*i)) | idx;
 					}
 					tmpBuf[p++] = int32tof(idx);
 				}
@@ -152,19 +163,30 @@ class H3DOut extends BaseLibrary {
 			root.parent = null;
 		}
 
-		var objects = [];
+		var objects = [], joints = [], skins = [];
 		var uid = 0;
 		function indexRec( t : TmpObject ) {
-			if( !t.isJoint ) t.index = uid++;
-			objects.push(t);
+			if( t.isJoint ) {
+				joints.push(t);
+			} else {
+				var isSkin = false;
+				for( c in t.childs )
+					if( c.isJoint ) {
+						isSkin = true;
+						break;
+					}
+				if( isSkin ) {
+					skins.push(t);
+				} else
+					objects.push(t);
+			}
 			for( c in t.childs )
 				indexRec(c);
 		}
 		indexRec(root);
 
 		// create joints
-		for( o in objects ) {
-			if( !o.isJoint ) continue;
+		for( o in joints ) {
 			if( o.isMesh ) throw "assert";
 			var j = new h3d.anim.Skin.Joint();
 			getDefaultMatrixes(o.model); // store for later usage in animation
@@ -177,17 +199,66 @@ class H3DOut extends BaseLibrary {
 			}
 		}
 
+		// mark skin references
+		for( o in skins ) {
+			var subDef = null;
+			for( j in o.childs ) {
+				subDef = getParent(j.model, "Deformer", true);
+				if( subDef != null ) break;
+			}
+			var def = getParent(subDef, "Deformer");
+			var geoms = getParents(def, "Geometry");
+			if( geoms.length == 0 ) continue;
+			if( geoms.length > 1 ) throw "Single skin applied to multiple geometries not supported";
+			var models = getParents(geoms[0],"Model");
+			if( models.length == 0 ) continue;
+			if( models.length > 1 ) throw "Single skin applied to multiple models not supported";
+			var m = models[0];
+			for( o2 in objects )
+				if( o2.model == m ) {
+					o2.skin = o;
+					// copy parent
+					var p = o.parent;
+					if( p != o2 ) {
+						o2.parent.childs.remove(o2);
+						o2.parent = p;
+						p.childs.push(o2);
+					}
+					// remove skin from hierarchy
+					o.parent.childs.remove(o);
+					// move not joint to new parent
+					// (only first level, others will follow their respective joint)
+					for( c in o.childs )
+						if( !c.isJoint ) {
+							o.childs.remove(c);
+							o2.childs.push(c);
+							c.parent = o2;
+						}
+					break;
+				}
+		}
+
+		objects = [];
+		indexRec(root); // reorder after we have changed hierarchy
+
+		var hskins = new Map(), tmpGeom = new Map();
+		// prepare things for skinning
+		for( g in this.root.getAll("Objects.Geometry") )
+			tmpGeom.set(g.getId(), { setSkin : function(_) { }, getVerticesCount : function() return Std.int(new hxd.fmt.fbx.Geometry(this, g).getVertices().length/3) } );
+
 		var hgeom = new Map<Int,{ gids : Array<Int>, mindexes : Array<Int> }>();
 		var hmat = new Map<Int,Int>();
+		var index = 0;
 		for( o in objects ) {
 
-			if( o.isJoint ) continue;
+			o.index = index++;
 
 			var model = new Model();
+			var ref = o.skin == null ? o : o.skin;
 			model.name = o.model.getName();
 			model.parent = o.parent == null || o.parent.isJoint ? 0 : o.parent.index;
-			//model.follow = o.parent != null && o.parent.isJoint ? o.parent.model.getName() : null;
-			var m = getDefaultMatrixes(o.model);
+			model.follow = o.parent != null && o.parent.isJoint ? o.parent.model.getName() : null;
+			var m = getDefaultMatrixes(ref.model);
 			var p = new Position();
 			p.x = m.trans == null ? 0 : -m.trans.x;
 			p.y = m.trans == null ? 0 : m.trans.y;
@@ -266,20 +337,18 @@ class H3DOut extends BaseLibrary {
 			}
 
 			var skin = null;
-			var rootJoints = [];
-			for( c in o.childs )
-				if( c.isJoint )
-					rootJoints.push(c.joint);
-
-			if( rootJoints.length > 0 ) {
-				throw "TODO";
-				skin = createSkin(hskins, hgeom);
+			if( o.skin != null ) {
+				var rootJoints = [];
+				for( c in o.skin.childs )
+					if( c.isJoint )
+						rootJoints.push(c.joint);
+				skin = createSkin(hskins, tmpGeom, rootJoints, bonesPerVertex);
+				model.skin = makeSkin(skin, o.skin);
 			}
 
 			var g = getChild(o.model, "Geometry");
 			var gdata = hgeom.get(g.getId());
 			if( gdata == null ) {
-				var skin = null;
 				var geom = buildGeom(new hxd.fmt.fbx.Geometry(this, g), skin, dataOut);
 				var gid = d.geometries.length;
 				d.geometries.push(geom);
@@ -298,6 +367,39 @@ class H3DOut extends BaseLibrary {
 		}
 	}
 
+	function makeSkin( skin : h3d.anim.Skin, obj : TmpObject ) {
+		var s = new Skin();
+		s.name = obj.model.getName();
+		s.joints = [];
+		for( jo in skin.allJoints ) {
+			var j = new SkinJoint();
+			j.name = jo.name;
+			j.parent = jo.parent == null ? -1 : jo.parent.index;
+			j.bind = jo.bindIndex;
+			j.position = makePosition(jo.defMat);
+			if( jo.transPos != null ) j.transpos = makePosition(jo.transPos);
+			s.joints.push(j);
+		}
+		return s;
+	}
+
+	function makePosition( m : h3d.Matrix ) {
+		var p = new Position();
+		var q = new h3d.Quat();
+		q.initRotateMatrix(m);
+		q.normalize();
+		p.sx = 1;
+		p.sy = 1;
+		p.sz = 1;
+		p.qx = q.x;
+		p.qy = q.y;
+		p.qz = q.z;
+		p.x = m._41;
+		p.y = m._42;
+		p.z = m._43;
+		return p;
+	}
+
 	function makeAnimation( anim : h3d.anim.Animation ) {
 		var a = new Animation();
 		a.name = anim.name;

+ 19 - 0
hxd/fmt/h3d/Data.hx

@@ -77,12 +77,31 @@ class Material {
 	}
 }
 
+class SkinJoint {
+	public var name : String;
+	public var parent : Index<SkinJoint>;
+	public var position : Position;
+	public var bind : Int;
+	public var transpos : Null<Position>;
+	public function new() {
+	}
+}
+
+class Skin {
+	public var name : String;
+	public var joints : Array<SkinJoint>;
+	public function new() {
+	}
+}
+
 class Model {
 	public var name : String;
 	public var parent : Index<Model>;
+	public var follow : Null<String>;
 	public var position : Position;
 	public var geometries : Null<Array<Index<Geometry>>>;
 	public var materials : Null<Array<Index<Material>>>;
+	public var skin : Null<Skin>;
 	public function new() {
 	}
 }

+ 31 - 5
hxd/fmt/h3d/Reader.hx

@@ -14,10 +14,12 @@ class Reader {
 	}
 
 	function readName() {
-		return i.readString(i.readByte());
+		var b = i.readByte();
+		if( b == 0xFF ) return null;
+		return i.readString(b);
 	}
 
-	function readPosition() {
+	function readPosition(hasScale=true) {
 		var p = new Position();
 		p.x = i.readFloat();
 		p.y = i.readFloat();
@@ -25,9 +27,15 @@ class Reader {
 		p.qx = i.readFloat();
 		p.qy = i.readFloat();
 		p.qz = i.readFloat();
-		p.sx = i.readFloat();
-		p.sy = i.readFloat();
-		p.sz = i.readFloat();
+		if( hasScale ) {
+			p.sx = i.readFloat();
+			p.sy = i.readFloat();
+			p.sz = i.readFloat();
+		} else {
+			p.sx = 1;
+			p.sy = 1;
+			p.sz = 1;
+		}
 		return p;
 	}
 
@@ -73,6 +81,7 @@ class Reader {
 			var m = new Model();
 			m.name = readName();
 			m.parent = i.readInt32();
+			m.follow = readName();
 			m.position = readPosition();
 			d.models.push(m);
 			var count = i.readByte();
@@ -83,6 +92,23 @@ class Reader {
 				m.geometries.push(i.readInt32());
 			for( k in 0...count )
 				m.materials.push(i.readInt32());
+			var name = readName();
+			if( name != null ) {
+				var s = new Skin();
+				s.name = name;
+				s.joints = [];
+				for( k in 0...i.readUInt16() ) {
+					var j = new SkinJoint();
+					j.name = readName();
+					j.parent = i.readUInt16() - 1;
+					j.position = readPosition(false);
+					j.bind = i.readUInt16() - 1;
+					if( j.bind >= 0 )
+						j.transpos = readPosition(false);
+					s.joints.push(j);
+				}
+				m.skin = s;
+			}
 		}
 
 		d.animations = [];

+ 24 - 4
hxd/fmt/h3d/Writer.hx

@@ -22,16 +22,18 @@ class Writer {
 		out.writeString(name);
  	}
 
-	function writePosition( p : Position ) {
+	function writePosition( p : Position, hasScale = true ) {
 		out.writeFloat(p.x);
 		out.writeFloat(p.y);
 		out.writeFloat(p.z);
 		out.writeFloat(p.qx);
 		out.writeFloat(p.qy);
 		out.writeFloat(p.qz);
-		out.writeFloat(p.sx);
-		out.writeFloat(p.sy);
-		out.writeFloat(p.sz);
+		if( hasScale ) {
+			out.writeFloat(p.sx);
+			out.writeFloat(p.sy);
+			out.writeFloat(p.sz);
+		}
 	}
 
 	public function write( d : Data ) {
@@ -52,6 +54,7 @@ class Writer {
 			out.writeInt32(g.indexCount);
 			out.writeInt32(g.indexPosition);
 		}
+
 		out.writeInt32(d.materials.length);
 		for( m in d.materials ) {
 			writeName(m.name);
@@ -60,10 +63,12 @@ class Writer {
 			out.writeByte(m.culling.getIndex());
 			out.writeFloat(m.killAlpha == null ? 1 : m.killAlpha);
 		}
+
 		out.writeInt32(d.models.length);
 		for( m in d.models ) {
 			writeName(m.name);
 			out.writeInt32(m.parent);
+			writeName(m.follow);
 			writePosition(m.position);
 			out.writeByte(m.geometries == null ? 0 : m.geometries.length);
 			if( m.geometries == null ) continue;
@@ -72,7 +77,22 @@ class Writer {
 				out.writeInt32(g);
 			for( m in m.materials )
 				out.writeInt32(m);
+			if( m.skin == null )
+				writeName(null);
+			else {
+				writeName(m.skin.name == null ? "" : m.skin.name);
+				out.writeUInt16(m.skin.joints.length);
+				for( j in m.skin.joints ) {
+					writeName(j.name);
+					out.writeUInt16(j.parent + 1);
+					writePosition(j.position, false);
+					out.writeUInt16(j.bind + 1);
+					if( j.bind >= 0 )
+						writePosition(j.transpos, false);
+				}
+			}
 		}
+
 		out.writeInt32(d.animations.length);
 		for( a in d.animations ) {
 			writeName(a.name);