pfSubdivSurface(3pf) OpenGL Performer 3.2.2 libpf C Reference Pages
NAME
pfNewSubdivSurface, pfGetSubdivSurfaceClassType, pfSubdivSurfaceFlags,
pfGetSubdivSurfaceFlags, pfSubdivSurfaceVal, pfGetSubdivSurfaceVal,
pfSubdivSurfaceMesh, pfGetSubdivSurfaceMesh,
pfSubdivSurfaceUpdateControlMesh - Represents a subdivision surface.
FUNCTION SPECIFICATION
#include <Performer/pf.h>
pfSubdivSurface* pfNewSubdivSurface(void *arena);
pfType* pfGetSubdivSurfaceClassType(void);
void pfSubdivSurfaceFlags(pfSubdivSurface* subdivsurface,
int which, int value);
int -
pfGetSubdivSurfaceFlags(pfSubdivSurface* subdivsurface,
int which);
void pfSubdivSurfaceVal(pfSubdivSurface* subdivsurface,
int which, float val);
void pfGetSubdivSurfaceVal(pfSubdivSurface* subdivsurface,
int which, float *val);
void pfSubdivSurfaceMesh(pfSubdivSurface* subdivsurface,
pfMesh *mesh);
pfMesh* -
pfGetSubdivSurfaceMesh(pfSubdivSurface* subdivsurface);
void -
pfSubdivSurfaceUpdateControlMesh(pfSubdivSurface* subdivsurface);
PARENT CLASS FUNCTIONS
The OpenGL Performer class pfSubdivSurface is derived from the parent
class pfGeode, so each of these member functions of class pfGeode are
also directly usable with objects of class pfSubdivSurface. Casting an
object of class pfSubdivSurface to an object of class pfGeode is taken
care of automatically. This is also true for casts to objects of
ancestor classes of class pfGeode.
int pfAddGSet(pfGeode* geode, pfGeoSet* gset);
int pfRemoveGSet(pfGeode* geode, pfGeoSet* gset);
int pfInsertGSet(pfGeode* geode, int index, pfGeoSet* gset);
int pfReplaceGSet(pfGeode* geode, pfGeoSet* old, pfGeoSet* new);
pfGeoSet * pfGetGSet(const pfGeode* geode, int index);
int pfGetNumGSets(const pfGeode* geode);
Page 1
pfSubdivSurface(3pf) OpenGL Performer 3.2.2 libpf C Reference Pages
Since the class pfGeode is itself derived from the parent class pfNode,
objects of class pfSubdivSurface can also be used with these functions
designed for objects of class pfNode.
pfGroup * pfGetParent(const pfNode *node, int i);
int pfGetNumParents(const pfNode *node);
void pfNodeBSphere(pfNode *node, pfSphere *bsph, int mode);
int pfGetNodeBSphere(pfNode *node, pfSphere *bsph);
pfNode* pfClone(pfNode *node, int mode);
pfNode* pfBufferClone(pfNode *node, int mode, pfBuffer *buf);
int pfFlatten(pfNode *node, int mode);
int pfNodeName(pfNode *node, const char *name);
const char * pfGetNodeName(const pfNode *node);
pfNode* pfFindNode(pfNode *node, const char *pathName,
pfType *type);
pfNode* pfLookupNode(const char *name, pfType* type);
int pfNodeIsectSegs(pfNode *node, pfSegSet *segSet,
pfHit **hits[]);
void pfNodeTravMask(pfNode *node, int which, uint mask,
int setMode, int bitOp);
uint pfGetNodeTravMask(const pfNode *node, int which);
void pfNodeTravFuncs(pfNode* node, int which,
pfNodeTravFuncType pre, pfNodeTravFuncType post);
void pfGetNodeTravFuncs(const pfNode* node, int which,
pfNodeTravFuncType *pre, pfNodeTravFuncType *post);
void pfNodeTravData(pfNode *node, int which, void *data);
void * pfGetNodeTravData(const pfNode *node, int which);
void pfNodeTravMode(pfNode* node, int which, int mode,
int val);
int pfGetNodeTravMode(const pfNode* node, int which,
int mode);
Since the class pfNode is itself derived from the parent class pfObject,
objects of class pfSubdivSurface can also be used with these functions
designed for objects of class pfObject.
void pfUserDataSlot(pfObject *obj, int slot, void *data);
void pfUserData(pfObject *obj, void *data);
void* pfGetUserDataSlot(pfObject *obj, int slot);
void* pfGetUserData(pfObject *obj);
int pfGetNumUserData(pfObject *obj);
int pfGetNamedUserDataSlot(const char *name);
const char* pfGetUserDataSlotName(int slot);
int pfGetNumNamedUserDataSlots(void);
int pfDeleteGLHandle(pfObject *obj);
Since the class pfObject is itself derived from the parent class
pfMemory, objects of class pfSubdivSurface can also be used with these
functions designed for objects of class pfMemory.
Page 2
pfSubdivSurface(3pf) OpenGL Performer 3.2.2 libpf C Reference Pages
pfType * pfGetType(const void *ptr);
int pfIsOfType(const void *ptr, pfType *type);
int pfIsExactType(const void *ptr, pfType *type);
const char * pfGetTypeName(const void *ptr);
int pfRef(void *ptr);
int pfUnref(void *ptr);
int pfUnrefDelete(void *ptr);
int pfUnrefGetRef(void *ptr);
int pfGetRef(const void *ptr);
int pfCopy(void *dst, void *src);
int pfDelete(void *ptr);
int pfIsFluxed(void *ptr);
int pfCompare(const void *ptr1, const void *ptr2);
void pfPrint(const void *ptr, uint which, uint verbose,
FILE *file);
void * pfGetArena(void *ptr);
DESCRIPTION
A pfSubdivSurface is used to define subdivision surfaces. A subdivision
surface is specified by a control mesh consisting of a set of connected
faces (usually triangles or quads). The control mesh is stored as a
pfMesh. Before rendering the subdivision surface, each face is
recursively subdivided into a finer mesh. For example, in case of Loop
subdivision, each triangle is subdivided into 4 new triangles at each
subdivision step. The positions of both original vertices and newly
introduced vertices are determined based on the subdivision rules.
Usually the position is a linear combination of the positions of the
original vertices of the face and vertices of neighboring faces. The
parameters of the linear combination are set in a such a way that the
resulting mesh after a few subdivision steps smoothens out sharp edges.
For example, if the control mesh is a tetrahedron after a few subdivision
step we obtain an oval shape. Optionally, it is possible to mark
selected edges not to be smooth. A great source of information on
subdivision surfaces is the Siggraph 2000 course on Subdivision for
Modeling and Animation (http://mrl.nyu.edu/publications/subdiv-
course2000/).
pfNewSubdivSurface creates and returns a handle to a pfSubdivSurface.
Like other pfNodes, pfSubdivSurfaces are always allocated from shared
memory and can be deleted using pfDelete.
To define a subdivision surface you have to specify its control mesh
using a command pfSubdivSurfaceMesh. The mesh is stored as a pfMesh. A
pfMesh is a data structure that stores the connectivity between
individual faces of the mesh. For each vertex and face we can access
neighboring vertices and faces, respectively. See pfMesh man page for
more details. To create a pfMesh, we can either specify its faces and
the connectivity one by one or use a function pfdAddNodeToMesh. This
function takes a pfNode, parses all its pfGeoSets, splits all primitives
into planar faces and add those faces into the specified pfMesh (see
pfdAddNodeToMesh man page).
Page 3
pfSubdivSurface(3pf) OpenGL Performer 3.2.2 libpf C Reference Pages
Before you set the mesh using pfSubdivSurfaceMesh you need to set various
parameters of the subdivision because different internal data structures
may be needed for different types of subdivision. The values are set
using pfSubdivSurfaceVal and flags using pfSubdivSurfaceFlags. The
following values can be set:
PFSB_SUBDIVISION_METHOD can be either PFSB_CATMULL_CLARK (Catmull-
Clark subdivision, the default) or
PFSB_LOOP (Loop subdivision).
PFSB_SUBDIVISION_LEVEL specifies the number of subdivision steps.
Usually 2 or 3 steps are quite reasonable.
The default is 0.
PFSB_MAX_DATA_HEIGHT_SW specifies the limit of data structures used
to evaluate the subdivision surface in
software. The default is unlimited, but if
you are running out of memory for large
models evaluated in software try to set
this value to something like 10,000. This
would mean that only 10,000 faces would be
evaluated at a time.
PFSB_MAX_PBUFFER_HEIGHT specifies the maximum height of a Pbuffer
(off-screen memory on a GPU) used for
evaluating the surface directly on the
graphics hardware (GPU). The default is
512. It should be a power of two.
PFSB_PBUFFER_WIDTH specifies the width of a Pbuffer (off-
screen memory on a GPU) used for evaluating
the surface directly on the graphics
hardware (GPU). The default is 1024 but
you can save GPU memory by specifying a
lower value in case you do not use high
subdivision level. It should be a power of
two.
The following flags can be set to 0 or 1:
PFSB_GPU_SUBDIVISION If set to 1, the surface is evaluated
directly on the graphics hardware (GPU).
The hardware must support floating point
fragment shaders (e.g. Onyx 4). The
default is 0.
PFSB_CONTROL_VERTICES_DYNAMIC
Allows to modify the vertices of the
control surface (only their position) on
the fly. See below for more information.
Page 4
pfSubdivSurface(3pf) OpenGL Performer 3.2.2 libpf C Reference Pages
The default is 0.
PFSB_USE_GEO_ARRAYS Store the resulting subdivided mesh (in
case of software evaluation) in
pfGeoArrays. Otherwise use regular
pfGeoSets. The default is 1.
PFSB_INDEXED_GEOARRAYS By default Performer represents the
subdivision surface as indexed pfGeoArrays
because vertex arrays cannot use lengths
array very efficiently. You can disable
indexing by setting this flag.
PFSB_SUBDIVIDE_TEXCOORDS By default, texture coordinates are
lineraly interpolated across each face.
This may skew the textures on some objects.
Bu setting this flag you will enable a mode
that will use subdivision rules for texturs
coordinates.
PFSB_TEXCOORDS_KEEP_BOUNDARY
If set to 1 and subdivision rules are used
for texture coordinates, the texture
coordinates of vertices on a boundary are
kept unchanges. The textures may look
skewed, but no part of a texture is cut.
The default is off.
Any of these flags can be globally overriden by setting an environment
variable of the same name.
Here is an example of setting up a subdivision surface and adding it into
a scene. Sample code can be found in
perf/samples/pguide/libpf/C++/subdivSurface.C. Example:
pfSubdivSurface *subdivSurface;
pfMesh *mesh;
subdSurf = pfNewSubdivSurface(arena);
mesh = pfNewMesh(arena);
if(method == PFSB_LOOP)
pfMeshFlags(mesh, PFM_FLAG_TRIANGULATE, 1); // important!
pfdAddNodeToMesh(root, mesh, 0); // part 0
pfSubdivSurfaceVal(subdSurf, PFSB_SUBDIVISION_LEVEL, subdivLevel);
pfSubdivSurfaceVal(subdSurf, PFSB_SUBDIVISION_METHOD, method);
pfSubdivSurfaceFlags(subdSurf, PFSB_GPU_SUBDIVISION, GPUsubdivision);
pfSubdivSurfaceMesh(subdSurf, mesh);
pfAddChild(scene, subdSurf);
Page 5
pfSubdivSurface(3pf) OpenGL Performer 3.2.2 libpf C Reference Pages
The major difference between Loop subdivision and Catmull-Clark
subdivision is in the type of faces they operate on. Loop subdivision
operates exclusively on triangles thus the control mesh has to be
triangulated. Since pfMesh does not know whether it is used in a
pfSubdivSurface and what subdivision method is used, you have to set a
flag PFM_FLAG_TRIANGULATE on the pfMesh before specifying the faces (see
the sample code above).
Catmull-Clark subdivision, on the other hand, operates on quads. If the
control mesh does not contain only quads, the first subdivision step is
performed using special rules so that an arbitrary face is divided into a
set of quads. Note that this step cannot be performed on a GPU. This
step introduces some discontinuities in the second derivative of the
curvature thus the surface may appear more bumpy around the edges of the
original control faces. Thus it is recommended to start with a control
mesh containing only quads for optimal results. The advantage of
Catmull-Clark subdivision is that it is supported by many modeling tools,
including Maya.
If the flag PFSB_CONTROL_VERTICES_DYNAMIC is set, you can modify the
position of vertices of the control mesh to animate the surface. You
need to call pfSubdivSurfaceUpdateControlMesh at each frame to confirm
the changes. Note that you cannot have any tranforms in the node
specifying the control mesh.
You can subdivide an arbitrary file loaded into performer by using subdiv
pseudoloader. It works similarly as trans or scale pseudoloader. Let's
say you want to subdivide truck.pfb in perfly. You can call perfly
truck.pfb.0,2,0.subdiv. The syntax of the loader is as follows:
<filename>.<method>,<subdivLevel>,<GPUon>.subdiv. Method is 0 for
Catmull-Clark, 1 for Loop subdivision, subdivision level is usually
around 2, GPUon is 1 if the evaluation should be done fully on a GPU.
Only the control mesh of a pfSubdivSurface is saved in the pfb or pfa
file. For debugging purposes or to avoid having to evaluate the
subidivision surface at each load you can specify a mode
PFPFB_SUBDIVSURFACE_SAVE_GEOSETS in pfdConverterMode_pfb or an
environmental variable PFPFB_SUBDIVSURFACE_SAVE_GEOSETS.
NOTES
Subdivision level 0 may result in incorrect normals.
Currently, the GPU subdivision supports only control meshes with vertices
that have less than 11 neighbors.
Current drivers on Onyx 4 and Windows platforms do not support super
buffers thus the GPU evaluation of subdivision surfaces is too slow.
This will be remedied in very near future.
Page 6
pfSubdivSurface(3pf) OpenGL Performer 3.2.2 libpf C Reference Pages
SEE ALSO
pfMesh, pfdAddNodeToMesh, pfRep, pfGeode
Page 7