Vertex program update from Brede.

This commit is contained in:
Robert Osfield
2003-01-22 20:48:10 +00:00
parent 6afedcc6d1
commit d6f25a112d

View File

@@ -1,187 +1,401 @@
#include <osg/Geode>
#include <osg/Geometry>
#include <osg/Material>
#include <osg/GL>
#include <osgGLUT/glut>
#include <osgGLUT/Viewer>
#include <osg/Vec3>
#include <osg/Vec4>
#include <osg/Quat>
#include <osg/Matrix>
#include <osg/ShapeDrawable>
#include <osg/Geometry>
#include <osg/Geode>
#include <osg/Transform>
#include <osg/Material>
#include <osg/NodeCallback>
#include <osg/Depth>
#include <osg/CullFace>
#include <osg/TexMat>
#include <osg/TexGen>
#include <osg/TexEnvCombine>
#include <osg/TextureCubeMap>
#include <osg/VertexProgram>
#include <osgDB/Registry>
#include <osgDB/ReadFile>
#include <osgGA/TrackballManipulator>
#include <osgGLUT/Viewer>
#include <osgGLUT/glut>
#include <osgUtil/SmoothingVisitor>
#include <osgUtil/Optimizer>
float refract = 1.01; // ratio of indicies of refraction
float fresnel = 2.0; // Fresnel multiplier
// A simple ambient, specular, and diffuse infinite lighting computation
// with a single light and an eye-space normal
// This vertex program is a slightly modified version of an example in
// the ARB_vertex_program spec. It uses local parameter 0 for ambient.
// If your cube have a blue ambient component it shows the vertex-
// program is working.
const char vpstr[] =
"!!ARBvp1.0 \n"
"!!ARBvp1.0 # Refraction \n"
" \n"
"ATTRIB iPos = vertex.position; \n"
"#ATTRIB iCol = vertex.color.primary; \n"
"ATTRIB iNormal = vertex.normal; \n"
"PARAM mvinv[4] = { state.matrix.modelview.invtrans }; \n"
"PARAM mvp[4] = { state.matrix.mvp }; \n"
"PARAM lightDir = state.light[0].position; \n"
"PARAM halfDir = state.light[0].half; \n"
"PARAM specExp = state.material.shininess; \n"
"PARAM ambientCol = program.local[0]; \n"
"PARAM diffuseCol = state.lightprod[0].diffuse; \n"
"PARAM specularCol = state.lightprod[0].specular; \n"
"TEMP xfNormal, temp, dots, newDiffuse; \n"
"PARAM esEyePos = { 0, 0, 0, 1 }; \n"
"PARAM const0123 = { 0, 1, 2, 3 }; \n"
"PARAM fresnel = program.local[0]; \n"
"PARAM refract = program.local[1]; \n"
"PARAM itMV[4] = { state.matrix.modelview.invtrans }; \n"
"PARAM MVP[4] = { state.matrix.mvp }; \n"
"PARAM MV[4] = { state.matrix.modelview }; \n"
"PARAM texmat[4] = { state.matrix.texture[0] }; \n"
"TEMP esPos; # position in eye-space \n"
"TEMP esNormal; # normal in eye-space \n"
"TEMP tmp, IdotN, K; \n"
"TEMP esE; # eye vector \n"
"TEMP esI; # incident vector (=-E) \n"
"TEMP esR; # first refract- then reflect-vector \n"
"OUTPUT oPos = result.position; \n"
"OUTPUT oColor = result.color; \n"
"OUTPUT oRefractMap = result.texcoord[0]; \n"
"OUTPUT oReflectMap = result.texcoord[1]; \n"
" \n"
"# Transform the vertex to clip coordinates. \n"
"DP4 oPos.x, mvp[0], iPos; \n"
"DP4 oPos.y, mvp[1], iPos; \n"
"DP4 oPos.z, mvp[2], iPos; \n"
"DP4 oPos.w, mvp[3], iPos; \n"
"# transform vertex to clip space \n"
"DP4 oPos.x, MVP[0], iPos; \n"
"DP4 oPos.y, MVP[1], iPos; \n"
"DP4 oPos.z, MVP[2], iPos; \n"
"DP4 oPos.w, MVP[3], iPos; \n"
" \n"
"# Transform the normal to eye coordinates. \n"
"DP3 xfNormal.x, mvinv[0], iNormal; \n"
"DP3 xfNormal.y, mvinv[1], iNormal; \n"
"DP3 xfNormal.z, mvinv[2], iNormal; \n"
"# Transform the normal to eye space. \n"
"DP3 esNormal.x, itMV[0], iNormal; \n"
"DP3 esNormal.y, itMV[1], iNormal; \n"
"DP3 esNormal.z, itMV[2], iNormal; \n"
" \n"
"# Compute diffuse and specular dot products and use LIT to compute \n"
"# lighting coefficients. \n"
"DP3 dots.x, xfNormal, lightDir; \n"
"DP3 dots.y, xfNormal, halfDir; \n"
"MOV dots.w, specExp.x; \n"
"LIT dots, dots; \n"
"# normalize normal \n"
"DP3 esNormal.w, esNormal, esNormal; \n"
"RSQ esNormal.w, esNormal.w; \n"
"MUL esNormal, esNormal, esNormal.w; \n"
" \n"
"# transform vertex position to eye space \n"
"DP4 esPos.x, MV[0], iPos; \n"
"DP4 esPos.y, MV[1], iPos; \n"
"DP4 esPos.z, MV[2], iPos; \n"
"DP4 esPos.w, MV[3], iPos; \n"
" \n"
"# vertex to eye vector \n"
"ADD esE, -esPos, esEyePos; \n"
"#MOV esE, -esPos; \n"
" \n"
"# normalize eye vector \n"
"DP3 esE.w, esE, esE; \n"
"RSQ esE.w, esE.w; \n"
"MUL esE, esE, esE.w; \n"
" \n"
"# calculate some handy values \n"
"MOV esI, -esE; \n"
"DP3 IdotN, esNormal, esI; \n"
" \n"
"# calculate refraction vector, Renderman style \n"
" \n"
"# k = 1-index*index*(1-(I dot N)^2) \n"
"MAD tmp, -IdotN, IdotN, const0123.y; \n"
"MUL tmp, tmp, refract.y; \n"
"ADD K.x, const0123.y, -tmp; \n"
" \n"
"# k<0, R = [0,0,0] \n"
"# k>=0, R = index*I-(index*(I dot N) + sqrt(k))*N \n"
"RSQ K.y, K.x; \n"
"RCP K.y, K.y; # K.y = sqrt(k) \n"
"MAD tmp.x, refract.x, IdotN, K.y; \n"
"MUL tmp, esNormal, tmp.x; \n"
"MAD esR, refract.x, esI, tmp; \n"
" \n"
"# transform refracted ray by cubemap transform \n"
"DP3 oRefractMap.x, texmat[0], esR; \n"
"DP3 oRefractMap.y, texmat[1], esR; \n"
"DP3 oRefractMap.z, texmat[2], esR; \n"
" \n"
"# calculate reflection vector \n"
"# R = 2*N*(N dot E)-E \n"
"MUL tmp, esNormal, const0123.z; \n"
"DP3 esR.w, esNormal, esE; \n"
"MAD esR, esR.w, tmp, -esE; \n"
" \n"
"# transform reflected ray by cubemap transform \n"
"DP3 oReflectMap.x, texmat[0], esR; \n"
"DP3 oReflectMap.y, texmat[1], esR; \n"
"DP3 oReflectMap.z, texmat[2], esR; \n"
" \n"
"# Fresnel approximation = fresnel*(1-(N dot I))^2 \n"
"ADD tmp.x, const0123.y, -IdotN; \n"
"MUL tmp.x, tmp.x, tmp.x; \n"
"MUL oColor, tmp.x, fresnel; \n"
" \n"
"# Accumulate color contributions. \n"
"MAD temp, dots.y, diffuseCol, ambientCol; \n"
"MAD oColor.xyz, dots.z, specularCol, temp; \n"
"MOV oColor.w, diffuseCol.w; \n"
"END \n";
osg::Geode* createGeometryCube()
osg::TextureCubeMap* readCubeMap()
{
osg::Geode* geode = new osg::Geode();
osg::TextureCubeMap* cubemap = new osg::TextureCubeMap;
//#define CUBEMAP_FILENAME(face) "nvlobby_" #face ".png"
#define CUBEMAP_FILENAME(face) "osg_" #face ".png"
// -------------------------------------------
// Set up a new Geometry which will be our cube
// -------------------------------------------
osg::Geometry* cube = new osg::Geometry();
osg::Image* imagePosX = osgDB::readImageFile(CUBEMAP_FILENAME(posx));
osg::Image* imageNegX = osgDB::readImageFile(CUBEMAP_FILENAME(negx));
osg::Image* imagePosY = osgDB::readImageFile(CUBEMAP_FILENAME(posy));
osg::Image* imageNegY = osgDB::readImageFile(CUBEMAP_FILENAME(negy));
osg::Image* imagePosZ = osgDB::readImageFile(CUBEMAP_FILENAME(posz));
osg::Image* imageNegZ = osgDB::readImageFile(CUBEMAP_FILENAME(negz));
// set up the primitives
cube->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POLYGON,0,4));
cube->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POLYGON,4,4));
cube->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POLYGON,8,4));
cube->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POLYGON,12,4));
cube->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POLYGON,16,4));
cube->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POLYGON,20,4));
if (imagePosX && imageNegX && imagePosY && imageNegY && imagePosZ && imageNegZ)
{
cubemap->setImage(osg::TextureCubeMap::POSITIVE_X, imagePosX);
cubemap->setImage(osg::TextureCubeMap::NEGATIVE_X, imageNegX);
cubemap->setImage(osg::TextureCubeMap::POSITIVE_Y, imagePosY);
cubemap->setImage(osg::TextureCubeMap::NEGATIVE_Y, imageNegY);
cubemap->setImage(osg::TextureCubeMap::POSITIVE_Z, imagePosZ);
cubemap->setImage(osg::TextureCubeMap::NEGATIVE_Z, imageNegZ);
// set up coords.
osg::Vec3Array* coords = new osg::Vec3Array;
coords->resize(24);
(*coords)[0].set( -1.0000f, 1.0000f, -1.000f );
(*coords)[1].set( 1.0000f, 1.0000f, -1.0000f );
(*coords)[2].set( 1.0000f, -1.0000f, -1.0000f );
(*coords)[3].set( -1.0000f, -1.0000f, -1.000 );
cubemap->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
cubemap->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
cubemap->setWrap(osg::Texture::WRAP_R, osg::Texture::CLAMP_TO_EDGE);
(*coords)[4].set( 1.0000f, 1.0000f, -1.0000f );
(*coords)[5].set( 1.0000f, 1.0000f, 1.0000f );
(*coords)[6].set( 1.0000f, -1.0000f, 1.0000f );
(*coords)[7].set( 1.0000f, -1.0000f, -1.0000f );
cubemap->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR);
cubemap->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
}
(*coords)[8].set( 1.0000f, 1.0000f, 1.0000f );
(*coords)[9].set( -1.0000f, 1.0000f, 1.000f );
(*coords)[10].set( -1.0000f, -1.0000f, 1.000f );
(*coords)[11].set( 1.0000f, -1.0000f, 1.0000f );
(*coords)[12].set( -1.0000f, 1.0000f, 1.000 );
(*coords)[13].set( -1.0000f, 1.0000f, -1.000 );
(*coords)[14].set( -1.0000f, -1.0000f, -1.000 );
(*coords)[15].set( -1.0000f, -1.0000f, 1.000 );
(*coords)[16].set( -1.0000f, 1.0000f, 1.000 );
(*coords)[17].set( 1.0000f, 1.0000f, 1.0000f );
(*coords)[18].set( 1.0000f, 1.0000f, -1.0000f );
(*coords)[19].set( -1.0000f, 1.0000f, -1.000f );
(*coords)[20].set( -1.0000f, -1.0000f, 1.000f );
(*coords)[21].set( -1.0000f, -1.0000f, -1.000f );
(*coords)[22].set( 1.0000f, -1.0000f, -1.0000f );
(*coords)[23].set( 1.0000f, -1.0000f, 1.0000f );
cube->setVertexArray( coords );
// set up the normals.
osg::Vec3Array* cubeNormals = new osg::Vec3Array;
cubeNormals->resize(6);
(*cubeNormals)[0].set(0.0f,0.0f,-1.0f);
(*cubeNormals)[1].set(1.0f,0.0f,0.0f);
(*cubeNormals)[2].set(0.0f,0.0f,1.0f);
(*cubeNormals)[3].set(-1.0f,0.0f,0.0f);
(*cubeNormals)[4].set(0.0f,1.0f,0.0f);
(*cubeNormals)[5].set(0.0f,-1.0f,0.0f);
cube->setNormalArray( cubeNormals );
cube->setNormalBinding( osg::Geometry::BIND_PER_PRIMITIVE );
// -------------------------
// make diffuse material red
// -------------------------
osg::StateSet* cubeState = new osg::StateSet();
osg::Material* redMaterial = new osg::Material();
const osg::Vec4 red( 1.0f, 0.0f, 0.0f, 1.0f );
redMaterial->setAmbient( osg::Material::FRONT_AND_BACK, red );
redMaterial->setDiffuse( osg::Material::FRONT_AND_BACK, red );
cubeState->setAttribute( redMaterial );
// ---------------------------------------------------
// Use vp local parameter 0 for ambient product (blue)
// ---------------------------------------------------
osg::VertexProgram* vp = new osg::VertexProgram();
vp->setVertexProgram( vpstr );
const osg::Vec4 blue( 0.0f, 0.0f, 1.0f, 1.0f );
vp->setProgramLocalParameter( 0, blue );
cubeState->setAttributeAndModes( vp, osg::StateAttribute::ON );
cube->setStateSet( cubeState );
geode->addDrawable( cube );
return geode;
return cubemap;
}
int main( int argc, char **argv )
// Update texture matrix for cubemaps
struct TexMatCallback : public osg::NodeCallback
{
public:
TexMatCallback(osg::TexMat& tm) :
_texMat(tm)
{
}
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
{
osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>(nv);
if (cv)
{
const osg::Matrix& MV = cv->getModelViewMatrix();
const osg::Matrix R = osg::Matrix::rotate( osg::Vec3(0,-1,0), osg::Vec3(0,0,1) );
osg::Quat q;
q.set(MV);
const osg::Matrix C = osg::Matrix::rotate( q.inverse() );
_texMat.setMatrix( C*R );
}
traverse(node,nv);
}
osg::TexMat& _texMat;
};
struct MoveEarthySkyWithEyePointCallback : public osg::Transform::ComputeTransformCallback
{
/** Get the transformation matrix which moves from local coords to world coords.*/
virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix,const osg::Transform*, osg::NodeVisitor* nv) const
{
osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>(nv);
if (cv)
{
osg::Vec3 eyePointLocal = cv->getEyeLocal();
matrix.preMult(osg::Matrix::translate(eyePointLocal));
}
return true;
}
/** Get the transformation matrix which moves from world coords to local coords.*/
virtual bool computeWorldToLocalMatrix(osg::Matrix& matrix,const osg::Transform*, osg::NodeVisitor* nv) const
{
osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>(nv);
if (cv)
{
osg::Vec3 eyePointLocal = cv->getEyeLocal();
matrix.postMult(osg::Matrix::translate(-eyePointLocal));
}
return true;
}
};
osg::Node* createSkyBox()
{
osg::StateSet* stateset = new osg::StateSet();
osg::TexEnv* te = new osg::TexEnv;
te->setMode(osg::TexEnv::REPLACE);
stateset->setTextureAttributeAndModes(0, te, osg::StateAttribute::ON);
osg::TexGen *tg = new osg::TexGen;
tg->setMode(osg::TexGen::NORMAL_MAP);
stateset->setTextureAttributeAndModes(0, tg, osg::StateAttribute::ON);
osg::TexMat *tm = new osg::TexMat;
stateset->setTextureAttribute(0, tm);
osg::TextureCubeMap* skymap = readCubeMap();
stateset->setTextureAttributeAndModes(0, skymap, osg::StateAttribute::ON);
stateset->setMode( GL_LIGHTING, osg::StateAttribute::OFF );
stateset->setMode( GL_CULL_FACE, osg::StateAttribute::OFF );
// clear the depth to the far plane.
osg::Depth* depth = new osg::Depth;
depth->setFunction(osg::Depth::ALWAYS);
depth->setRange(1.0,1.0);
stateset->setAttributeAndModes(depth, osg::StateAttribute::ON );
stateset->setRenderBinDetails(-1,"RenderBin");
osg::Drawable* drawable = new osg::ShapeDrawable(new osg::Sphere(osg::Vec3(0.0f,0.0f,0.0f),1));
osg::Geode* geode = new osg::Geode;
geode->setCullingActive(false);
geode->setStateSet( stateset );
geode->addDrawable(drawable);
osg::Transform* transform = new osg::Transform;
transform->setCullingActive(false);
transform->setComputeTransformCallback(new MoveEarthySkyWithEyePointCallback);
transform->addChild(geode);
osg::ClearNode* clearNode = new osg::ClearNode;
// clearNode->setRequiresClear(false);
clearNode->setCullCallback(new TexMatCallback(*tm));
clearNode->addChild(transform);
return clearNode;
}
osg::Node* addRefractStateSet(osg::Node* node)
{
osg::StateSet* stateset = new osg::StateSet();
osg::TextureCubeMap* reflectmap = readCubeMap();
stateset->setTextureAttributeAndModes( 0, reflectmap, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE );
stateset->setTextureAttributeAndModes( 1, reflectmap, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE );
osg::TexMat* texMat = new osg::TexMat;
stateset->setTextureAttribute(0, texMat);
// ---------------------------------------------------
// Vertex Program
// ---------------------------------------------------
osg::VertexProgram* vp = new osg::VertexProgram();
vp->setVertexProgram( vpstr );
vp->setProgramLocalParameter( 0, osg::Vec4( fresnel, fresnel, fresnel, 1.0f ) );
vp->setProgramLocalParameter( 1, osg::Vec4( refract, refract*refract, 0.0f, 0.0f ) );
stateset->setAttributeAndModes( vp, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE );
// ---------------------------------------------------
// fragment = refraction*(1-fresnel) + reflection*fresnel
// T0 = texture unit 0, refraction map
// T1 = texture unit 1, reflection map
// C.rgb = primary color, water color
// C.a = primary color, fresnel factor
// Cp = result from previous texture environment
// ---------------------------------------------------
// REPLACE function: Arg0
// = T0
osg::TexEnvCombine *te0 = new osg::TexEnvCombine;
te0->setCombine_RGB(osg::TexEnvCombine::REPLACE);
te0->setSource0_RGB(osg::TexEnvCombine::TEXTURE0);
te0->setOperand0_RGB(osg::TexEnvCombine::SRC_COLOR);
// INTERPOLATE function: Arg0 * (Arg2) + Arg1 * (1-Arg2)
// = T1 * C0.a + Cp * (1-C0.a)
osg::TexEnvCombine *te1 = new osg::TexEnvCombine;
// rgb = Cp + Ct
te1->setCombine_RGB(osg::TexEnvCombine::INTERPOLATE);
te1->setSource0_RGB(osg::TexEnvCombine::TEXTURE1);
te1->setOperand0_RGB(osg::TexEnvCombine::SRC_COLOR);
te1->setSource1_RGB(osg::TexEnvCombine::PREVIOUS);
te1->setOperand1_RGB(osg::TexEnvCombine::SRC_COLOR);
te1->setSource2_RGB(osg::TexEnvCombine::PRIMARY_COLOR);
te1->setOperand2_RGB(osg::TexEnvCombine::SRC_COLOR);
stateset->setTextureAttributeAndModes(0, te0, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
stateset->setTextureAttributeAndModes(1, te1, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
osg::Group* group = new osg::Group;
group->addChild(node);
group->setCullCallback(new TexMatCallback(*texMat));
group->setStateSet( stateset );
return group;
}
int main(int argc, char *argv[])
{
// initialize the GLUT
glutInit( &argc, argv );
glutInitDisplayString("rgba double depth>=16");
// create the commandline args.
std::vector<std::string> commandLine;
for(int i=1;i<argc;++i) commandLine.push_back(argv[i]);
for(int i=1; i<argc; ++i) commandLine.push_back(argv[i]);
// create the viewer and the model to it.
// initialize the viewer.
osgGLUT::Viewer viewer;
viewer.setWindowTitle(argv[0]);
// configure the viewer from the commandline arguments, and eat any
// parameters that have been matched.
viewer.readCommandLine(commandLine);
// add model to viewer.
viewer.addViewport( createGeometryCube() );
// configure the plugin registry from the commandline arguments, and
// eat any parameters that have been matched.
osgDB::readCommandLine(commandLine);
// register trackball maniupulators.
viewer.registerCameraManipulator(new osgGA::TrackballManipulator);
osg::Group* rootnode = new osg::Group;
rootnode->addChild(createSkyBox());
// load the nodes from the commandline arguments.
osg::Node* model = osgDB::readNodeFiles(commandLine);
if (!model)
{
const float radius = 1.0f;
osg::Geode* geode = new osg::Geode;
geode->addDrawable(new osg::ShapeDrawable(new osg::Sphere(osg::Vec3(0.0f,0.0f,0.0f),radius)));
model = geode;
}
// run optimization over the scene graph
osgUtil::Optimizer optimzer;
optimzer.optimize(model);
// create normals.
osgUtil::SmoothingVisitor smoother;
model->accept(smoother);
rootnode->addChild( addRefractStateSet(model) );
// add a viewport to the viewer and attach the scene graph.
viewer.addViewport(rootnode);
viewer.open();
// register trackball
viewer.registerCameraManipulator(new osgGA::TrackballManipulator);
// open the viewer window.
viewer.open();
// fire up the event loop.
viewer.run();
return 0;