OSG

来自CGTWiki
跳转至:导航搜索

网站

OSG官网

OSG中国

常用学习资料

文件:最长的一帧.pdf

文件:OSG快速入门.pdf

文件:OpenSceneGraph三维渲染引擎编程指南.pdf

文件:OpenSceneGraph三维渲染引擎设计与实践.pdf

文件:StepIntoOpenSceneGraph.pdf

基本概念

OSG中的三种重要的数据结构

LOD(level of detail)

是指根据物体模型的结点在显示环境中所处的位置和重要度,决定物体渲染的资源分配,降低非重要物体的面数和细节度,从而获得高效率的渲染运算。在OSG的场景结点组织结构中,专门提供了场景结点osg::LOD来表达不同的细节层次模型。其中,osg::LOD结点作为父节点,每个子节点作为一个细节层次,设置不同的视域,在不同的视域下显示相应的子节点。

数据分页

在城市三维场景中可以采用数据分页的方式进行动态调度。这里“分页”的意思是随着视口范围的变化,场景只加载和渲染当前视口范围内数据,并将离开视口范围内的数据清除内存(可以设定不同的数据卸载策略),不再渲染。保证内存中只有有限的数据量,场景的每一帧也只有有限的数据被送到图形渲染管道,从而提高渲染性能。

动态调度

OSG源代码中提供PagedLOD来进行模型的动态调度。在不同的视域下,PagedLOD动态读取不同细节层次的结点模型,实现了分页LOD显示。OSG内部采用osgDB::DatabasePager类来管理场景结点的动态调度,场景循环每一帧的时候,会将一段时间内不在当前视图范围内的场景子树卸载掉,并加载新进入到当前视图范围的新场景子树。OSG采用了多线程的方式来完成上述工作。

基本渲染流程

基本类

场景树

场景组织中有三个重要的节点类:Group、Geode、Drawable。 其中Drawable的子类Gemotry最为重要

  • geometry类可以直接有顶点和索引等数据,或者任意个primitiveSet实例。
  • vertex和vertex属性数据(颜色、法线、纹理坐标)存放在数组中。既然多个顶点可以共享相同的颜色、法线或纹理坐标,那么数组索引就可以用来将顶点数组映射到颜色、法线、或纹理坐标数组。
  • PrimitiveSet类:这个类松散的包装了OpenGL的基本图形-POINTS,LINES,LINE_STRIP,LINE_LOOP,...,POLYGON.
Primitiveset
构建geomtry的方法

从下面的代码可以看出,生成drawable对象的两种方法

  • 由Shape构建shapeDrawable对象。
  • 由顶点,法线等属性信息构建Geomtry对象,由primitiveSet对象设置其渲染绘制方法。


osg::Node* create()
{
    /** 
        geode is a leaf node,It must contain some drawables..
    */
    osg::Geode* geode = new osg::Geode;

    /** define a Geometry for draw a triangle.*/
    osg::Geometry* triangle = new osg::Geometry;
    geode->addDrawable(triangle);

    /** triangle Vertexs */
    osg::Vec3Array* Tvertex = new osg::Vec3Array;
    triangle->setVertexArray(Tvertex);
    Tvertex->push_back(osg::Vec3(-2.0,0.0,-1.0));
    Tvertex->push_back(osg::Vec3( 0.0,0.0,-1.0));
    Tvertex->push_back(osg::Vec3(-1.0,0.0, 1.0));
    
    /** set the color */
    osg::Vec3Array* Tcolor  = new osg::Vec3Array;
    triangle->setColorArray(Tcolor);
    triangle->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
    Tcolor->push_back(osg::Vec3(1.0,0.0,0.0));
    Tcolor->push_back(osg::Vec3(0.0,1.0,0.0));
    Tcolor->push_back(osg::Vec3(0.0,0.0,1.0));

    /** set the normal*/
    osg::Vec3Array* Tnormal = new osg::Vec3Array;
    Tnormal->push_back(osg::Vec3(0.0,-1.0,0.0));
    triangle->setNormalArray(Tnormal);
    triangle->setNormalBinding(osg::Geometry::BIND_OVERALL);

    /** set the Primitive use GL_TRIANGLES*/
    osg::PrimitiveSet* Tprimitive = new osg::DrawArrays(GL_TRIANGLES,0,3);
    triangle->addPrimitiveSet(Tprimitive);


    /** now  define a box(center,width)*/
    osg::Box* boxtest = new osg::Box(osg::Vec3(1.5,0.0,0.0),1.0);
    /** use the ShapeDrawable*/
    osg::ShapeDrawable* box = new osg::ShapeDrawable(boxtest);
    geode->addDrawable(box);

    return geode;
}

osg::drawArrays解析
class OSG_EXPORT DrawArrays : public PrimitiveSet
{
    public:
 
         DrawArrays(GLenum mode=0):
             PrimitiveSet(DrawArraysPrimitiveType,mode),
             _first(0),
             _count(0) {}
 
         DrawArrays(GLenum mode, GLint first, GLsizei count, int numInstances=0):
             PrimitiveSet(DrawArraysPrimitiveType, mode, numInstances),
             _first(first),
             _count(count) {}
 
         DrawArrays(const DrawArrays& da,const CopyOp& copyop=CopyOp::SHALLOW_COPY):
             PrimitiveSet(da,copyop),
             _first(da._first),
             _count(da._count) {}
 
         virtual Object* cloneType() const { return new DrawArrays(); }
         virtual Object* clone(const CopyOp& copyop) const { return new DrawArrays(*this,copyop); }
         virtual bool isSameKindAs(const Object* obj) const { return dynamic_cast<const DrawArrays*>(obj)!=NULL; }
         virtual const char* libraryName() const { return "osg"; }
         virtual const char* className() const { return "DrawArrays"; }
 
 
         void set(GLenum mode,GLint first, GLsizei count)
         {
             _mode = mode;
             _first = first;
             _count = count;
         }
 
         void setFirst(GLint first) { _first = first; }
         GLint getFirst() const { return _first; }
 
         void setCount(GLsizei count) { _count = count; }
         GLsizei getCount() const { return _count; }
 
         virtual void draw(State& state, bool useVertexBufferObjects) const;
 
         virtual void accept(PrimitiveFunctor& functor) const;
         virtual void accept(PrimitiveIndexFunctor& functor) const;
 
         virtual unsigned int getNumIndices() const { return static_cast<unsigned int>(_count); }
         virtual unsigned int index(unsigned int pos) const { return static_cast<unsigned int>(_first)+pos; }
         virtual void offsetIndices(int offset) { _first += offset; }
 
     protected:
 
         virtual ~DrawArrays() {}
 
         GLint   _first;
         GLsizei _count;
 };

这里有两个重要的虚函数:

 virtual void draw(State& state, bool useVertexBufferObjects) const;
 virtual void accept(PrimitiveFunctor& functor) const;
 virtual void accept(PrimitiveIndexFunctor& functor) const;
void DrawArrays::draw(State& state, bool) const
{
#if defined(OSG_GLES1_AVAILABLE) || defined(OSG_GLES2_AVAILABLE) || defined(OSG_GLES3_AVAILABLE)
    GLenum mode = _mode;
    if (_mode==GL_QUADS)
    {
        state.drawQuads(_first, _count, _numInstances);
        return;
    }
    else if (mode==GL_POLYGON)
    {
        mode = GL_TRIANGLE_FAN;
    }
    else if (mode==GL_QUAD_STRIP)
    {
        mode = GL_TRIANGLE_STRIP;
    }

    if (_numInstances>=1) state.glDrawArraysInstanced(mode,_first,_count, _numInstances);
    else glDrawArrays(mode,_first,_count);
#else
    if (_numInstances>=1) state.glDrawArraysInstanced(_mode,_first,_count, _numInstances);
    else glDrawArrays(_mode,_first,_count);
#endif
}

void DrawArrays::accept(PrimitiveFunctor& functor) const
{
    functor.drawArrays(_mode,_first,_count);
}

void DrawArrays::accept(PrimitiveIndexFunctor& functor) const
{
    functor.drawArrays(_mode,_first,_count);
}
osg::PrimitiveSet解析
class OSG_EXPORT PrimitiveSet : public BufferData
{
    public:

        enum Type
        {
            PrimitiveType,
            DrawArraysPrimitiveType,
            DrawArrayLengthsPrimitiveType,
            DrawElementsUBytePrimitiveType,
            DrawElementsUShortPrimitiveType,
            DrawElementsUIntPrimitiveType,
            MultiDrawArraysPrimitiveType,
            DrawArraysIndirectPrimitiveType,
            DrawElementsUByteIndirectPrimitiveType,
            DrawElementsUShortIndirectPrimitiveType,
            DrawElementsUIntIndirectPrimitiveType,
            MultiDrawArraysIndirectPrimitiveType,
            MultiDrawElementsUByteIndirectPrimitiveType,
            MultiDrawElementsUShortIndirectPrimitiveType,
            MultiDrawElementsUIntIndirectPrimitiveType
        };

        enum Mode
        {
            POINTS = GL_POINTS,
            LINES = GL_LINES,
            LINE_STRIP = GL_LINE_STRIP,
            LINE_LOOP = GL_LINE_LOOP,
            TRIANGLES = GL_TRIANGLES,
            TRIANGLE_STRIP = GL_TRIANGLE_STRIP,
            TRIANGLE_FAN = GL_TRIANGLE_FAN,
            QUADS = GL_QUADS,
            QUAD_STRIP = GL_QUAD_STRIP,
            POLYGON = GL_POLYGON,
            LINES_ADJACENCY = GL_LINES_ADJACENCY,
            LINE_STRIP_ADJACENCY = GL_LINE_STRIP_ADJACENCY,
            TRIANGLES_ADJACENCY = GL_TRIANGLES_ADJACENCY,
            TRIANGLE_STRIP_ADJACENCY = GL_TRIANGLE_STRIP_ADJACENCY,
            PATCHES = GL_PATCHES
        };

        PrimitiveSet(Type primType=PrimitiveType,GLenum mode=0, int numInstances=0):
            _primitiveType(primType),
            _numInstances(numInstances),
            _mode(mode) {}

        PrimitiveSet(const PrimitiveSet& prim,const CopyOp& copyop=CopyOp::SHALLOW_COPY):
            BufferData(prim,copyop),
            _primitiveType(prim._primitiveType),
            _numInstances(prim._numInstances),
            _mode(prim._mode) {}

        virtual bool isSameKindAs(const Object* obj) const { return dynamic_cast<const PrimitiveSet*>(obj)!=NULL; }
        virtual const char* libraryName() const { return "osg"; }
        virtual const char* className() const { return "PrimitiveSet"; }

        Type                    getType() const { return _primitiveType; }

        virtual osg::PrimitiveSet* asPrimitiveSet() { return this; }
        virtual const osg::PrimitiveSet* asPrimitiveSet() const { return this; }

        virtual const GLvoid*   getDataPointer() const { return 0; }
        virtual unsigned int    getTotalDataSize() const { return 0; }
        virtual bool            supportsBufferObject() const { return false; }

        virtual DrawElements* getDrawElements() { return 0; }
        virtual const DrawElements* getDrawElements() const { return 0; }

        void setNumInstances(int n) { _numInstances = n; }
        int getNumInstances() const { return _numInstances; }

        void setMode(GLenum mode) { _mode = mode; }
        GLenum getMode() const { return _mode; }

        virtual void draw(State& state, bool useVertexBufferObjects) const = 0;

        virtual void accept(PrimitiveFunctor& functor) const = 0;
        virtual void accept(PrimitiveIndexFunctor& functor) const = 0;

        virtual unsigned int index(unsigned int pos) const = 0;
        virtual unsigned int getNumIndices() const = 0;
        virtual void offsetIndices(int offset) = 0;

        virtual unsigned int getNumPrimitives() const;

        virtual void computeRange() const {}

    protected:

        virtual ~PrimitiveSet() {}

        Type            _primitiveType;
        int             _numInstances;
        GLenum          _mode;
};

Visitor

StateSet

SateSet类:保存一组定义状态数据(模式和属性)。场景中任何osg::Node都可以与一个StateSet相关联。

  • Modes(模式):与OpenGL中glEnable()和glDisable()相似。用于打开或关闭OpenGL 固定功能(fixed-function)的渲染管道,例如灯光,混合和雾效。方法 osg::StateSet::setMode()在StateSet 中保存一个模式信息。
  • Attibutes(属性):使用属性来指定状态参数,例如混和函数,材质属性,雾颜色等。方法osg::StateSet::setAttribute()在StateSet 中保存属性信息。
  • 纹理模式和属性:纹理模式和属性可应用在OpenGL 多重纹理的某个指定纹理单元上。应用程序必须在设定纹理模式和属性时提供纹理单元的信息,StateSet类的方法setTextureMode()和 setTextureAttribute()用于设定状态参量以及纹理单元信息。
  • 继承标志:OSG 提供了一些标志量,用于控制场景图形遍历中的状态值。缺省情况下,子节点中的状态集合将重载父节点的状态集合。

state类中的drawinstance方法

inline void glDrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei primcount)
{
  if (primcount>=1 && _glDrawArraysInstanced!=0) _glDrawArraysInstanced(mode, first, count, primcount);
  else glDrawArrays(mode, first, count);
}
inline void glDrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount )
{
  if (primcount>=1 && _glDrawElementsInstanced!=0) _glDrawElementsInstanced(mode, count, type, indices, primcount);
     else glDrawElements(mode, count, type, indices);
}

基本的绘制流程

OpenGL 是一种状态机,而这一机制在 OSG中的具体实现就是 osg∶State 类。它封装了几乎所有的 OpenGL 状态量、属性参数,以及顶点数组的设置。用户开发时对于渲染状态集(StateSet)、几何顶点数据(Geometry)的操作,实质上最终都是交由 State 类来保存和执行。它提供了对 OpenGL 状态堆找的处理机制,因而开发者不必反复考虑 OpenGL 堆栈处理的问题;它负责对即将进入消染管线的数据进行排序和优化;同时它还允许用户直接查询各种 OpenGL, 状态的当前值,而不必使用 glGet*()系列的 OpenGL函数这里再次给出 State 类中有关渲染状态设置和执行的函数, 并进一步对 OSG中渲染工作的封装方式进行分析。

常用代码

将节点写入文件

osgDB::writeNodeFile(*node, "d:\\test.osgt");

获取节点的坐标

class getWorldCoordOfNodeVisitor : public osg::NodeVisitor {
public:
     getWorldCoordOfNodeVisitor():
	 
     osg::NodeVisitor(NodeVisitor::TRAVERSE_PARENTS), done(false)
      {
         wcMatrix= new osg::Matrixd();
      }
      virtual void apply(osg::Node &node)
      {
         if (!done)
        {
           if ( 0 == node.getNumParents() ) // 到达根节点,此时节点路径也已记录完整
           {
              wcMatrix->set( osg::computeLocalToWorld(this->getNodePath()) );
              done = true;
           }
           traverse(node);
        }
      }
     osg::Matrixd* giveUpDaMat()
      {
         return wcMatrix;
      }
	  
	  
private:
   bool done;
   osg::Matrix* wcMatrix;
};
  • 使用方法
osg::Matrixd* getWorldCoords( osg::Node* node) 
{
   getWorldCoordOfNodeVisitor* ncv = new getWorldCoordOfNodeVisitor();
   if (node && ncv)
   {
     node->accept(*ncv);
      return ncv->giveUpDaMat();
   }
   else
   {
      return NULL;
   }
}

绘制基本图形

绘制经纬球[1]

#include <vector>

class SolidSphere
{
protected:

    osg::Geode      sphereGeode;
    osg::Geometry   sphereGeometry;
    osg::Vec3Array  sphereVertices;
    osg::Vec3Array  sphereNormals;
    osg::Vec2Array  sphereTexCoords;

    std::vector<osg::DrawElementsUInt> spherePrimitiveSets;

public:
    SolidSphere(float radius, unsigned int rings, unsigned int sectors)
    {
        float const R = 1./(float)(rings-1);
        float const S = 1./(float)(sectors-1);
        int r, s;

        sphereGeode.addDrawable( &sphereGeometry );

        // Establish texture coordinates, vertex list, and normals
        for(r = 0; r < rings; r++)
            for(s = 0; s < sectors; s++)
            {
                float const y = sin( -M_PI_2 + M_PI * r * R );
                float const x = cos(2*M_PI * s * S) * sin( M_PI * r * R );
                float const z = sin(2*M_PI * s * S) * sin( M_PI * r * R );

                sphereTexCoords.push_back( osg::Vec2(s*R, r*R) );

                sphereVertices.push_back ( osg::Vec3(x * radius,
                                                     y * radius,
                                                     z * radius) );

                sphereNormals.push_back  ( osg::Vec3(x, y, z) );

            }

        sphereGeometry.setVertexArray  ( &spehreVertices  );
        sphereGeometry.setTexCoordArray( &sphereTexCoords );

        // Generate quads for each face.  
        for(r = 0; r < rings-1; r++)
            for(s = 0; s < sectors-1; s++)
            {
                spherePrimitiveSets.push_back(
                    DrawElementUint( osg::PrimitiveSet::QUADS, 0 )
                );

                osg::DrawElementsUInt& face = spherePrimitiveSets.back();

                // Corners of quads should be in CCW order.
                face.push_back( (r + 0) * sectors + (s + 0) );
                face.push_back( (r + 0) * sectors + (s + 1) );
                face.push_back( (r + 1) * sectors + (s + 1) );
                face.push_back( (r + 1) * sectors + (s + 0) );

                sphereGeometry.addPrimitveSet( &face );
            }
    }

    osg::Geode     *getGeode()     const { return &sphereGeode;     }
    osg::Geometry  *getGeometry()  const { return &sphereGeometry;  }
    osg::Vec3Array *getVertices()  const { return &sphereVertices;  }
    osg::Vec3Array *getNormals()   const { return &sphereNormals;   }
    osg::Vec2Array *getTexCoords() const { return &sphereTexCoords; }

};

绘制MultiInstanced

低版本
#include <osgDB/ReadFile>
#include <osgViewer/Viewer>
#include <osg/Geometry>
#include <osg/Texture2D>

#include <osgDB/WriteFile>

#include <iostream>

void
createDAIGeometry( osg::Geometry& geom, int nInstances=1 )
{
    const float halfDimX( .5 );
    const float halfDimZ( .5 );

    osg::Vec3Array* v = new osg::Vec3Array;
    v->resize( 4 );
    geom.setVertexArray( v );

    // Geometry for a single quad.
    (*v)[ 0 ] = osg::Vec3( -halfDimX, 0., -halfDimZ );
    (*v)[ 1 ] = osg::Vec3( halfDimX, 0., -halfDimZ );
    (*v)[ 2 ] = osg::Vec3( halfDimX, 0., halfDimZ );
    (*v)[ 3 ] = osg::Vec3( -halfDimX, 0., halfDimZ );

    // Use the DrawArraysInstanced PrimitiveSet and tell it to draw 1024 instances.
    geom.addPrimitiveSet( new osg::DrawArrays( GL_QUADS, 0, 4, nInstances ) );
}


osg::StateSet*
createStateSet()
{
    osg::ref_ptr< osg::StateSet > ss = new osg::StateSet;

    // Create a vertex program that references the gl_InstanceID to
    // render each instance uniquely. gl_InstanceID will be in the range
    // 0 to numInstances-1 (1023 in our case).
    std::string vertexSource =
        "uniform sampler2D osgLogo; \n"
        "uniform float osg_SimulationTime; \n"

        "void main() \n"
        "{ \n"
            // Using the instance ID, generate "texture coords" for this instance.
            "vec2 tC; \n"
            "float r = float(gl_InstanceID) / 32.; \n"
            "tC.s = fract( r ); tC.t = floor( r ) / 32.; \n"
            // Get the color from the OSG logo.
            "gl_FrontColor = texture2D( osgLogo, tC ); \n"

            // Use the (scaled) tex coord to translate the position of the vertices.
            "vec4 pos = vec4( tC.s * 48., 0., tC.t * 48., 1. ); \n"

            // Compute a rotation angle from the instanceID and elapsed time.
            "float timeOffset = gl_InstanceID / (32. * 32.); \n"
            "float angle = ( osg_SimulationTime - timeOffset ) * 6.283; \n"
            "float sa = sin( angle ); \n"
            "float ca = cos( angle ); \n"
            // New orientation, rotate around z axis.
            "vec4 newX = vec4( ca, sa, 0., 0. ); \n"
            "vec4 newY = vec4( sa, ca, 0., 0. ); \n"
            "vec4 newZ = vec4( 0., 0., 1., 0. ); \n"
            "mat4 mV = mat4( newX, newY, newZ, pos ); \n"
            "gl_Position = ( gl_ModelViewProjectionMatrix * mV * gl_Vertex ); \n"
        "} \n";

    osg::ref_ptr< osg::Shader > vertexShader = new osg::Shader();
    vertexShader->setType( osg::Shader::VERTEX );
    vertexShader->setShaderSource( vertexSource );

    osg::ref_ptr< osg::Program > program = new osg::Program();
    program->addShader( vertexShader.get() );

    ss->setAttribute( program.get(),
        osg::StateAttribute::ON | osg::StateAttribute::PROTECTED );

    osg::ref_ptr< osg::Image> iLogo = osgDB::readRefImageFile( "Images/osg128.png" );
    if( !iLogo.valid() )
    {
        osg::notify( osg::ALWAYS ) << "Can't open image file osg128.png" << std::endl;
        return( NULL );
    }
    osg::Texture2D* texLogo = new osg::Texture2D( iLogo.get() );
    texLogo->setFilter( osg::Texture2D::MIN_FILTER, osg::Texture2D::LINEAR );
    texLogo->setFilter( osg::Texture2D::MAG_FILTER, osg::Texture2D::LINEAR );

    ss->setTextureAttribute( 0, texLogo );

    osg::ref_ptr< osg::Uniform > texLogoUniform =
        new osg::Uniform( "osgLogo", 0 );
    ss->addUniform( texLogoUniform.get() );

    return( ss.release() );
}


int main( int argc, char **argv )
{
    osg::ArgumentParser arguments(&argc, argv);

   // Make a scene graph consisting of a single Geode, containing
    // a single Geometry, and a single PrimitiveSet.
    osg::ref_ptr< osg::Geode > geode = new osg::Geode;

    osg::ref_ptr< osg::Geometry > geom = new osg::Geometry;
    // Configure the Geometry for use with EXT_draw_arrays:
    // DL off and buffer objects on.
    geom->setUseDisplayList( false );
    geom->setUseVertexBufferObjects( true );
    // OSG has no clue where out vertex shader will place the geometric data,
    // so specify an initial bound to allow proper culling and near/far computation.
    osg::BoundingBox bb( -1., -.1, -1., 49., 1., 49. );
    geom->setInitialBound( bb );
    // Add geometric data and the PrimitiveSet. Specify numInstances as 32*32 or 1024.
    createDAIGeometry( *geom, 32*32 );
    geode->addDrawable( geom.get() );

    // Create a StateSet to render the instanced Geometry.
    osg::ref_ptr< osg::StateSet > ss = createStateSet();
    geode->setStateSet( ss.get() );

    // osgDB::writeNodeFile(*geode, "instanced.osgt");

    osgViewer::Viewer viewer(arguments);
    viewer.setSceneData( geode.get() );
    return viewer.run();
}
高版本
  • main.cpp
#include "pch.h"
#include <osgViewer/Viewer>
#include <osgDB/ReadFile>
#include <osg/Shape>
#include <osg/Shapedrawable>
#include <osg/MatrixTransform>
#include "uniformCallback.h"


osg::Node * createNode()
{
	osg::Geode * geode = new osg::Geode;

	osg::Geometry * gm = new osg::Geometry;
	gm->setUseDisplayList(false);
	gm->setUseVertexBufferObjects(true);

	osg::Vec3Array * vertexArray = new osg::Vec3Array;
	vertexArray->push_back(osg::Vec3(0, 0, 0));
	vertexArray->push_back(osg::Vec3(1, 0, 0));
	vertexArray->push_back(osg::Vec3(1, 0, 1));
	vertexArray->push_back(osg::Vec3(0, 0, 1));
	gm->setVertexArray(vertexArray);

	osg::Vec3Array * normalArray = new osg::Vec3Array;
	normalArray->push_back(osg::Vec3(0, -1, 0));
	gm->setNormalArray(normalArray);
	gm->setNormalBinding(osg::Geometry::BIND_OVERALL);


	osg::Vec2Array* texcoords = new osg::Vec2Array(4);
	(*texcoords)[0].set(0.0f, 0.0f);
	(*texcoords)[1].set(1.0f, 0.0f);
	(*texcoords)[2].set(1.0f, 1.0f);
	(*texcoords)[3].set(0.0f, 1.0f);
	gm->setTexCoordArray(0, texcoords);


	gm->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, vertexArray->size(),3));
	geode->addDrawable(gm);

	osg::StateSet* stateset = gm->getOrCreateStateSet();


	osg::Texture2D * texture0 = new osg::Texture2D;
	texture0->setDataVariance(osg::Object::DYNAMIC); // protect from being optimized away as static state.
	texture0->setImage(osgDB::readImageFile("1.jpg"));
	texture0->setResizeNonPowerOfTwoHint(false);
	stateset->setTextureAttributeAndModes(0, texture0, osg::StateAttribute::ON);


	osg::Texture2D * texture1 = new osg::Texture2D;
	texture1->setDataVariance(osg::Object::DYNAMIC); // protect from being optimized away as static state.
	texture1->setImage(osgDB::readImageFile("2.jpg"));
	texture1->setResizeNonPowerOfTwoHint(false);
	stateset->setTextureAttributeAndModes(1, texture1, osg::StateAttribute::ON);

	gm->setVertexAttribArray(0, vertexArray);
	gm->setVertexAttribBinding(0, osg::Geometry::BIND_PER_VERTEX);

	gm->setVertexAttribArray(1, texcoords);
	gm->setVertexAttribBinding(1, osg::Geometry::BIND_PER_VERTEX);

	return geode;
}
int main()
{
	osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer;
	osg::Group * root = new osg::Group;

	osg::Node * node = createNode();
	root->addChild(node);

	osg::StateSet * ss = node->getOrCreateStateSet();
	osg::Program * program = new osg::Program;
	program->addBindFragDataLocation("VertexPosition", 0);
	program->addBindFragDataLocation("TexCorrd", 1);


	osg::Shader * vS = osgDB::readShaderFile(osg::Shader::VERTEX, "instanced.vert");
	osg::Shader * fS = osgDB::readShaderFile(osg::Shader::FRAGMENT, "instanced.frag");
	program->addShader(vS);
	program->addShader(fS);
	ss->setAttributeAndModes(program, osg::StateAttribute::ON);


	osg::Uniform* MVUniform = new osg::Uniform(osg::Uniform::Type::FLOAT_MAT4, "ModelViewMatrix");

	MVUniform->setUpdateCallback(new MVPCallback(viewer->getCamera()));
	ss->addUniform(MVUniform);

	osg::Uniform* PUniform = new osg::Uniform(osg::Uniform::Type::FLOAT_MAT4, "ProjectionMatrix");

	PUniform->setUpdateCallback(new MVPCallback(viewer->getCamera()));
	ss->addUniform(PUniform);

	osg::Uniform* sample0 = new osg::Uniform("sampler2d_0", 0);
	ss->addUniform(sample0);

	osg::Uniform* sample1 = new osg::Uniform("sampler2d_1", 1);
	ss->addUniform(sample1);

	viewer->setSceneData(root);
	viewer->setUpViewInWindow(35, 35, 1024, 800);


	return viewer->run();
}

  • uniformCallback
#include <osg/Texture2D>
#include<osg/camera>

class MVPCallback : public osg::Uniform::Callback
{

public:
	MVPCallback(osg::Camera * camera) :mCamera(camera) {
	}
	virtual void operator()(osg::Uniform* uniform, osg::NodeVisitor* nv) {
		osg::Matrix modelView = mCamera->getViewMatrix();
		
		osg::Matrix projectM = mCamera->getProjectionMatrix();
		if (uniform->getName() == "ModelViewMatrix")
			uniform->set(modelView);
		else if (uniform->getName() == "ProjectionMatrix")
			uniform->set(projectM);
	}

private:
	osg::Camera * mCamera;
};
  • shader
//顶点着色器
#version 430
layout (location=0) in vec3 VertexPosition;
layout (location=1) in vec2 TexCorrd;

uniform mat4 ModelViewMatrix;
uniform mat4 ProjectionMatrix;
layout (location=0) out vec2 Corrd;

void main()
{
	Corrd = TexCorrd;
	mat4 m4 = mat4(1,0,0,0,  0,1,0,0,  0,0,1,0, 0,0.2*gl_InstanceID,0,1);

	gl_Position = ProjectionMatrix*ModelViewMatrix *m4* vec4(VertexPosition,1.0);
}

//片元着色器
#version 430
layout (location=0) out vec4 FragColor;
in vec2 Corrd;

uniform sampler2D sampler2d_0;
uniform sampler2D sampler2d_1;
void main() {
   vec4 tmpColor = texture(sampler2d_0, Corrd);
   if(Corrd[1] > 0.5 ) 
		   tmpColor = texture(sampler2d_1, Corrd); 
   FragColor = tmpColor ;
}

shader相关

     https://github.com/FreeSouth/osgshader-cookbook.git  杨石兴
     https://github.com/vicrucann/shader-3dcurve.git   Victoria Rudakova


GLSL版本以330为分界线,330及以上使用的是高版本着色器,以下则是低版本着色器。OSG是兼容OpenGL的所以着色器语言既能用OGL低版本也可以用高版本的。如下使用的两个例子

shader加载普通模型[2]

#include <iostream>
#include <Windows.h>

#include <osgViewer/Viewer>
#include <osgDB/ReadFile>

using namespace std;

//设置纹理着色
static void ColorShader(osg::ref_ptr<osg::Node> node)
{
    const char * vertexShader = {
        "void main(void ){
"
        "   gl_FrontColor = gl_Color;
"
        "   gl_Position = gl_ModelViewProjectionMatrix*gl_Vertex;
"
        "}
"
    };

    const char * fragShader = {
        "void main(void){
"
        "   gl_FragColor = gl_Color;
"
        "}
"
    };

    osg::StateSet * ss = node->getOrCreateStateSet();
    osg::ref_ptr<osg::Program> program = new  osg::Program();
    program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragShader));
    program->addShader(new osg::Shader(osg::Shader::VERTEX, vertexShader));
    ss->setAttributeAndModes(program, osg::StateAttribute::ON);
}

int main()
{
    osg::ref_ptr<osg::Group> root= new osg::Group();

    string osgPath = "D:/Work/OSGBuild/OpenSceneGraph-Data/glider.osg";
    osg::Node * node = osgDB::readNodeFile(osgPath);
    root->addChild(node);
    
    ColorShader(node);

    osgViewer::Viewer viewer;
    viewer.setSceneData(root);
    viewer.setUpViewInWindow(100, 100, 800, 600);
    return viewer.run();
}


static void TextureShader(osg::ref_ptr<osg::Node> node)
{
    const char * vertexShader = {
        "void main(void ){
"
        "   gl_TexCoord[0] = gl_MultiTexCoord0;
"
        "   gl_Position = gl_ModelViewProjectionMatrix*gl_Vertex;
"
        "}
"
    };

    const char * fragShader = {
        "uniform sampler2D baseTexture;
"
        "void main(void){
"
        "   vec2 coord = gl_TexCoord[0].xy;
"
        "   vec4 C = texture2D(baseTexture, coord)
;"
        "   gl_FragColor = C;
"
        "}
"
    };

    osg::StateSet * ss = node->getOrCreateStateSet();
    osg::ref_ptr<osg::Program> program = new  osg::Program();
    program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragShader));
    program->addShader(new osg::Shader(osg::Shader::VERTEX, vertexShader));
    ss->setAttributeAndModes(program, osg::StateAttribute::ON);
}

int main()
{
    osg::ref_ptr<osg::Group> root= new osg::Group();

    string osgPath = "D:/Data/scene/Dayanta_OSGB/Data/MultiFoderReader.osgb";
    osg::Node * node = osgDB::readNodeFile(osgPath);
    root->addChild(node);
    
    TextureShader(node);

    osgViewer::Viewer viewer;
    viewer.setSceneData(root);
    viewer.setUpViewInWindow(100, 100, 800, 600);
    return viewer.run();
}

osg加载高版本的shader


#include <osg/shader>
#include <osg/Node>
#include <osgDB/ReadFile>
#include <osgDB/fileutils>
#include <osg/Geometry>
#include <osgViewer/viewer>
#include <osgViewer/ViewerEventHandlers>
#include <osgGA/StateSetManipulator>

//#include "GLExtSupportTest.h"

static char * vertexShader = {
		"#version 460 \n"
		"layout (location=0) in vec3 VertexPosition;\n"
		"layout (location=1) in vec4 VertexColor;\n"
		"out vec4 Color;\n"
	    "uniform mat4 MVP;"
		"void main()\n"
		"{\n"
			"   Color = VertexColor;\n"
			"   gl_Position = MVP * vec4(VertexPosition,1.0);\n"
	    "}\n"
};

static char * fragShader = {
		"#version 460 \n"
		"in vec4 Color;\n"
		"layout (location=0) out vec4 FragColor;\n"
		"void main() {\n"
		"   FragColor = Color;//vec4(0.5,0.5,0.5,0.4);\n"
		"}\n"
};
osg::Node *  CreateNode()
{
	osg::Geode * geode = new osg::Geode;
	osg::Geometry* polyGeom = new osg::Geometry();
	osg::Vec3Array* vertices = new osg::Vec3Array();
	vertices->push_back(osg::Vec3(-5, 0, 0));
	vertices->push_back(osg::Vec3(5, 0, 0));
	vertices->push_back(osg::Vec3(0, 0, 5));
	//polyGeom->setVertexArray(vertices);


	osg::ref_ptr<osg::Vec4Array> colorsArray = new osg::Vec4Array;
	colorsArray->push_back(osg::Vec4(1.0f, 0.0f, 0.0f, 1.0f));
	colorsArray->push_back(osg::Vec4(0.0f, 0.0f, 1.0f, 1.0f));
	colorsArray->push_back(osg::Vec4(0.0f, 1.0f, 0.0f, 1.0f));
	//  polyGeom->setColorArray(colorsArray.get());
		//polyGeom->setColorBinding(osg::Geometry::BIND_PER_VERTEX);

	polyGeom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES, 0, 3));

	/*
	The osg::Geometry class uses the setVertexAttribArray() and
	setVertexAttribBinding() methods to bind vertex attributes to shaders. They should
	be provided per vertex. GLSL's built-in vertex attributes include the gl_Position, gl_
	Normal, and gl_MultiTexCoord* variables. However, you may still specify your own
	vertex attributes, such as tangents or vertex weights.
	Try declaring an attribute in the vertex shader and make use of the osg::Geometry's vertex
	attribute arrays. Another important task that you need to perform is to bind the external
	attribute array and the GLSL attribute, with the help of the addBindAttribLocation()
	method of osg::Program. It has a name and an index parameter, the first of which
	indicates the attribute name in the shader source code, and the second should correspond
	to the input index value of setVertexAttribArray().
	*/
	polyGeom->setVertexAttribArray(0, vertices);
	polyGeom->setVertexAttribBinding(0, osg::Geometry::BIND_PER_VERTEX);
	polyGeom->setVertexAttribArray(1, colorsArray.get());
	polyGeom->setVertexAttribBinding(1, osg::Geometry::BIND_PER_VERTEX);

	geode->addDrawable(polyGeom);
	return geode;
}

class MVPCallback : public osg::Uniform::Callback
{
public:
	MVPCallback(osg::Camera * camera) :mCamera(camera) {
	}
	virtual void operator()(osg::Uniform* uniform, osg::NodeVisitor* nv) {
		osg::Matrix modelView = mCamera->getViewMatrix();
		osg::Matrix projectM = mCamera->getProjectionMatrix();
		uniform->set(modelView * projectM);
	}

private:
	osg::Camera * mCamera;
};
int main(int argc, char *argv[]) {

	osgViewer::Viewer viewer;

	osg::Group * root = new osg::Group;
	osg::ref_ptr<osg::Node>node = CreateNode();

	osg::StateSet * ss = node->getOrCreateStateSet();
	osg::Program * program = new osg::Program;
	program->addBindFragDataLocation("VertexPosition", 0);
	program->addBindFragDataLocation("VertexColor", 1);

	osg::Shader * vS = new osg::Shader(osg::Shader::FRAGMENT, fragShader);
	osg::Shader * fS = new osg::Shader(osg::Shader::VERTEX, vertexShader);
	osg::Uniform* MVPUniform = new osg::Uniform(osg::Uniform::Type::FLOAT_MAT4, "MVP");
	MVPUniform->setUpdateCallback(new MVPCallback(viewer.getCamera()));
	ss->addUniform(MVPUniform);//对应的Program和Uniform要加到同一个Node下的StateSet中
	program->addShader(vS);
	program->addShader(fS);
	ss->setAttributeAndModes(program, osg::StateAttribute::ON);
	//此处回调只调用一次,用于判断当前系统对OGL的扩展支持情况等

	root->addChild(node);
	viewer.setSceneData(root);
	//viewer.setRealizeOperation(new GLExtSupportTest());
	viewer.setUpViewInWindow(100, 100, 800, 600);

	viewer.addEventHandler(new osgViewer::StatsHandler);

	viewer.addEventHandler(new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()));
	viewer.addEventHandler(new osgViewer::ThreadingHandler);
	viewer.addEventHandler(new osgViewer::WindowSizeHandler);
	viewer.addEventHandler(new osgViewer::RecordCameraPathHandler);
	viewer.addEventHandler(new osgViewer::LODScaleHandler);
	viewer.addEventHandler(new osgViewer::ScreenCaptureHandler);
	viewer.run();

	return 0;
}


osg高版本的shader加载纹理[3]

#include <osgViewer/Viewer>
#include <osgDB/ReadFile>
#include <osg/Shape>
#include <osg/Shapedrawable>
#include <osg/MatrixTransform>
#include <osg/Texture2D>

static char * vertexShader= {  
		"#version 430 \n"  
		"layout (location=0) in vec3 VertexPosition;\n"
		"layout (location=1) in vec2 TexCorrd;\n"	
		"uniform mat4 MVP;"	
		"out vec2 Corrd;\n"  
		"void main()\n"  
		"{\n"
		"   Corrd = TexCorrd;"
		"   gl_Position = MVP * vec4(VertexPosition,1.0);\n"  
		"}\n"  
};

static char * fragShader ={  
		"#version 430 \n" 
		"uniform sampler2D sampler2d_0;\n"
		"uniform sampler2D sampler2d_1;\n"
		"layout (location=0) out vec4 FragColor;\n"  
		"in vec2 Corrd;\n"  
		"void main() {\n"
		"   vec4 tmpColor = texture(sampler2d_0, Corrd);"
		"   if(Corrd[1] > 0.5 ) \n"
		"		   tmpColor = texture(sampler2d_1, Corrd); \n"
		"   FragColor = tmpColor ;\n"  
		"}\n"
};

class MVPCallback: public osg::Uniform::Callback  
{
public:  
		MVPCallback(osg::Camera * camera):mCamera(camera){  
		}  
		virtual void operator()( osg::Uniform* uniform, osg::NodeVisitor* nv){  
				osg::Matrix modelView = mCamera->getViewMatrix();  
				osg::Matrix projectM = mCamera->getProjectionMatrix();  
				uniform->set(modelView * projectM);  
		}  

private:  
		osg::Camera * mCamera;  
}; 

osg::Node * createNode()
{
		osg::Geode * geode = new osg::Geode;

		osg::Geometry * gm = new osg::Geometry;

		osg::Vec3Array * vertexArray = new osg::Vec3Array;
		vertexArray->push_back(osg::Vec3(0,0,0));
		vertexArray->push_back(osg::Vec3(1,0,0));
		vertexArray->push_back(osg::Vec3(1,0,1));
		vertexArray->push_back(osg::Vec3(0,0,1));
		gm->setVertexArray(vertexArray);

		osg::Vec3Array * normalArray = new osg::Vec3Array;
		normalArray->push_back(osg::Vec3(0,-1,0));
		gm->setNormalArray(normalArray);
		gm->setNormalBinding(osg::Geometry::BIND_OVERALL);


		osg::Vec2Array* texcoords = new osg::Vec2Array(4);
		(*texcoords)[0].set(0.0f,0.0f);
		(*texcoords)[1].set(1.0f,0.0f);
		(*texcoords)[2].set(1.0f,1.0f);
		(*texcoords)[3].set(0.0f,1.0f);
		gm->setTexCoordArray(0,texcoords);


		gm->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,vertexArray->size()));
		geode->addDrawable(gm);

		osg::StateSet* stateset = gm->getOrCreateStateSet();


		osg::Texture2D * texture0 = new osg::Texture2D;
		texture0->setDataVariance(osg::Object::DYNAMIC); // protect from being optimized away as static state.
		texture0->setImage(osgDB::readImageFile("Images/forestWall.png"));	
		stateset->setTextureAttributeAndModes(0,texture0,osg::StateAttribute::ON);


		osg::Texture2D * texture1 = new osg::Texture2D;
		texture1->setDataVariance(osg::Object::DYNAMIC); // protect from being optimized away as static state.
		texture1->setImage(osgDB::readImageFile("Images/purpleFlowers.png"));
		stateset->setTextureAttributeAndModes(1,texture1,osg::StateAttribute::ON);
		
		gm->setVertexAttribArray(0,vertexArray);  
		gm->setVertexAttribBinding(0, osg::Geometry::BIND_PER_VERTEX);

		gm->setVertexAttribArray(1,texcoords);       
		gm->setVertexAttribBinding(1, osg::Geometry::BIND_PER_VERTEX);
	
		return geode;		
}
int main()
{
		  osg::ref_ptr<osgViewer::Viewer> viewer  = new osgViewer::Viewer;
		 

		osg::Group * root = new osg::Group;

		osg::Node * node = createNode();
		root->addChild(node);	

		osg::StateSet * ss = node->getOrCreateStateSet();
		osg::Program * program = new osg::Program;
		program->addBindFragDataLocation("VertexPosition",0);
		program->addBindFragDataLocation("TexCorrd",1);

		osg::Shader * vS = new osg::Shader(osg::Shader::FRAGMENT,fragShader);
		osg::Shader * fS = new osg::Shader(osg::Shader::VERTEX,vertexShader);
		program->addShader(vS);  
		program->addShader(fS);  
		ss->setAttributeAndModes(program,osg::StateAttribute::ON);


		osg::Uniform* MVPUniform = new osg::Uniform( "MVP",osg::Matrix());
		MVPUniform->setUpdateCallback(new MVPCallback(viewer->getCamera()));
		ss->addUniform(MVPUniform);
		osg::Uniform* sample0 = new osg::Uniform("sampler2d_0",0);
		ss->addUniform(sample0);

		osg::Uniform* sample1 = new osg::Uniform("sampler2d_1",1);
		ss->addUniform(sample1);

		viewer->setSceneData(root);
		viewer->setUpViewInWindow(35, 35, 1024, 800);


		return viewer->run();
}

加载倾斜摄影[4]

倾斜摄影技术是国际摄影测量领域近十几年发展起来的一项技术,该技术通过从一个垂直、四个倾斜、五个不同的视角同步采集影像,获取到丰富的建筑物顶面及侧视的高分辨率纹理。它不仅能够真实地反映地物情况,高精度地获取物方纹理信息,还可通过先进的定位、融合、建模等技术,生成真实的三维城市模型。该技术在欧美等发达国家已经广泛应用于应急指挥、国土安全、城市管理、房产税收等行业。

倾斜摄影

#include <iostream>
#include <string>
#include <QDir>
#include <osgViewer/Viewer>
#include <osgDB/ReadFile>
#include <iostream>
#include <string>
#include <QDir>
#include <osgViewer/Viewer>
#include <osgDB/ReadFile>
#include <osgDB/WriteFile>

using namespace std;

//查找目录下所有的文件夹
static void findDir(string dir, vector<string>& subDirs)
{
	//
	subDirs.clear();
	QDir fromDir(QString::fromLocal8Bit(dir.c_str()));
	QStringList filters;
	//
	QFileInfoList fileInfoList = fromDir.entryInfoList(filters, QDir::AllDirs | QDir::Files);
	foreach(QFileInfo fileInfo, fileInfoList)
	{
		if (fileInfo.fileName() == "." || fileInfo.fileName() == "..")
		{
			continue;
		}
		if (fileInfo.isDir())
		{
			QByteArray dir = fileInfo.filePath().toLocal8Bit();
			subDirs.push_back(dir.data());
		}
	}
}
//得到文件路径的文件名   C:\\b\\a(.txt) -> a
static std::string DirOrPathGetName(std::string filePath)
{
	size_t m = filePath.find_last_of('/');
	if (m == string::npos)
	{
		return filePath;
	}
	size_t p = filePath.find_last_of('.');
	if (p != string::npos && p > m)				//没有点号或者
	{
		filePath.erase(p);
	}
	std::string dirPath = filePath;
	dirPath.erase(0, m + 1);
	return dirPath;
}
void createObliqueIndexes(std::string fileDir)
{
	string dataDir = fileDir + "\\Data";
	osg::ref_ptr<osg::Group> group = new osg::Group();
	vector<string> subDirs;
	findDir(dataDir, subDirs);
	for (size_t i = 0; i < subDirs.size(); i++)
	{
		string name = DirOrPathGetName(subDirs[i]);
		string path = subDirs[i] + "\\" + name + ".osgb";
		osg::ref_ptr<osg::Node> node = osgDB::readNodeFile(path);
		osg::ref_ptr<osg::PagedLOD> lod = new osg::PagedLOD();
		auto bs = node->getBound();
		auto c = bs.center();
		auto r = bs.radius();
		lod->setCenter(c);
		lod->setRadius(r);
		lod->setRangeMode(osg::LOD::RangeMode::PIXEL_SIZE_ON_SCREEN);
		osg::ref_ptr<osg::Geode> geode = new osg::Geode;
		geode->getOrCreateStateSet();
		lod->addChild(geode.get());
		std::string relativeFilePath = "\\Data\\" + name + "\\" + name + ".osgb";  //相对路径
		lod->setFileName(0, "");
		lod->setFileName(1, relativeFilePath);
		lod->setRange(0, 0, 1.0);	
		lod->setRange(1, 1.0, FLT_MAX);
		lod->setDatabasePath("");
		group->addChild(lod);
	}
	std::string outputLodFile = fileDir + "/Data.osgb";
	osgDB::writeNodeFile(*group, outputLodFile);
}



int main(int argc, char *argv[])
{
	if ( argc == 0)
	{
		string fileDir = QDir::currentPath().toStdString();
		std::string outputLodFile = fileDir + "\\Data.osgb";
		createObliqueIndexes(fileDir);
	}
	else if(argc =1)
	{
		string fileDir = argv[1];
		std::string outputLodFile = fileDir + "\\Data.osgb";
		createObliqueIndexes(fileDir);
	}
	else
	{

	}
	return 0;

}


遍历目录

#include <iostream>
#include <string>
#include <windows.h>

int find_path(const char *);

char save_path[MAX_PATH]={ 0 };//结果输出路径;    
char szPath[MAX_PATH]={ 0 };
char result[MAX_PATH]={ 0 };
FILE* pf_path_file;

int find_path_save_file(const char* lp_path, const char* out_file_name)
{
    pf_path_file = fopen(out_file_name, "w");
    int cnt = find_path(lp_path);
    fclose(pf_path_file);
    return cnt;
}
void str_tok(char *str) //分离文件目录
{
    char *p=NULL;
    char delims[]="\\";
    p=strtok(str, delims );
    while(p!=NULL)
    {
        strcpy(result,p);
        p=strtok(NULL,delims );      
    };
}
void str_extension(char *str) //分离文件扩展名;
{
    char *p=NULL;
    char delims[]=".";
    p=strtok(str, delims );
    while(p!=NULL)
    {
        strcpy(result,p);
        p=strtok(NULL,delims );      
    };
}

int find_path(const char* lp_path)// 遍历搜索目录
{
    static int cnt = 0;
    HANDLE hFile; 

    WIN32_FIND_DATAA wfd; //数据结构;
    char sz_path[MAX_PATH] = { 0 };
    char buf[MAX_PATH * 2] = { 0 };
    char fileName[MAX_PATH]= { 0 };
    char temp[MAX_PATH]={ 0 };//临时数组;
    char parseFileName[MAX_PATH]={ 0 };
    
    strcpy(sz_path, lp_path);
    strcat(sz_path, "\\*.*"); //匹配任何文件包括文件夹目录;
    hFile = FindFirstFile(sz_path, &wfd); 

    if (hFile != INVALID_HANDLE_VALUE)
     {
        do
        {  
            if(wfd.cFileName[0] == '.') //如果是.或..则过滤; 
                continue; 
            else if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) //如果是目录则递归;
            { 
                strcpy(sz_path, lp_path);
                strcat(sz_path,"\\");
                strcat(sz_path, wfd.cFileName);    //拼接目录全路径名;
                
                find_path(sz_path);               //调用递归;
            }
            else 
            {                                                            
                strcpy(parseFileName,wfd.cFileName);
                str_extension(parseFileName);//分离文件的扩展名;

                if(!(strcmp(result,"pgm"))) //过滤规则,只接受.pgm文件,这里可以修改规则;
                {
                    strcpy(fileName,lp_path);//合成文件名全路径
                    strcat(fileName,"\\");
                    strcat(fileName,wfd.cFileName);/* 例:"c:\dir\test\1.pgm" */
                    
                    std::cout<<fileName<<std::endl;
                    
                    strcpy(temp,lp_path);                            
                    str_tok(temp); //获取目录
                                        
                    sprintf(buf,"%s;%s",fileName,result);                
                    fprintf(pf_path_file, "%s\n",buf);    
                    ++cnt;
                }                                                    
            }
        }while(FindNextFile(hFile, &wfd)); 
    }
    return cnt;
}
int main()
{
    GetCurrentDirectory(MAX_PATH, szPath); //当前目录

    strcpy(save_path,szPath);//结果result.txt放在当前目录中;
    strcat(save_path,"\\result.txt");
    
    find_path_save_file(szPath,save_path);    
    return 0;
}


BigPic = cell(m, n);
for i = 1 : m * n
    BigPic{i} = imread(strcat(file_path,'\',files(StartID + i).name));
end
BigPic = cell2mat(BigPic);