VRender User's Manual

How does it work ?

Basically, VRender is called with parameters and a drawing function. When executed, it turns OpenGL into feedback mode and calls the drawing function, then turns OpenGL back into its original drawing mode to get the rendered geometric primitives in window coordinates. After that, the challenging part is to sort everything so as to be able to render everything back to front in the postscript file.

What should I do ?

Using VRender only needs to call the following method declared in VRender.h:
	void vrender::VectorialRender(RenderCB DrawFunc, void *callback_params, VRenderParams& render_params) ;
WARNING: Your draw() function should not contain any operation related to the OpenGL render mode or to the OpenGL context; otherwise you'll add some nice pieces to your core dump collection. Typical examples of calls that should not be inside draw() are: glXSwapBuffers(), glXCreateContext(), and glRenderMode(), but this list is not exhaustive.

Rendering parameters

All rendering parameters are listed in the table below along with their default value and the method in class VRenderParams to set them up:

Parameter/OptionValuesExplainationVRenderParams MethodDefault
Sorting algorithmNoSorting
BSPSort
TopologicalSort
AdvancedTopo-
logicalSort
This is the sorting algorithm to use. See below for more details about each method.setSortMethod(value)BSPSort
Output formatEPS
PS
XFIG
SVG
Format to output the drawing. Names speek for themseves. SVG is not supported yet, but will soon be.setFormat(value)EPS
Output filenameAny stringFile name to output the drawing.setFilename(value)NULL
Progress functionAny function of type void f(float,const std::string&)The supplied function will be called at regular intervals. The string parameters is describes the currently performed operation, while the float parameter indicates in the in the interval [0,1] the progress of this operation. This can be used to make a progress bar in your own application.setProgressFunction(value)NULL
Hidden face removaltrue/falseCleverly suppresses hidden faces from the output instead of just rendering them back to front.setOption(CullHiddenFaces,value)false
Black and whitetrue/falseRenders plain polygons in white and lines in black.setOption(RenderBlackAndWhite,value)false
Add backgroundtrue/falseRenders a rectangle behind the scene to simulate the effect of the glClear() call.setOption(AddBackground,value)false
Tighten bounding boxtrue/falseTighten the bounding box to the rectangular region occupied by primitives.setOption(TightenBoundingBox,value)false
Cull back facestrue/falseEarly backface culling applied to the polygons before any sorting operation. This helps reducing the number of polygons if backface culling is not enabled in your drawing function. Otherwise culled polygons do not appear in the feedback buffer anyway.setOption(OptimizeBackFaceCulling,
value)
false

Sorting algorithms

The different sorting methods are explained below into more details. Each has its own advantage, so I kept them all in the lib:
Method Short explaination Example
No sorting Do not sort primitives and keep the original order into which they were sent to OpenGL. This is usefull for shooting 2D drawings were sorting is not relevant, or when rendering only black lines.
BSPPrimitives are sorted into a BSP which splitting planes are based on the primitive themselves. This is a very stable algorithm although it tends to split primitives much more than necessary.
Topological sort Primitives are compared together related to the viewpoint and categorized as upper/below or independent. Naturally, intersecting primitives may result into both upper and below. From this we build a precedence graph which is then rendered back to front. This is perfect for most meshes were no polygons intersect each other.
Advanced topological sort Same as topological sort, except that cycles are properly broken. This results into a correct rendering in any case, but only splitting primitives when necessary. Output size is usualy much smaller than that of the BSP method. Computation time is significantly larger.

Example code

This features a very simple example code which calls VRender. The code is inspired to what is done internaly in the QGLViewer library. First, define the draw() and progress functions (See above):

// This class is responsible for drawing, and lots of other nice stuff.
class QGLViewer ;

// The drawing function passed to VRender.
static void drawVectorial(void* param)
{
	static_cast<QGLViewer*>(param)->drawGL();
}

// The progress function passed to VRender.
static void progressFunction(float f, const std::string& info)
{
	// Example one: just output the info
	
	fprintf(stdout,"%1.2f completed (%s)",f*100,info.c_str()) ;

	// Example two: let's use a progress bar, it's nicer.
	
	static QProgressBar *pbar = NULL ;

	if(!pbar)
	{
		pbar = new QProgressBar(200) ;
		pbar->show() ;
	}

	pbar->setCaption(info) ;
	pbar->setProgress((int)(f*200)) ;
}

Then define the main function which first launches an interface to get the parameters set, and then calls vrender::VectorialRender() with these parameters.

int QGLViewer::saveVectorialSnapshot()
{
	static EPSInterface* interf = NULL;

	//  Launch an interface with buttons and check-boxes so as to allow the user to choose 
	// the vector rendering options.

	if (!interf)
		interf = new EPSInterface(widget);

	if(interf->exec() == QDialog::Rejected)
		return -1;

	// Now, get back the user's choices.
	// And store them into the VRenderParams structure defined for that in VRender.h

	vrender::VRenderParams vrp ;

	vrp.setOption(vrender::VRenderParams::OptimizeBackFaceCulling,interf->backFaceCullingEnabled()) ;
	vrp.setOption(vrender::VRenderParams::RenderBlackAndWhite,	interf->blackAndWhiteEnabled()) ;
	vrp.setOption(vrender::VRenderParams::AddBackground,		interf->includeBackgroundEnabled()) ;
	vrp.setOption(vrender::VRenderParams::TightenBoundingBox,interf->tightenBBoxEnabled()) ;
	vrp.setOption(vrender::VRenderParams::CullHiddenFaces,	interf->cullHiddenFacesEnabled()) ;
	vrp.setSortMethod(interf->sortMethod()) ;

	QString FileName = QFileDialog::getSaveFilename("*.eps") ;

	vrp.setFilename(FileName) ;

	// Now setup progress display function (defined at top of the file)
	vrp.setProgressFunction(progressFunction) ;

	//  And call the renderer. Note that params is set to be this, so that VectorialRender will pass this
	// to drawVectorial which in turns will call the draw() method of this. This is inelegant, but this is the
	// only way of passing a non static method as a parameter.

	vrender::VectorialRender(drawVectorial,(void *)this,vrp) ;
}

FAQ

Q1: My postscript displays whitish edges inside polygons Q2: Polygons are not sorted adequately with respect to lines Q3: I get unexpected core dumps, whatever the rendering parameters and viewpoint Q4: Sometimes, depending on the viewpoint, primitives are not sorted ok Q5: The library does not compile under windows Q6: Their is a bug

Valid XHTML 1.0! Valid CSS! Last modified on Thursday, March 3, 2005.