Browse Source

hmd multimaterial and skin split complete

Nicolas Cannasse 11 năm trước cách đây
mục cha
commit
ed56ab3b30

+ 0 - 18
h3d/prim/FBXModel.hx

@@ -89,24 +89,6 @@ class FBXModel extends MeshPrimitive {
 		return m;
 	}
 
-	public function getMaterialByTriangle() {
-		var mids = geom.getMaterials();
-		var pos = 0;
-		var count = 0;
-		var mats = [];
-		for( p in geom.getPolygons() ) {
-			count++;
-			if( p >= 0 )
-				continue;
-			var m = mids[pos++];
-			for( i in 0...count - 2 )
-				mats.push(m);
-			count = 0;
-		}
-		return mats;
-	}
-
-
 	override function alloc( engine : h3d.Engine ) {
 		dispose();
 

+ 28 - 4
h3d/prim/HMDModel.hx

@@ -4,7 +4,10 @@ class HMDModel extends MeshPrimitive {
 
 	var data : hxd.fmt.hmd.Data.Geometry;
 	var dataPosition : Int;
+	var indexCount : Int;
+	var indexesTriPos : Array<Int>;
 	var entry : hxd.res.FileEntry;
+	var curMaterial : Int;
 
 	public function new(data, dataPos, entry) {
 		this.data = data;
@@ -16,6 +19,10 @@ class HMDModel extends MeshPrimitive {
 		return data.bounds;
 	}
 
+	override function selectMaterial( i : Int ) {
+		curMaterial = i;
+	}
+
 	override function alloc(engine:h3d.Engine) {
 		dispose();
 		buffer = new h3d.Buffer(data.vertexCount, data.vertexStride);
@@ -29,12 +36,18 @@ class HMDModel extends MeshPrimitive {
 		buffer.uploadBytes(bytes, 0, data.vertexCount);
 		hxd.impl.Tmp.saveBytes(bytes);
 
-		indexes = new h3d.Indexes(data.indexCount);
+		indexCount = 0;
+		indexesTriPos = [];
+		for( n in data.indexCounts ) {
+			indexesTriPos.push(Std.int(indexCount/3));
+			indexCount += n;
+		}
+		indexes = new h3d.Indexes(indexCount);
 
 		entry.skip(data.indexPosition - (data.vertexPosition + size));
-		var bytes = hxd.impl.Tmp.getBytes(data.indexCount * 2);
-		entry.read(bytes, 0, data.indexCount * 2);
-		indexes.uploadBytes(bytes, 0, data.indexCount);
+		var bytes = hxd.impl.Tmp.getBytes(indexCount * 2);
+		entry.read(bytes, 0, indexCount * 2);
+		indexes.uploadBytes(bytes, 0, indexCount);
 		hxd.impl.Tmp.saveBytes(bytes);
 
 		entry.close();
@@ -52,4 +65,15 @@ class HMDModel extends MeshPrimitive {
 		}
 	}
 
+	override function render( engine : h3d.Engine ) {
+		if( curMaterial < 0 ) {
+			super.render(engine);
+			return;
+		}
+		if( indexes == null || indexes.isDisposed() )
+			alloc(engine);
+		engine.renderMultiBuffers(getBuffers(engine), indexes, indexesTriPos[curMaterial], Std.int(data.indexCounts[curMaterial]/3));
+		curMaterial = -1;
+	}
+
 }

+ 17 - 0
hxd/fmt/fbx/Geometry.hx

@@ -28,6 +28,23 @@ class Geometry {
 		return mats == null ? null : mats.get("Materials").getInts();
 	}
 
+	public function getMaterialByTriangle() {
+		var mids = getMaterials();
+		var pos = 0;
+		var count = 0;
+		var mats = [];
+		for( p in getPolygons() ) {
+			count++;
+			if( p >= 0 )
+				continue;
+			var m = mids[pos++];
+			for( i in 0...count - 2 )
+				mats.push(m);
+			count = 0;
+		}
+		return mats;
+	}
+
 	public function merge( g : Geometry, materials : Array<Int> ) {
 		var vl = getVertices();
 		var vcount = Std.int(vl.length / 3);

+ 57 - 25
hxd/fmt/fbx/HMDOut.hx

@@ -30,6 +30,7 @@ class HMDOut extends BaseLibrary {
 		var normals = geom.getNormals();
 		var uvs = geom.getUVs();
 		var colors = geom.getColors();
+		var mats = geom.getMaterials();
 
 		// build format
 		g.vertexFormat = [
@@ -57,13 +58,16 @@ class HMDOut extends BaseLibrary {
 		if( gt == null ) gt = new h3d.col.Point();
 
 		var vbuf = new hxd.FloatBuffer();
-		var ibuf = new hxd.IndexBuffer();
+		var ibufs = [];
+
+		if( skin.isSplit() )
+			for( _ in skin.splitJoints ) ibufs.push(new hxd.IndexBuffer());
 
 		g.bounds = new h3d.col.Bounds();
 		var tmpBuf = new haxe.ds.Vector(stride);
 		var vertexRemap = [];
 		var index = geom.getPolygons();
-		var count = 0;
+		var count = 0, matPos = 0, stri = 0;
 		for( pos in 0...index.length ) {
 			var i = index[pos];
 			count++;
@@ -140,10 +144,28 @@ class HMDOut extends BaseLibrary {
 				vertexRemap.push(found);
 			}
 
-			for( n in 0...count - 2 ) {
-				ibuf.push(vertexRemap[start + n]);
-				ibuf.push(vertexRemap[start + count - 1]);
-				ibuf.push(vertexRemap[start + n + 1]);
+			// by-skin-group index
+			if( skin != null && skin.isSplit() ) {
+				for( n in 0...count - 2 ) {
+					var idx = ibufs[skin.triangleGroups[stri++]];
+					idx.push(vertexRemap[start + n]);
+					idx.push(vertexRemap[start + count - 1]);
+					idx.push(vertexRemap[start + n + 1]);
+				}
+			}
+			// by-material index
+			else if( mats != null ) {
+				var mid = mats[matPos++];
+				var idx = ibufs[mid];
+				if( idx == null ) {
+					idx = new hxd.IndexBuffer();
+					ibufs[mid] = idx;
+				}
+				for( n in 0...count - 2 ) {
+					idx.push(vertexRemap[start + n]);
+					idx.push(vertexRemap[start + count - 1]);
+					idx.push(vertexRemap[start + n + 1]);
+				}
 			}
 
 			index[pos] = i; // restore
@@ -155,9 +177,12 @@ class HMDOut extends BaseLibrary {
 		for( i in 0...vbuf.length )
 			dataOut.writeFloat(vbuf[i]);
 		g.indexPosition = dataOut.length;
-		g.indexCount = ibuf.length;
-		for( i in 0...ibuf.length )
-			dataOut.writeUInt16(ibuf[i]);
+		g.indexCounts = [];
+		for( idx in ibufs ) {
+			g.indexCounts.push(idx.length);
+			for( i in idx )
+				dataOut.writeUInt16(i);
+		}
 
 		return g;
 	}
@@ -261,7 +286,7 @@ class HMDOut extends BaseLibrary {
 		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,{ gid : Int, mindexes : Array<Int> }>();
+		var hgeom = new Map<Int,Int>();
 		var hmat = new Map<Int,Int>();
 		var index = 0;
 		for( o in objects ) {
@@ -361,6 +386,8 @@ class HMDOut extends BaseLibrary {
 				}
 			}
 
+			var g = getChild(o.model, "Geometry");
+
 			var skin = null;
 			if( o.skin != null ) {
 				var rootJoints = [];
@@ -368,27 +395,23 @@ class HMDOut extends BaseLibrary {
 					if( c.isJoint )
 						rootJoints.push(c.joint);
 				skin = createSkin(hskins, tmpGeom, rootJoints, bonesPerVertex);
+				if( skin.boundJoints.length > maxBonesPerSkin ) {
+					var g = new hxd.fmt.fbx.Geometry(this, g);
+					var idx = g.getIndexes();
+					skin.split(maxBonesPerSkin, [for( i in idx.idx ) idx.vidx[i]], mids.length > 1 ? g.getMaterialByTriangle() : null);
+				}
 				model.skin = makeSkin(skin, o.skin);
 			}
 
-			var g = getChild(o.model, "Geometry");
-			var gdata = hgeom.get(g.getId());
-			if( gdata == null ) {
+			var gid = hgeom.get(g.getId());
+			if( gid == null ) {
 				var geom = buildGeom(new hxd.fmt.fbx.Geometry(this, g), skin, dataOut);
-				var gid = d.geometries.length;
+				gid = d.geometries.length;
 				d.geometries.push(geom);
-				gdata = {
-					gid : gid,
-					mindexes : [0],
-				};
-				hgeom.set(g.getId(), gdata);
-			}
-			model.geometry = gdata.gid;
-			model.materials = [];
-			for( i in gdata.mindexes ) {
-				if( mids[i] == null ) throw "assert"; // TODO : create a null material color
-				model.materials.push(mids[i]);
+				hgeom.set(g.getId(), gid);
 			}
+			model.geometry = gid;
+			model.materials = mids;
 		}
 	}
 
@@ -406,6 +429,15 @@ class HMDOut extends BaseLibrary {
 				j.transpos = makePosition(jo.transPos);
 			s.joints.push(j);
 		}
+		if( skin.splitJoints != null ) {
+			s.split = [];
+			for( sp in skin.splitJoints ) {
+				var ss = new SkinSplit();
+				ss.materialIndex = sp.material;
+				ss.joints = [for( j in sp.joints ) j.index];
+				s.split.push(ss);
+			}
+		}
 		return s;
 	}
 

+ 1 - 1
hxd/fmt/fbx/Library.hx

@@ -138,7 +138,7 @@ class Library extends BaseLibrary {
 			if( skinData.boundJoints.length > maxBonesPerSkin ) {
 				var model = Std.instance(skinData.primitive, h3d.prim.FBXModel);
 				var idx = model.geom.getIndexes();
-				skinData.split(maxBonesPerSkin, [for( i in idx.idx) idx.vidx[i]], model.multiMaterial ? model.getMaterialByTriangle() : null);
+				skinData.split(maxBonesPerSkin, [for( i in idx.idx) idx.vidx[i]], model.multiMaterial ? model.geom.getMaterialByTriangle() : null);
 			}
 			skin.setSkinData(skinData);
 		}

+ 9 - 1
hxd/fmt/hmd/Data.hx

@@ -61,7 +61,7 @@ class Geometry {
 	public var vertexStride : Int;
 	public var vertexFormat : Array<GeometryFormat>;
 	public var vertexPosition : DataPosition;
-	public var indexCount : Int;
+	public var indexCounts : Array<Int>;
 	public var indexPosition : DataPosition;
 	public var bounds : h3d.col.Bounds;
 	public function new() {
@@ -88,9 +88,17 @@ class SkinJoint {
 	}
 }
 
+class SkinSplit {
+	public var materialIndex : Int;
+	public var joints : Array<Index<SkinJoint>>;
+	public function new() {
+	}
+}
+
 class Skin {
 	public var name : String;
 	public var joints : Array<SkinJoint>;
+	public var split : Null<Array<SkinSplit>>;;
 	public function new() {
 	}
 }

+ 5 - 0
hxd/fmt/hmd/Library.hx

@@ -72,6 +72,11 @@ class Library {
 			s.allJoints.push(j);
 			s.namedJoints.set(j.name, j);
 		}
+		if( skin.split != null ) {
+			s.splitJoints = [];
+			for( ss in skin.split )
+				s.splitJoints.push( { material : ss.materialIndex, joints : [for( j in ss.joints ) s.allJoints[j]] } );
+		}
 		cachedSkin.set(skin.name, s);
 		return s;
 	}

+ 32 - 18
hxd/fmt/hmd/Reader.hx

@@ -50,6 +50,36 @@ class Reader {
 		return b;
 	}
 
+	function readSkin() {
+		var name = readName();
+		if( name == null )
+			return 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);
+		}
+		var count = i.readByte();
+		if( count > 0 ) {
+			s.split = [];
+			for( k in 0...count ) {
+				var ss = new SkinSplit();
+				ss.materialIndex = i.readByte();
+				ss.joints = [for( k in 0...i.readByte() ) i.readUInt16()];
+				s.split.push(ss);
+			}
+		}
+		return s;
+	}
+
 	public function readHeader() : Data {
 		var d = new Data();
 		var h = i.readString(3);
@@ -70,7 +100,7 @@ class Reader {
 			g.vertexStride = i.readByte();
 			g.vertexFormat = [for( k in 0...i.readByte() ) new GeometryFormat(readName(), FORMATS[i.readByte()])];
 			g.vertexPosition = i.readInt32();
-			g.indexCount = i.readInt32();
+			g.indexCounts = [for( k in 0...i.readByte() ) i.readInt32()];
 			g.indexPosition = i.readInt32();
 			g.bounds = readBounds();
 			d.geometries.push(g);
@@ -101,23 +131,7 @@ class Reader {
 			m.materials = [];
 			for( k in 0...i.readByte() )
 				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;
-			}
+			m.skin = readSkin();
 		}
 
 		d.animations = [];

+ 27 - 13
hxd/fmt/hmd/Writer.hx

@@ -45,6 +45,28 @@ class Writer {
 		out.writeFloat(b.zMax);
 	}
 
+	function writeSkin( s : Skin ) {
+		writeName(s.name == null ? "" : s.name);
+		out.writeUInt16(s.joints.length);
+		for( j in s.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.writeByte(s.split == null ? 0 : s.split.length);
+		if( s.split != null ) {
+			for( ss in s.split ) {
+				out.writeByte(ss.materialIndex);
+				out.writeByte(ss.joints.length);
+				for( i in ss.joints )
+					out.writeUInt16(i);
+			}
+		}
+	}
+
 	public function write( d : Data ) {
 		var old = out;
 		var header = new haxe.io.BytesOutput();
@@ -60,7 +82,9 @@ class Writer {
 				out.writeByte(f.format.getIndex());
 			}
 			out.writeInt32(g.vertexPosition);
-			out.writeInt32(g.indexCount);
+			out.writeByte(g.indexCounts.length);
+			for( i in g.indexCounts )
+				out.writeInt32(i);
 			out.writeInt32(g.indexPosition);
 			writeBounds(g.bounds);
 		}
@@ -87,18 +111,8 @@ class Writer {
 				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);
-				}
-			}
+			else
+				writeSkin(m.skin);
 		}
 
 		out.writeInt32(d.animations.length);