PDA

View Full Version : OpenGL Shaders in a scene graph



ToolTech
05-01-2004, 12:19 PM
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 (http://www.gizmosdk.se) for win32, Irix,Mac OS X and linux.

Dirk
05-02-2004, 06:34 AM
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 (http://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.

ToolTech
05-03-2004, 04:56 AM
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,FAL SE)
{
// 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(),TRU E);

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_COL LECT_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)keysta te,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,(gzR eal)(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 &amp;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.