-
-
Notifications
You must be signed in to change notification settings - Fork 98
Add Avatar State Package & XProp addressing #444
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: developer
Are you sure you want to change the base?
Conversation
- add Avatar State as a new package - introduce XProp addressing
Your suggestion seems to boil down to
but these are all still selectors and it creates an entirely new semantic universe for one to ask questions about "wait, which type is the important one here? What was the API designer's mental model here?" (and to be wrong about their speculations). I also don't seen an example demonstrating how ambiguous/redundant names are handled. Unfortunately, I think everything really is an object, both abstractly and concretely. The suggested language seems difficult to parse and the mental model justifying it is not strongly articulated. It seems more like it is working backwards from some data to describe its typical structure but it may not account comprehensively for weird - but plausible - hierarchies and component setups. |
|
It is probably also worth noting that although exact pointers may be resolvable left-to-right, the typical algorithm to resolve ambiguous queries (which in our case could be useful for any avatar gimmick that can attach to different parts of a hierarchy) are typically resolved from the most specific component to the least specific component. Some kind of component index to accelerate queries may help with that, since traversing a level up the hierarchy can be assumed to be very cheap. EDIT: silly me, the spec md didn't load for me so I skipped over it. Reading it. |
|
Okay, read over the spec. My substantive critique is:
|
At build we require basis avatar's and objects to not have duplicate gameobject names. So shouldn't be an issue at build, but if allowed a script could change the name of gameobject which can introduce the duplicate issue. |
|
|
My other comment I have is that couldn't this all be incorporated into cilbox or at least a cilbox script generator that will handle state syncing. Similar to how vrchat only deals with the privatives of ints, floats, and bools. Making an entire underlying system that is separate from our current scripting engine would just add complexity that not needed. |
It could, yes. Though the intention is for this to sync every avatar in the scene. Cilbox is interpreted CIL which is inherently slower, not to mention non-burst-able. Therefore I am building this as though it is an included package. If avatar state ends up being lightweight enough and someone wants to make a cilbox version that might be the way to go. Ultimately complex behavior and gimicks should be done with dynamicly loaded and sandboxed scripting of some kind, but that is intentionally out of scope. It is my opinion that a moderately flat and simple system will cover 85-95% of what people do with avatars (excluding scripted props like guns/knives/ect) VRC has different syncing methodology, full state is sent per packet so there isnt much the server or client needs to keep track of other than the most recent message. Parameter compression systems still work with the the most recent packet but do partial syncs per packet that rotate through the full state. We can do better by doing a bit of work on the server to keep track of avatar state. This will save on bandwidth and client complexity, but sacrifices a bit on server complexity. |
Yes, but this is not a problem. Basis would import these into whatever runtime format it needs. Users of Blender would still need to go through a common 3D model format to get to Basis, like glTF or FBX.
The typing is handled by the specification, not by the pointer itself. If you point to glTF
What you are describing here is almost exactly the same as Godot's NodePath syntax. https://docs.godotengine.org/en/stable/classes/class_nodepath.html To translate your example NodePath, it would be The existence of such a syntax requires that some characters are banned from the names of GameObjects. Godot disallows
In Godot's way,
This is a good requirement. Blender does this, Godot's glTF importer does this, G4MF does this. This enables us to unambiguously refer to GameObjects by name. |
My thought is to keep these serialized separately during authorship, since the exact method of embedding and extracting of this meta is inconsistent or inaccessible depending on the tool being used. glTF is the best candidate for embedding it with
This is true for known specs, but breaks down if you have systems that are dynamic or custom built. Say for example a unity scripting facet.
hahaha you are right, thats cool. Interesting to see how similar it is. Good to know since this would map fairly easily over to Godot.
Good practice, yeah. I would get @dooly123 to sign off on that since thats more a BEE file thing. The current spec has support for escape sequences in node names that would prevent most of the ways those would be abused.
This assumes that what is root is tied to the file/avatar root which isnt always assumed, for example a script on an avatar wanting to write a value to
agree. I think XProp could be thought of as more the start of a simplistic IDL/schema system, if you include avatar state as a whole. Authors serialize what an avatar can do and how they expect values to be, then the runtime can compress, morph, overwrite, ect without needing to meddle with the internals of how authors built their avatars. |
|
Question on not allowed in path, |
|
@Toys0125 Why would you want tooling to not perform the rename as soon as possible? I would find it very annoying to have the in-editor names not match the names after building, that sounds horrible to debug. As for Godot replaces |
Note that performance capture and replay is an explicitly desirable feature and will be unavoidable to implement anyways as a result. The question isn't whether the server complexity is increased by supporting it but whether it increases more when layered on top or when refactoring becomes required to support it. |
|
A note about the For example a writer and reader both internally represent a value as Part of the intent of Xprop is to be able to provide a binding interface and UI generation. example: Even that is fairly unnecessary since a rudimentary UI system could just read just a list of Xprops and generate a usable interface. I realize writing this however that this type info can just as well be included adjacently for ui generation, and is extraneous everywhere else since data types are typically known- especially with facets. I will be removing typehint from the spec. (it is Christmas eve so not today though.) |
Overview
This is the start of a series of PRs to build up avatar toggles/expressions (aka Avatar State) in Basis. Feedback and collaboration is desired as this will be fairly impactful for many framework users, end users, and content authors.
Goals of Avatar State
No Complex Behavior
It is a non-goal to handle complex behavior. Complex behavior should be written in a script or some other dynamic, application or future system. It will handle value updates on various aspects of an avatar and not much more.
Readable and Portable Serialization
Avatar authors should easily be able to debug and modify properties on their clothing, textures, scripts, and shaders. This means what is being modified should be easily understood, which unity animation name is not. (see XProp)
Ideally authors should be able to build these directly in the context of third party tools like blender. This means much of the serialized values should be stored as JSON (or easily converted to/from).
Sparse Wire Format
Avatar state is shared sparsely (deltas) to keep bandwidth usage low. Avatar state should include a manifest of what can be synced/modified. Syncing should only be sending updates by reference to that manifest and the new value. This means late joiners or lost events requires server stored state.
XProp
There already are ways in unity (SerializedPropertyName) to point to a property on a script or material. However this is not a unified or particularly readable format for content authors and users.
glTF has a much simpler scheme that boils down to JSON pointers https://datatracker.ietf.org/doc/html/rfc6901 however this is inherently tied to the file format and how it is serialized for that specific file. JSON pointers also inherently have loose typing, a specific path can refer to a single value or an entire object. This introduces complexity in the classic "everything is an object" way. Target values should be a simple scalar (float/bool/int) or very close (float3/rgb) so we can build ui and networking without doing too much work (and maybe squeak out more performance later on by being smart about compression/alignment).
Therefore I'm committing an xkcd 927.
Ok, now what?
What is consistent across many different 3d software is the hierarchy.
/Head/Hair/HatWith just that its possible to refer to a specific node in the tree easily, The problem is when we want to do something that's either on or related to that node. This is where we only specify what rough interface (aka facet) we can use to point to.
/Head/Hair/Hat::xformThis doesn't get us to a specific value, just what we can start using to read the following. The following can be fairly simple for well known and consistent properties.
/Head/Hair/Hat::xform:scaleNow we can make our hat big, what if we only want a really tall hat? Implementer and the parser doesnt really know how to do that, so lets have some simple types that the user can modify without needing to dig into the runtime to figure out what the target property actually is.
/Head/Hair/Hat::xform<float3>:scaleWhat about changing its color? Well we can define material properties easily enough through a straight "_MainColor". The issue is that there often more than one material on a given mesh, so lets make a way to specify that.
/Head/Hair/Hat::mat(2)<float3>:_MainColorInterpolating between values is common enough when changing values, however for some common values (quaternions and colors) behave poorly when linearly interpolated. It would also be nice for the UI to have a color picker, so lets add another type.
/Head/Hair/Hat::mat(2)<rgba>:_MainColorLets say we want to work with a unity Monobehavior directly! We already have a way to add qualifiers so let's add another for the type name, and for which one it is.
/Head/Hair/Hat::behavior(ParticleSystem, 0)<bool>:enabledIs
/Headat the scene root? root of the avatar? relative to the script? Lets add some distinction for authors and the sanity of admins.#/Head/Hair/Hat::behavior(ParticleSystem, 0)<bool>:enabledThen we can canonicalize it at runtime and insert the path leading up to that avatar! XProp starting with
/are now always root of the scene./RemoteAvatars/mriise/Head/Hair/Hat::behavior(ParticleSystem, 0)<bool>:enabledFor more info read XPropSpec.md