uniform int osg_FrameNumber:當前OSG程序運行的幀數; uniform float osg_FrameTime:當前OSG程序的運行總時間; uniform float osg_DeltaFrameTime:當前OSG程序運行每幀的間隔時間; uniform mat4 osg_ViewMatrix:當前OSG攝像機的觀察矩陣; uniform mat4 osg_ViewMatrixInverse:當前OSG攝像機觀察矩陣的逆矩陣。 uniform mat4 osg_ModelViewMatrix:內置gl_ModelViewMatrix uniform mat4 osg_ModelViewProjectionMatrix:內置gl_ModelViewProjectionMatrix uniform mat4 osg_ProjectionMatrix:內置gl_ProjectionMatrix uniform mat3 osg_NormalMatrix:內置gl_NormalMatrix
- attribute:應用程序與頂點着色器的接口,使用頂點屬性定義函數進行定義;
- uniform:應用程序與所有着色器的接口,定義不隨頂點變化的“一致變量”;
- varying:着色器之間的“易變變量”接口,用於傳遞插值得到的頂點數據;
- const:用於聲明常量數據;
- in:作為函數形參進行傳遞,函數返回時不保留改變,只保留傳入值;
- out:作為函數形參進行傳遞,本身未定義,函數返回時保留改變值;
- inout:作為函數形參進行傳遞,可以定義傳入值,也會保留返回時的改變值。
- uniform mat4 gl_NormalMatrix:法線變換矩陣;
- uniform mat4 gl_ModelViewMatrix:模型視點變換矩陣;
- attribute vec4 gl_Vertex:頂點坐標屬性;
- attribute vec4 gl_MultiTexCoord0:紋理單元0的紋理坐標屬性;
- varying vec4 gl_TexCoord[0]:紋理單元0的實際紋理坐標。
-
實現片元着色器的一段示例代碼如下: uniform sampler2D texture; varying vec3 tangent; void main( void ) { gl_FragColor = texture2D( texture, gl_TexCoord[0] ); }
着色器一致變量的接口類。對於OpenGL着色語言而言,一致變量(uniform)是用戶應用程序與着色器的主要交互接口。Uniform類支持綁定多種類型的一致變量,並使用set()和setArray()更新變量或變量數組的值。而為了實現一致變量的每幀變化,進而達到頂點和片元的各種動畫特效,Uniform類還提供了相應的回調工具:使用setUpdateCallback設置自定義的回調類,並在其中更新這個一致變量的值,以實現所需的效果。
#include <osgViewer/Viewer> #include <osg/ShapeDrawable> #include <osg/Geode> #include <osg/Vec3> #include <osg/Program> #include <osg/Shader> #include <osg/Uniform> using namespace osg; /////////////////////////////////////////////////////////////////////////// // in-line GLSL source code static const char *blockyVertSource = { "// blocky.vert - an GLSL vertex shader with animation\n" "// the App updates uniforms \"slowly\" (eg once per frame) for animation.\n" "uniform float Sine;\n" "const vec3 LightPosition = vec3(0.0, 0.0, 4.0);\n" "const float BlockScale = 0.30;\n" "// varyings are written by vert shader, interpolated, and read by frag shader.\n" "varying float LightIntensity;\n" "varying vec2 BlockPosition;\n" "void main(void)\n" "{\n" " // per-vertex diffuse lighting\n" " vec4 ecPosition = gl_ModelViewMatrix * gl_Vertex;\n" " vec3 tnorm = normalize(gl_NormalMatrix * gl_Normal);\n" " vec3 lightVec = normalize(LightPosition - vec3 (ecPosition));\n" " LightIntensity = max(dot(lightVec, tnorm), 0.0);\n" " // blocks will be determined by fragment's position on the XZ plane.\n" " BlockPosition = gl_Vertex.xz / BlockScale;\n" " // scale the geometry based on an animation variable.\n" " vec4 vertex = gl_Vertex;\n" " vertex.w = 1.0 + 0.4 * (Sine + 1.0);\n" " gl_Position = gl_ModelViewProjectionMatrix * vertex;\n" "}\n" }; static const char *blockyFragSource = { "// blocky.frag - an GLSL fragment shader with animation\n" "// the App updates uniforms \"slowly\" (eg once per frame) for animation.\n" "uniform float Sine;\n" "const vec3 Color1 = vec3(1.0, 1.0, 1.0);\n" "const vec3 Color2 = vec3(0.0, 0.0, 0.0);\n" "// varyings are written by vert shader, interpolated, and read by frag shader.\n" "varying vec2 BlockPosition;\n" "varying float LightIntensity;\n" "void main(void)\n" "{\n" " vec3 color;\n" " float ss, tt, w, h;\n" " ss = BlockPosition.x;\n" " tt = BlockPosition.y;\n" " if (fract(tt * 0.5) > 0.5)\n" " ss += 0.5;\n" " ss = fract(ss);\n" " tt = fract(tt);\n" " // animate the proportion of block to mortar\n" " float blockFract = (Sine + 1.1) * 0.4;\n" " w = step(ss, blockFract);\n" " h = step(tt, blockFract);\n" " color = mix(Color2, Color1, w * h) * LightIntensity;\n" " gl_FragColor = vec4 (color, 1.0);\n" "}\n" }; /////////////////////////////////////////////////////////////////////////// // callback for animating various Uniforms (currently only the SIN uniform) class AnimateCallback : public osg::UniformCallback { public: enum Operation { SIN }; AnimateCallback(Operation op) : _operation(op) {} virtual void operator() (osg::Uniform* uniform, osg::NodeVisitor* nv) { float angle = 2.0 * nv->getFrameStamp()->getSimulationTime(); float sine = sinf(angle); // -1 -> 1 switch (_operation) { case SIN: uniform->set(sine); break; } } private: Operation _operation; }; int main(int, char **) { // construct the viewer. osgViewer::Viewer viewer; // use a geode with a Box ShapeDrawable osg::Geode* basicModel = new osg::Geode(); basicModel->addDrawable(new osg::ShapeDrawable(new osg::Box(osg::Vec3(0.0f, 0.0f, 0.0f), 1.0f))); // create the "blocky" shader, a simple animation test osg::StateSet *ss = basicModel->getOrCreateStateSet(); osg::Program* program = new osg::Program; program->setName("blocky"); //program->addShader(new osg::Shader(osg::Shader::VERTEX, blockyVertSource)); //program->addShader(new osg::Shader(osg::Shader::FRAGMENT, blockyFragSource)); program->addShader(osg::Shader::readShaderFile(osg::Shader::VERTEX, "blocky.vert")); program->addShader(osg::Shader::readShaderFile(osg::Shader::FRAGMENT, "blocky.frag")); ss->setAttributeAndModes(program, osg::StateAttribute::ON); // attach some animated Uniform variable to the state set osg::Uniform* SineUniform = new osg::Uniform("Sine", 0.0f); ss->addUniform(SineUniform); SineUniform->setUpdateCallback(new AnimateCallback(AnimateCallback::SIN)); // run the osg::Viewer using our model viewer.setSceneData(basicModel); return viewer.run(); } /*EOF*/