Sat, Sep 7, 10:13 PM CDT

Renderosity Forums / Poser Technical



Welcome to the Poser Technical Forum

Forum Moderators: Staff

Poser Technical F.A.Q (Last Updated: 2024 Sep 06 11:12 am)

Welcome to the Poser Technical Forum.

Where computer nerds can Pull out their slide rules and not get laughed at. Pocket protectors are not required. ;-)

This is the place you come to ask questions and share new ideas about using the internal file structure of Poser to push the program past it's normal limits.

New users are encouraged to read the FAQ sections here and on the Poser forum before asking questions.



Checkout the Renderosity MarketPlace - Your source for digital art content!



Subject: Antonia Technical


odf ( ) posted Thu, 20 August 2009 at 8:36 AM · edited Sun, 25 August 2024 at 1:16 AM

Antonia is a Poser figure I've been working on for some time with the help of many talented members of this community. There's a 100+ pages long thread about her in the Poser forum. I've learned a lot during the course of the project and am stilling learning new things every day. Others have told me similar things.

Recently, I've had some conversations with lesbentley about the more nitty-gritty aspects of Poser figure development and I thought it would be good to have these discussions in public so that more people can give input or just read along like in the original thread.

I've found that talking about a real project gives things a quite different perspective. There've been lots of discussions about the best way to make a Poser figure, but here someone - be it myself or one of my co-conspirators - will at some point have to pick one of the many proposed solutions and make it work.

So here goes... :laugh: First point on the agenda: how to get morph sets from different vendors play nicely with each other? In the next post, I'll sketch some of my ideas.

-- I'm not mad at you, just Westphalian.


Sa_raneth ( ) posted Thu, 20 August 2009 at 8:52 AM

this sounds like a good project 


odf ( ) posted Thu, 20 August 2009 at 9:00 AM

So, how do we get those morphs into our figure? Let's assume we are using some kind of morph injection, which seems a reasonable way to go. There are basically two problems:

  1. We need to create the channels to inject those morphs into.
    2) We'd like to organize our morphs in logical groups so that we have a chance to find them later on.

Both problems are easy to solve if we use only one set of morphs from one creator at a time. We'll just add a number of blank channels to each actor into which the morphs inject, and the injection pose comes with an appropriate grouping for the morph set. Yay!

But with the blank channel model it is at some point inevitable that two morphs from different sets use the same channel. So we can't use those morphs together. Another problem is that whenever a pose file defines channel grouping in an actor, Poser throws away all existing grouping and starts over from scratch. So whichever pose file is loaded last gets its grouping, and everything else is thrown back into a flat list.

Obviously, since PMDs can create their own channels, they solve the first problem. But they don't solve the second. DAZ has a system that apparently solves both problems, but is quite complicated and from what little I've seen seems rather fragile.

-- I'm not mad at you, just Westphalian.


odf ( ) posted Thu, 20 August 2009 at 9:19 AM

So, the DAZ idea sounds really good at first sight: use 'readScript' instructions in each actor to include the bits that changed. So the base CR2 stays the same all the time and only the included files change. Excellent, no? Ooh, wait a minute...

Again, two problems, right here at this stage:

  1. People are used to making changes to their figures within Poser and saving the results. So the "unchanged CR2" seems to clash big time with the way people generally work with Poser files. In effect, everyone would have to use the DAZ system to make things work nicely. Maybe I'm missing something here, but that's how it appears to me.

2) We need an include file - several actually - for each actor. That's a large number of files. And it gets worse because for each morph set, we need another bunch of files for each actor which the included files can include. And then we need an installer to rewrite the level 1 include files in order to include all the level 2 include files.

Now wait a minute. The whole reason for us to invent the 'readScript' scheme was to avoid rewriting Poser files. But now we realize we have made everything immensely complicated and still have to rewrite Poser files. So why not rewrite the original CR2 and be done with it?

So here comes my wicked plan - and please tell me if I'm completely crazy: I propose to write a program - probably a Python script that can run inside or outside of Poser - that reads a CR2 figure file and an injection PZ2 and produces a new CR2 file and a new PZ2. The new CR2 will have the combined channel grouping from the original CR2 and the original PZ2. It will also include all the channels from the original CR2 plus enough empty morph channels to inject all the morphs from the original PZ2.

Now the twist: since some of the channels the original PZ2 wants to inject into might collide with ones already used in the original CR2, we rename those channels. That's reason one why we also have to create a new PZ2. Reason two is that we have to remove all channel grouping from the PZ2 so that it doesn't destroy the nice grouping that we've created in the output CR2.

The nice thing about this plan is that people can simply continue to work with figures and injection poses like they have before until they run into trouble with conflicting morph sets. Only then do they have to use my CR2/PZ2 rewriting script.

So far so good. Now tell me how I'm wrong. :laugh:

-- I'm not mad at you, just Westphalian.


LaurieA ( ) posted Thu, 20 August 2009 at 9:36 AM

I wish I could tell you if  you are wrong or right, but it sounds wonderfully "sneaky" somehow ;o).

Another thread bookmarked.

Laurie



JoEtzold ( ) posted Thu, 20 August 2009 at 11:37 AM

Hi odf,

that's a delta-file-concept every only half-good programmer can understand and agree, I guess. Will say it's a good idea.

What I don't understand fully is the need of the second rewritten pz2. I would combine the cr2 and the pz2 directly to one new cr2 which is complet. OK, if you intend to load only some of more morphs than you will need the channel dummies. But I found it mostly impossible to load only the one or other morph. So including all morphs from the pz2 into a new cr2 in one run should not been to worse.

But I think you will need some background mechanics in your scripting prog.
If I got the idea right you may have one original basic cr2 and more than one concurrent pz2's for the same actors by may be serveral creators.

So in this scenario the prog need something like a list to choose from (but please not in flex, could be done easier), something like a companion ini-file.

So it would be best to give the prog a information there the cr2 and all pz2's are located. Then the user can choose from the list which pz2's (multiple choice) should be included and the prog will generate a new cr2 including all choosen morphs.
This should also work if the morphs are in pmd's with one exception, duplicate internal names could not be resolved. But this would be the same problem as with rewriting a pz2 to a new version.

Optional you could give the user possibility to give the new cr2 a significant name and a save directory. And optional the chance to load it directly into poser.

This would be the difference for using the prog from poser or standalone. I think python should be fine to do all this, maybe with the help of some external modules which are not standard in poser environment.


nyguy ( ) posted Thu, 20 August 2009 at 12:17 PM

Quote -

Obviously, since PMDs can create their own channels, they solve the first problem. But they don't solve the second. DAZ has a system that apparently solves both problems, but is quite complicated and from what little I've seen seems rather fragile.

Have you tried ### Binary Morph Editor?

Poserverse The New Home for NYGUY's Freebies


lesbentley ( ) posted Thu, 20 August 2009 at 1:13 PM

@ odf,

I'm having trouble understanding what you are proposing here. You say, quote:

"Now the twist: since some of the channels the original PZ2 wants to inject into might collide with ones already used in the original CR2, we rename those channels.

Should that read:

"Now the twist: since some of the channels the new PZ2 wants to inject into might collide with ones already used in the original CR2, we rename those channels."


tlc ( ) posted Thu, 20 August 2009 at 1:18 PM

Okay... I think I understand it. You have the main character's cr2 and then have a pz2 that has the morph's INJ/REM stuff in it. You then create a new cr2 that combines the two. Yes?

Questions:
1> Wouldn't this mean you have to know in advance which morphs you want to use and make a pz2 that contains them all?

2> Alright you have the new cr2 and have been morphing the character and you find you need another morph or somebody produces a set of morphs that you could use on the figure. What do you do then?

Create Poser Mats for free in DS3


odf ( ) posted Fri, 21 August 2009 at 6:29 AM

Okay, I hope I can answer all the questions in one go. First, it was probably unwise of me to speak of 'original' and 'new' files. Let's rather call them input and output files.

So there's an input cr2, which is not necessarily the original cr2 the character was shipped with, but what you currently use. It may have your favorite texture and pose preloaded, it may include custom morphs, etc. Most importantly, it could well be a result of previous applications of the script I am proposing to write. So this can be an iterative process. You buy or download a new morph pack and add channels and groups for it in your favorite cr2. Then you buy another new morph pack and you do it again. No need to start from the original cr2 each time, as long as the one you're currently using isn't for some reason badly corrupted.

Then there's the input pz2, which is 'new' in the sense that in contains morphs that the cr2 is not yet prepared for. Otherwise there'd be no point, would it? :laugh:

The program will obviously have to produce an output cr2, which will contain updated grouping and updated lists of morph channels. Now JoEtzold suggested to simply load all the morphs into the output cr2 so that there's no need to also rewrite the information from the input pz2 and produce an output pz2 from it. But that may not always be desirable. A cr2 can get pretty large when lots of morphs are loaded into it, which eventually will slow down the loading process and eat up precious main memory within Poser. So unless you always use all the morph packs you have at the same time, you might not want them all preloaded.

So if I just prepare the cr2 to take those morphs without necessarily preloading them all, since I don't expect morph makers to be totally disciplined and make sure their internal channel names never collide, I'd like to have a mechanism to avoid conflicts. Hence the provision for an additional output pz2 with modified channel names and with the grouping removed, so that they do nothing else than inject the morphs that my cr2 was prepared for.

I could use basically the same mechanism to support binary morphs if I found the pmd format documented somewhere or if someone like Dimension3D, who obviously understands that format, donated some code to extract the channel names from the pmd and, if necessary, change them to produce an output pmd file. Failing that, all I can do is look at the pz2 that injects the morphs from the pmd and use the information that's in there.

Finally, regarding Binary Morph Editor (brought up by nyguy): it's a fantastic program and I can't recommend it enough to anyone making or juggling with morphs. But honestly, I'd like something that I can distribute with Antonia for free and that's almost trivial to use.

So in the first iteration, the program would just take a single input cr2 and a single input pz2 and produce a new cr2 and, if necessary, a new pz2. Once this works and looks sufficiently robust, I'd add some code to work more smoothly with large or complex runtimes, and maybe the option to preload the morphs instead of just preparing blank channels for them.

All the fancy extra stuff like splitting or combining packages, adding or removing individual morphs or converting between binary and textual deltas can be done with other software for now and might be added later on when the basic system has proved itself.

Okay, hopefully I've covered everything that was unclear. Your turn again... :-D

-- I'm not mad at you, just Westphalian.


JoEtzold ( ) posted Fri, 21 August 2009 at 12:09 PM

Ah, Ok, now I understand. The idea to have all morphs directly in the "new" cr2 came from the "original" cr2. I was in the opinion that this was everytime the same, so no revolving work.

As you have declared it makes sense to have also new "output" pz2 besides "output" cr2.

The idea to have also the possibility to have all morphs included in a cr2 should consist.
This for example is the easiest precondition for using D3D's morphing clothes. This prog need the figure morphs to copy the to the clothes. OK, it can read them via pz2 but a fully complete figure is easier to work with.

B.t.w. D3D, you should ask for help with the PMD. Could do it in german via PM.
As far as I have understood him the PMD files a only compressed morph data like otherwise given in the cr2 or pz2. The compression migth be the same as used  otherwise by poser, thatis gzip stream.
But thats acompanied by some information for the channel data. So you should ask him for this format.


lesbentley ( ) posted Sat, 22 August 2009 at 5:23 PM

I think I have a better understanding what you a proposing now. It all sounds like a good idea to me. With WIP cr2 I don't want to have to carry all the morph deltas in the cr2, but want all the channels there ready in case I do want to inject a particular morph, so I approve of the idea of an output cr2 and pz2.

I think it would be a good idea if your script also allowed the user to add a channel with an arbitrary name to the cr2, without needing or writing a pz2.


odf ( ) posted Sat, 22 August 2009 at 9:09 PM

Quote - I think it would be a good idea if your script also allowed the user to add a channel with an arbitrary name to the cr2, without needing or writing a pz2.

That should be easy enough to do, but I wonder what you would use such a channel for.

-- I'm not mad at you, just Westphalian.


lesbentley ( ) posted Sun, 23 August 2009 at 6:33 AM

It just seems like I am always needing to create new morph channels for one reason or another, and in the case of a single morph, I think it would be quicker to just type in the name rather than having to brows for and select a pz2. Also I might have a pz2 with several morphs in it, but I only want to inject one of those. Thirdly I might want to pre-rig a cr2 for several morphs I plan to make, adding them one as a time to the pre-rigged cr2 to check how they work together as I make them, but I don't want to have to break the work flow with each new pz2, by having to stop to make a new output cr2.


odf ( ) posted Sun, 23 August 2009 at 7:06 AM

Okay, but I think you're talking tools for developers here. That's a separate issue for me.

I think there should be a collection of scripts to support Antonia developers as well, but I wasn't talking about those yet. I know there exist Poser Python scripts that can create empty channels, or take an obj file and turn it into a full-body morph. So maybe it's enough to collect those and maybe adjust them a little.

-- I'm not mad at you, just Westphalian.


odf ( ) posted Sun, 23 August 2009 at 8:29 AM

Hmm, reading through the thread again, I guess I never really talked about end users vs developers explicitly. My bad!

But I think it would be good to make something for end users first, assuming that developers will be smart enough to figure out a workflow that suits them using the already available tools. That end user tool should be as easy to use as possible, so I'd rather avoid adding any extra functionality that's not strictly necessary. For developers, I can later on add whatever is deemed necessary, my limited spare time allowing.

Anyway, I think I've heard some tentative agreement, so I'll see what I can cook up and put it up here once I've got something marginally presentable.

-- I'm not mad at you, just Westphalian.


lesbentley ( ) posted Sun, 23 August 2009 at 9:28 AM

Quote - Okay, but I think you're talking tools for developers here.

True.

Quote - But I think it would be good to make something for end users first...

That makes sense.


lesbentley ( ) posted Tue, 25 August 2009 at 3:56 PM

Quote - lesbentley: I didn't know about "linkParms". Pretty cool stuff! I think for things like cat-eyes or pupil dilation it's perfect.

Now I wonder if it's possible to rig the eyes so that moving the left eye would also move the right eye and vice versa, but one could still achieve a cross-eyes look via a separate dial.

(above quote is from another thread) It should be possible, but I'm not sure I would not recommend it, as I think it makes things unnecessarily messy and complex, when the current system of control dials in the head works well. Personally I might have gone for ERC and control dials in the head for Dilate and CatEye, except there is no way I can inject a new valueParm channel from a pz2. I can't even inject a delta-less targetGeom, as Poser only saves targetGeom to a PMD when they have deltas in them. So 'linkParms' was more of a workaround here than anything else.

Problems with linkParms are that once channels are linked there is no way (that I know of) to unlink them, short of editing the cr2. Also it's a strictly one-to-one link, once a channel is linked it can't be linked to a second channel, and there is no control ratio.

If you did want to do it I think this should work. Link two channels, say yrot in each eye, then create a new hidden rotateY channel named "yrot2" in each eye. Then slave the "yrot2" channels to a valueParm (or targetGeom) in the head named "Cross-Eyes".

Whilst we are on the subject of the eyes. Some morphs will move the eye sockets. In a case like that translating the eye to fit the socket via a pose or its dial, is not good, because the fist time you apply a stock pose, it will reset the translations back to zero. So IMO the translate channels in the eyes should be slaved to valuParm (not targetGeom) channels in the head, in much the same way you have done for eye rotations. People who make morphs that move the sockets can then inject slaving code into the CTRL channels in the head, to translate the eyes when the morph is applied. The CTRL channels need to be built into the cr2 because of the difficulties associated with injecting new CTRL channels from a pz2. The CTRL channels for translation should be valueParm, precisly because their values will not be saved to a pose file. You don't want a pose saved for the purpose of turning the head, to translate the eyes.

For rotating both eyes you have used targetGeom channels. This means that if a pose saved with "Include morph channels in pose set" it will include those rotations set via the CTRL channels, but a pose saved without that option will not. Unlike eye translation it is probably a good idea to save eye rotations to a pose file, but the inconsistency here may confuse some users. I think this inconsistency can be resolved my creating a ghost actor as a child of BODY (named, say "actor CTRL:1"). The ghost actor would then contain translateY channels like this:

actor CTRL:1
    {
    name    CTRL
    off
    bend 1
    dynamicsLock        1
    hidden        0
    addToMenu    1
    includeInDepthCue        0
    parent BODY:1
    channels
        {
        translateY CTRLEyesLeftRight
            {
            name EyesLeftRight
            initValue 0
            hidden 0
            forceLimits 0
            trackingScale 0.04
            keys
                {
                static  0
                k  0  0
                }
            interpStyleLocked 0
            }
        translateY CTRLEyesUpDown
            {
            name EyesUpDown
            initValue 0
            hidden 0
            forceLimits 0
            trackingScale 0.04
            keys
                {
                static  0
                k  0  0
                }
            interpStyleLocked 0
            }
        }
    }

And in the 'figure' section, after the 'defaultPick' line you would place this code: linkParms head:1 CTRLEyesLeftRight CTRL:1 CTRLEyesLeftRight linkParms CTRL:1 CTRLEyesLeftRight head:1 CTRLEyesLeftRight

    linkParms    head:1
             CTRLEyesUpDown
             CTRL:1
             CTRLEyesUpDown
    linkParms    CTRL:1
             CTRLEyesUpDown
             head:1
             CTRLEyesUpDown

Because a pose file will always record a translation channel in the CTRL:1 (unless "Select Subset" is used to exclude that actor) the value of the CTRL channels will always be recorded and applied by a pz2 file. This stuff about a CTRL:1 actor is a bit experimental, but I did do a quick test, and it seems to work well. If you would like to see a cr2 rigged as above, I could email you one.


odf ( ) posted Tue, 25 August 2009 at 6:44 PM

Wow, I'm once again stunned by your knowledge. Good stuff! I never fully understood the differences between valueParm and targetGeom channels.

One thing confuses me, though: I always thought it was possible to create valueParm channels from a pz2, but not targetGeom ones. Maybe I remember wrong. I guess I'll have to go through the pz2 thread again to refresh my knowledge.

-- I'm not mad at you, just Westphalian.


LaurieA ( ) posted Tue, 25 August 2009 at 8:12 PM · edited Tue, 25 August 2009 at 8:14 PM

Quote -

Quote - lesbentley: I didn't know about "linkParms". Pretty cool stuff! I think for things like cat-eyes or pupil dilation it's perfect.

Now I wonder if it's possible to rig the eyes so that moving the left eye would also move the right eye and vice versa, but one could still achieve a cross-eyes look via a separate dial.

(above quote is from another thread) It should be possible, but I'm not sure I would not recommend it, as I think it makes things unnecessarily messy and complex, when the current system of control dials in the head works well. Personally I might have gone for ERC and control dials in the head for Dilate and CatEye, except there is no way I can inject a new valueParm channel from a pz2. I can't even inject a delta-less targetGeom, as Poser only saves targetGeom to a PMD when they have deltas in them. So 'linkParms' was more of a workaround here than anything else.

Problems with linkParms are that once channels are linked there is no way (that I know of) to unlink them, short of editing the cr2. Also it's a strictly one-to-one link, once a channel is linked it can't be linked to a second channel, and there is no control ratio.

If you did want to do it I think this should work. Link two channels, say yrot in each eye, then create a new hidden rotateY channel named "yrot2" in each eye. Then slave the "yrot2" channels to a valueParm (or targetGeom) in the head named "Cross-Eyes".

Whilst we are on the subject of the eyes. Some morphs will move the eye sockets. In a case like that translating the eye to fit the socket via a pose or its dial, is not good, because the fist time you apply a stock pose, it will reset the translations back to zero. So IMO the translate channels in the eyes should be slaved to valuParm (not targetGeom) channels in the head, in much the same way you have done for eye rotations. People who make morphs that move the sockets can then inject slaving code into the CTRL channels in the head, to translate the eyes when the morph is applied. The CTRL channels need to be built into the cr2 because of the difficulties associated with injecting new CTRL channels from a pz2. The CTRL channels for translation should be valueParm, precisly because their values will not be saved to a pose file. You don't want a pose saved for the purpose of turning the head, to translate the eyes.

For rotating both eyes you have used targetGeom channels. This means that if a pose saved with "Include morph channels in pose set" it will include those rotations set via the CTRL channels, but a pose saved without that option will not. Unlike eye translation it is probably a good idea to save eye rotations to a pose file, but the inconsistency here may confuse some users. I think this inconsistency can be resolved my creating a ghost actor as a child of BODY (named, say "actor CTRL:1"). The ghost actor would then contain translateY channels like this:

actor CTRL:1
    {
    name    CTRL
    off
    bend 1
    dynamicsLock        1
    hidden        0
    addToMenu    1
    includeInDepthCue        0
    parent BODY:1
    channels
        {
        translateY CTRLEyesLeftRight
            {
            name EyesLeftRight
            initValue 0
            hidden 0
            forceLimits 0
            trackingScale 0.04
            keys
                {
                static  0
                k  0  0
                }
            interpStyleLocked 0
            }
        translateY CTRLEyesUpDown
            {
            name EyesUpDown
            initValue 0
            hidden 0
            forceLimits 0
            trackingScale 0.04
            keys
                {
                static  0
                k  0  0
                }
            interpStyleLocked 0
            }
        }
    }

And in the 'figure' section, after the 'defaultPick' line you would place this code: linkParms head:1 CTRLEyesLeftRight CTRL:1 CTRLEyesLeftRight linkParms CTRL:1 CTRLEyesLeftRight head:1 CTRLEyesLeftRight

    linkParms    head:1
             CTRLEyesUpDown
             CTRL:1
             CTRLEyesUpDown
    linkParms    CTRL:1
             CTRLEyesUpDown
             head:1
             CTRLEyesUpDown

Because a pose file will always record a translation channel in the CTRL:1 (unless "Select Subset" is used to exclude that actor) the value of the CTRL channels will always be recorded and applied by a pz2 file. This stuff about a CTRL:1 actor is a bit experimental, but I did do a quick test, and it seems to work well. If you would like to see a cr2 rigged as above, I could email you one.

So, lets say for the sake of argument (and because I've actually created them...lol). I have morphs that make the eyes move apart/closer and up/down and in/out. I can bring the eyeballs with them??? As it stands now tho, I can only move the eyeballs with a morph target which distorts them sometimes if I don't make the falloff big enough. If I could actually move the eyeballs and not distort them that'd be perfect.

Laurie



lesbentley ( ) posted Tue, 25 August 2009 at 9:56 PM

Quote - One thing confuses me, though: I always thought it was possible to create valueParm channels from a pz2, but not targetGeom ones. Maybe I remember wrong. I guess I'll have to go through the pz2 thread again to refresh my knowledge.

From P6 up, you can create valueParm channels from a pz2, with the line "createFullBodyMorph [NameOfMorph]" but as far as I know, that command will only create a valuePaem in the BODY actor. That's fine if you think everything should be set from the Body. Peresonally I like to control the eyes from the head actor.

I do have a utility pose "(almost) UNIVERSAL Move Both Eyes at Once" that can add dials to translate scale and rotate both eyes at once, in almost any figure. But it adds the dials to the BODY, I think they should be in the head, but the only way I can think of to put them in the head is to build them into the cr2.


odf ( ) posted Tue, 25 August 2009 at 10:48 PM

Thanks Les! Yeah, I found the post were you explained it in the pz2 thread. Just my bad memory, I guess.

Another blow to modularity!

-- I'm not mad at you, just Westphalian.


lesbentley ( ) posted Tue, 25 August 2009 at 11:13 PM · edited Tue, 25 August 2009 at 11:14 PM

@ Laurie,> Quote - So, lets say for the sake of argument (and because I've actually created them...lol). I have morphs that make the eyes move apart/closer and up/down and in/out. I can bring the eyeballs with them??? As it stands now tho, I can only move the eyeballs with a morph target which distorts them sometimes if I don't make the falloff big enough. If I could actually move the eyeballs and not distort them that'd be perfect.

Yes you can do that.

  1. Make your face morph.

  2. Translate the eyes until they fit the eye sockets. Increments of the Tran dials may be too coarse to get exact placement, you may need to click on a dial then type in the number. Now select the left eye, do Copy (Ctrl+C), open Notepad, do Paste (Ctrl+V). This gives you a record of the parameter values for that eye. Now do the same for the right eye.

  3. Make the pz2 file to inject the face morph, by what ever method you normally use. Open the pz2 in a text editor, and add this code:

actor lEye
        {
        channels
                {
                translateX xtran
                        {
                        valueOpDeltaAdd
                                Figure
                                head
                                <span style="color:rgb(0,204,255);">MorphName</span>
                        deltaAddDelta <span style="color:rgb(255,0,0);">0.0010</span>
                        }
                translateY ytran
                        {
                        valueOpDeltaAdd
                                Figure
                                head
                                <span style="color:rgb(0,204,255);">MorphName</span>
                        deltaAddDelta <span style="color:rgb(255,0,0);">0.0034</span>
                        }
                translateZ ztran
                        {
                        valueOpDeltaAdd
                                Figure
                                head
                                <span style="color:rgb(0,204,255);">MorphName</span>
                        deltaAddDelta <span style="color:rgb(255,0,0);">0.0033</span>
                        }
                }
        }
actor rEye
        {
        channels
                {
                translateX xtran
                        {
                        valueOpDeltaAdd
                                Figure
                                head
                                <span style="color:rgb(0,204,255);">MorphName</span>
                        deltaAddDelta <span style="color:rgb(255,0,0);">-0.0010</span>
                        }
                translateY ytran
                        {
                        valueOpDeltaAdd
                                Figure
                                head
                                <span style="color:rgb(0,204,255);">MorphName</span>
                        deltaAddDelta <span style="color:rgb(255,0,0);">0.0034</span>
                        }
                translateZ ztran
                        {
                        valueOpDeltaAdd
                                Figure
                                head
                                <span style="color:rgb(0,204,255);">MorphName</span>
                        deltaAddDelta <span style="color:rgb(255,0,0);">0.0033</span>
                        }
                }
        }

Replace the numbers in red above with the values you saved in notepad for the respective channels. Replace "MorphName" with the dial name of your morph. Save the file and test it in Poser. Now step #2 above assumes that you can translate the eyes. I just checked, and the translate channels in Antonia's eyes are both hidden and locked (tut, tut). So you will have to give me a few minutes to write a pose to undo that.

To be continued...


lesbentley ( ) posted Tue, 25 August 2009 at 11:41 PM · edited Tue, 25 August 2009 at 11:52 PM

Here is the pz2 (pose) file to show the translate channels and un-force limits: { //SwowEyeTran.pz2 version { number 3 }

        createFullBodyMorph _

actor lEye:1
        {
        channels
                {
                translateX xtran
                        {
                        hidden 0
                        forceLimits 0
                        min -100000
                        max 100000
                        }
                translateY ytran
                        {
                        hidden 0
                        forceLimits 0
                        min -100000
                        max 100000
                        }
                translateZ ztran
                        {
                        hidden 0
                        forceLimits 0
                        min -100000
                        max 100000
                        }
                }
        }

actor rEye:1
        {
        channels
                {
                translateX xtran
                        {
                        hidden 0
                        forceLimits 0
                        min -100000
                        max 100000
                        }
                translateY ytran
                        {
                        hidden 0
                        forceLimits 0
                        min -100000
                        max 100000
                        }
                translateZ ztran
                        {
                        hidden 0
                        forceLimits 0
                        min -100000
                        max 100000
                        }
                }
        }
}

The code from my last post is generic, and will work on most figures that have eyes with the internal names "lEye" and "rEye". However I did not expect the limits to be bolted down to zero in Antonia. In order for the code from my last post to be of use to an end user, you will have to add the lines: forceLimits 0
min -100000
max 100000

For example:

                translateX xtran
                        {
                        forceLimits 0
                        min -100000
                        max 100000
                        valueOpDeltaAdd
                                Figure
                                head
                                MorphName
                        deltaAddDelta 0.0010
                        }


odf ( ) posted Tue, 25 August 2009 at 11:52 PM

Oops! I guess I went a bit OCD on those translation channels. :laugh: Sorry!

I guess I should change those limits back to the usual values and add poses to unlock and relock the channels.

-- I'm not mad at you, just Westphalian.


lesbentley ( ) posted Tue, 25 August 2009 at 11:53 PM · edited Tue, 25 August 2009 at 11:55 PM

[cross post]
@ odf,

I have finally found a reason to complain about Antonia. She is an excellent figure in many ways, but IMHO the limits should not be forced to zero on the eyes. Neither do a approve of hiding the translate channels in the eyes. I guess you must have had your reasons, perhaps something to do with scaling the head, but people need to be able to translate the eyes in order to accommodate morphs that move the eye sockets.

Well she is still in a preview release, and I guess that's to work out bugs like this. She is already better than V4 in many respects, and keeps getting better with every release.


LaurieA ( ) posted Tue, 25 August 2009 at 11:57 PM

Quote -
Here is the pz2 (pose) file to show the translate channels and un-force limits: { //SwowEyeTran.pz2 version { number 3 }

        createFullBodyMorph _

actor lEye:1
        {
        channels
                {
                translateX xtran
                        {
                        hidden 0
                        forceLimits 0
                        min -100000
                        max 100000
                        }
                translateY ytran
                        {
                        hidden 0
                        forceLimits 0
                        min -100000
                        max 100000
                        }
                translateZ ztran
                        {
                        hidden 0
                        forceLimits 0
                        min -100000
                        max 100000
                        }
                }
        }

actor rEye:1
        {
        channels
                {
                translateX xtran
                        {
                        hidden 0
                        forceLimits 0
                        min -100000
                        max 100000
                        }
                translateY ytran
                        {
                        hidden 0
                        forceLimits 0
                        min -100000
                        max 100000
                        }
                translateZ ztran
                        {
                        hidden 0
                        forceLimits 0
                        min -100000
                        max 100000
                        }
                }
        }
}

The code from my last post is generic, and will work on most figures that have eyes with the internal names "lEye" and "rEye". However I did not expect the limits to be bolted down to zero in Antonia. In order for the code from my last post to be of use to an end user, you will have to add the lines: forceLimits 0
min -100000
max 100000

For example:

                translateX xtran
                        {
                        forceLimits 0
                        min -100000
                        max 100000
                        valueOpDeltaAdd
                                Figure
                                head
                                MorphName
                        deltaAddDelta 0.0010
                        }

BLESS YOU sir, bless you...lol. A real life saver ;o).

Laurie



odf ( ) posted Tue, 25 August 2009 at 11:58 PM

lesbentley: Yes, that was a mistake on my part. People asked me to lock the translation channels and I just did it for all body parts indiscriminately. I forgot that it might be useful to move the eyes around.

-- I'm not mad at you, just Westphalian.


LaurieA ( ) posted Tue, 25 August 2009 at 11:58 PM · edited Wed, 26 August 2009 at 12:00 AM

Quote - ... Well she is still in a preview release, and I guess that's to work out bugs like this. She is already better than V4 in many respects, and keeps getting better with every release.

She's wonderful to be sure ;o). A really nice figure all round. And since I pretty much hate the gen 4 figures, she'll get used by me often ;o).

Plus the fact that it's kinda exciting and rather fun to be included in the development...lol.

Laurie



lesbentley ( ) posted Wed, 26 August 2009 at 12:28 AM

@ odf,

The jaws and tongue might be other actors that people might sometimes want to translate, also the hands if IK chains get added. Personally I don't get the point of forcing translation limits to zero for any actor. I all my time using Poser I have only ever once seen it cause a problem, and I'm not aware of any other figures that use limits that way. Perhaps there is a point, but it is beyond me. I don't suppose it will do any harm so long as the actors mentioned above can be translated.


odf ( ) posted Wed, 26 August 2009 at 12:40 AM

Yes, jaws and hands as well. As I said, I might have gone a bit OCD on those poor channels. :laugh:

I think the main point of the whole exercise was to prevent people from grabbing and dragging actors with the translate tool by accident. That never happened to me as far as I remember, but apparently some people had that problem.

I generally like to hide channels that end users normally shouldn't need, and also prevent them from changing them accidentally. Of course, there then has to be some provision to unhide them if necessary.

-- I'm not mad at you, just Westphalian.


lesbentley ( ) posted Wed, 26 August 2009 at 12:57 AM · edited Wed, 26 August 2009 at 12:58 AM

@ odf,

As far as I know the translate tool works exactly the same, whether the translate channels are forced or not. You can't use the translate tool to pull an arm of a chest. It's usually best to use one of the rotate tools, rather than the translate tools, but I don't think limits make a difference one way or another. The only time translation limits would be useful would be if the translate dials became unhidden, but that is not something that is likely to happen by accident, and if someone intentionally unhides them (requires custom a pose file), they probably have a good reason.


lesbentley ( ) posted Wed, 26 August 2009 at 9:13 AM

With great embarrassment, I find I must publish a retraction

In post #18 on the first page, I describe a method involving a ghost actor "actor CTRL:1" and 'readScript'. The method does not work!

When I try to use it, saved poses apply at double strength. I'm having the same problem with readScript in other situations too. I don't know if it is something I am doing wrong, or a fundamental bug with readScript. If I find out any more info I will pass it on. Sorry for any inconvenience this may have caused.


odf ( ) posted Sun, 30 August 2009 at 1:19 AM · edited Sun, 30 August 2009 at 1:20 AM

So, I've done some more work on my fledgling Poser file manipulation library and wrote a script that would read a cr2 and write a new one with a list of empty targetGeom channels added to every actor. Since it uses my library, the script itself is very short. About half of it is the template text for the new channels. It is also reasonably fast. For Antonia, it takes two or three seconds on my one-year-old Toshiba laptop.

I know I had a wish list for Poser file surgery scripts in the main Antonia thread, but I forgot to copy it out, and it's impossible to find things in that monster of a thread. So let's just start a new one.

What I've already done:
1) Shift an actor and all its descendants by a given vector.
2) Add a channel with given content to every actor or every actor except BODY.

Things I think would be useful:
1) Extract the scaling from each actor and write it into a pose file.
2) Generate a pose file from a template and a list of actors.
3) Compare two files and generate a list of their differences, disregarding changes in white space, number formatting or the ordering of statements in cases where it is not relevant (this one might take a while).

More ideas are very welcome, no matter how crazy. I'm hoping to eventually build an API that will make it dead easy for people with a little bit of Python knowledge to mess with Poser files programmatically to their hearts contents. The irregular structure of Poser files will make this quite tricky in parts, so I'm not making any promises. But I'll see how far I can get.

-- I'm not mad at you, just Westphalian.


odf ( ) posted Sun, 30 August 2009 at 3:49 AM · edited Sun, 30 August 2009 at 4:00 AM

file_438316.txt

Here's what I have so far. The library is attached. With that in your PYTHONPATH, you can use the following script to add the same set of channels to every actor (the first two arguments are the input and output file, the rest are the channel names). Python 2.5 required.
#!/usr/bin/env
python<br></br><br></br>
import sys<br></br>
from poserFile import *<br></br><br></br>
TEMPLATE_TEXT = """<br></br>
targetGeom -<br></br>
    {<br></br>
    name -<br></br>
    initValue 0<br></br>
    hidden 1<br></br>
    forceLimits 4<br></br>
    min -10000<br></br>
    max 10000<br></br>
    trackingScale 0.01<br></br>
    keys<br></br>
           
{<br></br>
           
static  0<br></br>
           
k  0  0<br></br>
           
}<br></br>
    interpStyleLocked 0<br></br>
    }<br></br>
"""<br></br>
template =
PoserFile(TEMPLATE_TEXT.splitlines()).root.firstChild<br></br><br></br><br></br>
if __name__ == "__main__":<br></br>
    content = PoserFile(file(sys.argv[1]))<br></br>
   <br></br>
    for body in content.figureRoots:<br></br>
        for actor in
body.descendants:<br></br>
           
channels = actor.content.select('channels')[0]<br></br>
           
for name in sys.argv[3:]:<br></br>
               
node = template.clone()<br></br>
               
node.fields[1] = name<br></br>
               
node.select('name')[0].fields[1] = name<br></br>
               
channels.appendChild(node)<br></br><br></br>
    content.writeTo(file(sys.argv[2],
"w"))<br></br>

-- I'm not mad at you, just Westphalian.


odf ( ) posted Sun, 30 August 2009 at 3:53 AM · edited Sun, 30 August 2009 at 3:54 AM

The script for moving actors together with their descendants is only slightly longer. The following is what I did to adjust the rigging after changing the default upper arm length on Antonia:

#!/usr/bin/env
python<br></br><br></br>
import sys<br></br>
from poserFile import PoserFile<br></br><br></br>
def shiftPoint(node, v):<br></br>
    for i in range(1, len(node.fields)):<br></br>
        node.fields[i] =
str(float(node.fields[i]) + v[i-1])<br></br><br></br>
def shiftChannel(node, v):<br></br>
    inSpheres = False<br></br>
    for child in node.children:<br></br>
        if child.firstField ==
'center':<br></br>
           
shiftPoint(child, v)<br></br>
        elif child.firstField ==
'sphereMatsRaw':<br></br>
           
inSpheres = True<br></br>
        elif inSpheres:<br></br>
           
try:<br></br>
               
w = map(float, child.fields)<br></br>
           
except ValueError:<br></br>
               
inSpheres = False<br></br>
           
else:<br></br>
               
if w and w[-1] == 1:<br></br>
                   
for i in range(len(v)):<br></br>
                       
child.fields[i] = str(float(w[i]) + v[i])<br></br><br></br>
def shiftActor(actor, v):<br></br>
    parent = actor.parent<br></br>
    for channels in
actor.content.select('channels'):<br></br>
        for channel in
channels.children:<br></br>
           
if channel.get('otherActor') == parent.name:<br></br>
               
shiftChannel(channel, v)<br></br>
    for channels in
parent.content.select('channels'):<br></br>
        for channel in
channels.children:<br></br>
           
if channel.get('otherActor') == actor.name:<br></br>
               
shiftChannel(channel, v)<br></br>
    for node in actor.content.select('origin'):<br></br>
        shiftPoint(node, v)<br></br>
    for node in
actor.content.select('endPoint'):<br></br>
        shiftPoint(node, v)<br></br><br></br>
def shiftActorAndDescendants(actor, v):<br></br>
    for node in actor.subtree:<br></br>
        shiftActor(node, v)<br></br><br></br><br></br>
if __name__ == "__main__":<br></br>
    tree = PoserFile(file(sys.argv[1]))<br></br><br></br>
   
shiftActorAndDescendants(tree.actor('rForeArm:1'),<br></br>
                            
[-0.013467, -0.001708, 0.000797])<br></br>
   
shiftActorAndDescendants(tree.actor('lForeArm:1'),<br></br>
                            
[0.013467, -0.001708, 0.000797])<br></br><br></br>
    tree.writeTo(file(sys.argv[2],
'w'))<br></br>

-- I'm not mad at you, just Westphalian.


odf ( ) posted Sun, 30 August 2009 at 3:59 AM · edited Sun, 30 August 2009 at 4:04 AM

I'm not asking the non-programmers among you to understand all this. I've just posted those scripts to show that some powerful stuff can be one with not many lines of code. And since all this works directly on the files, it is not restricted to whatever the Poser Python API lets us do.

PS: Each of these take less than a second on my laptop for the default Antonia cr2. Compare that to firing up Poser, loading a figure, locating and running a script and then saving as a new figure.

-- I'm not mad at you, just Westphalian.


odf ( ) posted Mon, 31 August 2009 at 5:30 AM · edited Mon, 31 August 2009 at 5:30 AM

knocks on microphone

Test ... test ... Is this thing working at all?

I implemented the first two items on my list. Next up:
1) Remove all morph channels or just the deltas from a figure.
2) Make a 'blank' cr2 for as a template for clothes rigging, with customizable "chop off" points.

-- I'm not mad at you, just Westphalian.


lesbentley ( ) posted Tue, 01 September 2009 at 5:42 PM

Quote - knocks on microphone

I for one hear you loud and clear, and am salivating at the possibilities you offer, but it's too late at night, and I have drunk too much beer to be able to give any sort of coherent comment at the moment.


odf ( ) posted Tue, 01 September 2009 at 6:49 PM · edited Tue, 01 September 2009 at 6:51 PM

Hi Les, good to see you here! I was starting to worry the guy in the next booth had something more interesting to offer. :laugh:

I'm done with the delta removal script. Stripping a cr2 for use as a clothes template is a bit more complex because it involves removing references to deleted actors and a number of other fine points. But since it's a major pain to do this kind of thing by hand, I think that script would really be quite useful.

It occurred to me that empty morph channels should probably be inserted at the beginning of the channel list, not the end, although I'm still a bit fuzzy on how the whole channel order thing plays out. Anyway, in order to change that, one could change the "appendChild" in the second-to-last line of code in my fifth post on this page to "prependChild".

I've decided to put the code on github to make it easier for people to keep up with my progress. I'll let you know the URL as soon as it's up.

-- I'm not mad at you, just Westphalian.


odf ( ) posted Wed, 02 September 2009 at 6:38 AM

Okay, the code is now online: http://github.com/odf/pfool/tree/master

It's all very bare-bones and preliminary - no docs, no GUI, etc. - but as I keep working on it and adding stuff, it should start to take shape. At any rate, you can now look over my shoulder while I code this stuff. :laugh:

-- I'm not mad at you, just Westphalian.


lesbentley ( ) posted Wed, 02 September 2009 at 12:12 PM

Quote - It occurred to me that empty morph channels should probably be inserted at the beginning of the channel list, not the end, although I'm still a bit fuzzy on how the whole channel order thing plays out.

I'm fuzzy on that myself, but I do know that in a cr2 the order of rotation channels relative to one another is relevant, as is the whether the rotations come before or after the translations. I don't think the order of translation channels relative to one another matters. I think that targetGeom should come above transforms and JPs. I haven't seen any evidence that the position of valueParm is relevant, but feel it is probably best to put them above transforms and JPs.

A geomChan is always placed at the very bottom of the stack in my experience, though I don't know it that is necessary.


odf ( ) posted Wed, 02 September 2009 at 6:59 PM

Thanks, Les! I'll try to stick with that order. It seems safest.

If I find the time, I might start on a GUI this weekend.

-- I'm not mad at you, just Westphalian.


odf ( ) posted Sun, 06 September 2009 at 9:41 AM · edited Sun, 06 September 2009 at 9:42 AM

No GUI yet, but I now have a script that changes channel names (targetGeom and valueParm) in a Poser file and updates references to those channels accordingly. Anyone here who's comfortable enough running things from the command line is welcome to give it a try. The script uses regular expressions, so it's possible to rename a whole bunch of channels with a single command.

This will be the middle part of my file rewriting trick to prepare a figure for a specific morph injection pose:
1) Open the input cr2 and collect all channels that currently exist in the figure.
2) Open the input pz2, rename all channels that collide with ones from the cr2 and write the result as the output pz2.
3) For every channel now in the output pz2, add a blank one with the same name to the figure and write the result as the output cr2.

(Obviously referring to just targetGeom and valueParm channels again.)

I have scripts that can do 2) and 3), and 1) is basically a subroutine of 2). That means all I have to do now is decide on a renaming strategy and put the pieces together.

When all this works I'll add another part to prevent injection poses from messing up existing dial groups. But I think the channel surgery is more important, so I'll take care of that first. At some point in the future I might also add an option to merge the complete content of the pz2 into the figure file for people who like all their morphs to be preloaded.

-- I'm not mad at you, just Westphalian.


odf ( ) posted Sat, 12 September 2009 at 10:54 PM · edited Sat, 12 September 2009 at 10:57 PM

Okay, I've implemented steps 1) through 3) now, except that currently step 3) just clones the channel with everything in it. But it's easy to add a "strip deltas" option. I've also made a very simple GUI. No serious testing yet, but if you want, you can always download the latest version from github and try it out.

I think the best way to think about this whole Poser file rewriting library I'm trying to develop is as pose files on steroids. Pose files are great. One can do all kinds of wonderful stuff with them, but they have (at least) two serious limitations: one, they cannot create new channels in actors (unless one uses PMDs, but that's another story), and two, there's not enough fine control from within Poser when exporting poses. For example, I haven't found a way to make Poser export the scaling channels.

So I think the two basic functions of my library should be pose extraction and pose injection. For pose extraction, one should be able to not only select the actors to extract from, but also select the channels and even non-channel parameters like 'visible' etc. to include into the pose file.

For pose injection, whatever is in the pose file should be merged into the figure file in a sensible way. Pretty much what Poser does now, but with (at least) two important modifications: channels not in the figure file should be created, and if the pose file contains dial groups, those should be merged into the existing ones rather than replacing them.

I'm still thinking that automatic renaming of channels in a pose file will be a powerful tool, but maybe it should not be done by default when injecting. Instead, it should either be a separate action or an optional step. The injection script would compare the names of the targetGeom and valueParm channels in the figure and pose file, and if any name occurred in both, it would ask the user whether to overwrite those channels or create new ones with unique names.

Another thing that I think might be very useful are pose file templates. For example, you want to insert a channel with certain parameters into every actor, or into a certain set of actors. Wouldn't it be great if you could write a pose file and instead of writing, say

actor lThigh<br></br>
    {<br></br>
    channels<br></br>
        {<br></br>
        targetGeom xxx<br></br>
           
{<br></br>
           
...<br></br>
           
}<br></br>
        }<br></br>
    }<br></br>
actor lShin<br></br>
    {<br></br>
    channels<br></br>
        {<br></br>
        targetGeom xxx<br></br>
           
{<br></br>
           
...<br></br>
           
}<br></br>
        }<br></br>
    }<br></br>

with the content of both "xxx" channels identical, you could instead write something like

actor [lThigh, lShin,
rThigh, rShin]<br></br>
    {<br></br>
    channels<br></br>
        {<br></br>
        targetGeom xxx<br></br>
           
{<br></br>
           
...<br></br>
           
}<br></br>
        }<br></br>
    }<br></br>

and have the same content inserted into all the listed actors?

What'cha think?

-- I'm not mad at you, just Westphalian.


odf ( ) posted Sun, 13 September 2009 at 12:36 AM · edited Sun, 13 September 2009 at 12:43 AM

Side note / rant:

So, after about two days' worth of research on how to get this crap to end users who are not particularly computer-savvy or happen to own Poser 8, I officially declare Python a dead language.

It is ridiculous that the official Windows source code is still tied to the Microsoft compiler and that there is apparently no support to speak of for MingW. It is also ridiculous that apparently there's still no equivalent to an executable JAR file in the Python world.

This reminds me of why about five years ago I decided to ditch years worth of Python code from another project and redo everything in Java. That despite the fact that Java is a pretty painful language to code in.

My point is: if anyone who can talk Python wonders why they won't be able to read my source code anymore (unless of course they learn Scala, which I recommend anyway), or why they will have to download several megabytes for an executable instead of just a few KB, that's the explanation.

I want a standalone - or as close as I can get to one - that's independent of Poser, because not everyone has it, or a recent enough version of it. I don't want to buy a Microsoft compiler and I definitely don't want to program in C or C++. Also, I don't want to have to build different versions for PC and Mac. Since Python fails to deliver, I'll switch to JVM-based development, just as I did five years ago.

This is how it will go:
  Step 1: Install Java.
  Step 2: Download my JAR file.
  Step 3: Execute my JAR file.
  Step 4: Repeat Step 3 as needed.

:glare:

-- I'm not mad at you, just Westphalian.


odf ( ) posted Sat, 19 September 2009 at 12:35 AM

So, one of the things I'm working on is to specify content by selection patterns. For example, with the current version of the library, you can say something like

Document.fromFile("xx.cr2").extract("actor",
"channels", "scale.*", "keys",
"k").write("zz.pz2")

and that will grab all the scale settings for actors from the figure file xx.cr2 and write them into a pose file named zz.pz2.

Or you could say

val doc =
Document.fromFile("xx.cr2")<br></br>
doc.root.delete("actor head:.*", "channels",
"targetGeom", "indices|numbDeltas|deltas")<br></br>
doc.write("zz.cr2")

to clear all the deltas from the head actor and write the modified figure to a new file zz.cr2

The arguments of the extract and delete methods are selection patterns that each specify a list of lines or sections in the Poser file. So for examples, if the first argument says "actor", it looks for all actor sections and continues the search within those. Then if the second argument says "channels", it looks for channels sections within the actor ones, and so forth. The API is still in the process of materializing, which is why it would be great to have some more request on what the library should be able to do easily (hint, hint).

One thing I'm wondering about the best syntax for those patterns. At the moment, I'm using a sequence of arguments, each of which is a regular expression, plus some special syntax for negation and arbitrary "in between" paths. For example, extract("actor", "channels", "groups", "", "!groupNode") would pick up anything within a dial groups section that is not a group node. The "" stands for "anything in between" and the "!" stands for "does not match".

I wonder if something closer to Unix-like file paths with wildcards would be useful. Then instead of extract("actor", "channels", "scale.*", "keys", "k") , one could say extract("actor/channels/scale*/keys/k"). This might feel more familiar to most people than regular expressions. I'd still need some not so familiar syntax on top of that, but that's also true if I go with regular expression.

Any input would be much appreciated.

-- I'm not mad at you, just Westphalian.


nruddock ( ) posted Sat, 19 September 2009 at 5:25 AM · edited Sat, 19 September 2009 at 5:29 AM

Quote - I wonder if something closer to Unix-like file paths with wildcards would be useful.

Actually the concept(s) your looking for are provided by XPath.
As Poser files are structured and hierarchical information which quite naturally map to a set of objects in a tree structure exactly like the XML DOM.
There's also at least two free libraries that implement it for you
-> http://commons.apache.org/jxpath/
-> http://jaxen.codehaus.org/
The JXPath library is probably the better of the two as jaxen needs you to implement interfaces for custom object models rather than working "out of the box".

Given the similarity of Poser files and XML files, having a DOM-like model and/or adaptor would allow the use of XSLT to manipulate them.


odf ( ) posted Sat, 19 September 2009 at 7:12 AM · edited Sat, 19 September 2009 at 7:17 AM

Thanks for the tip, nruddock! I've actually considered using something similar. Full XPath syntax would be quite the overkill here, but those libraries might come in handy for other things.

Implementation isn't really the issue here, mind you. Everything I've shown in my earlier post is already running, and any extensions one could possibly want for Poser files are almost trivial to add. The main question is, how to write down a path expression in the most user-friendly way. One string with an XPath-like syntax? A list of argument each of which represents one path component? Or an internal DSL using operators, possibly looking something like this:

doc "actor"
@ "head*" "channels" 
("indices"|"numbDeltas"|"deltas")
delete

(The forward slash "/" can't be used as an operator in Scala since it's already taken for comments. But the backslash "" is fine.)

-- I'm not mad at you, just Westphalian.


Privacy Notice

This site uses cookies to deliver the best experience. Our own cookies make user accounts and other features possible. Third-party cookies are used to display relevant ads and to analyze how Renderosity is used. By using our site, you acknowledge that you have read and understood our Terms of Service, including our Cookie Policy and our Privacy Policy.