Student Recreation of "Colossus"
Epoch: a space combat game
Keepsake: a short interactive movie, themes of loss

Panda3D Manual: Egg Syntax

The Egg Syntax

This is a condensed version of the Egg Syntax document, incorporating only syntax definitions in common use. For complete documentation, please see the Egg Syntax documentation from the Panda3D source code repository.


General Syntax

Egg files consist of a series of sequential and hierarchically-nested entries. In general, the syntax of each entry is:

 <Entry-type> name { contents }

Comment text should be enclosed in quotation marks:

 <Comment> { text }

Local Information Entries

These nodes contain information relevant to the current level of nesting only.

 <Scalar> name { value }

Scalars are attributes of the entry the Scalar is in. Name is the attribute name with value as the contents of that attribute.

Global Information Entries

These nodes contain information relevant to the file as a whole. They can be nested along with geometry nodes, but this nesting is irrelevant and the only significant placement rule is that they should appear before they are referenced.

Coordinate System

 <CoordinateSystem> { string }

This entry indicates the coordinate system used in the egg file; the egg loader will automatically make a conversion if necessary. The following strings are valid: Y-up, Z-up, Y-up-right, Z-up-right, Y-up-left, or Z-up-left. (Y-up is the same as Y-up-right, and Z-up is the same as Z-up-right.)


This describes a texture file that can be referenced later with <TRef> { name }.

<Texture> name {

Texture Scalars

This is not a complete list of texture attributes. Please refer to the full document for all scalars and their value definitions

 <Scalar> alpha-file { alpha-filename }
 <Scalar> alpha-file-channel { channel }
 <Scalar> format { format-definition }
 <Scalar> type { texture-type }
 <Scalar> envtype { environment-type }
 <Scalar> tex-gen { mode }
 <Scalar> stage-name { name }
 <Scalar> uv-name { name }
 <Scalar> rgb-scale { scale }
 <Scalar> alpha-scale { scale }
 <Scalar> alpha { alpha-type }
 <Transform> { transform-definition }


This defines a set of material attributes that may later be referenced with <MRef> { name }.

<Material> name {

Material Scalars

 <Scalar> diffr { number }
 <Scalar> diffg { number }
 <Scalar> diffb { number }
 <Scalar> diffa { number }
 <Scalar> ambr { number }
 <Scalar> ambg { number }
 <Scalar> ambb { number }
 <Scalar> amba { number }
 <Scalar> emitr { number }
 <Scalar> emitg { number }
 <Scalar> emitb { number }
 <Scalar> emita { number }
 <Scalar> specr { number }
 <Scalar> specg { number }
 <Scalar> specb { number }
 <Scalar> speca { number }
 <Scalar> shininess { number }
 <Scalar> local { flag }

Vertex Pool

A vertex pool is a set of vertices. All geometry is created by referring to vertices by number in a particular vertex pool. There may be one or several vertex pools in an egg file, but all vertices that make up a single polygon must come from the same vertex pool. The body of a <VertexPool> entry is simply a list of one or more <Vertex> entries, as follows:

<VertexPool> name {
  <Vertex> number1 {
  <Vertex> numer2 {


A <Vertex> entry is only valid within a vertex pool definition. The number is the index by which this vertex will be referenced. It is optional; if it is omitted, the vertices are implicitly numbered consecutively beginning at one. If the number is supplied, the vertices need not be consecutive.

The vertex's coordinates are always given in world space, regardless of any transforms before the vertex pool or before the referencing geometry. If the vertex is referenced by geometry under a transform, the egg loader will do an inverse transform to move the vertex into the proper coordinate space without changing its position in world space. One exception is geometry under an <Instance> node; in this case the vertex coordinates are given in the space of the <Instance> node. (Another exception is a <DynamicVertexPool>; see below.)

  <Vertex> number {
    x y z [w]
Vertex Attributes
 <Normal> { x y z [morph-list] }
 <RGBA> { r g b a [morph-list] }
 <UV> [name] { u v [w] [tangent] [binormal] [morph-list] }
 <Dxyz> target { x y z }

Geometry Entries

Geometry entries reference Vertex pool entries to generate renderable geometry for Panda to use.


A polygon consists of a sequence of vertices from a single vertex pool. Vertices are identified by pool-name and index number within the pool; indices is a list of vertex numbers within the given vertex pool. Vertices are listed in counterclockwise order. Although the vertices must all come from the same vertex pool, they may have been assigned to arbitrarily many different joints regardless of joint connectivity (there is no "straddle-polygon" limitation). See Joints, below.

The polygon syntax is quite verbose, and there isn't any way to specify a set of attributes that applies to a group of polygons--the attributes list must be repeated for each polygon. This is why egg files tend to be very large.

<Polygon> name { 
    <VertexRef> { 
        <Ref> { pool-name } 

Polygon Attributes

 <TRef> { texture-name }
 <Texture> { filename }
 <MRef> { material-name }
 <Normal> { x y z [morph-list] }
 <RGBA> { r g b a [morph-list] }
 <BFace> { boolean-value }
 <Scalar> bin { bin-name }
 <Scalar> draw_order { number }
 <Scalar> visibility { hidden | normal }

Grouping Entries

A <Group> node is the primary means of providing structure to the egg file. Groups can contain vertex pools and polygons, as well as other groups. The egg loader translates <Group> nodes directly into PandaNodes in the scene graph (although the egg loader reserves the right to arbitrarily remove nodes that it deems unimportant--see the <Model> flag, below to avoid this). In addition, the following entries can be given specifically within a <Group> node to specify attributes of the group.

<Group> name {

Grouping Attributes

 <DCS> { boolean-value }
 <DCS> { dcs-type }
 <Model> { boolean-value }
 <Dart> { boolean-value }
 <Switch> { boolean-value }

Group Scalars

 <Scalar> fps { frame-rate }
 <Scalar> bin { bin-name }
 <Scalar> draw_order { number }
 <Scalar> visibility { hidden | normal }
 <Scalar> decal { boolean-value }
 <Scalar> decalbase { boolean-value }
 <Scalar> collide-mask { value }
 <Scalar> from-collide-mask { value }
 <Scalar> into-collide-mask { value }
 <Scalar> blend { mode }
 <Scalar> blendop-a { mode }
 <Scalar> blendop-b { mode }
 <Scalar> blendr { red-value }
 <Scalar> blendg { green-value }
 <Scalar> blendb { blue-value }
 <Scalar> blenda { alpha-value }

Other Group Attributes


 <Billboard> { type }

This entry indicates that all geometry defined at or below this group level is part of a billboard that will rotate to face the camera. Type is either "axis" or "point", describing the type of rotation.

Billboards rotate about their local axis. In the case of a Y-up file, the billboards rotate about the Y axis; in a Z-up file, they rotate about the Z axis. Point-rotation billboards rotate about the origin.

There is an implicit <Instance> around billboard geometry. This means that the geometry within a billboard is not specified in world coordinates, but in the local billboard space. Thus, a vertex drawn at point 0,0,0 will appear to be at the pivot point of the billboard, not at the origin of the scene.


 <SwitchCondition> {
    <Distance> { 
       in out [fade] <Vertex> { x y z }

The subtree beginning at this node and below represents a single level of detail for a particular model. Sibling nodes represent the additional levels of detail. The geometry at this node will be visible when the point (x, y, z) is closer than "in" units, but further than "out" units, from the camera. "fade" is presently ignored.


 <Tag> key { value }

This attribute defines the indicated tag (as a key/value pair), retrievable via NodePath::get_tag() and related interfaces, on this node.


 <Collide> name { type [flags] }

This entry indicates that geometry defined at this group level is actually an invisible collision surface, and is not true geometry. The geometry is used to define the extents of the collision surface. If there is no geometry defined at this level, then a child is searched for with the same collision type specified, and its geometry is used to define the extent of the collision surface (unless the "descend" flag is given; see below).

   Valid types so far are:
     The geometry represents an infinite plane.  The first polygon
     found in the group will define the plane.
     The geometry represents a single polygon.  The first polygon is
     The geometry represents a complex shape made up of several
     polygons.  This collision type should not be overused, as it
     provides the least optimization benefit.
     The geometry represents a sphere.  The vertices in the group are
     averaged together to determine the sphere's center and radius.
     The geometry represents an inverse sphere.  This is the same as
     Sphere, with the normal inverted, so that the solid part of an
     inverse sphere is the entire world outside of it.  Note that an
     inverse sphere is in infinitely large solid with a finite hole
     cut into it.
     The geometry represents a tube.  This is a cylinder-like shape
     with hemispherical endcaps; it is sometimes called a capsule or
     a lozenge in other packages.  The smallest tube shape that will
     fit around the vertices is used.

   The flags may be any zero or more of:
     Throws the name of the <Collide> entry, or the name of the
     surface if the <Collide> entry has no name, as an event whenever
     an avatar strikes the solid.  This is the default if the
     <Collide> entry has a name.
     Rather than being a solid collision surface, the defined surface
     represents a boundary.  The name of the surface will be thrown
     as an event when an avatar crosses into the interior, and
     name-out will be thrown when an avatar exits.
     Instead of creating only one collision object of the given type,
     each group descended from this node that contains geometry will
     define a new collision object of the given type.  The event
     name, if any, will also be inherited from the top node and
     shared among all the collision objects.

     Don't discard the visible geometry after using it to define a
     collision surface; create both an invisible collision surface
     and the visible geometry.
     Stores a special effective normal with the collision solid that
     points up, regardless of the actual shape or orientation of the
     solid.  This can be used to allow an avatar to stand on a
     sloping surface without having a tendency to slide downward.


 <ObjectType> { type }

This is a short form to indicate one of several pre-canned sets of attributes. Type may be any word, and a Config definition will be searched for by the name "egg-object-type-word", where "word" is the type word. This definition may contain any arbitrary egg syntax to be parsed in at this group level.

   A number of predefined ObjectType definitions are provided:
     This is equivalent to <Collide> { Polyset descend }.  The
     geometry defined at this root and below defines an invisible
     collision solid.
     This is equivalent to <Collide> { Polyset descend intangible }.
     The geometry defined at this root and below defines an invisible
     trigger surface.
     Equivalent to <Collide> { Sphere descend }.  The geometry is
     replaced with the smallest collision sphere that will enclose
     it.  Typically you model a sphere in polygons and put this flag
     on it to create a collision sphere of the same size.
     Equivalent to <Collide> { Tube descend }.  As in sphere, above,
     but the geometry is replaced with a collision tube (a capsule).
     Typically you will model a capsule or a cylinder in polygons.
     Equivalent to <Collide> { Sphere keep descend }.  A collision
     bubble is placed around the geometry, which is otherwise
     Equivalent to <Scalar> collide-mask { 0 }.  It means that the
     geometry beginning at this node and below should never be
     collided with--characters will pass through it.
     This has no equivalent; it is treated as a special case.  It
     means that the geometry at this node and below should not be
     translated.  This will normally be used on scale references and
     other modeling tools.
   There may also be additional predefined egg object types not
   listed here; see the *.pp files that are installed into the etc
   directory for a complete list.
 <Transform> { transform-definition }
 <VertexRef> { indices <Ref> { pool-name } }

Joint Nodes

<Joint> name {

A joint is a highly specialized kind of grouping node. A tree of joints is used to specify the skeletal structure of an animated character.

A joint may only contain one of three things. It may contain a entry, as above, which defines the joint's unanimated (rest) position; it may contain lists of assigned vertices or CV's; and it may contain other joints. A tree of <Joint> nodes only makes sense within a character definition, which is created by applying the <DART> flag to a group. See <DART>, above. The vertex assignment is crucial. This is how the geometry of a character is made to move with the joints. The character's geometry is actually defined outside the joint tree, and each vertex must be assigned to one or more joints within the tree. This is done with zero or more <VertexRef> entries per joint, as the following: <VertexRef> { indices [<Scalar> membership { m }] <Ref> { pool-name } } This is syntactically similar to the way vertices are assigned to polygons. Each <VertexRef> entry can assign vertices from only one vertex pool (but there may be many <VertexRef> entries per joint). Indices is a list of vertex numbers from the specified vertex pool, in an arbitrary order. The membership scalar is optional. If specified, it is a value between 0.0 and 1.0 that indicates the fraction of dominance this joint has over the vertices. This is used to implement soft-skinning, so that each vertex may have partial ownership in several joints. The <VertexRef> entry may also be given to ordinary <Group> nodes. In this case, it treats the geometry as if it was parented under the group in the first place. Non-total membership assignments are meaningless.

Bundle and Table entries

A table is a set of animated values for joints. A tree of tables with the same structure as the corresponding tree of joints must be defined for each character to be animated. Such a tree is placed under a <Bundle> node, which provides a handle within Panda to the tree as a whole.

Bundles may only contain tables; tables may contain more tables, bundles, or any one of the following (<Scalar> entries are optional, and default as shown):

<S$Anim> name { 
  <Scalar> fps { 24 }
  <V> { values }