Panda3D Manual: Vertices in Panda3D
  <<prev top next>>  

How Panda Stores Vertex Information

As with any major 3D engine, geometry in Panda3D is primarily defined by vertices. So before we discuss how to actually make geometry we have to discuss how Panda3D handles them.The following information only applies to Panda3D 1.1. For more information you can visit the Panda Developers Wiki

Vertex Format

In order to define a vertex Panda3D has to know what format the vertex has. The format decides what information the vertex can store(such as color, texture coordinate, normals, etc..). That information is stored in an object from the GeomVertexFormat class. Panda3D comes with several predefined formats which you can get from the GeomVertexFormat.get*() family of functions. The naming format for these functions are:

V3This means the position of the vertex is encoded in the format. All formats begin with this.
n3This means the normal (3 components) of each vertex is encoded in the format.
cp or c4This means the color of each vertex is encoded in the format. cp means the color will be packed DirectX style while c4 means the color will be stored in four bytes, OpenGL style. Panda will automatically convert the types at runtime if you are not using the native backend (cp for OpenGl or c4 for DirectX).
t2This means the texture coordinates (2 components) of each vertex are encoded in the format.

You can omit options you dont want but the formats have to be added in the order listed above. For example:

 #this is valid
GeomVertexFormat.getV3n3()
#this isnt valid(V3 must always come first)
GeomVertexFormat.getn3V3()
#this is valid
GeomVertexFormat.getV3cpt2()
#this isnt valid (color must come before texture)
GeomVertexFormat.getV3t2cp()
#this is plain wrong
GeomVertexFormat.getcpV3t2n3()

Making Your Own Custom Format

In addition to the formats that come with Panda you can define your own. However this is advance usage and will only be touched upon here. See the Panda 1.1 documentation (which should be out soon) for more information. GeomVertexFormat is really a container of GeomVertexArrayFormat objects.These objects are made up of GeomVertexColumn objects which describe what attributes the format encodes in the vertices. Having one GeomVertexArrayFormat object with all the GeomVertexColumn objects is practically the same as having a seperate GeomVertexArrayFormat object for each GeomVertexColumn. The following example should make things clearer:

format=GeomVertexFormat()

formatArray=GeomVertexArrayFormat()

#we use the addColumn(name, numComponents, NumericType, Contents) function
#Contents tell Panda how to update the information, if neccessary
#i.e. if you apply a transformation to this geometry all columns that have
#Geom.CPoint for Contents will be updated appropriately

#the hard way to get the V3n3cpt2 format
formatArray.addColumn(InternalName.make("vertex"), 3,Geom.NTFloat32, Geom.CPoint)
formatArray.addColumn(InternalName.make("color"), 4,Geom.NTPackedDcba, Geom.CColor)
formatArray.addColumn(InternalName.make("normal"), 3,Geom.NTFloat32, Geom.CVector)
formatArray.addColumn(InternalName.make("texcoord"), 2,Geom.NTFloat32, Geom.CTexcoord)

#if we can keep adding more GeomVertexArrayFormat objects as long as none of
#the columns have the same name
format.addArray(formatArray)

#we have to register formats before we use them.
format=GeomVertexFormat.registerFormat(format)

#now format can be used just as any other GeomVertexFormat

None of the GeomVertexArrayFormat objects can have GeomVertexColumn objects with the same name. Furthermore, the column names "vertex", "color", "normal", and "texcoord" are the only attributes that directly map to their counterpart ("vertex" will hold the current position of the vertex in Panda, "color" will hold the current color assigned through Panda, etc...). The standard formats above are already setup to use these default names. Any attributes you add other than these have no meaning to Panda (not unlike the setTag interface for NodePaths).


Vertex Data

GeomVertexData objects are used to hold the information encoded in vertices. They have a row for each vertex and a column for each attribute the vertex should have (i.e. color, etc...). You need to have at least one of these objects before you can make any vertices of your own. You can create them using GeomVertexData(name, format, usageHint). name is just the arbitrary name you want to give it. format is an object from the GeomVertexFormat class. This lets the GeomVertexData object know how many columns it should have. The last parameter usageHint tells Panda what optimizations it can perform on the vertices in this GeomVertexData object. The types of usage hints are:

Geom.UHClientDon't attempt to upload the data; always keep it on the client. This is used for very special purposes only; typically you would use Geom.UHStream instead.
Geom.UHStreamFor objects that are going to be rendered a few times and then discarded.
Geom.UHDynamicFor objects that will have their data modified by the program.
Geom.UHStaticFor objects that will not have their state change during the program (This does not count animations or scene graph transformations).

These hints are ordered from most dynamic to most static. The most common usage hint, by far, is Geom.UHStatic; if you have any uncertainty, you should probably use this one.

Using the constructor is the only functionality of the GeomVertexData class that you should really use. Use GeomVertexReader to read the information in a GeomVertexData object or GeomVertexWriter to change/add information (both classes are discussed below).

An example:

format=GeomVertexFormat.getV3n3cpt2()

#use this if you want to create vertices whose information wont change often
myVertexData=GeomVertexData("holds my vertices", format, Geom.UHStatic)

Reading and Writing Vertex Information

Messing around directly with GeomVertexData objects directly leaves a lot of room for error. The preferred way to read/write information from/to a GeomVertexData object is to use the GeomVertexReader and GeomVertexWriter classes. Both are optimized for reading/writing down the same column (the same attribute). You can change columns if you need to using their setColumn functions, but if you have to change columns often it is more efficient to create multiple GeomVertexReader/GeomVertexWriter objects, one for each column.

Whenever you perform a read/write function with these classes they automatically move down to the next row (next vertex). You can get the row you are currently on by calling getReadRow() and getWriteRow() respectively. You can also set the row using the setRow(newRow) function for both classes. To find out if you are at the end of column use isAtEnd().

If you are reading and writing at the same time you must create the GeomVertexWriter objects before GeomVertexReader objects. However using the class GeomVertexRewriter, which has the functionality of both classes, is the preferred way to read/write data at the same time.

GeomVertexWriter

This class has two sets of functions. The setData*(...) functions will crash if you try to write when isAtEnd() is True. Use this set of functions if you wish to modify the vertices in a GeomVertexData object but not add to them. The addData*(...) functions will automatically add a row to the GeomVertexData object if it reaches the end.

The syntax is the same for both sets of functions. You have setData or addData followed by the number of components (1,2,3 or 4) and then followed by the type(i for integer or f for float). For example:

 #assume a V3n3cpt2 format
#the constructor takes the GeomVertexData object you want to modify and the column you want
#to go down. If you dont specify the column you start out at the zeroth column in vdata. myWriter=GeomVertexWriter(vdata, "vertex")

#this will crash if there are no vertices
myWriter.setData3f(0.0,0.0,0.0)

#this will work no matter what
myWriter.addData3f(0.0, 0.0, 0.0)

#now we want to edit the texture coordinats
myWriter=GeomVertexWriter(vdata, "texcoord")

#now we use addData2f instead since this is only two components
myWriter.addData2f(0.0,0.0)

All the setData and addData functions have a vector counterpart where appropriate.

GeomVertexReader

This class only has one set of functions, the getData*(....) functions. Their naming syntax follows the same rules as the setData and addData functions but you can only use "f" as the type. The getData*(...) functions all return vecotrs of the appropriate type when neccessary (Vec4 for four components, but just the number for one component attributes).

A brief example:

 #assume a V3n3cpt2 format
#the constructor takes the GeomVertexData object you want to read and the column you want
#to go down. If you dont specify the column you start out at the zeroth column in vdata. myReader=GeomVertexReader(vdata, "vertex")

#this will crash if there are no vertices
position=myReader.getData3f()

#now we want to read the texture coordinats
myReader=GeomVertexReader(vdata, "texcoord")

#now we use getData2f instead since this is only two components
texcoord=myReader.getData2f()

  <<prev top next>>