diff --git a/src/Demos/osgvertexprogram/osgvertexprogram.cpp b/src/Demos/osgvertexprogram/osgvertexprogram.cpp index f09513471..31cee885d 100644 --- a/src/Demos/osgvertexprogram/osgvertexprogram.cpp +++ b/src/Demos/osgvertexprogram/osgvertexprogram.cpp @@ -1,187 +1,401 @@ -#include -#include -#include +#include +#include +#include + #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include +#include +#include + #include -#include -#include +#include +#include + +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(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(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(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 commandLine; - for(int i=1;iaddChild(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;