浏览代码

support multimaterial + skin split

ncannasse 11 年之前
父节点
当前提交
59500f7690
共有 4 个文件被更改,包括 54 次插入25 次删除
  1. 8 7
      h3d/anim/Skin.hx
  2. 24 9
      h3d/prim/FBXModel.hx
  3. 18 7
      h3d/scene/Skin.hx
  4. 4 2
      hxd/fmt/fbx/Library.hx

+ 8 - 7
h3d/anim/Skin.hx

@@ -40,7 +40,7 @@ class Skin {
 	public var primitive : h3d.prim.Primitive;
 
 	// spliting
-	public var splitJoints(default, null) : Array<Array<Joint>>;
+	public var splitJoints(default, null) : Array<{ material : Int, joints : Array<Joint> }>;
 	public var triangleGroups : haxe.ds.Vector<Int>;
 
 	var envelop : Array<Array<Influence>>;
@@ -109,7 +109,7 @@ class Skin {
 		envelop = null;
 	}
 
-	public function split( maxBones : Int, index : Array<Int> ) {
+	public function split( maxBones : Int, index : Array<Int>, triangleMaterials : Null<Array<Int>> ) {
 		if( isSplit() )
 			return true;
 		if( boundJoints.length <= maxBones )
@@ -120,7 +120,7 @@ class Skin {
 
 		// collect joints groups used by triangles
 		var curGroup = new Array<Joint>(), curJoints = [];
-		var ipos = 0, tpos = 0;
+		var ipos = 0, tpos = 0, curMat = triangleMaterials == null ? 0 : triangleMaterials[0];
 		while( ipos <= index.length ) {
 			var tjoints = [], flush = false;
 			if( ipos < index.length ) {
@@ -137,21 +137,22 @@ class Skin {
 					}
 				}
 			}
-			if( curGroup.length + tjoints.length <= maxBones && ipos < index.length ) {
+			if( curGroup.length + tjoints.length <= maxBones && ipos < index.length && (triangleMaterials == null || triangleMaterials[tpos] == curMat) ) {
 				for( j in tjoints )
 					curGroup.push(j);
 				triangleGroups[tpos++] = splitJoints.length;
 				ipos += 3;
 			} else {
-				splitJoints.push(curGroup);
+				splitJoints.push({ material : curMat, joints : curGroup });
 				curGroup = [];
 				curJoints = [];
+				if( triangleMaterials != null ) curMat = triangleMaterials[tpos];
 				if( ipos == index.length ) break;
 			}
 		}
 
 		// assign split indexes to joints
-		var groups = [for( i in 0...splitJoints.length ) { id : i, reserved : [], joints : splitJoints[i] }];
+		var groups = [for( i in 0...splitJoints.length ) { id : i, reserved : [], joints : splitJoints[i].joints, mat : splitJoints[i].material }];
 		var joints = [for( j in boundJoints ) { j : j, groups : [], index : -1 } ];
 		for( g in groups )
 			for( j in g.joints )
@@ -187,7 +188,7 @@ class Skin {
 				if( j == null ) j = boundJoints[0];
 				jl.push(j);
 			}
-			splitJoints.push(jl);
+			splitJoints.push( { material : g.mat, joints : jl } );
 		}
 
 		// rebind

+ 24 - 9
h3d/prim/FBXModel.hx

@@ -84,6 +84,24 @@ 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();
 
@@ -108,10 +126,8 @@ class FBXModel extends MeshPrimitive {
 
 		// skin split
 		var sidx = null, stri = 0;
-		if( skin != null && skin.isSplit() ) {
-			if( multiMaterial ) throw "Multimaterial not supported with skin split";
+		if( skin != null && skin.isSplit() )
 			sidx = [for( _ in skin.splitJoints ) new hxd.IndexBuffer()];
-		}
 
 		// triangulize indexes : format is  A,B,...,-X : negative values mark the end of the polygon
 		var count = 0, pos = 0, matPos = 0;
@@ -223,7 +239,7 @@ class FBXModel extends MeshPrimitive {
 					}
 				}
 				// by-material index
-				if( mats != null ) {
+				else if( mats != null ) {
 					var mid = mats[matPos++];
 					var idx = midx[mid];
 					if( idx == null ) {
@@ -255,15 +271,14 @@ class FBXModel extends MeshPrimitive {
 		if( cbuf != null ) addBuffer("color", h3d.Buffer.ofFloats(cbuf, 3));
 
 		indexes = h3d.Indexes.alloc(idx);
-		if( mats != null ) {
-			groupIndexes = [];
-			for( i in midx )
-				groupIndexes.push(i == null ? null : h3d.Indexes.alloc(i));
-		}
 		if( sidx != null ) {
 			groupIndexes = [];
 			for( i in sidx )
 				groupIndexes.push(i == null ? null : h3d.Indexes.alloc(i));
+		} else if( mats != null ) {
+			groupIndexes = [];
+			for( i in midx )
+				groupIndexes.push(i == null ? null : h3d.Indexes.alloc(i));
 		}
 	}
 

+ 18 - 7
h3d/scene/Skin.hx

@@ -135,7 +135,7 @@ class Skin extends MultiMaterial {
 		if( skinData.splitJoints != null ) {
 			splitPalette = [];
 			for( a in skinData.splitJoints )
-				splitPalette.push([for( j in a ) currentPalette[j.bindIndex]]);
+				splitPalette.push([for( j in a.joints ) currentPalette[j.bindIndex]]);
 		} else
 			splitPalette = null;
 	}
@@ -165,16 +165,27 @@ class Skin extends MultiMaterial {
 			super.sync(ctx);
 	}
 
+	override function emit( ctx : RenderContext ) {
+		if( splitPalette == null )
+			super.emit(ctx);
+		else {
+			for( i in 0...splitPalette.length ) {
+				var m = materials[skinData.splitJoints[i].material];
+				if( m != null )
+					ctx.emit(m, this, i);
+			}
+		}
+	}
+
 	override function draw( ctx : RenderContext ) {
 		if( splitPalette == null ) {
 			super.draw(ctx);
 		} else {
-			for( i in 0...splitPalette.length ) {
-				skinShader.bonesMatrixes = splitPalette[i];
-				primitive.selectMaterial(i);
-				ctx.uploadParams();
-				primitive.render(ctx.engine);
-			}
+			var i = ctx.drawPass.index;
+			skinShader.bonesMatrixes = splitPalette[i];
+			primitive.selectMaterial(i);
+			ctx.uploadParams();
+			primitive.render(ctx.engine);
 		}
 		if( showJoints )
 			throw "TODO"; //ctx.addPass(drawJoints);

+ 4 - 2
hxd/fmt/fbx/Library.hx

@@ -961,8 +961,10 @@ class Library {
 				defaultModelMatrixes.get(m.name).wasRemoved = o.model.getId();
 			}
 			// set skin after materials
-			if( skinData.boundJoints.length > maxBonesPerSkin )
-				skinData.split(maxBonesPerSkin, Std.instance(skinData.primitive,h3d.prim.FBXModel).geom.getIndexes().vidx);
+			if( skinData.boundJoints.length > maxBonesPerSkin ) {
+				var model = Std.instance(skinData.primitive, h3d.prim.FBXModel);
+				skinData.split(maxBonesPerSkin, model.geom.getIndexes().vidx, model.multiMaterial ? model.getMaterialByTriangle() : null);
+			}
 			skin.setSkinData(skinData);
 		}