Alembic Exporter

124678

Comments

  • Padone said:

    @TheMysteryIsThePoint

    If it may help as for geografts the diffeomorphic approach is to import them as is to allow for morphs, then to merge them once the morphs are imported fine. This is complex enough since there are also some cases of nesting geografts in parent child relationship. Plus geografts are often using multiple shells to blend materials.

    As for shells the diffeomorphic approach is to translate them into an extra material layer. This is not entirely correct since in daz studio a shell does get its own geometry. But since shells are generally used to add an extra material layer this works fine enough and has the advantage of reducing unnecessary geometry complexity. This may very well conflict with shell geometry from an alembic importer though.

    https://bitbucket.org/Diffeomorphic/import_daz/issues/38/better-geografts

    https://bitbucket.org/Diffeomorphic/import_daz/issues/70/weird-geograft-issue

    Thanks, @Padone, I think I am beginning to understand. I'll think more about this once the normals and materials issues are completely solved.

  • Hi guys, I don't have any unit tests on Windows, and I don't undedrstand what Blender is doing 100% yet, but I've fixed the normals problem as far as I can tell. I'll publish the updated version tomorrow. The materials scripts will come a little later as there are some things I have to work out in order to best leverage the work already done in the Daz Importer, which I grow more impressed with every time I look at its source. It is doing a lot.

  • OK, version 1.10 is at https://drive.google.com/open?id=1rd5wjf58A9E5pQfV2Kp2E7jA6FjcDZGD

    The normals issue has been resolved, I think, and it should no longer gratuitously ask if you want to save the configuration.

    The "separate" checkbox for surfaces is meant to give the option to export a surface as a separate object, as often it is useful to apply different modifiers to it once in Blender. That has not been implemented yet.

     I changed the buttons to make manipulating the ignore/dynamic checkboxes a bit more convenient, but after I uploaded the new version , I discovered a small bug in the "check/clear all" button: It creates "separate" checkboxes for objects, which of course doesn't make any sense. They have no effect on anything, though.

    Please test and let me know of any issues.

  • Version 1.10.1 is up, fixing those bugs, and making the dialog smaller. The buttons at the bottom now act as toggles.

    I'm going to work on the materials script, and then the separate functionality.

  • JClaveJClave Posts: 64

    Version 1.10.1 is up, fixing those bugs, and making the dialog smaller. The buttons at the bottom now act as toggles.

    I'm going to work on the materials script, and then the separate functionality.

    Thanks a lot for your hard work.

    I tested both 1.10.1 and 1.10 just now.

    I'm not sure what I'm doing wrong.

    But I still have the normal bug when I import Alembic using this in Blender. (tested 2.90, 2.83, 2.82)

     

    Capture.PNG
    1047 x 1009 - 849K
  • PadonePadone Posts: 3,688
    edited July 2020

    @JClave From what I can see that's a unsubdivided model, if autosmooth to 89.9 is used that's the daz default then it's expected that some polygons will be flat, see the ears for example. If you subdivide the model then it should work fine.

    Otherwise autosmooth can be set to smooth everything.

    Post edited by Padone on
  • JClaveJClave Posts: 64
    Padone said:

    @JClave From what I can see that's a unsubdivided model, if autosmooth to 89.9 is used that's the daz default then it's expected that some polygons will be flat, see the ears for example. If you subdivide the model then it should work fine.

    Otherwise autosmooth can be set to smooth everything.

    I have tested both caged export and subd applied export.

    I had the normal issue on both.

    As discussed earlier, there's a workaround to fix this, which is applying 'Set From Faces' in Edit Mode.

    It sounded like @TheMysteryIsThePoint fixed this issue in the latest updates but I'm puzzled about the bug existing in my testing.

     

    capture 2.png
    1083 x 975 - 816K
  • PadonePadone Posts: 3,688
    edited July 2020

    Got it. I did a simple export of a full animation at the current subd level, I guess this is what alembic is for since it has to bake all the modifiers and physics to vertex animation. It seems I got no issues with normals it's everything fine here. Scene included.

    I didn't test materials since I understand it's a work in progress yet.

    If I may suggest something. I'd place the menu in file > Alembic Exporter rather than edit, possibly in the import export section, since it's where usually the exporters get placed. Also daz studio has its own folder for exported files that opens up when you export to any format, so in my opinion the alembic exporter should use the export folder rather than creating a new folder in the scenes folder. I mean the scenes folder in daz studio is for scenes and it's not intended for exported data. Also the exported file could have the same name of the daz scene instead of a generic alembic name.

    test.jpg
    271 x 483 - 29K
    duf
    duf
    alembic.duf
    196K
    export.jpg
    215 x 299 - 18K
    Post edited by Padone on
  • TheMysteryIsThePointTheMysteryIsThePoint Posts: 2,946
    edited July 2020
    Padone said:
    If I may suggest something. I'd place the menu in file > Alembic Exporter rather than edit, possibly in the import export section, since it's where usually the exporters get placed. Also daz studio has its own folder for exported files that opens up when you export to any format, so in my opinion the alembic exporter should use the export folder rather than creating a new folder in the scenes folder. I mean the scenes folder in daz studio is for scenes and it's not intended for exported data. Also the exported file could have the same name of the daz scene instead of a generic alembic name.

    Of course, @Padone, your input is particularly welcome. I knew it was wrong as I was implementing it; the SDK example on which I based the exporter had it under the edit menu and I simply never got around to moving it to the proper place. I will certainly move it.

    Personally, I export to a particular directory that is project, scene, shot, and character specific, and more importantly, is on a NAS device I can access from Linux, where I do everything else, amd that has RAID and also backed up offsite. I think I will make the default directory this Daz export directory, as you say.

    Also, the scene name is generic, but the directory it resides in is not. Sometimes it is useful for the alembic file to have a generic name, so I should make this configurable.

    Thanks!

    Post edited by TheMysteryIsThePoint on
  • JClave said:

    Thanks a lot for your hard work.

    I tested both 1.10.1 and 1.10 just now.

    I'm not sure what I'm doing wrong.

    But I still have the normal bug when I import Alembic using this in Blender. (tested 2.90, 2.83, 2.82)

    Hi @JClave,

    You exported a single frame, right? Please try turning smoothing off in the properties window's Vertex tab, under the Normals panel.

    Blender treats these cases differently. When it's a single frame, Blender doesn't apply a Mesh Sequence Cache Modifier at all, and I think that modifier handles normals differently since after 2.80 (which doesn't exhibit any of these abnormalities). I can't say that I completely understand what is going on yet.

  • marblemarble Posts: 7,500

    I'm hanging on for the finished materials script and any progress on the Geografts. I've become a little lost trying to follow the conversation above because there are so many references to things like subdivision yet no mention of which application or perhaps a menu item in the script itself. Clealry there are some familiar with all aspects and all applications involved but I'm not one of them so I would appreciate a mention of where to find the suggested actions.

  • marble said:

    I'm hanging on for the finished materials script and any progress on the Geografts. I've become a little lost trying to follow the conversation above because there are so many references to things like subdivision yet no mention of which application or perhaps a menu item in the script itself. Clealry there are some familiar with all aspects and all applications involved but I'm not one of them so I would appreciate a mention of where to find the suggested actions.

    Hi @marble, the materials script is going to require a little more thinking, but as far as I know, geografts currently work at least in the sense that all the geometry you want gets exported, the problem being that it also exports some that you don't. Did you have some difficulty discovering what those surfaces were, and configuring the exporter to ignore them?

  • marblemarble Posts: 7,500
    marble said:

    I'm hanging on for the finished materials script and any progress on the Geografts. I've become a little lost trying to follow the conversation above because there are so many references to things like subdivision yet no mention of which application or perhaps a menu item in the script itself. Clealry there are some familiar with all aspects and all applications involved but I'm not one of them so I would appreciate a mention of where to find the suggested actions.

    Hi @marble, the materials script is going to require a little more thinking, but as far as I know, geografts currently work at least in the sense that all the geometry you want gets exported, the problem being that it also exports some that you don't. Did you have some difficulty discovering what those surfaces were, and configuring the exporter to ignore them?

    TBH I didn't try again. I decided to wait until the various components come together and are ready. That includes materials, geografts, normals, subdivision and whatever else. I'm hoping for some kind of walkthough on how to get from A to B (or DS to B) because there is so much that I am not familiar with. For example, the part of the discussion on subdivision was lost on me as was the reference to the "cage". I feel like I'm a casual jogger trying to keep up with Olympic sprinters at times.

  • I thought I would ask, before I started to implement this:

    PAs are very sloppy about naming their material groups, and none use any name space method to prevent name collisions.

    Daz Importer does an admirable job of renaming them to make them unique, but the most obvious method of re-texturing the Alembic export depends on it's notion of the material group names being the same as the Daz Importer's notion. This adds a point of fragility to the re-texturing effort since it would have to mimic Daz Importer's logic for making the material group names unique so that it would derive the same names. I don't want to do this.

    So, since I do not think Daz Importer cares what the material groups are called, I am thinking that the Alembic Exporter could just change any material group names in order to make them all unique, before Daz Importer is run, so that Daz Importer will never have to change them.

    But the question is: Does anything else in Daz Studio care what the material group names are? I could pretty easily have an option like "convert to export-friendly material group names" and also "revert to original material group names", but this would seem like a hack on top of a hack.

    I'm open to suggestions. Am I missing an easier option?

     

  • JClaveJClave Posts: 64
    edited July 2020

    You exported a single frame, right? Please try turning smoothing off in the properties window's Vertex tab, under the Normals panel.

    Blender treats these cases differently. When it's a single frame, Blender doesn't apply a Mesh Sequence Cache Modifier at all, and I think that modifier handles normals differently since after 2.80 (which doesn't exhibit any of these abnormalities). I can't say that I completely understand what is going on yet.

    Yes correct. I exported a single frame.

    Disabling Smoothing does not help in this case. Only the 'Set From Face' button mentioned earlier fixes it.
     

    I thought I would ask, before I started to implement this:

    PAs are very sloppy about naming their material groups, and none use any name space method to prevent name collisions.

    Daz Importer does an admirable job of renaming them to make them unique, but the most obvious method of re-texturing the Alembic export depends on it's notion of the material group names being the same as the Daz Importer's notion. This adds a point of fragility to the re-texturing effort since it would have to mimic Daz Importer's logic for making the material group names unique so that it would derive the same names. I don't want to do this.

    So, since I do not think Daz Importer cares what the material groups are called, I am thinking that the Alembic Exporter could just change any material group names in order to make them all unique, before Daz Importer is run, so that Daz Importer will never have to change them.

    But the question is: Does anything else in Daz Studio care what the material group names are? I could pretty easily have an option like "convert to export-friendly material group names" and also "revert to original material group names", but this would seem like a hack on top of a hack.

    I'm open to suggestions. Am I missing an easier option?

     

    Sorry, I'm not clear what 'material group' is referring to.

    #1 Is it referring to individual material in the following?

    https://imgur.com/oM3byeK

    #2 Or is it referring to the following in Daz?

    https://imgur.com/thMPBTk

     

    If you are referring to #1,

    Diffeomorphic uses material id's that are in the .duf file:

    https://imgur.com/yRxx9aR

    If you follow this approach, that would make logical sense to me.

    These id's are unique in a given scene.

     

    I'm writing my own material script to work with your alemic exporter as well.

    So if you go down this path, it would help me in addition to being compatible with Diffeomorphic

    Post edited by JClave on
  • mindsongmindsong Posts: 1,701
    edited July 2020

    FWIW, I can only suggest that a possible answer may lie in looking at the existing Blender naming conventions, rather than dragging the mentioned DS naming messes forward.

    That said, if the existing DS names (e.g. "Left_Iris_1") have usable meaning, regardless the ad-hoc nature and conventions used, we'd hate to lose that in the transfer since manual material tweaking in Blender will he easier with any available tagging.

    So, if there is a Blender material naming convention in place, perhaps looking at the question from that lens would help inspire a workable choice. I'm also thinking formatting, more than re-mapping. Maybe just prefix or suffix the DS materials with numbers or such, and replace special chars (e.g. spaces, etc.) with '_' or such.

    (I believe I understand the question being asked correctly)

    cheers,

    --ms

    ETA - As I scratch the surface of this gem, it's already impressive how nice it is when something "just works"... Speaks to the craftsman.

    Post edited by mindsong on
  • JClave said:

    You exported a single frame, right? Please try turning smoothing off in the properties window's Vertex tab, under the Normals panel.

    Blender treats these cases differently. When it's a single frame, Blender doesn't apply a Mesh Sequence Cache Modifier at all, and I think that modifier handles normals differently since after 2.80 (which doesn't exhibit any of these abnormalities). I can't say that I completely understand what is going on yet.

    Yes correct. I exported a single frame.

    Disabling Smoothing does not help in this case. Only the 'Set From Face' button mentioned earlier fixes it.

    All's well that ends well, I suppose, but like I said, I don't understand what's going on. For me, with a single frame, I need only turn smoothing off.

    JClave said:

     


     

    I thought I would ask, before I started to implement this:

    PAs are very sloppy about naming their material groups, and none use any name space method to prevent name collisions.

    Daz Importer does an admirable job of renaming them to make them unique, but the most obvious method of re-texturing the Alembic export depends on it's notion of the material group names being the same as the Daz Importer's notion. This adds a point of fragility to the re-texturing effort since it would have to mimic Daz Importer's logic for making the material group names unique so that it would derive the same names. I don't want to do this.

    So, since I do not think Daz Importer cares what the material groups are called, I am thinking that the Alembic Exporter could just change any material group names in order to make them all unique, before Daz Importer is run, so that Daz Importer will never have to change them.

    But the question is: Does anything else in Daz Studio care what the material group names are? I could pretty easily have an option like "convert to export-friendly material group names" and also "revert to original material group names", but this would seem like a hack on top of a hack.

    I'm open to suggestions. Am I missing an easier option?

     

    Sorry, I'm not clear what 'material group' is referring to.

    #1 Is it referring to individual material in the following?

    https://imgur.com/oM3byeK

    #2 Or is it referring to the following in Daz?

    https://imgur.com/thMPBTk

     

    If you are referring to #1,

    Diffeomorphic uses material id's that are in the .duf file:

    https://imgur.com/yRxx9aR

    If you follow this approach, that would make logical sense to me.

    These id's are unique in a given scene.

     

    I'm writing my own material script to work with your alemic exporter as well.

    So if you go down this path, it would help me in addition to being compatible with Diffeomorphic

    In trying to explain myself better, I think I found a more robust solution, as sometimes happens :) I do see that value in staying Diffeo-compatible, and that is my goal. There's just too much quality work done in it for it not to be the pole star around which we all revolve.

     

  • JClave said:
    If you are referring to #1,

    Diffeomorphic uses material id's that are in the .duf file:

    https://imgur.com/yRxx9aR

    OK, I think I'm getting it. In the snippet you showed, the globally unique ID is "Face-1", while the surface is "Face". The Daz importer uses the ID instead of the Surface Name because in Blender, we don't really have "Surface Name" and instead the material slot takes on the name of the material, which has to be globally unique. So the ID is a much better equivlent for material slot names than Surface Name. Also, it's not the Daz Importer numbering the material IDs, it's Daz Studio.

    I think the propert solution is to just modify the Alembic Exporter to also use the material ID (which is globally unique) as the Alembic Face Set name that ultimately determine the material slot name. Right now it uses the Surface Name, which is not globally unique. Doing so is a bug because if there were ever a name collision in the Surface Name of two distinct objects, they would both get the same material in Blender.

    Thanks for your input, I know what needs to be done now.

  • mindsongmindsong Posts: 1,701
    edited July 2020
    JClave said:
    ...

    All's well that ends well, I suppose, but like I said, I don't understand what's going on. For me, with a single frame, I need only turn smoothing off.

    I was gonna do two frame exports just to get the desired result... :)

    I'll have to review the history/discussion now that I'm playing with this. Too cool, this.

    JClave said:
    ...

    I'm writing my own material script to work with your alemic exporter as well.

    So if you go down this path, it would help me in addition to being compatible with Diffeomorphic

    In trying to explain myself better, I think I found a more robust solution, as sometimes happens :) I do see that value in staying Diffeo-compatible, and that is my goal. There's just too much quality work done in it for it not to be the pole star around which we all revolve.

    yay - to your new idea/approach, but esp. to your stayng diffeo-compatible.  Appreciating that you're taking on that challenge. It will be appreciated.

    --ms

    (edits - rewording thoughts)

    Post edited by mindsong on
  • mindsong said:

    FWIW, I can only suggest that a possible answer may lie in looking at the existing Blender naming conventions, rather than dragging the mentioned DS naming messes forward.

    That said, if the existing DS names (e.g. "Left_Iris_1") have usable meaning, regardless the ad-hoc nature and conventions used, we'd hate to lose that in the transfer since manual material tweaking in Blender will he easier with any available tagging.

    So, if there is a Blender material naming convention in place, perhaps looking at the question from that lens would help inspire a workable choice. I'm also thinking formatting, more than re-mapping. Maybe just prefix or suffix the DS materials with numbers or such, and replace special chars (e.g. spaces, etc.) with '_' or such.

    (I believe I understand the question being asked correctly)

    cheers,

    --ms

    ETA - As I scratch the surface of this gem, it's already impressive how nice it is when something "just works"... Speaks to the craftsman.

    Believe it or not, I'm siding with Daz Studio on this one. I don't understand why Blender would not provide the same level of indirection that Daz Studio has, i.e. material slots have names, independent of the material assigned to them. Why would the material slot associated with the faces that make up the rubies of a crown object not be named "gems" and refer to a material called "ruby"? Instead, the material slot assumes the name of whatever material applied to it and is referred to by its ordinal position. I don't get why that would be the case, unless Blender predates C++ and there were no associative container types, just arrays?

    In any case, we're kind of stuck with it and I just figured out (with @JClave's help) what Thomas probably did a long time ago: Blender's material slots are much more akin to Daz Studio's Material IDs than to Daz Studio's Surface Names.

    Ha ha, slow and steady wins the race... we'll get there.

  • mindsong said:
    JClave said:
    ...

    All's well that ends well, I suppose, but like I said, I don't understand what's going on. For me, with a single frame, I need only turn smoothing off.

    I was gonna do two frame exports just to get the desired result... :)

    I'll have to review the history/discussion now that I'm playing with this. Too cool, this.

    JClave said:
    ...

    I'm writing my own material script to work with your alemic exporter as well.

    So if you go down this path, it would help me in addition to being compatible with Diffeomorphic

    In trying to explain myself better, I think I found a more robust solution, as sometimes happens :) I do see that value in staying Diffeo-compatible, and that is my goal. There's just too much quality work done in it for it not to be the pole star around which we all revolve.

    yay - to your new idea/approach, but esp. to your stayng diffeo-compatible.  Appreciating that you're taking on that challenge. It will be appreciated.

    --ms

    (edits - rewording thoughts)

    Like I said, the more Diffeo code I look at, the more I appreciate how Thomas and company are incredibly thorough and detail oriented. I'd be an arrogant fool to think that I could just ignore all of that and come up with something better. Thomas is a giant and I am smart enough to stand on his shoulders.

  • PadonePadone Posts: 3,688
    edited July 2020

    @TheMysteryIsThePoint

    Just to say that I agree with @JClave to use the daz studio material ids. As for material groups they're used by diffeomorphic in the mini material editor to allow the user to change multiple materials at once the same as in daz studio, that's actually a weak point in the blender material manager, but this shouldn't concern the alembic exporter I guess.

    groups.jpg
    363 x 296 - 29K
    Post edited by Padone on
  • Sometimes I want to just give up. It's as if Daz is an entity, and is somewhere in the darkness laughing at me and my meager efforts to use Daz the way I want to.

    The class that probably knows what material is associated with each surface, DzMaterialFaceGroup, is undocumented, and I can't figure out how to determine the material associated with a surface, in order to get its asset ID to name the Blender material slot, like Daz Importer does.

    I can dump all the materials associated with a node, and print their asset IDs, and sure enough, as @JClave pointed out, they look much like the material slots that Daz Importer uses.

    Each face is associated with a material group, but the link between a material group and a material (and therefore an id) is unknown, so I don't know with which id to associate each face.

    If I can't figure this one out, the Alembic Exporter is going to have to parse the duf file as well, because obviously, the information is in there.

  • mindsongmindsong Posts: 1,701

    FWIW, Per some initial tests, if you are a user of the VWD cloth and hair simulation engine (from rendo) in DS, it looks like @TheMysteryIsThePoint's exporter will properly 'see' and export the simulated mesh animated sequence (xxx_VWD) as a 'standard' alembic (*.abc) file. Do the export along with the animated figure, and it imports and renders perfectly (at least on my basic tests) in Blender. In this way DS becomes a VWD simulation to *.abc converter, If you use/like VWD, and your final workflow animations are based out of DS, this could be a huge win. Also, if an arbitrary cloth item is simulating/colliding off of static DS non-figure scene elements (e.g. drapes in a window, w/ wind, flags in the wind, sheets on beds, etc.), it's also pretty handy.

    Implications: You can now export your VWD sim-d items to alternate rendering platorms (like Blender), using this shiny new working and up-to-date alembic exporter. Bravo!

    more yay,

    --ms

  • JClaveJClave Posts: 64
    edited July 2020

    Sometimes I want to just give up. It's as if Daz is an entity, and is somewhere in the darkness laughing at me and my meager efforts to use Daz the way I want to.

    The class that probably knows what material is associated with each surface, DzMaterialFaceGroup, is undocumented, and I can't figure out how to determine the material associated with a surface, in order to get its asset ID to name the Blender material slot, like Daz Importer does.

    I can dump all the materials associated with a node, and print their asset IDs, and sure enough, as @JClave pointed out, they look much like the material slots that Daz Importer uses.

    Each face is associated with a material group, but the link between a material group and a material (and therefore an id) is unknown, so I don't know with which id to associate each face.

    If I can't figure this one out, the Alembic Exporter is going to have to parse the duf file as well, because obviously, the information is in there.

    Another alternative is to name them in a way that includes both object name and material name.

    i.e. {object id}#{material name} -> "Victoria8.001#Face"

    (if it's possible to get object id, that is)

    Then the material script in Blender could infer which material in .duf the names map to.

    This plugin is so close to revolutionizing how people can render Daz content smiley

     

     

    Post edited by JClave on
  • JClave said:

    Another alternative is to name them in a way that includes both object name and material name.

    i.e. {object id}#{material name} -> "Victoria8.001#Face"

    (if it's possible to get object id, that is)

    Then the material script in Blender could infer which material in .duf the names map to.

    This plugin is so close to revolutionizing how people can render Daz content smiley

    That was actually my first idea, just encoding the material slots as something like collection#object#material, but the problem of how to know what Daz Importer material slot corresponds to what Alembic Importer material slot would remain, and that's what I mean by "Diffeo Compatible". In order to work, and always work, I'd have to reckon the material slots in precisely the same way. I was not expecting to discover that the C++ API appears to have less information than the DSON.

  • JClaveJClave Posts: 64

    That was actually my first idea, just encoding the material slots as something like collection#object#material, but the problem of how to know what Daz Importer material slot corresponds to what Alembic Importer material slot would remain, and that's what I mean by "Diffeo Compatible". In order to work, and always work, I'd have to reckon the material slots in precisely the same way. I was not expecting to discover that the C++ API appears to have less information than the DSON.

    You could also submit a code change to Diffeomorphic source control that accounts for your custom material naming if the material naming is too hard.

    I feel that this falls pretty low on the scale of "important to get right" given there are alternate workarounds.

  • PadonePadone Posts: 3,688

    @TheMysteryIsThePoint

    If you can't find a better option I'd go with reading the duf file. That for materials only should be fast enough anyway. I see Thomas exports the material labels in the export hd script so I don't know if this may be useful. But he doesn't export the material ids that are available only in the duf file.

  • mindsongmindsong Posts: 1,701
    JClave said:
    ...

    This plugin is so close to revolutionizing how people can render Daz content smiley

    yes - y'all have no idea! (or perhaps you do...:)

    --ms

  • OK, it turns out that I was misunderstanding the relationship between material groups and materials. The level of indirection that I though existed, doesn't really, and it is similar to Blender: The material group's name is also the material's name. So all I need to do is find the material of the same name, and name the group after the material's asset id, and we're done, right?

    Wrong, of course.

    material->getAssetId() returns not the same id from the DSON, but the material's shader. I have no idea why. After a brief period of elation thinking I may not have to parse the DSON after all, I may have to.

    But it did later dawn on me that once I have the material's id, and it should now match the Daz Importer, we will have acheived perfect compatibility: If one imports a model with Daz importer first, and then imports with Alembic, the Alembic model will assume all the textures automatically. That's worth the trouble to parse some DSON :) Then I think it may be useful to rename the materials to something more orthogonal, and move them to a material encyclopedia from where they can be linked later.

    This is going to take a little longer, but I think I can see the light at the end of the tunnel, and then we can move on to other cool functionality.

Sign In or Register to comment.