Closed viperscape closed 9 years ago
Cool!
The important bits, for me, keeping in mind that I personally want to use this for editing animation blend trees and state machines, would be:
Connection<SkeletalPose>
, while the "Blend Parameter" socket accepts a Connection<f32>
This probably requires a bit more of a specialized structure than just a generic graph.
I think edges can use an enum to specify connection types under one Type, and you can specify connections from multiple nodes, though probably max 1-1. Does that make sense? Otherwise I think we'll have to use runtime reflection with Any and TypeIds. So far I think hashmap with uuids will work fine, though removing nodes might incur cost, more on that soon. Can you elaborate on the sockets idea and blend trees? I'll read up as well
So I have a initial rough draft of some working graph code. Take a peek at what it's starting to shape up as. Lots more to do though!
Note that I have very minimal Edge data (just a To-Node and Weight), I think this might be ideal because it's less house keeping, edge's can then be generated at render time with a Uuid of (from.uuid + to.uuid) or something similar perhaps.
Looking good so far :)
To elaborate, here's a rough drawing of what a blend tree editor could look like:
This shows a really simple blend tree that blends the output of two animation clips, weighted by some float parameter between 0 and 1. Its important that the editor doesn't let you make invalid connections between sockets, e.g. you shouldn't be able to connect the 'output' socket of one AnimClip to the 'output' socket of another AnimClip, or hook up a float value socket to the 'Input 1' socket of the LerpBlend node.
See here for what the blend tree data looks like, and how I really don't want to force people to edit that by hand :)
Here's a rough idea of what the data structures could look like to support socket connections:
struct Node {
// Sockets on the right of the nodes, can only be connected to outputs
input_sockets: Vec<InputSocketUuid>,
// Sockets on the left lf the nodes, can only be connected to inputs
output_sockets: Vec<OutputSocketUuid>,
// SourceData could be a trait that describes a list of editable properties for the node
// (Similar to the old `EditableNode` trait)
data: Box<SourceData>,
}
type SocketType = String;
struct Socket {
socket_type: SocketType,
// Maybe it should also keep track of its node? not sure
node: NodeUuid,
label: String,
}
// Connections should validate that the input and output SocketTypes match
struct Connection{
input: InputSocketUuid,
output: OutputSocketUuid,
data: Box<SourceData>,
}
struct Graph {
nodes: HashMap<NodeUuid, Node>,
// Sockets on the right of the nodes, can only be connected to outputs
input_sockets: HashMap<InputSocketUuid, Socket>,
// Sockets on the left lf the nodes, can only be connected to inputs
output_sockets: HashMap<OutputSocketUuid, Socket>,
// It might be easier to keep the Connection/Edge map on the graph itself, otherwise to
// identify an edge/connection with its Uuid, we also need to know what its parent node is
connections: HashMap<ConnectionUuid, Connection>
}
// For a little extra type saftey, we can use different type aliases for Uuid:
type NodeUuid = Uuid;
type InputSocketUuid = Uuid;
type OutputSocketUuid = Uuid;
type ConnectionUuid = Uuid;
I guess the really big question is that if we also want an editor for a 'simple' graph, where nodes are directly connected by edges, maybe that needs to use a different editor/data structure altogether?
I feel a bit more confident in the graph code now, so I want to tackle two things: bringing in a trait so the backend can be swapped out for something like petgraph if wanted; and the blend graph with node guards like you are aiming for. I think we can get both a basic graph and a blend graph in one code base
As seen here I am wondering if it beneficial or necessary to create a transformation trait, and perhaps even some basic functionality for node transformations, such as the mixer in a blend graph. I'm not sure how this would work really, but seeing what I've read up on blend graphs, this seems like a good idea. If the blend will only ever use a single float value(like crouch_run, stand_run, blend_float), it'd be considerably simpler to reuse the edge-weight factors for this; however then a blend is locked in to a single describing factor and that just seems too limiting.
closed by #24 more discussion on node-connection types can continue here
I've started working on a custom graph backend as well a trait system to use other libs; I want to share soon as I get something working, but wanted to see exactly what we'll need for this to be useful so starting a discussion.