فهرست منبع

[animgraph] Default pose node

Clément Espeute 9 ماه پیش
والد
کامیت
5e175f3ca2

+ 4 - 0
bin/style.css

@@ -4261,3 +4261,7 @@ graph-editor-root properties-container graph-parameters ul graph-parameter.folde
 graph-editor-root properties-container graph-parameters ul graph-parameter.folded .ico-chevron-down {
   transform: rotate(-90deg);
 }
+graph-editor-root properties-container graph-parameters ul graph-parameter .ico-chevron-down {
+  transition: transform 0.25s;
+  transform: rotate(0deg);
+}

+ 5 - 0
bin/style.less

@@ -5041,6 +5041,11 @@ graph-editor-root {
 					&.folded .ico-chevron-down {
 						transform: rotate(-90deg);
 					}
+
+					.ico-chevron-down {
+						transition: transform 0.25s;
+						transform: rotate(0deg);
+					}
 				}
 			}
 		}

+ 18 - 15
hide/view/animgraph/AnimGraphEditor.hx

@@ -60,18 +60,21 @@ class AnimGraphEditor extends GenericGraphEditor {
         });
     }
 
-    public function refreshAnimation() {
-        var anim = animGraph.getAnimation();
-        previewModel.playAnimation(anim);
-        previewAnimation = cast previewModel.currentAnimation;
-        refreshPamamList();
-    }
+    public function setPreview(newOutput: hrt.animgraph.nodes.AnimNode) {
+        previewNode = newOutput;
+
+        // refresh animation
+        {
+            if (previewModel == null)
+                return;
+            var anim = animGraph.getAnimation();
+            previewModel.playAnimation(anim);
+            previewAnimation = cast previewModel.currentAnimation;
+            refreshPamamList();
+        }
 
-    public function setPreview(newPreview: hrt.animgraph.nodes.AnimNode) {
-        previewNode = newPreview;
-        refreshAnimation();
         if (previewNode != null) {
-            var index = animGraph.nodes.indexOf(newPreview);
+            var index = animGraph.nodes.indexOf(newOutput);
             if (index == -1)
                 throw "Invalid node";
             previewAnimation.outputNode = cast previewAnimation.animGraph.nodes[index];
@@ -93,8 +96,6 @@ class AnimGraphEditor extends GenericGraphEditor {
 
             paramElement.toggleClass("folded", true);
 
-
-
             var name = paramElement.find("input");
             name.on("change", (e) -> {
                 var prev = param.name;
@@ -127,7 +128,6 @@ class AnimGraphEditor extends GenericGraphEditor {
                 e.dataTransfer.setDragImage(paramElement.get(0), Std.int(paramElement.width()), 0);
 
                 e.dataTransfer.setData("index", '${paramIndex}');
-
             }
 
             var content = new Element("<content></content>").appendTo(paramElement);
@@ -168,8 +168,7 @@ class AnimGraphEditor extends GenericGraphEditor {
         previewModel = scenePreview.loadModel("character/Kobold01/Model.FBX");
         scenePreview.s3d.addChild(previewModel);
 
-        // var anim = hxd.res.Loader.currentInstance.load("character/Kobold01/Anim_attack01.FBX").toModel().toHmd().loadAnimation();
-        // previewModel.playAnimation(anim);
+        setPreview(previewNode);
     }
 
     override function getNodes() : Iterator<IGraphNode> {
@@ -281,11 +280,15 @@ class AnimGraphEditor extends GenericGraphEditor {
     override function addEdge(edge : Edge) : Void {
         var inputNode = animGraph.getNodeByEditorId(edge.nodeToId);
         inputNode.inputEdges[edge.inputToId] = {target: animGraph.getNodeByEditorId(edge.nodeFromId), outputIndex: edge.outputFromId};
+
+        setPreview(previewNode);
     }
 
     override function removeEdge(nodeToId: Int, inputToId : Int) : Void {
         var inputNode = animGraph.getNodeByEditorId(nodeToId);
         inputNode.inputEdges[inputToId] = null;
+
+        setPreview(previewNode);
     }
 
     function addParameter() {

+ 6 - 2
hrt/animgraph/AnimGraphInstance.hx

@@ -21,6 +21,8 @@ class AnimGraphInstance extends h3d.anim.Animation {
 
 	var target : h3d.scene.Object = null;
 
+	var syncCtx = new hrt.animgraph.nodes.AnimNode.GetBoneTransformContext();
+
 	function new(animGraph:AnimGraph) {
 		// Todo : Define a true length for the animation OR make so animations can have an undefined length
 		super(animGraph.name, 1000, 1/60.0);
@@ -78,9 +80,11 @@ class AnimGraphInstance extends h3d.anim.Animation {
 		for (obj in objects) {
 			var obj : AnimGraphAnimatedObject = cast obj;
 			workMatrix.identity();
-			outputNode.getBoneTransform(obj.id, workMatrix);
-			@:privateAccess
+			syncCtx.reset(obj);
 
+			outputNode.getBoneTransform(obj.id, workMatrix, syncCtx);
+
+			@:privateAccess
 			var targetMatrix = if (obj.targetSkin != null) {
 				obj.targetSkin.jointsUpdated = true;
 				obj.targetSkin.currentRelPose[obj.targetJoint] ??= new h3d.Matrix();

+ 23 - 1
hrt/animgraph/Tools.hx

@@ -1,7 +1,6 @@
 package hrt.animgraph;
 
 class Tools {
-
 	@:haxe.warning("-WInlineOptimizedField")
 	static public function weightedBlend(inRotations: Array<h3d.Quat>, inReference: h3d.Quat, inWeights: Array<Float>, outRotation: h3d.Quat) {
 		outRotation.set(0,0,0,0);
@@ -30,4 +29,27 @@ class Tools {
 		inline outRotation.multiply(inReference, outRotation);
 		if (outRotation.w < 0) outRotation.conjugate();
 	}
+
+
+	static var workMatrix = new h3d.Matrix();
+	static public function splitMatrix(inMatrix: h3d.Matrix, outMatrix: h3d.Matrix) {
+		workMatrix.load(inMatrix);
+		var scale = inline workMatrix.getScale();
+		workMatrix.prependScale(1.0/scale.x, 1.0/scale.y, 1.0/scale.z);
+		var quat = inline new h3d.Quat();
+		inline quat.initRotateMatrix(workMatrix);
+
+		outMatrix.zero();
+
+		outMatrix._11 = scale.x;
+		outMatrix._22 = scale.y;
+		outMatrix._33 = scale.z;
+		outMatrix._12 = quat.x;
+		outMatrix._13 = quat.y;
+		outMatrix._21 = quat.z;
+		outMatrix._23 = quat.w;
+		outMatrix.tx = inMatrix.tx;
+		outMatrix.ty = inMatrix.ty;
+		outMatrix.tz = inMatrix.tz;
+	}
 }

+ 39 - 3
hrt/animgraph/nodes/AnimNode.hx

@@ -11,6 +11,40 @@ class GetBoneContext {
 	public var targetObject:h3d.scene.Object;
 }
 
+class GetBoneTransformContext {
+	public function new() {
+
+	}
+
+	public function reset(target: hrt.animgraph.AnimGraphInstance.AnimGraphAnimatedObject) {
+		defMatrix = null;
+		targetObj = target;
+	}
+
+	var targetObj : hrt.animgraph.AnimGraphInstance.AnimGraphAnimatedObject;
+
+	static var tmpWorkMatrix = new h3d.Matrix();
+	var tmpDefMatrix = new h3d.Matrix();
+	var defMatrix : h3d.Matrix = null;
+
+	/**
+		In the decomposed format
+	**/
+	@:haxe.warning("-WInlineOptimizedField")
+	public function getDefPose() : h3d.Matrix {
+		if (defMatrix != null) return defMatrix;
+		var m = if (targetObj.targetSkin != null) {
+			targetObj.targetSkin.getSkinData().allJoints[targetObj.targetJoint].defMat;
+		} else {
+			targetObj.targetObject.defaultTransform;
+		}
+		Tools.splitMatrix(m, tmpWorkMatrix);
+
+		defMatrix = tmpDefMatrix;
+		return defMatrix;
+	}
+}
+
 /**
 	An anim node outpus a animation that can be consumed as input parameter by other nodes
 **/
@@ -42,8 +76,10 @@ class AnimNode extends Node {
 			switch (input.type) {
 				case TAnimation:
 					var anim : AnimNode = cast Reflect.getProperty(this, input.name);
-					if (anim == null)
+					if (anim == null) {
+						currentInputId ++;
 						continue;
+					}
 					var animBones = anim.getBones(ctx);
 					for (name => id in animBones) {
 						var ourBoneId = boneMap.getOrPut(name, {
@@ -53,7 +89,7 @@ class AnimNode extends Node {
 							}
 							currentBoneId;
 						});
-						boneIdToAnimInputBone[getInputBoneId(ourBoneId, currentInputId)] = id; // we offset the id by one to differientate the 0 from the uninitialized entires in the array
+						boneIdToAnimInputBone[getInputBoneId(ourBoneId, currentInputId)] = id;
 					}
 					currentInputId ++;
 				default:
@@ -63,7 +99,7 @@ class AnimNode extends Node {
 		return boneMap;
 	}
 
-	function getBoneTransform(boneId: Int, outMatrix: h3d.Matrix) : Void {
+	function getBoneTransform(boneId: Int, outMatrix: h3d.Matrix, ctx: GetBoneTransformContext) : Void {
 	}
 
 	#if editor

+ 8 - 3
hrt/animgraph/nodes/Blend.hx

@@ -6,22 +6,27 @@ class Blend extends AnimNode {
 	@:input var alpha : Float = 0.5;
 
 	var tempMatrix: h3d.Matrix = new h3d.Matrix();
-	override function getBoneTransform(boneId:Int, outMatrix:h3d.Matrix) {
+	override function getBoneTransform(boneId:Int, outMatrix:h3d.Matrix, ctx: AnimNode.GetBoneTransformContext) {
 		if (a != null) {
 			var sourceBoneId = boneIdToAnimInputBone[getInputBoneId(boneId, 0)];
 			if (sourceBoneId != -1) {
-				a.getBoneTransform(sourceBoneId, tempMatrix);
+				a.getBoneTransform(sourceBoneId, tempMatrix, ctx);
 			} else {
 				tempMatrix = @:privateAccess h3d.anim.SmoothTransition.MZERO;
 			}
+		} else {
+			tempMatrix.load(ctx.getDefPose());
 		}
+
 		if (b != null) {
 			var sourceBoneId = boneIdToAnimInputBone[getInputBoneId(boneId, 1)];
 			if (sourceBoneId != -1) {
-				b.getBoneTransform(sourceBoneId, outMatrix);
+				b.getBoneTransform(sourceBoneId, outMatrix, ctx);
 			} else {
 				outMatrix.load(@:privateAccess h3d.anim.SmoothTransition.MZERO);
 			}
+		} else {
+			outMatrix.load(ctx.getDefPose());
 		}
 
 		var m1 = tempMatrix;

+ 2 - 2
hrt/animgraph/nodes/BlendPerBone.hx

@@ -34,7 +34,7 @@ class BlendPerBone extends AnimNode {
 		return map;
 	}
 
-	override function getBoneTransform(boneId: Int, outMatrix: h3d.Matrix) : Void {
+	override function getBoneTransform(boneId: Int, outMatrix: h3d.Matrix, ctx: AnimNode.GetBoneTransformContext) : Void {
 		for (animId in 0...2) {
 
 			var animBoneId = boneIdToAnimInputBone[getInputBoneId(boneId, animId)];
@@ -44,7 +44,7 @@ class BlendPerBone extends AnimNode {
 			if (anim == null) {
 				continue;
 			}
-			anim.getBoneTransform(animBoneId, outMatrix);
+			anim.getBoneTransform(animBoneId, outMatrix, ctx);
 			break;
 		}
 	}

+ 40 - 0
hrt/animgraph/nodes/DefaultPose.hx

@@ -0,0 +1,40 @@
+package hrt.animgraph.nodes;
+
+class DefaultPose extends AnimNode {
+
+	var object = h3d.scene.Object;
+	var objects : Array<{?object: h3d.scene.Object, ?skin: h3d.scene.Skin, ?joint: Int, ?matDecomposed: h3d.Matrix}> = [];
+
+	override function getBones(ctx:hrt.animgraph.nodes.AnimNode.GetBoneContext):Map<String, Int> {
+		objects = [];
+		var bones : Map<String, Int> = [];
+
+		var targetObjects = ctx.targetObject.findAll((f) -> f);
+		for (obj in targetObjects) {
+			var index = objects.length;
+			objects.push({object: obj});
+			bones.set(obj.name, index);
+		}
+
+		var skins = ctx.targetObject.findAll((f) -> Std.downcast(f, h3d.scene.Skin));
+		for (skin in skins) {
+			for (joint in skin.getSkinData().allJoints) {
+				var index = objects.length;
+				objects.push({skin: skin, joint: joint.index});
+				bones.set(joint.name, index);
+			}
+		}
+		return bones;
+	}
+
+	override function getBoneTransform(boneId:Int, outMatrix:h3d.Matrix, ctx:hrt.animgraph.nodes.AnimNode.GetBoneTransformContext) {
+		var bone = objects[boneId];
+		if (bone.matDecomposed == null) {
+			var m = bone.skin != null ? bone.skin.getSkinData().allJoints[bone.joint].defMat : bone.object.defaultTransform;
+			bone.matDecomposed = new h3d.Matrix();
+
+			Tools.splitMatrix(m, bone.matDecomposed);
+		}
+		outMatrix.load(bone.matDecomposed);
+	}
+}

+ 1 - 1
hrt/animgraph/nodes/Input.hx

@@ -36,7 +36,7 @@ class Input extends AnimNode {
 		@:privateAccess anim.isSync = false;
 	}
 
-	override function getBoneTransform(id: Int, matrix: h3d.Matrix) {
+	override function getBoneTransform(id: Int, matrix: h3d.Matrix, ctx: AnimNode.GetBoneTransformContext) {
 		// todo : add sync outside the getBoneMatrix to avoid checks
 		@:privateAccess
 		if (!anim.isSync) {