Przeglądaj źródła

[animgraph] Refactored AnimGraphInstance to be independant of the AnimGraph prefab

Clément Espeute 9 miesięcy temu
rodzic
commit
775a243e16

+ 3 - 11
hide/view/animgraph/AnimGraphEditor.hx

@@ -1,5 +1,5 @@
 package hide.view.animgraph;
 package hide.view.animgraph;
-
+using Lambda;
 import hide.view.GraphInterface;
 import hide.view.GraphInterface;
 import hrt.animgraph.*;
 import hrt.animgraph.*;
 
 
@@ -72,23 +72,15 @@ class AnimGraphEditor extends GenericGraphEditor {
         {
         {
             if (previewModel == null)
             if (previewModel == null)
                 return;
                 return;
-            var anim = animGraph.getAnimation();
+            var anim = animGraph.getAnimation(previewNode);
             previewModel.playAnimation(anim);
             previewModel.playAnimation(anim);
             previewAnimation = cast previewModel.currentAnimation;
             previewAnimation = cast previewModel.currentAnimation;
             refreshPamamList();
             refreshPamamList();
         }
         }
 
 
-        if (previewNode != null) {
-            var index = animGraph.nodes.indexOf(newOutput);
-            if (index == -1)
-                throw "Invalid node";
-            previewAnimation.outputNode = cast previewAnimation.animGraph.nodes[index];
-            @:privateAccess previewAnimation.bind(previewAnimation.target);
-        }
-
         // copy runtime parameters
         // copy runtime parameters
         for (index => param in animGraph.parameters) {
         for (index => param in animGraph.parameters) {
-            previewAnimation.animGraph.parameters[index].runtimeValue = param.runtimeValue;
+            animGraph.parameters[index].runtimeValue = param.runtimeValue;
         }
         }
         graphEditor.refreshPreviewButtons();
         graphEditor.refreshPreviewButtons();
     }
     }

+ 2 - 3
hrt/animgraph/AnimGraph.hx

@@ -18,7 +18,6 @@ typedef SerializedEdge = {
 
 
 @:access(hrt.animgraph.AnimGraphInstance)
 @:access(hrt.animgraph.AnimGraphInstance)
 class AnimGraph extends hrt.prefab.Prefab {
 class AnimGraph extends hrt.prefab.Prefab {
-	public var instance(default, null) : AnimGraphInstance;
 
 
 	var nodes: Array<Node> = [];
 	var nodes: Array<Node> = [];
 	var parameters : Array<Parameter> = [];
 	var parameters : Array<Parameter> = [];
@@ -35,8 +34,8 @@ class AnimGraph extends hrt.prefab.Prefab {
 		Get the animation "template" for this AnimGraph.
 		Get the animation "template" for this AnimGraph.
 		This anim should be instanciated using getInstance() after that (or use the h3d.scene.Object.playAnimation() function that does this for you)
 		This anim should be instanciated using getInstance() after that (or use the h3d.scene.Object.playAnimation() function that does this for you)
 	**/
 	**/
-	public function getAnimation(previewNode: Node = null) : AnimGraphInstance {
-		return instance ??= new AnimGraphInstance(this);
+	public function getAnimation(previewNode: hrt.animgraph.nodes.AnimNode = null) : AnimGraphInstance {
+		return AnimGraphInstance.fromAnimGraph(this, previewNode);
 	}
 	}
 
 
 	override function save() {
 	override function save() {

+ 58 - 31
hrt/animgraph/AnimGraphInstance.hx

@@ -1,5 +1,6 @@
 package hrt.animgraph;
 package hrt.animgraph;
-
+using Lambda;
+using hrt.tools.MapUtils;
 class AnimGraphAnimatedObject extends h3d.anim.Animation.AnimatedObject {
 class AnimGraphAnimatedObject extends h3d.anim.Animation.AnimatedObject {
 	public var id : Int;
 	public var id : Int;
 
 
@@ -12,8 +13,7 @@ class AnimGraphAnimatedObject extends h3d.anim.Animation.AnimatedObject {
 @:access(hrt.animgraph.AnimGraph)
 @:access(hrt.animgraph.AnimGraph)
 @:access(hrt.animgraph.Node)
 @:access(hrt.animgraph.Node)
 class AnimGraphInstance extends h3d.anim.Animation {
 class AnimGraphInstance extends h3d.anim.Animation {
-	var animGraph : AnimGraph;
-	var outputNode : hrt.animgraph.nodes.AnimNode;
+	var rootNode : hrt.animgraph.nodes.AnimNode;
 	var workMatrix = new h3d.Matrix();
 	var workMatrix = new h3d.Matrix();
 
 
 	var boneMap: Map<String, Int> = [];
 	var boneMap: Map<String, Int> = [];
@@ -24,38 +24,70 @@ class AnimGraphInstance extends h3d.anim.Animation {
 	var syncCtx = new hrt.animgraph.nodes.AnimNode.GetBoneTransformContext();
 	var syncCtx = new hrt.animgraph.nodes.AnimNode.GetBoneTransformContext();
 	var defaultPoseNode = new hrt.animgraph.nodes.DefaultPose();
 	var defaultPoseNode = new hrt.animgraph.nodes.DefaultPose();
 
 
-	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);
-		this.animGraph = animGraph;
+	static function fromAnimGraph(animGraph:AnimGraph, outputNode: hrt.animgraph.nodes.AnimNode = null) : AnimGraphInstance {
+		outputNode ??= cast animGraph.nodes.find((node) -> Std.downcast(node, hrt.animgraph.nodes.Output) != null);
+		if (outputNode == null)
+			throw "Animgraph has no output node";
 
 
-		defaultPoseNode = new hrt.animgraph.nodes.DefaultPose();
-		var output : hrt.animgraph.nodes.Output = cast Lambda.find(animGraph.nodes, (node) -> Std.downcast(node, hrt.animgraph.nodes.Output) != null);
-		if (output != null) {
-			map(output, updateNodeInputs);
-			outputNode = output.a;
-		}
+		var inst = new AnimGraphInstance(outputNode, animGraph.name, 1000, 1/60.0);
 
 
 		for (param in animGraph.parameters) {
 		for (param in animGraph.parameters) {
-			parameterMap.set(param.name, param);
+			inst.parameterMap.set(param.name, param);
 			param.runtimeValue = param.defaultValue;
 			param.runtimeValue = param.defaultValue;
 		}
 		}
+
+		return inst;
+	}
+
+	function new(rootNode: hrt.animgraph.nodes.AnimNode, name: String, framesCount: Int, sampling: Float) {
+		// Todo : Define a true length for the animation OR make so animations can have an undefined length
+		super(name, framesCount, sampling);
+		this.rootNode = rootNode;
+
+		defaultPoseNode = new hrt.animgraph.nodes.DefaultPose();
 	}
 	}
 
 
 	override function clone(?target: h3d.anim.Animation) : h3d.anim.Animation {
 	override function clone(?target: h3d.anim.Animation) : h3d.anim.Animation {
 		if (target != null) throw "Unexpected";
 		if (target != null) throw "Unexpected";
-		var newAnimGraph : AnimGraph = cast animGraph.clone();
-		var inst = super.clone(new AnimGraphInstance(newAnimGraph));
+
+		var inst = new AnimGraphInstance(null, name, frameCount, sampling);
+		inst.rootNode = cast cloneRec(rootNode, inst);
+		super.clone(inst);
 		return inst;
 		return inst;
 	}
 	}
 
 
+	static function cloneRec(node: hrt.animgraph.Node, inst: AnimGraphInstance) : hrt.animgraph.Node {
+		var cloned = hrt.animgraph.Node.createFromDynamic(node.serializeToDynamic());
+
+		var clonedParam = Std.downcast(cloned, hrt.animgraph.nodes.FloatParameter);
+		if (clonedParam != null) {
+			var nodeParam : hrt.animgraph.nodes.FloatParameter = cast node;
+			clonedParam.parameter = inst.parameterMap.getOrPut(nodeParam.parameter.name, {
+				var newParam = new hrt.animgraph.AnimGraph.Parameter();
+				@:privateAccess newParam.copyFromOther(nodeParam.parameter);
+				nodeParam.parameter.runtimeValue = nodeParam.parameter.defaultValue;
+				newParam;
+			});
+		}
+
+		for (id => edge in node.inputEdges) {
+			if (edge?.target != null) {
+				var targetClone = cloneRec(edge.target, inst);
+				cloned.inputEdges[id] = {target: targetClone, outputIndex: edge.outputIndex};
+			} else {
+				cloned.inputEdges[id] = null;
+			}
+		}
+		return cloned;
+	}
+
 	public function getBones(ctx : hrt.animgraph.nodes.AnimNode.GetBoneContext) : Map<String, Int> {
 	public function getBones(ctx : hrt.animgraph.nodes.AnimNode.GetBoneContext) : Map<String, Int> {
-		if (outputNode == null)
+		if (rootNode == null)
 			return null;
 			return null;
 
 
-		map(outputNode, updateNodeInputs);
+		map(rootNode, updateNodeInputs);
 
 
-		boneMap = outputNode.getBones(ctx);
+		boneMap = rootNode.getBones(ctx);
 		return boneMap;
 		return boneMap;
 	}
 	}
 
 
@@ -76,14 +108,14 @@ class AnimGraphInstance extends h3d.anim.Animation {
 	}
 	}
 
 
 	override function sync(decompose : Bool = false ) {
 	override function sync(decompose : Bool = false ) {
-		if (outputNode == null)
+		if (rootNode == null)
 			return;
 			return;
 		for (obj in objects) {
 		for (obj in objects) {
 			var obj : AnimGraphAnimatedObject = cast obj;
 			var obj : AnimGraphAnimatedObject = cast obj;
 			workMatrix.identity();
 			workMatrix.identity();
 			syncCtx.reset(obj);
 			syncCtx.reset(obj);
 
 
-			outputNode.getBoneTransform(obj.id, workMatrix, syncCtx);
+			rootNode.getBoneTransform(obj.id, workMatrix, syncCtx);
 
 
 			@:privateAccess
 			@:privateAccess
 			var targetMatrix = if (obj.targetSkin != null) {
 			var targetMatrix = if (obj.targetSkin != null) {
@@ -137,7 +169,7 @@ class AnimGraphInstance extends h3d.anim.Animation {
 	function map(root: Node, cb: (node:Node) -> Void) {
 	function map(root: Node, cb: (node:Node) -> Void) {
 		function rec (node: Node) {
 		function rec (node: Node) {
 			cb(node);
 			cb(node);
-			for (inputId => edge in node.inputEdges) {
+			for (edge in node.inputEdges) {
 				if (edge == null) continue;
 				if (edge == null) continue;
 				rec(edge.target);
 				rec(edge.target);
 			}
 			}
@@ -147,22 +179,17 @@ class AnimGraphInstance extends h3d.anim.Animation {
 
 
 	override function update(dt:Float):Float {
 	override function update(dt:Float):Float {
 		var dt2 = super.update(dt);
 		var dt2 = super.update(dt);
-		if (outputNode == null)
+		if (rootNode == null)
 			return dt2;
 			return dt2;
 
 
-		for (node in animGraph.nodes) {
-			node.tickedThisFrame = false;
-		}
-
-		tickRec(outputNode, dt);
+		map(rootNode, (node) -> node.tickedThisFrame = false);
+		tickRec(rootNode, dt);
 
 
 		return dt2;
 		return dt2;
 	}
 	}
 
 
 	function tickRec(node: hrt.animgraph.Node, dt: Float) {
 	function tickRec(node: hrt.animgraph.Node, dt: Float) {
-		var inputs = node.getInputs();
-
-		for (inputId => edge in node.inputEdges) {
+		for (edge in node.inputEdges) {
 			if (edge == null) continue;
 			if (edge == null) continue;
 			var outputNode = edge.target;
 			var outputNode = edge.target;
 			if (!outputNode.tickedThisFrame) {
 			if (!outputNode.tickedThisFrame) {

+ 1 - 1
hrt/animgraph/Macros.hx

@@ -39,7 +39,7 @@ class Macros {
 			cl = cl.superClass?.t.get();
 			cl = cl.superClass?.t.get();
 		}
 		}
 
 
-		if (inheritAnimNode) {
+		if (inheritAnimNode && cl.name != "Output" /* Output don't have an anim output ironically */) {
 			outputs.push(macro {
 			outputs.push(macro {
 				name: "",
 				name: "",
 				type: Node.OutputType.TAnimation,
 				type: Node.OutputType.TAnimation,

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

@@ -9,7 +9,7 @@ class FloatParameter extends Node {
 	}
 	}
 
 
 	override function tick(dt: Float) : Void {
 	override function tick(dt: Float) : Void {
-		value = parameter.runtimeValue;
+		value = parameter?.runtimeValue ?? 0;
 	}
 	}
 
 
 	override function getOutputNameOverride(name: String) : String {
 	override function getOutputNameOverride(name: String) : String {

+ 9 - 1
hrt/animgraph/nodes/Output.hx

@@ -3,7 +3,7 @@ package hrt.animgraph.nodes;
 /**
 /**
 	The result of this node can be used as an animation by other systems
 	The result of this node can be used as an animation by other systems
 **/
 **/
-class Output extends Node {
+class Output extends AnimNode {
 
 
 	@:input var a: AnimNode;
 	@:input var a: AnimNode;
 
 
@@ -29,4 +29,12 @@ class Output extends Node {
 		};
 		};
 		return info;
 		return info;
 	}
 	}
+
+	override function getBones(ctx:hrt.animgraph.nodes.AnimNode.GetBoneContext):Map<String, Int> {
+		return a.getBones(ctx);
+	}
+
+	override function getBoneTransform(boneId:Int, outMatrix:h3d.Matrix, ctx:hrt.animgraph.nodes.AnimNode.GetBoneTransformContext) {
+		return a.getBoneTransform(boneId, outMatrix, ctx);
+	}
 }
 }