典型的shader砖块

效果:

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();

}
原文地址:https://www.cnblogs.com/airduce/p/10062747.html