Using a <Transform> in an Egg file I'm writing myself

Disclaimer/background: I’m a new user of Panda3d, and I’m not writing games - I’m mostly looking at it to render 3d things made of… geometry. There will be animation. I’m not a very visual person and have tried and failed to use tools like Blender. And besides, I want to make this stuff from code, not by drawing.

My short term objective is to write model .egg files; I’ve been writing these out and popping them up in pview for inspection. I’ve drawn a box and a sphere and a pyramid successfully. Now I’m trying to draw two spheres (think simple orrery) separated by some distance.

I’m having trouble understanding how a Group’s <Transform> affects the position of the group, if at all. The Egg Syntax documents say that all points are in world space. My sphere code generates spheres centred on the origin. So I get a pair of nested spheres. What effect does a <Transform> node have, if the vertices are all in world space?

I’d hoped to just provide a transform containing a <Translate> to shift the second sphere away, but clearly my mental model is wrong. Like this:

<Group> "sphere(10.000000x20)" {
    <Transform> {
      <Translate> { 100 0 0 }
    }
    <VertexPool> "sphere(10.000000x20)" {
      <Vertex> 1 {
        0 6.123233995736766e-16 -10
        <UV> { 0 0 }
      }
      <Vertex> 2 {
        0 1.5643446504023093 -9.876883405951379
        <UV> { 0 0.05 }
      }

and so on.

What’s the sanest approach to defining a sphere not at the origin, if I’ve got code which generates a sphere-at-the-origin?

What’s the effect of the <Transform> node in a model?

Thanks,
Cameron Simpson

I’ve been doing some digging around in this forum, paricularly this post: Egg "Transform" node cancelled by loader - #6 by drwr

From this I gather that in Egg files:

  • vertices are in world coordinates (as stated in the docs)
  • the in memory models derived from the Egg files keep their contents in “local” coordinates, from which world/rendering coordinates are derives from the transforms applied to the node they’re in
  • therefore the transforms in a <Group> are a record of how the world coordinates were arrived at, if only to reverse these to get the in memory local coordinates

So it’s sounding like the approach I’ll take is to provide a sequence of transforms to the sphere (or whatever I make) which (a) apply the transform to the vertices and (b) record the transform for transcription in the Egg file when written.

Is that sane?

Cheers,
Cameron Simpson

Hi, welcome to the forums!

Yes, you’ve figured it out correctly.

The Transform mostly affects the transformation of any resulting nodes that are created. Otherwise they would all be at (0, 0, 0).

However, you could alternatively use the <Instance> node instead of the <Group> node if you want to create a local coordinate space for the vertices therein. Personally, I’d just apply the transform.

Thanks for confirming that.

The <Instance> is attractive, in that I wouldn’t have to transform all the vertices in my object definition - I could defer all that to Panda’s rendering engine once it loads the model? But wouldn’t I have the same problem placing the <Instance>? It isn’t clear to me from the Egg Syntax document how an <Instance> takes its place in the Model’s world.

Supposing I’ve got 2 <Instances> defining spheres (in my current example, and of course they’re spherical collections of polygons). If I defined 2 sphere-ish <Instance>s of 1.0 radius spheres, can you show me what the surrounding Egg file might look like if I wanted them 10.0 units apart?

Cheers,
Cameron Simpson

An Instance is identical to a Group except that it defines a local coordinate space that the vertices are considered relative to.

I’m running with <Instance>s for now. Example of the second sphere, offset 100 units from the first sphere (which sits untranslated at the origin):

<Instance> "sphere(10.000000x20)" {
    <Transform> {
      <Translate> { 100 0 0 }
    }
    <VertexPool> "sphere(10.000000x20)" {
      <Vertex> 1 {
        0 6.123233995736766e-16 -10
        <UV> { 0 0 }
      }

This avoids embedding transformation support (in terms of computing transformations on vertices) in my authoring/export code, and feels like a good fit for my current approach.

To clarify my mental model:

  • <Group>s use world coordinates, and their transforms represent those used to arrive at those coordinates, and are reversed to make local coordinates for use in the model nodes inside Panda?
  • <Instance>s use a local coordinate space, and their transforms are applied to the model nodes, which hold the instance local space coordinates?

For me, this feels like a good approach:

  • create objects of desired form
  • place them in the world

I’m using homegrown classes to represent the Egg nodes and the higher level things which contain or generate them, so doing translations in the authoring end will be kind of slow, whereas an <Instance> lets me specify the core object and let Panda apply the transforms efficiently once the model is loaded.

Cheers,
Cameron Simpson