OpenGL Shaders in a scene graph

We have just released a new version of the scene graph Gizmo3D with full support for GLSL combined with ARB vp/fp. Would like some feedback of our hierarchical model of state changes that uses the shaders. Feel free to download and try at www.gizmosdk.se for win32, Irix,Mac OS X and linux.

Originally posted by ToolTech:
We have just released a new version of the scene graph Gizmo3D with full support for GLSL combined with ARB vp/fp. Would like some feedback of our hierarchical model of state changes that uses the shaders. Feel free to download and try at www.gizmosdk.se for win32, Irix,Mac OS X and linux.
It sounds interesting, but I couldn’t find much info about that, and it wasn’t obvious from the headers. Can you give us a quick overview of how you integrated shaders in your system?

Thanks

Dirk

P.S.: It is a cross-over topic, but I think it would be more appropriate for the Scenegraphs Forum.

Here is a program that uses either OpenGL Shaders or ARB fp/vp in parallell.

  

// *****************************************************************************
// File			: shaders.cpp
// Module		: 
// Description	: Test app to show shader usage
// Author		: Anders Modén          
// Product		: Gizmo3D 1.2 RC 5
//              
// Copyright © 2003- Saab Training Systems AB, Sweden	
//                      
// NOTE:	Gizmo3D is a high performance 3D Scene Graph and effect visualisation 
//			C++ toolkit for Linux, Mac OS X, Windows (Win32) and IRIX® for  
//			usage in Game or VisSim development.
//
//
// Revision History...                                                  
//                                                                      
// Who  Date    Description                                             
//                                                                      
// AMO  030707  Created file    
//
// ******************************************************************************

// The general include
#include "gzGizmo3DLibrary.h"

#define USE_GLSL


#ifdef USE_GLSL		// Test if we shall try a low level or high level shader

const gzString vertexProgram	="glsl_PFLight.vsh";
const gzString fragmentProgram	="glsl_PFLight.fsh";

#else

const gzString vertexProgram	="PFLight.vsh";
const gzString fragmentProgram	="PFLight.fsh";

#endif

// And here comes the Java look alike app. It is a matter of taste.

class MyWindow : public gzWindow
{
public:
	MyWindow(gzApplication *app , gzGraphicsFormat *format , gzString filename ):gzWindow(gzString("Gizmo3D : ")+gzTime::now(TRUE).asString(),NULL,app,format,FALSE)
	{
			// Create a scene to render -------------------------------------
			// We must have a scene that the camera can "look at"
			m_scene=new gzScene("Database Loader Example Scene");
			
			// Create some light environment group. This way we get lighting into the model
			// All stuff under this is lit with material s etc.
			gzEnvironment *group=new gzEnvironment;

			// Create a backface culling state
			// We don't want to render backfaces. this way we can "force" the geoms to be rendered without 
			// backfaces. It also enable the use of the shaders

			m_state=new gzState;

			m_state->setMode(GZ_STATE_POLYGON_MODE,GZ_STATE_ON);
			m_state->setBackPolygonMode(GZ_POLYGON_MODE_CULL);
			m_state->setFrontPolygonMode(GZ_POLYGON_MODE_FILL);
			m_state->disableAllNonEnabledModes();	// We need this for the top global state

			gzState::setGlobalState(getContext(),m_state);
			

			// ---------------------- DB loading ------------------------------

			// Create a object node from a generic db file
			
			model=gzDbManager::loadDB(filename);

			if(model)	// We got a model
			{
			
					gzState *state;

					state=model->getState();

					if(!state)
						state=new gzState;


					// Set the vertex program

					gzGFXProgram *program_vp=new gzGFXProgram;

					program_vp->loadProgramScript(vertexProgram);

					state->setGFXProgram(GZ_GFX_VERTEX_PROGRAM,program_vp);
					

					// Set the fragment program

					gzGFXProgram *program_fp=new gzGFXProgram;

					program_fp->loadProgramScript(fragmentProgram);

					state->setGFXProgram(GZ_GFX_FRAGMENT_PROGRAM,program_fp);
					
					program_fp->setLocalParameter("color",gzVec4(1,0.5,0.3,1));

					//gzGFXProgram::setGlobalParameter("color",gzVec4(1,0.5,0.3,1));

					// Enable GFX programs

					state->setMode(GZ_STATE_GFX_PROGRAM,GZ_STATE_ON);

					model->setState(state);


			}

			gzNodeOptimizer opt;		// We let the optimizer take away redundant geometry etc.

			opt.setMaxRecursionDepth(0);

			model=opt.optimize(model,(gzNodeOptimizeLevel)(GZ_NODE_OPTIMIZE_DONT_COMBINE_NAME_ENCODED/*|GZ_NODE_OPTIMIZE_DONT_CONCAT_GEOMETRY*/));

			// -------------------- lights --------------------------------

			// Add some dynamic light
			m_spin=new gzLight;						// This is the lamp that we move around
			m_spin->setSpecularColor(0.2f,0.2f,0.2f);
			m_spin->setDiffuseColor(0.5f,0.5f,0.5f);
			m_spin->setAmbientColor(0.3f,0.3f,0.3f);
			m_spin->setPosition(26,10,90);

			group->addLight(m_spin);

			// ------------------------ some global settings --------------

			gzEnvironment::setTwoSideLighting(getContext(),TRUE);

			gzEnvironment::setLocalViewer(getContext(),TRUE);

			// Translate the model and scale it

			gzTransform *trans=new gzTransform;

			trans->addNode(model);
				
			trans->unitScale();

			trans->scale(30.0f,30.0f,30.0f);

			group->addNode(trans);
			
			// Add a geometry alike lamp to show position of light

			m_lamp=new gzTransform;

			gzGeometry *sphere=new gzGeometrySphere(1 , 20 ,gzVec4(1.0,1.0,1.0,1.0) );

			m_lamp->addNode( sphere );

			// Set mouse press state
			m_inMousePress=FALSE;



			// And add the group to the scene as well
			m_scene->addNode(group);

			// And add the lamp
			m_scene->addNode(m_lamp);

						
			// Now we want to look at the scene. Grab the default perspective camera from the window and set the scen as the
			// active one.
			getCamera()->setScene(m_scene);
			getCamera()->setNearClipPlane(1);
			getCamera()->setFarClipPlane(2000);

			// Lets add some movement to the scene

			m_input=new gzSimpleMouseViewControl(getCamera());

			addInputInterface(m_input);

			// Hmm. trivial
			setBackground(0.0f,0.0f,1.0f,1.0f);

			// and show us ...
			show();

			// hm. wonder why I put this one here ?
			angle=2.22f;

	};


	/*
		The following code snippet is a virtual function to catch the window messages
		for pressed, repeated and released keys
	*/

	gzBool onKey(gzKeyValue key , gzKeyState keystate , gzLong mouse_x , gzLong mouse_y)
	{
		switch(key)
		{
			case ' ':	// Space pressed // default to non shader view

				if(keystate == GZ_KEY_STATE_PRESSED)
				{
					gzState *state=new gzState;

					state->setOverride(GZ_STATE_GFX_PROGRAM,GZ_STATE_ON);

					state->setMode(GZ_STATE_GENERATE_DEBUG_INFO,GZ_STATE_ON);
					state->setDebugMode((gzStateDebugMode)(GZ_STATE_DEBUG_COLLECT_STATS));

					state->disableAllNonEnabledModes();

					gzState::setGlobalState(getContext(),state);
				}
				if(keystate == GZ_KEY_STATE_RELEASED)
				{
					gzState::setGlobalState(getContext(),m_state);
				}
				break;

			case GZ_KEY_LBUTTON :

				if((keystate == GZ_KEY_STATE_PRESSED) && !m_inMousePress)
				{
					setCaptureMouse(TRUE);
					setHideMouse(TRUE);
					m_inMousePress=TRUE;
				}
				else if((keystate == GZ_KEY_STATE_RELEASED) && m_inMousePress)
				{
					setHideMouse(FALSE);
					setCaptureMouse(FALSE);
					m_inMousePress=FALSE;
				}
				break;

		}

		return gzWindow::onKey((gzKeyValue)key,(gzKeyState)keystate,mouse_x,mouse_y);
	}


	gzVoid onIdle()
	{
		// Hmm. Now i remember. The spinning lamp..

		angle+=0.003f;

		if(angle>2*GZ_PI)
			angle-=(gzReal)(2*GZ_PI);

		m_spin->setPosition((gzReal)(50*cos(5*angle)),5.0f,(gzReal)(50*sin(angle/2)+20));

		m_lamp->setTranslation((gzReal)(50*cos(5*angle)),5.0f,(gzReal)(50*sin(angle/2)+20));

	}

	virtual ~MyWindow()
	{
		if(m_input)
			delete m_input;

	}

	gzRefPointer<gzState>		m_state;

	gzLight *					m_spin;

	gzReal						angle;

	gzTransform	*				m_lamp;
	
	gzBool						m_inMousePress;

	gzNode						*model;

	gzScene						*m_scene;

	gzSimpleMouseViewControl	*m_input;

};

// Definition of a sample application
// The application provides an initialisation and an onIdle loop manager
// to do the refresh of the window

class WindowApp : public gzApplication
{
public:
		
	WindowApp():m_win(NULL),m_format(NULL)
	{
	}

    ~WindowApp()
	{
		if(m_win)
		{
			delete m_win;
		}

	}

    void Create(gzString filename)
	{
		m_format = new gzGraphicsFormat;

		m_format->useStencil(TRUE);

		m_win = new MyWindow(this,m_format,filename);

		gzPerspCamera *camera=gzDynamic_Cast<gzPerspCamera>(m_win->getCamera());

		camera->setPosition(30,30,150);
		camera->lookAt(0,0,0);
		camera->useInfiniteFarPlane(TRUE);

	}

	void onIdle()
	{
		if(m_win)
		{
			m_win->onIdle();

			m_win->triggerKeyEvaluation();

			if(!m_win->refreshWindow())	// Yield some time if no rendering
				gzSleep(30);

		}

	}

private:

	friend class MyWindow;
	
	MyWindow                *m_win;
	gzGraphicsFormat        *m_format;
};


int main(int argc, char *argv[])
{

	gzMessage::setMessageLevel(GZ_MESSAGE_MEM_DEBUG);

	gzCheckLibraryVersion();


	try
	{ 
		gzString	filename="script.3ds";

		gzLicense::notifyDefaultLicense();
	
		gzGraphicsEngine::useEngine(GZ_ENGINE_OPENGL);
	
		gzInitializeDbManagers();

		if(argc > 1)
		{
			argv++;
			argc--;
			while(argc > 0)
			{
				if(argv[0][0] == '-')
				{
					switch(toupper(argv[0][1]))
					{

						case 'M' :
							filename=gzString(*(++argv));
							argc--;
							break;

					}

				}
				argv++;
				argc--;
			}
		}

		// Make the application
		WindowApp app;
	      
		// Create the scene and the window
		app.Create(	filename);
		
		// run the application
		app.run();

	}
	catch(gzBaseError &error)       // In case of exceptions thrown we want to print the message
	{
		error.reportError();
	}

	gzShutDownGizmo();

	return 0;
}

As we use the state hierarchy mechanism, we can add a top state where defualt shaders are defined and then later in the hierarchy replace a sibling child with a new fragment shader etc.

The combination of textures and other resourses still works and the system can fallback on other shaders or fixed pipe.

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.