效果:
shader.vs:
#version 140 //顶点 in vec4 MCvertex; //法线 in vec3 MCnormal; //怀疑这些以osg_打头的都是osg的内置变量 in vec3 osg_SimulationTime; uniform mat4 osg_ModelViewMatrix; uniform mat4 osg_ModelViewProjectionMatrix; uniform mat3 osg_NormalMatrix; //光照位置 uniform vec3 LightPosition ; //镜面光强度 const float SpecularContribution = 0.3; //散射光强度 const float DiffuseContribution = 1.0 - SpecularContribution; //光照强度值 out float LightIntensity; //顶点的x,y值 out vec2 MCposition; void main() { //物体坐标系->世界坐标系->相机坐标系的转换 vec3 ecPosition = vec3(osg_ModelViewMatrix * MCvertex); //法线转到相机坐标系 vec3 tnorm = normalize(osg_NormalMatrix * MCnormal); //光照的方向 vec3 lightVec = normalize(vec3(LightPosition[0],LightPosition[1],LightPosition[2]*osg_SimulationTime) - ecPosition); //计算出反射方向 vec3 reflectVec = reflect(-lightVec, tnorm); vec3 viewVec = normalize(-ecPosition); float diffuse = max(dot(lightVec, tnorm), 0.0); float spec = 0.0; if (diffuse > 0.0) { spec = max(dot(reflectVec, viewVec), 0.0); spec = pow(spec, 16.0); } LightIntensity = DiffuseContribution * diffuse + SpecularContribution * spec; MCposition = MCvertex.xy; gl_Position = osg_ModelViewProjectionMatrix * MCvertex; }
shader.fs:
#version 140 //转的颜色 和 砖缝的颜色 uniform vec3 BrickColor = vec3(0,1,0), MortarColor = vec3(1,0,0); //转的长和宽 uniform vec2 BrickSize = vec2(0.3,0.15); //砖的宽和高相对于砖缝的宽和高之间的比例 uniform vec2 BrickPct = vec2(0.9,0.85); //顶点的x、y in vec2 MCposition; //光照强烈度 in float LightIntensity; //片元颜色 out vec4 FragColor; void main() { vec3 color; vec2 position, useBrick; //得到砖块行号和砖块列号 position = MCposition / BrickSize; //frack(x) = 1-floor(x),floor(x)=返回小于或等于x的最近整数。相当于取小数部分 if (fract(position.y * 0.5) >= 0.5) position.x += 0.5; //计算片元在当前砖块中的位置(取小数部分) position = fract(position); //step(edge0,x) 如果x>edge0,返回1,否则,返回0 useBrick = step(position, BrickPct); //mix(x,y,a)=x*(1.0-a)+y*a,其实可以简写 //color = mix(MortarColor, BrickColor, useBrick.x * useBrick.y); if(useBrick.x * useBrick.y == 0){ color = MortarColor; }else {color = BrickColor;} color *= LightIntensity; FragColor = vec4(color, 1.0); }
main.cpp
#include <osgViewer/Viewer> #include <osgDB/ReadFile> #include <osg/Shape> #include <osg/Shapedrawable> #include <osg/MatrixTransform> osg::ref_ptr<osg::MatrixTransform> lightPos; class MyNodeVisitor : public osg::NodeVisitor { public: MyNodeVisitor() :osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN){} virtual void apply(osg::Geode& node) { for (int i = 0; i < node.getNumParents(); ++i) { osg::ref_ptr<osg::Geometry> polyGeom = dynamic_cast<osg::Geometry*>(node.getDrawable(i)); if (!polyGeom)return; polyGeom->setVertexAttribArray(0, polyGeom->getVertexArray()); polyGeom->setVertexAttribBinding(0, osg::Geometry::BIND_PER_VERTEX); polyGeom->setVertexAttribArray(1, polyGeom->getColorArray()); polyGeom->setVertexAttribBinding(1, osg::Geometry::BIND_PER_VERTEX); polyGeom->setVertexAttribArray(2, polyGeom->getNormalArray()); polyGeom->setVertexAttribBinding(2, polyGeom->getNormalBinding()); } } }; int main() { osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer; osg::ref_ptr<osg::Node> geode = osgDB::readNodeFile("cow.osg");//CreateNode(); MyNodeVisitor visitor; geode->accept(visitor); osg::ref_ptr<osg::StateSet> stateSet = geode->getOrCreateStateSet(); osg::ref_ptr<osg::Shader> vShader = new osg::Shader(osg::Shader::VERTEX); vShader->loadShaderSourceFromFile("./data/shader.vs"); osg::ref_ptr<osg::Shader> fShader = new osg::Shader(osg::Shader::FRAGMENT); fShader->loadShaderSourceFromFile("./data/shader.fs"); osg::ref_ptr<osg::Program> program = new osg::Program; program->addShader(vShader.get()); program->addShader(fShader.get()); program->addBindAttribLocation("MCvertex", 0); program->addBindAttribLocation("MCnormal", 2); osg::ref_ptr<osg::Uniform> M4 = new osg::Uniform("LightPosition", osg::Vec3d(0, 2, 0)); stateSet->addUniform(M4.get()); stateSet->setAttributeAndModes(program.get(), osg::StateAttribute::ON); osg::ref_ptr<osg::Group> root = new osg::Group; root->addChild(geode); viewer->setSceneData(root); viewer->setUpViewInWindow(35, 35, 1024, 800); viewer->realize(); osg::ref_ptr<osg::State> state = viewer->getCamera()->getGraphicsContext()->getState(); state->setUseModelViewAndProjectionUniforms(true); return viewer->run(); }
下面的main.cpp添加了一些与shader无关的东西,在上面的main.cpp中我拿掉了,并把shader提出去了,看着头疼。
main.cpp
#include <osgViewer/Viewer> #include <osgDB/ReadFile> #include <osg/Shape> #include <osg/Shapedrawable> #include <osg/MatrixTransform> static char * vertexShader = { "#version 140 " //顶点 "in vec4 MCvertex; " //法线 "in vec3 MCnormal; " //怀疑这些以osg_打头的都是osg的内置变量 "in vec3 osg_SimulationTime; " "uniform mat4 osg_ModelViewMatrix; " "uniform mat4 osg_ModelViewProjectionMatrix; " "uniform mat3 osg_NormalMatrix; " //光照位置 "uniform vec3 LightPosition ; " //镜面光强度 "const float SpecularContribution = 0.3; " //散射光强度 "const float DiffuseContribution = 1.0 - SpecularContribution; " //光照强度值 "out float LightIntensity; " //顶点的x,y值 "out vec2 MCposition; " "void main() " "{ " //物体坐标系->世界坐标系->相机坐标系的转换 " vec3 ecPosition = vec3(osg_ModelViewMatrix * MCvertex); " //法线转到相机坐标系 " vec3 tnorm = normalize(osg_NormalMatrix * MCnormal); " //光照的方向 " vec3 lightVec = normalize(vec3(LightPosition[0],LightPosition[1],LightPosition[2]*osg_SimulationTime) - ecPosition); " //计算出反射方向 " vec3 reflectVec = reflect(-lightVec, tnorm); " " vec3 viewVec = normalize(-ecPosition); " " float diffuse = max(dot(lightVec, tnorm), 0.0); " " float spec = 0.0; " " if (diffuse > 0.0) " " { " " spec = max(dot(reflectVec, viewVec), 0.0); " " spec = pow(spec, 16.0); " " } " " LightIntensity = DiffuseContribution * diffuse + SpecularContribution * spec; " " MCposition = MCvertex.xy; " " gl_Position = osg_ModelViewProjectionMatrix * MCvertex; " "} " }; static char * fragShader = { " #version 140 " //转的颜色 和 砖缝的颜色 " uniform vec3 BrickColor = vec3(0,1,0), MortarColor = vec3(1,0,0); " //转的长和宽 " uniform vec2 BrickSize = vec2(0.3,0.15); " //砖的宽和高相对于砖缝的宽和高之间的比例 " uniform vec2 BrickPct = vec2(0.9,0.85); " //顶点的x、y " in vec2 MCposition; " //光照强烈度 " in float LightIntensity; " //片元颜色 " out vec4 FragColor; " " void main() " " { " " vec3 color; " " vec2 position, useBrick; " //得到砖块行号和砖块列号 " position = MCposition / BrickSize; " //frack(x) = 1-floor(x),floor(x)=返回小于或等于x的最近整数。相当于取小数部分 " if (fract(position.y * 0.5) >= 0.5) " " position.x += 0.5; " //计算片元在当前砖块中的位置(取小数部分) " position = fract(position); " //step(edge0,x) 如果x>edge0,返回1,否则,返回0 " useBrick = step(position, BrickPct); " //mix(x,y,a)=x*(1.0-a)+y*a,其实可以简写, " //color = mix(MortarColor, BrickColor, useBrick.x * useBrick.y); " "if(useBrick.x * useBrick.y == 0){ color = MortarColor; }else {color = BrickColor;} " " color *= LightIntensity; " " FragColor = vec4(color, 1.0); " "} " }; osg::ref_ptr<osg::MatrixTransform> lightPos; class MyNodeVisitor : public osg::NodeVisitor { public: MyNodeVisitor() :osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN){} virtual void apply(osg::Geode& node) { for (int i = 0; i < node.getNumParents(); ++i) { osg::ref_ptr<osg::Geometry> polyGeom = dynamic_cast<osg::Geometry*>(node.getDrawable(i)); if (!polyGeom)return; polyGeom->setVertexAttribArray(0, polyGeom->getVertexArray()); polyGeom->setVertexAttribBinding(0, osg::Geometry::BIND_PER_VERTEX); polyGeom->setVertexAttribArray(1, polyGeom->getColorArray()); polyGeom->setVertexAttribBinding(1, osg::Geometry::BIND_PER_VERTEX); polyGeom->setVertexAttribArray(2, polyGeom->getNormalArray()); polyGeom->setVertexAttribBinding(2, polyGeom->getNormalBinding()); } } }; class LightPosCallback : public osg::Uniform::Callback { public: LightPosCallback() { } virtual void operator()(osg::Uniform* uniform, osg::NodeVisitor* nv) { osg::Matrix m = lightPos->getMatrix(); uniform->set(m.getTrans()); } }; osg::ref_ptr<osg::Node> createlight() { osg::ref_ptr<osg::ShapeDrawable> sun_sd = new osg::ShapeDrawable; osg::ref_ptr<osg::Sphere> sun_sphere = new osg::Sphere; sun_sphere->setName("SunSphere"); sun_sphere->setRadius(0.5); sun_sd->setShape(sun_sphere); sun_sd->setColor(osg::Vec4(1.0, 0.0, 0.0, 1.0)); osg::ref_ptr<osg::Geode> sun_geode = new osg::Geode; sun_geode->setName("SunGeode"); sun_geode->addDrawable(sun_sd.get()); return sun_geode; } class KeyboardEventHandler : public osgGA::GUIEventHandler { public: KeyboardEventHandler(){} virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter&) { switch (ea.getEventType()) { case(osgGA::GUIEventAdapter::KEYDOWN) : { if (ea.getKey() == 'x')//绕x轴旋转 { osg::Matrix trans = lightPos->getMatrix(); trans = trans * osg::Matrix::rotate(osg::PI_2 / 10, osg::X_AXIS); lightPos->setMatrix(trans); } if (ea.getKey() == 'y')//绕y轴旋转 { osg::Matrix trans = lightPos->getMatrix(); trans = trans * osg::Matrix::rotate(osg::PI_2 / 10, osg::Y_AXIS); lightPos->setMatrix(trans); } if (ea.getKey() == 'z')//绕z轴旋转 { osg::Matrix trans = lightPos->getMatrix(); trans = trans * osg::Matrix::rotate(osg::PI_2 / 10, osg::Z_AXIS); lightPos->setMatrix(trans); } } } return false; } }; int main() { osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer; osg::ref_ptr<osg::Node> geode = osgDB::readNodeFile("cow.osg");//CreateNode(); MyNodeVisitor visitor; geode->accept(visitor); osg::ref_ptr<osg::StateSet> stateSet = geode->getOrCreateStateSet(); osg::ref_ptr<osg::Shader> vShader = new osg::Shader(osg::Shader::VERTEX, vertexShader); osg::ref_ptr<osg::Shader> fShader = new osg::Shader(osg::Shader::FRAGMENT, fragShader); osg::ref_ptr<osg::Program> program = new osg::Program; program->addShader(vShader.get()); program->addShader(fShader.get()); program->addBindAttribLocation("MCvertex", 0); program->addBindAttribLocation("MCnormal", 2); osg::ref_ptr<osg::Uniform> M4 = new osg::Uniform("LightPosition", osg::Vec3d(2, 0, 0)); M4->setUpdateCallback(new LightPosCallback()); stateSet->addUniform(M4.get()); stateSet->setAttributeAndModes(program.get(), osg::StateAttribute::ON); lightPos = new osg::MatrixTransform; lightPos->setMatrix(osg::Matrix::translate(0, 0, 5)); lightPos->addChild(createlight()); osg::ref_ptr<osg::Group> root = new osg::Group; //root->addChild(osgDB::readNodeFile("d:/ah64_apache.3ds")); root->addChild(lightPos.get()); root->addChild(geode); viewer->addEventHandler(new KeyboardEventHandler()); viewer->setSceneData(root); viewer->setUpViewInWindow(35, 35, 1024, 800); viewer->realize(); osg::ref_ptr<osg::State> state = viewer->getCamera()->getGraphicsContext()->getState(); state->setUseModelViewAndProjectionUniforms(true); return viewer->run(); }