Panda3D Manual: Creating Geometry from Scratch
<<prev | top | next>> |
## Creating Geometry of Your Own Making your own geometry on the fly can be broken down into 3 steps: 1)Create a GeomVertexData object to hold the vertices of your geometry. Add the data for all the vertices you will need. 2)Create `GeomPrimitive` objects and assign vertices to them 3)Create a `Geom` object with the object created in step 1 and add all the primitives you created. You can know put this Geom in a GeomNode and render the geometry. The following sections explains these processes in detail. ## The Geom and GeomPrimitive Class `GeomPrimitive` is the base class for all the primary shapes that Panda can draw (GeomLines, GeomLinestrips, GeomPoints, GeomTriangles, GeomTrifans, and GeomTristrips). Any geometry that is rendered is broken down into these shapes. You cannot mix objects of different fundamental types, for instance, GeomLines, GeomTriangles, and GeomPoints, in the same Geom; but you can (and should) put GeomTriangles, GeomTrifans, and GeomTristrips together, or GeomLines and GeomLinestrips together. Each kind of GeomPrimitive constructor accepts a UsageHint parameter. The list of possible UsageHints is the same as that given for `GeomVertexData` objects. `GeomPrimitive` objects keep track of what vertices to use by storing a list of integers. These integers tell the object which row in the `GeomVertexData` object it will be associated with has the vertex it needs. This is why when you add a vertex to a `GeomPrimitive` object, using `addVertex(rowNum)`, you have to supply the row of the vertex. There are also some convenience functions built on top of `addVertex`. `addConsecutiveVertices(int start, int vertNum)` adds `vertNum` vertices from the `GeomVertexData` object starting from the row `start`. There is also `addNextVertices(numAdd)` which acts like `addConsecutiveVertices` but uses the last vertex you have added as `start`. When you are done adding the vertices to a `GeomPrimitive` object for each primitive you must call the `closePrimitive()` function. This makes sure that the number of vertices you have added to the primitive define it properly. Note that each GeomPrimitive object can store more than one of its particular kind of primitive; for instance, you can store many triangles in a single GeomTriangles object, and many triangle strips in a single GeomTristrips. You do this by adding all the vertex numbers in order, calling closePrimitive() after you have added the vertices for each primitive. When this process is done you have to place these `GeomPrimitive` objects in a `Geom` object. You must pass the `GeomVertexData` object to the `Geom` constructor. You can add many GeomPrimitives to a single Geom, but primitives in the same Geom object must take their vertices from the same GeomVertexData. Furthermore, several Geom objects can share the same GeomVertexData object. You can add primitives to Geom objects by using `addPrimitive(myPrimitive)` where myPrimitive is the `GeomPrimitive` you want to add. When the `Geom` object is setup, you can now place it in a `GeomNode` object and place it in the scene graph using `addGeom(myGeom)` where `myGeom` is the `Geom` object you want to add. Usage tip: modern PC graphics cards can render many thousands of triangles in a frame, but the PC bus can only handle a few hundred triangle batches in a 60Hz frame. In Panda, each GeomPrimitive is sent to the graphics card as a single batch, therefore, it is important to minimize the number of GeomPrimitive objects in your scene graph, and to put as many triangles as possible within a single GeomPrimitive--assuming they are all going to be onscreen at the same time anyway. On the other hand, if you put too many unrelated triangles in the same GeomPrimitive, with both offscreen and onscreen triangles in the same primitive, then you will be wasting time drawing all of the offscreen triangles. Finding the best balance point is difficult and depends on the quality of graphics hardware your application is targeting. As a general rule of thumb, it is best to use as few GeomPrimitives as possible for small, atomic objects, but also to break up your scene into many individual objects (i.e. GeomNodes) that can easily be culled when they go offscreen. An example to clarify things:
#in this example, we'll show how to make a square from scratch #There is no "GeomQuad" class so we have to use two triangles. #step 1) create GeomVertexData and add vertex information format=GeomVertexFormat.getV3() vdata=GeomVertexData("vertices", format, Geom.UHStatic) vertexWriter=GeomVertexWriter(vdata, "vertex") vertexWriter.addData3f(0,0,0) vertexWriter.addData3f(1,0,0) vertexWriter.addData3f(1,0,1) vertexWriter.addData3f(0,0,1) #step 2) make primitives and assign vertices to them tris=GeomTriangles(Geom.UHStatic) #have to add vertices one by one since they are not in order tris.addVertex(0) tris.addVertex(1) tris.addVertex(3) #indicates that we have finished adding vertices for the first triangle. tris.closePrimitive() #since the coordinates are in order we can use this convenience function. tris.addConsecutiveVertices(1,3) #add vertex 1, 2 and 3 tris.closePrimitive() #step 3) make a Geom object to hold the primitives squareGeom=Geom(vdata) squareGeom.addPrimitive(tris) #now put squareGeom in a GeomNode. You can now position your geometry in the scene graph. squareGN=GeomNode("square") squareGN.addGeom(squareGeom) render.attachNewNode(squareGN)
<<prev | top | next>> |