Grappling with .egg Transform matrix

I’d love to take a closer look at the matrices involved, partly because I’d like to figure it out so that I can perhaps fix the dae2egg exporter, but I’m afraid I’m rather swamped in the coming two months. :frowning:

As for why it can’t load the .egg file, this looks like a simple syntax error. In fact, I think you left out the important part from the error - the actual syntax error comes before that. Perhaps you didn’t match { and } ? Or used an invalid scalar? There’s surely an error somewhere before the traceback. If not, please send the .egg file so I can try it for myself.

I don’t know what I could have left out. Here is everything that Python gives me, when the error is thrown:

Python 2.7.3 (default, Apr 10 2012, 23:31:26) [MSC v.1500 32 bit (Intel)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> ================================ RESTART ================================
>>> 

Traceback (most recent call last):
  File "C:\MyPrograms\Poser\Smith Micro\Poser Pro 2014\Runtime\Python\poserScripts\TDMTfiles\Panda3d\Roaming-Ralph\model_viewer.py", line 147, in <module>
    gameApp = Application()
  File "C:\MyPrograms\Poser\Smith Micro\Poser Pro 2014\Runtime\Python\poserScripts\TDMTfiles\Panda3d\Roaming-Ralph\model_viewer.py", line 28, in __init__
    self.panda = Actor("models/AntoniaLo/Yabee_test.egg")#,{"animset":"models/AntoniaLo/Yabee_test-Anim0"})
  File "C:\Panda3D-1.8.1\direct\actor\Actor.py", line 277, in __init__
    self.loadModel(models, copy = copy, okMissing = okMissing)
  File "C:\Panda3D-1.8.1\direct\actor\Actor.py", line 1908, in loadModel
    model = loader.loadModel(modelPath, loaderOptions = loaderOptions, okMissing = okMissing)
  File "C:\Panda3D-1.8.1\direct\showbase\Loader.py", line 170, in loadModel
    raise IOError, message
IOError: Could not load model file(s): ['models/AntoniaLo/Yabee_test.egg']
>>> 

That’s pretty much what I posted before. For context, I’m not doing anything unusual when loading the file. Here is the loader block, which is very simple because I haven’t begun doing anything advanced yet with Panda itself, while I’m still trying to get files to work properly.

    use_poser = 0
    use_anim = -1

    if use_poser:
      self.panda = Actor("models/AntoniaLo/AntoniaA_poser2egg_fig.egg",{"animset":"models/AntoniaLo/AntoniaA_poser2egg_anim"})
    else:
      #self.panda = Actor("models/AntoniaLo/Poser_to_dae2egg.egg",{"animset":"models/AntoniaLo/a.egg"})
      #self.panda = Actor("models/AntoniaLo/Poser_to_dae2egg_fig.egg",{"animset":"models/AntoniaLo/poser_to_dae2egg_anim.egg"})
      #self.panda = Actor("models/AntoniaLo/Antonia_dae_to_blender_260.egg",{"animset":"models/AntoniaLo/Antonia_dae_to_blender_260-anim1"})
      #self.panda = Actor("models/AntoniaLo/Antonia_dae_to_blender_260_3b.egg",{"animset":"models/AntoniaLo/Antonia_dae_to_blender_260_3b-anim1"})
      self.panda = Actor("models/AntoniaLo/Yabee_test.egg")#,{"animset":"models/AntoniaLo/Yabee_test-Anim0"})
      
      
      #self.panda = Actor("models/AntoniaLo/AntoniaA.egg",{"animset":"models/AntoniaLo/a.egg"})
      #self.panda = Actor("models/AntoniaLo/Antonia_x2egg_fig_OLD.egg",{"animset":"models/AntoniaLo/Antonia_x2egg_anim_OLD"})
    
    self.panda.reparentTo(render)
    if not use_poser:
      self.panda.setScale(20.0)
    #self.panda.setPos(ralphStartPos)
    #self.panda.setHpr(180.0,0.0,0.0)#added = YXZ
    if use_anim != -2:
      if use_anim == -1:
        self.panda.loop("animset")
      else:
        self.panda.pose("animset",use_anim)
    

    
    #self.panda = Actor("panda", {"walk": "panda-walk"})
    #self.panda.reparentTo(render)
    #self.panda.loop("walk")

All of the import statements that are commented out represent alternate models for code testing, and all of those models import without error, using the same code. The problem doesn’t seem to be my Panda code, but the Yabee_test.egg. The Yabee_test.egg fails to load, with the same error, both with and without any attempt to load the associated animation.

I can appreciate that you’re busy, and I thank you for the time you’ve been putting into trying to help me. I suspect that I will have moved on to other things, in a couple of months, given my current problems with Panda. Which is a pity, because we’re both struggling with the same issues, in terms of file import. If the timelines worked out a bit differently, we might have been able to collaborate on solving the problem, to perhaps get .dae import working fully. As it is, Panda doesn’t actually support Collada where it matters, which is with animated files. Panda has alternatives for static mesh import, but it has few working pathways to get an animated model into properly functioning .egg format. It’s frustrating to choose to work with Panda based on the claim that a format is supported, only to learn after hours or days or weeks of testing that the claim is false. Panda should not advertise Collada support, at this time, or should explain that “support” in this case means “partial support”, and “partial support” means “animation not working”. That really would be more fair to the potential user base. I had to do conversion tests backwards and forwards and then dig around on the forums before I learned that dae2egg doesn’t support animation. That’s not right. :frowning:

But, as I said, thank you for your help. :slight_smile:


If you’ll let me know how to send you the file(s), I can provide all the examples you could possibly want or need, and then some. :laughing:

With respect to converting a Collada worldspace bind pose matrix to localspace, the current Blender source code may be worth checking out. Their Collada importer seems to be doing the same thing. They have all of their Collada code conveniently grouped, set apart from the rest of the code. The Blender source is under the GPL license and can be freely adapted. Hypothetically, one could rip out their Collada code and use it as the foundation for a working dae2egg converter. Something similar was done with the Roadkill UV unwrapping application, which is just Blender’s old UV code placed in a separate application.

I’m rather wondering about the current “2egg” binary handling. It seems like one single “2egg” binary could take in the necessary data in a set format, then write out an egg file. Then this could be harnessed by other binaries, or Python scripts, which would read an input file and send the appropriately formatted arrays to the generic 2egg writer. This would allow more flexibility for the users, and provide a more extensible foundation for egg conversion.

Slowly getting a bit closer, with Poser export handling. As seen in the attached image, UV seams need to be fixed by splitting the vertices along the seams. Not really sure whether assigning multiple UV sets would be the appropriate way to handle split texture vertices. That seems to be the handling advised in a thread on this forum, but every other example I’ve seen in other game formats splits the vertices at UV seams. Hmm. The vertex weights still need to be handled, as well.


I seem to be treating this thread as though it were my own personal Panda blog or something. Umm. :open_mouth:

I may have made an interesting discovery, though, with the joint matrix problem. Upon examining a Collada file exported from Poser, I find that its matrices are identical to mine. :open_mouth: Apparently the actor orientation isn’t supposed to be embedded in the matrix as I had expected.

This brings up a bit of a puzzle. The Collada matrices are in worldspace, while Panda needs localspace. Or so I have read. But if all of the worldspace matrices are just identity matrices, presumably no matrix multiplication of actor by parent will result in anything different. So… I may or may not have the correct answer already, which would be both good and bad. Good, in that I could stop struggling with the matter. Bad, in that the rotations are still a bit wonky in places. Hmm.

On edit: Editing this to change “or” to “of”, but also want to complete the thought about identity matrices. The working Joint Transform matrices in poser2egg are merely identity matrices with origins set for the translation part. Anything else ruins the joints in Panda. Poser’s Collada exports, remarkably, show the same handling for the joint matrices. To put a Collada matrix in Panda format, multiplication by the inverse parent matrix is needed. The inverse of the identity matrix is also an identity matrix. Multiplying any matrix by the identity matrix renders only the matrix itself. Multiplying an identity matrix by an inverted identity matrix returns… an identity matrix. So if Poser’s Collada joint matrices are taken as evidence that a Panda exporter should use the same approach, there’s absolutely nothing to be gained from trying to work with the joint matrices at all. This means that any remaining joint rotation inaccuracies need to be handled in the animation, where any approach runs up against potential Euler conversion complications. It will be interesting to see what, if anything, works. Success in this case would be matching the results of a Poser Collada export, which can be imported into Blender with correct rotations. Obviously there’s a way to compensate for the lack of orientation data in a joint matrix, but the correct approach remains a mystery…

I’ve had to rewrite the mesh-processing portion of the exporter, to make it more flexible for UV, morph, and vertex weight handling. It’s now splitting vertices between polygons only at UV seams, more in line with the standards I’ve seen in (for example) .md5 exporters than in the .egg exporters/converters I’ve encountered. Here’s the vertex count information for the same file, in various different conversion formats:

Poser dae export: 10801 vertices, 9656 polygons
chickenR91 conversion: 38614 vertices , 9656 polygons
dae2egg conversion: 38614 vertices, 9656 polygons
poser2egg (old): 38614 vertices, 9656 polygons
poser2egg (current): 12494 vertices, 9656 polygons

The resulting file is slimmer, and presumably there are potential performance gains to be had in Panda from using a file with fewer vertices. That would depend on how Panda handles such things internally, I suppose. I would be interested in any information about the matter. (Note that 38614 is the same value as the length of Poser’s polygon sets array for the figure’s unimesh, and the value crops up repeatedly because other Panda exporters/converters create a new vertex for every polygon corner. The 10801 value from Poser’s dae exporter is the true number of vertices in the Poser figure’s unimesh, which would be the minimum vertex count for any export of the mesh. It’s a pity the .egg format can’t handle split texture vertices. That shortcoming is the only flaw I’ve noted in an otherwise extremely flexible and tolerant 3D file format.)

In addition, the exporter is now able to bake Poser’s per-actor scaling into the exported mesh, along with select morph deformations. Handling joint scaling in the animation is problematic, as Poser and Panda implement joint scaling very differently. Panda’s joint scaling is similar to Poser’s propagating scale option, in which a scaled parent also scales all of its children. An exported animation can compensate for this, but so far my test results with that process don’t quite match what Poser is doing. To preserve the intended shape of the exported figure, the scaling deformations apparently need to be baked in. This handling is in line with that of the Poser Collada exporter, as well.

The next problem is trying to calculate the correct vertex weights (joint membership) for an actor. As seen in the attached image, the weights still are not correct. Poser splits its geometries into separate portions by actor (bone/joint), and Poser Python only offers direct information about weights for an actor itself, not for an actor’s parent or children. This complicates matters in a case such as the join of five fingers with a hand. The parent’s (hand’s) partially-weighted vertices share weights with children (fingers), but which children share which weights? I’m going to have to work with vertex neighbor data, to determine how to allocate the shared weight values. Complicated, but certainly easier than the puzzling joint matrix matter. :laughing:


In order to view .egg files more conveniently, I’ve hacked together a simple collapsible .egg file viewer using Ttk Treeview. Might be useful for someone.

#!/usr/bin/env python
# http://stackoverflow.com/questions/16746387/tkinter-treeview-widget
import os
import Tkinter as tk
import ttk
import tkFileDialog


class App(tk.Frame):
    def __init__(self, master, path):
        master.title("Egg File Viewer")
        tk.Frame.__init__(self, master)

        self.masterFrame = ttk.Frame(self.master, width=1300, height=1000)
        self.masterFrame.grid(row=0,column=0)
        
        self.tree = ttk.Treeview(self.masterFrame, height="40")
        ysb = ttk.Scrollbar(self.masterFrame, orient='vertical', command=self.tree.yview)
        xsb = ttk.Scrollbar(self.masterFrame, orient='horizontal', command=self.tree.xview)
        self.tree.configure(yscroll=ysb.set, xscroll=xsb.set)
        self.tree.heading('#0', text=path, anchor='w')
        self.tree.column('#0',minwidth=0, width=1200, stretch=False)        

        root_node = self.tree.insert('', 'end', text=os.path.basename(path), open=True)
        self.display_eggfile(root_node, path)

        self.tree.grid(row=0, column=0)
        ysb.grid(row=0, column=1, sticky='ns')
        xsb.grid(row=1, column=0, sticky='ew')
        self.grid()

    def display_eggfile(self, parent, path):
        if os.path.exists(path):
            f = open(path)
            lines = f.readlines()
            f.close()            
            brackets = [parent]
            for num, line in enumerate(lines):
                line = line.replace("\n","")
                if line == "":
                    continue
                oid = self.tree.insert(brackets[len(brackets)-1], 'end', text=line, open=False)
                if line.find("{") != -1:
                    for rep in range(line.count("{")):
                        brackets.append(oid)
                if line.find("}") != -1:
                    for rep in range(line.count("}")):
                        closed = brackets.pop()
                
if __name__ == "__main__":    
    root = tk.Tk()
    path_to_my_project =tkFileDialog.askopenfilename(filetypes=[("Panda3D EGG Files", "*.egg *.EGG")],parent=root)
    root.destroy() # Silly business to prevent tkFileDialog from interfering with Treeview scrollbar focus
    root = tk.Tk()
    app = App(root, path=path_to_my_project)
    app.mainloop()

It’s looking like the only really good way to get the joint vertex weight data out of Poser is to parse it from a Collada export of a figure. Unfortunately, that requires a Pro version of Poser. Proper animation handling seems to require knowledge about a Poser actor’s joint rotation order, which is only available in Poser 10/Poser Pro 2014, with the addition of actor.Gimbal() to Poser Python. That means I have a working process for Poser export to .egg format, but it can only be used by those who have Poser Pro 2014, and (in the future) later Pro versions of Poser.

This is a bit frustrating, really. :imp:

The attached image shows what Poser Python will tell me about joint weights, contrasted with what can be acquired from a Collada export. The PPy weight set is pretty much useless. To expand upon this to have all the information needed for proper export, one would practically have to generate the weights from scratch, using very general rules and a lot of guesswork. As I like to point out, Poser Python is full of holes. :laughing:


Okay. After being sidelined for a few days by a toothache, I’ve gotten back to this. The vertex weights from a Poser Collada export of the test figure have been successfully applied for export to .egg format. The attached shows my test figure with the correct joints in Panda. So poser2egg has a working process, which unfortunately requires Poser Pro 2014, as noted above. I’m going to try to come up with a way to get (hopefully halfway decent) blended weights at the joints for cases where a Collada export is not available.


Excellent work!

Now that the weights are correct and I can see what I’m doing, I’m trying once again to tackle this joint orientation problem, which brings the thread back to its original topic. How to implement any rotation in that transform block? At the link provided by rdb, it is revealed that the same rotations need to be present both in the transform block and in the animation. Ideally, this could simply be a case of plugging in the same data in both places. But, ah, it is not so straightforward. :laughing: It becomes, at least in my case, a question of knowing how to guarantee the same data in both cases.

If I were the King of Panda, I would implement a few changes to the .egg format, to make it easier to work with and thus make conversions to and from .egg more approachable. I think everyone would agree that Panda3D could use more format conversion pathways. There are darned few working methods to get a figure with animated joints into .egg format to use in Panda. This is to the detriment of Panda overall. If it is hard to use, fewer people will use it. If it is difficult to do the most basic things, such as getting your animated models into .egg format, the range of potential users is severely restricted. So I would make these changes, to make the .egg format more approachable.

First, I would build into Panda an automated method to apply that Transform data to the joint animations. Panda knows what it wants, here, so why can’t it just do it internally? As it stands, even rdb, apparently one of the Panda programmers, can’t work out how to properly convert data for conversion to .egg format. The .x and .dae converters are broken and don’t provide full conversion, because this is an area where Panda makes things more difficult than they need to be.

Second, I would allow animation rotation data to be submitted in forms other than Euler angles. I can port a pose from Poser to Blender using quaternions and a couple of matrix transforms. The rotations come out correct, without any need to worry about Euler rotation order. Panda would benefit from a process like that. This is something else that could be handled internally by Panda. Read the rotations as quaternion, strip the parent’s transform matrix from the quat as matrix, and apply the resulting rotations. As it stands, a project like mine is hampered by the inherent problems with Euler conversions. Again, it seems like Panda should know what it wants from us and should help us along the way to providing good input data.

The third thing is more trifling, but I would expand the .egg format to permit multiple texture vertex references per vertex. This is not the same as “multiple UV sets”. This is splitting a texture vertex between polygons, for more flexible mapping of UVs. Texture vertices arguably belong to polygons more than vertices. A flexible handling of texture vertices can be found in the .obj format, among others. There can be as many texverts per vert as there are polys for that vert. This would make .egg more flexible and make conversions easier.

All of which is the grumbling, rambling way around to stating that there is still no evident solution to the .egg Transform matrix problem. :laughing: The problem seems to come down to Euler conversions or rotation ordering, or both. I have seen “good” test results in two cases. First, where I send no Transform rotation information at all, which is what I’ve been doing by default. Send the identity matrix as the Transform, and there are no problems. Unfortunately in that case the joints are often incorrect, to a greater or lesser extent. The second good result is seen only in the zeroed pose, as discussed in rdb’s link. When the Transform matrix itself is submitted as the only animation rotation data, everything looks fine. Until actual animation is mixed into the process, at which point there seem to be complications with the Euler conversion. For the third or fourth time, I reach the conclusion that there is no solution to this problem available to me. I would chalk this up to my being not-too-bright, except that rdb (who is obviously much smarter than I am) has the same trouble. So it sort of looks to me like this is an area where Panda could actually be improved.

You raise some good points.

Well, the transformations only need to be the same in the rest pose, or whatever it’s called. The way it works is that Panda copies the transformation from the joint table to the actual joints, which isn’t entirely absurd to me. If Poser gives transformations relative to the rest pose, then you should just have to transform the joints by the rest pose matrix, and if it gives them relative to the character root, you need to transform them by the inverse of their parent’s transform, though I suppose you know more about how much more complicated it actually gets than that.

I agree. It doesn’t take being a “King of Panda” to suggest these types of changes, though; and we will always consider your patches. :wink:

I may be a “Panda programmer”, but that doesn’t mean I’m familiar with every subsystem in Panda. :wink: I agree that Panda should be improved in this aspect, and having a reliable COLLADA pipeline would really help in this regard, I think.

You can use matrices, though, can’t you? In fact, that’s what I would recommend - keeping it in matrix form so that you don’t have to worry about the order of transformations.
It’s probably trivial to add support to use quaternions in .egg, given the fact that Panda already has all the methods for representing them and converting them to matrices or euler angles.

If there are two polygons sharing a vertex, simply create two vertices with the same position and have the polygons refer to different vertices. In most cases, there is no reason to unify vertex references between polygons if this gets in the way; the .egg loader is really good at optimising the loaded geometry in general.

The way you’re winking at me, I get the sense that I’m being mocked, as much as helped. A little wink for the audience while we humor this cdrei guy. Makes me edgy.

Can we submit animations in matrix format? I can only go by what I’ve read in the documentation, what I’ve seen in the (rather limited) range of example .egg files, and what I might discern from testing. The Egg Syntax documentation tells me this:

Here, it is suggested that we are submitting data for a matrix, but not submitting it as a matrix. The “rotate by pitch, heading, roll” is problematic, for my situation. I start with Euler rotations in Poser, then need to convert to matrix in order to process these by the default pose. Then I need to convert back to Euler in order to submit the data to Panda. In the course of this, problems crop up. Quite possibly I have faulty conversion code somewhere, but, if so, where? I’ve tested every bit of matrix-to-Euler code I can find. I have code which correctly converts the Poser rotations back and forth with minimal error, but it fails when the rest pose is factored in. At any rate, I see no evidence in the documentation that I can submit the animations in matrix format. :question:

How can I explain the problem clearly? Poser gives me no data about a rest pose matrix. In a Collada export, the rest pose matrix is an identity matrix with the proper translation portion added, which is to say, there are no rotations factored in. However, the joint orientation rotations do need to be factored in, for proper animation results. For the animation data, Poser will only give me the Euler rotations of a joint, as submitted using the Poser input dials. It will give me this in Euler, matrix, or quaternion formats, but it’s the same data. The cleanest way to access it is taking the Euler angles straight from those input dials, which avoids any conversion back to Euler from another format. This data, however, includes no information about the joint orientation. The joint orientation is what needs to be in the Panda Transform matrix for the rest pose state. Mixing orientation into the animation rotation only results in the sort of translocation errors that you reported in your linked thread. The attached images struggle to illustrate what I’m babbling about. Poser doesn’t cooperate with this effort, and Panda doesn’t provide any tools to ease the way. Part of my trouble is that I’m still not 100% certain what Panda wants from me. I do what seems to be correct, based on the only information I have available, but it isn’t what Panda actually requires.

The results I can get without factoring in the Poser joint orientation are close, as seen in one of the attached images, but still far enough from being correct as to be useless. It really begins to look like this isn’t an approachable problem, which is why I kvetch a bit about Panda’s shortcomings. How can one get an animated file into .egg format, without owning Maya or 3DS Max? Chicken is broken in recent Blender versions. Yabee has never been expanded to properly handle joint animations (which seems rather absurd). Panda’s own dae2egg and x2egg converters are broken and do not support joint animations either. Panda does not provide the tools needed by a user to convert a file into .egg format. Yet Panda makes the claim of supporting the dae and x formats, in spite of this. I’m sure you can understand how this is frustrating.

I’m sure I’m not explaining any of this well, and I’m equally sure that no one has any answers for me, whether I explain it well or not. :laughing: Sadly, I’m reaching the conclusion that this simply isn’t going to work. :cry:




Showing the best results so far for any effort to implement the joint orientations. This is the “best” because only the fingers have really gone crazy. :laughing: There are errors with any joint which needs to have orientation set, and the orientations of the fingers vary more extremely from the global axes than in other actors. Exactly what Panda wants in this case for correct handling seems uncertain. At the very least, there is a huge gap in the Panda documentation in this respect.


I’m not sure why you think I’m mocking you. I’m surely not, I can assure you. If anything, I admire your persistence, though I’m slightly frustrated that I’m not able to be of more help to you.

Sorry, I don’t know why I thought that it’s possible to write joint matrices in an .egg file. I re-read the documentation and you’re right.

I don’t really understand enough about this stuff to comment on the transformation stuff that Poser uses. It seems weird why the transformation and orientation of a joint would behave differently with respect to each other. It seems like this would be one set of transformations, and the only thing to figure out would be the specific coordinate system and the order of operations. If you can convert an arbitrarily rotated Poser object to a set of and commands in an .egg , then I guess that you would know the order, which is however you can order those to get it right in that case.

As for other ways to get it into Panda: well, another way might be to circumvent the .egg format entirely and write it straight to Panda’s structures. This means that you also don’ t have to deal with .egg’s weird conventions, like specifying vertices in world coordinates or not being able to use matrices for joint transforms. There is not much documentation for this, however.

Perhaps you could share your work I could get the trial of Poser and see if I can’t get some more insight into your issues? (I can’t promise that I’ll be of help, though, as this is not my area of expertise as I’ve already indicated.)

I am obsessive, when there’s a problem to be solved. :laughing: I am also cranky, when there isn’t enough information available to solve the problem. I tend to be paranoid about internet wink-y emoticons. Sometimes they are used as a sort of sarcasm flag. Other times they merely indicate good humor. I never know which is the case, unfortunately.

Well, a joint’s Transform block data can be submitted as a matrix. The animation data cannot. If we could submit animation rotations in some form other than Euler, it might reduce some problems with conversion to .egg format. Or it might not. However, more options could only be good, I would assume.

I do need to submit the Euler rotations for animation in the proper joint rotation order, so, yes, I do know that part. There are some oddities, however, with the coordinate system part. I am using Y-up-right, for the Poser system with Y up, +Z forward, and +X pointing to my right (a figure’s left). Yet I need to flip the sign of all my Z rotations, when submitting them to Panda. I assume Panda, then, is treating Y-up-right as though it had +Z pointing backward, not forward. Actually, this point touches upon one last idea I can test, for the orientation. I have not been flipping the Z rotations for orientation, as I have been for the animations. Possibly that is confusing matters, but I expect this test to fail like all the others. :laughing: However, the fact that Panda requires this Z rotation sign flip indicates that there’s an oddity somewhere in what Panda is doing. To some extent I seem to be fighting against a Panda idiosyncrasy, possibly a bug.

I can provide my testing code and everything but the textures for the figure, which are not redistributable. However, I’m not sure there is a trial version of Poser Pro 2014 available. This export script will only work in Poser Pro 2014, for full application of the process (which is to say, the ability to export a Poser Collada file). Poser 10 would be able to run the script using a Collada example file I could provide, but I’m not even sure there’s a trial version of Poser 10 available. At any rate, I think that’s more than you should have to do, for a problem such as this.

Ah, but see, you describe (when referring to Poser) a left-handed Y-up coordinate system (with +z being forward), not a right-handed one (which would have -z being forward). If Poser uses this, then you should in fact set the tag at the top to “y-up-left”, and you can specify everything in the .egg file in Poser coordinates without needing to flip the sign on the Z coordinates.

Panda will automatically convert to the internal (z-up-right) coordinate system when loading the .egg file, as long as you properly indicate what coordinate system the coordinates in the .egg file are specified in (by the use of this CoordinateSystem tag).

Interesting. I inherited Y-Up-Right from the previous maintainer of poser2egg. When I switch to Y-Up-Left, the attached image shows what happens. :open_mouth: All of my polygons are now backward, which I assume indicates that the winding order needs to be reversed when I build them. The figure now faces away from the default camera, rather than toward it. All X rotations are now backwards. The switch from Right to Left seems to have created some new oddities, and I can see why is-blackhole or Sartori decided that Y-Up-Right must be more correct. In every respect other than that flipped Z rotation issue, Y-Up-Right seems more compatible with Poser’s data than does Y-Up-Left. :open_mouth:

This leaves me with the option of rewriting portions of the script to cooperate with Y-Up-Left, in hopes that this change of coordinate system will correct the Transform matrix woes. Not a lot of fun, but perhaps worth testing. Sigh.

Edited to note that I have here tested setting the " { Y-Up-Left }" flag in the .egg files. I have also tried setting loadPrcFileData(’’, ‘coordinate-system yup-left’) in my Panda test code. That also flips everything around wildly.


Overall, Y-Up-Right seems more correct for Poser, if I assume that Panda is intended to correctly interpret the input data based on the submitted coordinate system. Whereas Y-Up-Right only requires flipped Z rotations, Y-Up-Left requires flipped polygons, recalculated normals, flipped X rotations, and perhaps other compensatory steps. My Panda model viewing code is derived from an example which uses the panda.egg file, and I am using the same camera setup as was used in that example. With poser2egg using Y-Up-Right, the figure faces forward, toward the camera, just like the panda.egg panda.

I get the sense that there’s something funny going on here… :open_mouth: The pieces don’t fit together properly, somewhere.

Meanwhile, I have tested flipping the Z rotation for the joint orientation. The result is just a slightly varied form of the same oddities I was seeing without flipping that Z sign. So that isn’t the solution to my problems, alas. :cry:

Hmm. I’m really thinking there’s no solution to this problem. I took a closer look at the Collada exports from Poser, and they seem to have the same problems with rotation accuracy. When I was seeing more accurate rotations, those were derived from custom poses that I had exported from Poser as quaternions, then applied in Blender using a custom script, then exported using ChickenR91.

Which makes me wonder if it’s time to think about this problem differently. What works best with Poser and Blender is a custom pose format. Why can’t such a thing be written for Panda? I wonder what you can tell me about setting joint rotations within Panda. I haven’t gotten to the point of exploring such things yet, being preoccupied with the Poser exporter. Can Panda set rotations as quaternion? If so, that would give me a way around this .egg export problem. I could export the figure in .egg format and the animation in a custom pose format.

The pose format I used with the Blender pose loader was simply:

Body,0.0,0.0,0.0,0.942072,0.000000,0.000000,0.000000,1.0,1.0,1.0
GoalCenterOfMass_4,0.0,0.0,0.0,1.000000,0.000000,0.000000,0.000000,1.0,1.0,1.0
CenterOfMass_4,0.0,0.0,0.0,1.000000,0.000000,0.000000,0.000000,1.0,1.0,1.0
Waist,0.0,0.0,0.0,0.882482,0.120103,0.449894,-0.066300,1.0,1.0,1.0
Hip,0.0,0.0,0.0,0.974456,-0.216040,-0.013217,-0.059617,1.0,1.0,1.0
Abdomen,0.0,0.0,0.0,0.999313,-0.026236,0.000687,0.026151,1.0,1.0,1.0
Chest,0.0,0.0,0.0,0.990249,-0.139308,0.000000,0.000000,1.0,1.0,1.0
Neck,0.0,0.0,0.0,0.979262,-0.105704,-0.156430,0.073498,1.0,1.0,1.0
Head,0.0,0.0,0.0,0.996846,-0.015065,-0.054289,0.055900,1.0,1.0,1.0

Which is just joint name, translation, rotation as quaternion, xyz scale. Application of the pose uses the following approach:

quat = (rest_matrix * quat_as_matrix * rest_matrix_invert).toQuat()

Which requires the ability to set rotations as quaternions, as well as a reliably accurate method of converting between quaternion and matrix forms. Of course, this works in Blender because Blender applies its own rest matrix information upon creating an armature (as shown in the code samples I posted on page 1 of this thread). If Panda only considers the Transform matrix submitted in the .egg file, this process might not help me at all because I am submitting identity matrices.

Still, it’s a thought, and I’m running out of ideas, here. :laughing: Would Panda cooperate to allow me to implement a custom pose format like this? :question: