VR-Vantage 2.4 API Documentation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
exampleCustomShaders

This example shows how to create custom shaders using Virtual Programs.

It contains a simple example fragment shader function and a simple example vertex fragment shader funtion. The fragment shader uses a uniform to modify the color of the fragment. The vertex shader uses a uniform to modify the scale of the model.

Building the Example

VR-Vantage includes pre-built versions of the example plug-in. To build it yourself, follow the instructions at Building VR-Vantage Examples, Applications, and Plug-ins.

Running the Example

This example is a plug-in. You can run it by running ./bin/exampleCustomShaders_stealth.bat (on Windows) or ./bin/exampleCustomShaders_stealth.sh (on Linux). This example is indented to be run without a terrain. When VR-Vantage starts close the startup dialog. Press 'r', 'R', 'g', 'G', 'b', and 'B' to change the color of the model. Press 'x', 'X', 'y', 'Y', 'z' and 'Z' to change scale of the model. For more information about running examples, please see Running Applications and Examples.

Example Source Files


DtExampleModel.cxx

// /******************************************************************************
// ** Copyright (c) 2016 MAK Technologies, Inc.
// ** All rights reserved.
// ******************************************************************************/
#include <osg/Uniform>
#include <osgEarth/VirtualProgram>
namespace makVrv
{
//Contructor that sets up the shaders and uniforms for the stateset passed in
DtExampleShaderManager::DtExampleShaderManager( DtDe& de, osg::StateSet *ss)
: myDe(de)
, myModelStateSet(ss)
{
//Create uniforms for the color and scale of the model
myColorToAdd = ss->getOrCreateUniform("colorToAdd", osg::Uniform::FLOAT_VEC3);
myColorToAdd->set(osg::Vec3(0.0f,0.0f,0.0f));
myScale = ss->getOrCreateUniform("scale", osg::Uniform::FLOAT_VEC3);
myScale->set(osg::Vec3(1.0f,1.0f,1.0f));
//Virtual Programs are how shaders are handled in VR-Vantage.
// They allow multiple shader functions to be added anywhere in the scenegraph
// and it handles the main function and program creation.
// Just get or create the virtual program for any stateset and
// all nodes below that stateset will use the functions on the virtual program
myVirtualProgram = osgEarth::VirtualProgram::getOrCreate(ss);
//create a function that will add the colorToAdd uniform to the current color.
// customLightingFunction is the name of the function to call from main
// second parameter is the fragment shader code that is to be included in the program
// third parameter is the location (lighting is the second of three fragment locations)
// fourth parameter is a function that can use the current state to disable this function
// fifth parameter is the order (100.0 will make this run after all other lighting functions.)
myVirtualProgram->setFunction("customLightingFunction",
"uniform vec3 colorToAdd;\
void customLightingFunction(inout vec4 color) \
{\
color.rgb += colorToAdd;\
}\
",
osgEarth::ShaderComp::LOCATION_FRAGMENT_LIGHTING,
NULL,
100.0
);
//create a function that will scale the vertex location by the scale uniform.
// customVertexFunction is the name of the function to call from main
// second parameter is the vertex shader code that is to be included in the program
// third parameter is the location (model functions will get the vertex in model space)
// fourth parameter is a function that can use the current state to disable this function
// fifth parameter is the order (100.0 will make this run after all other vertex model functions.)
myVirtualProgram->setFunction("customVertexFunction",
"uniform vec3 scale;\
void customVertexFunction(inout vec4 vertexModel) \
{\
vertexModel.xyz *= scale;\
}\
",
osgEarth::ShaderComp::LOCATION_VERTEX_MODEL,
NULL,
100.0
);
}
DtExampleShaderManager::~DtExampleShaderManager()
{
}
//Function for changing the color that will be added to the fragments color
void DtExampleShaderManager::changeColorOverride(int color, float deltaChange)
{
osg::Vec3 curVal;
myColorToAdd->get(curVal);
switch(color)
{
case 0:
curVal.x() += deltaChange;
curVal.x() = curVal.x() < -1.0 ? -1.0 : curVal.x();
curVal.x() = curVal.x() > 1.0 ? 1.0 : curVal.x();
break;
case 1:
curVal.y() += deltaChange;
curVal.y() = curVal.y() < -1.0 ? -1.0 : curVal.y();
curVal.y() = curVal.y() > 1.0 ? 1.0 : curVal.y();
break;
case 2:
curVal.z() += deltaChange;
curVal.z() = curVal.z() < -1.0 ? -1.0 : curVal.z();
curVal.z() = curVal.z() > 1.0 ? 1.0 : curVal.z();
break;
default:
break;
}
myColorToAdd->set(curVal);
}
//Function for modifying the scale that will be applied to the model
void DtExampleShaderManager::changeScale(int axis, float deltaChange)
{
osg::Vec3 curVal;
myScale->get(curVal);
switch(axis)
{
case 0:
curVal.x() += deltaChange;
curVal.x() = curVal.x() < -5.0 ? -5.0 : curVal.x();
curVal.x() = curVal.x() > 5.0 ? 5.0 : curVal.x();
break;
case 1:
curVal.y() += deltaChange;
curVal.y() = curVal.y() < -5.0 ? -5.0 : curVal.y();
curVal.y() = curVal.y() > 5.0 ? 5.0 : curVal.y();
break;
case 2:
curVal.z() += deltaChange;
curVal.z() = curVal.z() < -5.0 ? -5.0 : curVal.z();
curVal.z() = curVal.z() > 5.0 ? 5.0 : curVal.z();
break;
default:
break;
}
myScale->set(curVal);
}
}

DtExampleModel.h

// /******************************************************************************
// ** Copyright (c) 2016 MAK Technologies, Inc.
// ** All rights reserved.
// ******************************************************************************/
#ifndef DtExampleShaderManager_H_
#define DtExampleShaderManager_H_
#include <vrvCore/DtDe.h>
#include <osg/ref_ptr>
namespace osg
{
class StateSet;
class Uniform;
}
namespace osgEarth
{
class VirtualProgram;
}
namespace makVrv
{
class DtExampleShaderManager
{
public:
DtExampleShaderManager(DtDe& de, osg::StateSet *ss);
//Function for changing the color that will be added to the fragments color
virtual void changeColorOverride(int color, float deltaChange);
//Function for modifying the scale that will be applied to the model
virtual void changeScale(int axis, float deltaChange);
protected:
DtDe& myDe;
//model state set to attach the custom shaders to
osg::ref_ptr<osg::StateSet> myModelStateSet;
//Uniforms used by the custom shaders
osg::ref_ptr<osg::Uniform> myColorToAdd;
osg::ref_ptr<osg::Uniform> myScale;
//virtual program for the stateset
osg::ref_ptr<osgEarth::VirtualProgram> myVirtualProgram;
};
}
#endif

DtExampleModelInstance.cxx

/******************************************************************************
** Copyright (c) 2016 MAK Technologies, Inc.
** All rights reserved.
******************************************************************************/
#include <vrvCore/DtDe.h>
#include <boost/bind.hpp>
#include <osgEarth/VirtualProgram>
// The name of the geometry file to load.
static const std::string dataFile =
"$(DATA_DIR)/Vehicles/FixedWing/DC-10_RED_V7.0.flt/DB_DC10_RED_V7.0.medf";
DtModelInstance* loadModelInstanceToTheSceneGraph(DtDe* de);
void createShaderManager(DtDe* de, osg::StateSet *modelStateSet);
using namespace makVrv;
void init(DtDe& de)
{
// Ensure that init only gets called once
// (not strictly necessary here, but this is good practice in general)
// We only want to create the example driver if we're running in master mode:
if (de.isInMasterMode())
{
// The driver must be created after the DE's initialization is finished,
// to make sure all the objects it uses exist.
&loadModelInstanceToTheSceneGraph, &de));
}
}
{
// Setup the plugin. Normally, the init function and functionality
// should be in its own library.
init(*de);
return true;
}
// This is a helper function to load a geometry file and add it to the scene-
// graph. A model-definition is first given to a model-instance telling it
// which geometry file is to be loaded. Then the realize() function is called
// on the model-instance to load the file from disk. Last the root node from
// the model-instance is added to the scene-graph.
DtModelInstance* loadModelInstanceToTheSceneGraph(DtDe* de)
{
// We're done with the signal, so disconnect from it
&loadModelInstanceToTheSceneGraph, de));
// Create a model definition describing the model to load.
// The DtModelDefinition class is used to describe several attributes about
// the model. For this example we just specify the name of the geometry
// file to load.
DtModelDefinition md("theModel");
md.setParameter("filename", dataFile);
// Create a model instance and load a file from the model definition.
// In this example we use a DtOsgSimpleModelInstance as the type of model-
// instance that will be added to the scene. Since we are creating this
// object directly without the use of a factory, we're required to call
// the realize() function to actually load the model.
if (! mi->realize(md))
{
delete mi;
return NULL;
}
// Create a transform to move the model away from the origin.
// The default observer starts at 0,0,0. Move the transform, 100 units
// away and rotate it to look nice.
osg::ref_ptr<osg::PositionAttitudeTransform> pat =
new osg::PositionAttitudeTransform();
pat->setPosition(osg::Vec3(0,100,0));
pat->setAttitude(osg::Quat(
osg::DegreesToRadians(-10.0f), osg::Vec3(1.0f, 0.0f, 0.0f),
osg::DegreesToRadians(-30.0f), osg::Vec3(0.0f, 1.0f, 0.0f),
osg::DegreesToRadians(150.0f), osg::Vec3(0.0f, 0.0f, 1.0f)));
// Add the root-node of the model to the transform.
pat->addChild(mi->rootNode());
// Add the transform to the prop-root of the renderer.
DtOsgRenderer& renderer = (DtOsgRenderer&)de->renderer();
renderer.addNodeToRoot(pat, renderer.propRoot());
//create a shader manager for this model
createShaderManager(de, mi->rootNode()->getOrCreateStateSet());
return mi;
}
void createShaderManager(DtDe* de, osg::StateSet *modelStateSet)
{
// Create the manager that will manage the shaders for the model
DtExampleShaderManager* shaderManager = new DtExampleShaderManager(*de, modelStateSet);
// Add a key binding that calls the example model manager's function:
// The input driver responds to input events by calling key functions. To
// bind a key to an arbitrary function, there are two steps:
// 1. Create a KeyFunction that calls the desired function and add it
// to the input driver
// 2. Add a key binding from some key to the KeyFunction defined in step 1
// to the keymap
// Create the KeyFunction
DtInputDriver& inputDriver = de->driverManager().inputDriver();
keyMapManager.addKeyFunction( "Inc Red", boost::bind(
keyMapManager.addKeyFunction( "Inc Green", boost::bind(
keyMapManager.addKeyFunction( "Inc Blue", boost::bind(
keyMapManager.addKeyFunction( "Dec Red", boost::bind(
keyMapManager.addKeyFunction( "Dec Green", boost::bind(
keyMapManager.addKeyFunction( "Dec Blue", boost::bind(
keyMapManager.addKeyFunction( "Inc X Scale", boost::bind(
keyMapManager.addKeyFunction( "Inc Y Scale", boost::bind(
keyMapManager.addKeyFunction( "Inc Z Scale", boost::bind(
keyMapManager.addKeyFunction( "Dec X Scale", boost::bind(
keyMapManager.addKeyFunction( "Dec Y Scale", boost::bind(
keyMapManager.addKeyFunction( "Dec Z Scale", boost::bind(
// Bind the above key functions to some keys in the default
// ("Observer Frame") key map
DtKeyMap* obsFrame = keyMapManager.findKeyMap( "Observer Frame" );
if ( obsFrame )
{
//map functions for modifing the size and animation rate of the cubes.
inputDriver.addKeyBinding( obsFrame, DtKeyState::KEY_R, "Inc Red" , DtKeyState::NO_MODIFIER, true);
inputDriver.addKeyBinding( obsFrame, DtKeyState::KEY_G, "Inc Green", DtKeyState::NO_MODIFIER, true);
inputDriver.addKeyBinding( obsFrame, DtKeyState::KEY_B, "Inc Blue", DtKeyState::NO_MODIFIER, true);
inputDriver.addKeyBinding( obsFrame, DtKeyState::KEY_R, "Dec Red" , DtKeyState::SHIFT_MODIFIER, true);
inputDriver.addKeyBinding( obsFrame, DtKeyState::KEY_G, "Dec Green" , DtKeyState::SHIFT_MODIFIER, true);
inputDriver.addKeyBinding( obsFrame, DtKeyState::KEY_B, "Dec Blue" , DtKeyState::SHIFT_MODIFIER, true);
inputDriver.addKeyBinding( obsFrame, DtKeyState::KEY_X, "Inc X Scale" , DtKeyState::NO_MODIFIER, true);
inputDriver.addKeyBinding( obsFrame, DtKeyState::KEY_Y, "Inc Y Scale", DtKeyState::NO_MODIFIER, true);
inputDriver.addKeyBinding( obsFrame, DtKeyState::KEY_Z, "Inc Z Scale", DtKeyState::NO_MODIFIER, true);
inputDriver.addKeyBinding( obsFrame, DtKeyState::KEY_X, "Dec X Scale" , DtKeyState::SHIFT_MODIFIER, true);
inputDriver.addKeyBinding( obsFrame, DtKeyState::KEY_Y, "Dec Y Scale" , DtKeyState::SHIFT_MODIFIER, true);
inputDriver.addKeyBinding( obsFrame, DtKeyState::KEY_Z, "Dec Z Scale" , DtKeyState::SHIFT_MODIFIER, true);
}
}

DtExampleModelInstance.h

/******************************************************************************
** Copyright (c) 2016 MAK Technologies, Inc.
** All rights reserved.
******************************************************************************/
#ifndef exampleCustomShaders_h_
#define exampleCustomShaders_h_
// Get proper local export symbol
#ifdef _WIN32
#ifdef DT_DLL_EXAMPLECUSTOMSHADER
#define DT_DLL_EXAMPLECUSTOMSHADER __declspec ( dllexport )
#else
#define DT_DLL_EXAMPLECUSTOMSHADER __declspec ( dllimport )
#endif
#else
#define DT_DLL_EXAMPLECUSTOMSHADER
#endif
// Setup proper plugin export symbol
#define DT_DE_PLUGIN_EXPORT_MACRO DT_DLL_EXAMPLECUSTOMSHADER
// Declare & export the plugin initialization function (bool initDeModule(DtDe* de))
using namespace makVrv;
// Work function for the plugin initialization
// Callback to create the DtExampleModelManager which handles cube creation
#endif


Copyright © 2005-2018 VT MAK. All Rights Reserved (www.mak.com)