这个的确时非常基础的入门书籍,而且讲的非常清楚。我来总结一下对我自己的知识备忘录。

你需要:OSG源码、 OpenThreads(以获得多线程支持)、第三方支持(libTIFF、libPNG等)
一些简单的命令:
osgviewer -help
osgviewer --clear-color 1.0,1.0,1.0,1.0 cow.osg (设置背景颜色)
osgviewer --samples 16 cow.osg (启用16子像素的多重采样)
osgviewer --image osg256.png  (读取一张图片)
osgviewer --help-all

一些显示模式的查看:
Polygon mode: 反复按下w 可以切换线框模式、点模式、填充多边形渲染模式
Texture mapping: 反复按下t 切换显示/不显示模式的贴图
Lighting: 反复按下L 切换禁止/允许光照
背面拣除:反复按下b 触发/禁止背面拣除
全屏模式:反复按下f

性能显示:
反复按s  
(反映了场景图形的渲染方式)每一帧都有这三个步骤:P34
1. 更新(update): 更新的场景图形,比如飞行的飞机。更新操作由节点对应的回调函数完成。
2. 拣选:检查场景中所有节点的包围体,按是否在适口内、透明与不透明来排序。
3. 绘制:将拣选过程中的几何体列表,调用底层API来实现几何体渲染。

如果要在程序运行时实现允许和禁止各种条件下Switch 开关的子节点显示,你需要使用节点更新回调(osg::NodeCallback)
或者节点访问(osg::NodeVisitor)来控制场景图形的节点和各帧渲染。

一种简华性能调试过程的方法(可观察到所消耗的时间) P27
提高性能需要注意的地方: P33
1. 节点结构
2. 场景拣选
3. 细节层次(LOD)
4. 透明(要实现透明或半透明几何体正确和高效渲染,需要首先渲染所有不透明几何体,在渲染透明几何体。且透明几何体必须按照深度排序
              按照“从后到前”的顺序渲染)
5. 状态改动最少化
6. 模型读取

OSG_NOTIFY_LEVEL : NOTICE   std:cout (显示osg的各种调试信息)
交运算:
关于相交,之前就做过类似的东西,但是这里有一些类当时没有用到
InterSector 、LineSegmentIntersector、PolytopeIntersector、PlaneIntersector、IntersectionVisitor
优化类:Optimizer、Statistics(返回一个场景图形中节点的总数和类型)
模型加载:
有时候从文件读取各部分数据库信息时,需要在不干扰当前渲染的前提下以后台线程的方式进行。osgDB::DatabasePager提供这样的功能。
其他拥有强大功能的NodeKits
osgFX库、osgParticle库、osgSim库、osgText库、osgTerrain库、osgShadow库

常用的OSG工具程序  P49
osgarchive:向.osga中添加新的文件,实现包的分解和列表
osgconv:转换文件格式。尤其游泳的是可以将任意文件格式转换为经过优化的ive格式
osgdem:将高程图等高度数据及图像数据转换为分页的地形数据库
osgversion:将当前OSG版本以及一些记录了OSG源代码改动情况和贡献者信息送入std::cout
osgviewer

模型格式:.osg :通常较大且载入较为缓慢

2.1内存管理
所有都继承自osg::Referenced类
 ref_ptr<>  :程序只需要简单地释放指向根节点的指针   
                   所以将指针保存在ref_ptr<>中要好过使用标准c++指针变量。继承自Referenced的对象不可以直接释放空间,只能通过将计数器
                   减少到0的方式来释放内存。
                   OSG场景图形(包括状态、法线、顶点数组等)都可以进行内存引用计数。
                   这样也是可以的:
                   osg::Geode* geode = new osg::Geode;
                   grp->addChild(geode); ///父节点grp内部的ref_ptr<>已经可以负责管理新的osg::Geode所占用的内存了。

osg::Vec3 、osg::Vec3Array:保存顶点和法线数据
osg::Vec4、osg::Vec4Array :保存颜色数据
osg::Vec2、osg::Vec2Array:2D纹理坐标

osg::Node::ParentList是一个保存标准c++指针的std::vector 虽然一个Node保存了所有父节点的地址,但是Node类并不需要使用OSG内存管理
                                 机制来引用其父节点。当父节点被释放时,父节点会自动从子节点的相应列表中删除自己。
一个节点通常只有一个父节点(getNumParents()返回0) ,假如一个节点有多个父节点,用户可能希望以此来多次渲染同一幅子图,而不必重复
创建这幅子图的拷贝。这个子节点不会被释放,直到所有父节点放弃引用它为止。

//******************************************基础节点********************************************
osg::Geode
osg::Node
osg::Group
osg::Geometry
osg::MatrixTransform
osg::PositionAttitudeTransform       osg::Transform允许用户指定参考系:osg::TRansform::RELATIVE_RF  osg::Transform::ABSOLUTE_RF

OSG中的Matrix采用左乘:例子:使Vec3变量v沿着新的原点矩阵T,按照矩阵R执行旋转变换代码:
                                           osg::Matrix T;
                                           T.makeTraslate(x,y,z);  osg::Matrix R;  R.makeRotate(angle,axis); Vec3 vPime = v*R*T;

左乘RST
osg::ref_ptr<osg::MatrixTransfrom> mt = new osg::MatrixTransform;
osg::Matrix m;
m.setTranslate(x,y,z);
mt->setMatrix(m);

osg::ref_ptr<osg::MatrixTransfrom> rot = new osg::MatrixTransform;
rot->setMatrix(osg::Matrix::rotate(osg::DegreesToRadians(45.0),1,0,0)*osg::Matrix::scale(0.5,0.5,0.5),osg::Matrix::translate(4,0,-2));
rot->addChild(osgcoll.get());

osg::PositionAttitudeTransform  四元数——围绕axis 旋转thea弧度 Float thea(M_PI *0.5f); osg::Vec3 axis(0.7.7f,0.707f,0.f);  osg::Quat q0(thea,axis);
适用yaw(绕Z轴)、pitch(绕X轴)、roll(绕Y轴)角度创建一个四元数 
osg::Vec3 yawAxis(0.f,0.f,1.f);  osg::Vec3 pitchAxis(1.f,0.f,0.f)  osg::Vec3 rollAxis(0.f,1.f,0.f);
osg::Quat q1(yawRad, yawAxis, pitchRad, pitchAxis, rollRad, rollAxis);

osg::LOD 细节层次   (最大值与最小值)
lod->addChild( geode.get(), 0.f, 1000.f );
缺省条件下,LOD 计算视点到物体包络体中心点的距离。如果这样并不符合渲染要求,那么用户可以指定一个自定义的中心点:例如:
osg::ref_ptr<osg::LOD> lod = new osg::LOD;
// 使用用户定义的中心点来计算距离。
lod->setCenterMode( osg::LOD::USER_DEFINED_CENTER );
// 设置自定义中心点的X 坐标10,Y 坐标100。
Lod->setCenter( osg::Vec3( 10.f, 100.f, 0.f ) );
如果要重新设置距离计算的缺省特性为物体的包络球, 可以调用osg::LOD::setCenterMode(osg::LOD::USE_BOUNDING_SPHERE_CENTER )。
缺省条件下,LOD 使用距离的最大值和最小值来表示范围,但是用户也可以要求LOD 使用像素大小来设置范围值,此时如果子节点在屏幕上的像素大小
符合其有效范围,LOD 将显示这个子节点。要设置LOD 节点的有效范围模式,可以调用osg::LOD::setRangeMode(),并设置参数为PIXEL_SIZE_ON_SCREEN,
或者DISTANCE_FROM_EYE_POINT

osg::Switch (开关节点)
典型用法有:根据当前渲染的负荷有选择地渲染子图形以实现渲染性能的均衡,或者在游戏的界面和层级之间有选择地切换
switch->addChild( group1.get(), false );  //不渲染此节点
switch->setNewChildDefaultValue( false );  //改变新加入节点的缺省值
上面的代码段只是理想化的情况。如果要在程序运行时实现允许和禁止各种条件下Switch 开关的子节点显示,你需要使用节点更新回调(osg::NodeCallback)
或者节点访问(osg::NodeVisitor)来控制场景图形的节点和各帧渲染
****************************************************************************************************************************

*********************************************鼠标操作***************************************************
1.  接收鼠标事件。osgGA 库提供了允许程序接收鼠标事件的事件类,它具备平台无关的特性。
2.  判断场景图形的哪个部分被鼠标光标覆盖。osgUtil 库提供了一种相交集(intersection)类,可以在鼠标XY 坐标的周围创建包围盒,并判断包围盒与场景图形的相交情况。osgUtil 将按照由前至后的顺序返回与包围
    盒相交的节点列表。 
    在handle()中,检查GUIEventAdapter 参数传递的事件类型,并针对需要的事件类型执行相应的操作。方法返回true 时将阻止其它事件处理器继续接收事件消息。 P140 这个例子概括的蛮好的
    OSG 使用一种名为多胞体(polytope)的金字塔形包围盒代替射线,以克服上述的问题。这种金字塔形的顶峰位于视点,其中心轴直接穿过鼠标(光标)的位置。它距离视点的宽度是由视场和程序控制的宽度参数决定的。
*********************************************************************************************************

*********************************************渲染状态***************************************************
1. 用户需要尽量使关联到场景图形的StateSet 最少化。StateSet 越少,内存的占用也越少,OSG 在一次场景图形遍历中所耗费的工作量也越少。StateSet 类派
生自Referenced,以实现更好的数据共享。也就是说,共享同一个StateSet 的Node或Drawable 类不需要额外的代码来清理其内存空间。
2. OSG 将渲染状态分成两个部分,渲染属性(attribute)和渲染模式(mode)。简单来说,渲染模式是指渲染的某个功能,而渲染属性是
  这个功能的控制变量和参数。
如果要设置渲染状态的值,用户程序需要执行以下几步操作:
a. 为将要设置状态的Node 或Drawable 对象提供一个StateSet 实例。//osg::StateSet* state = obj->getOrCreateStateSet();
b. 在StateSet 实例中设置状态的渲染模式和渲染属性。

Attribute:  osg::StateSet* state = geom->getOrCreateStateSet();osg::CullFace* cf = new osg::CullFace( osg::CullFace::BACK );state->setAttribute( cf );
             当应用程序将CullFace 属性关联到一个StateSet 时,只是记录了用户的请求,而不是直接向OpenGL 发送命令。在绘图遍历(draw traversal)中,OSG 将跟踪状态数据的变
             化,并在必要的时候发送命令glCullFace()到OpenGL。
Mode:   osg::StateSet* state = geom->getOrCreateStateSet();  state->setMode( GL_FOG, osg::StateAttribute::ON );
Attribute&Mode:  OSG 提供了一个简单的可以同时设置属性和模式的单一函数接口. 下面的代码段将关联Blend 融合检验的属性,同时许可颜色融合模式。
                      osg::BlendFunc* bf = new osg::BlendFunc();   state->setAttributeAndMode( bf );

状态继承特性: 当你设置节点的渲染状态时,这个状态将被赋予当前的节点及其子节点。如果子节点对同一个渲染状态设置了不同的属性参数,那么新的子节点状态参数将会覆盖原有的。
当然也可以进行设置!!!!! osg::StateAttribute::OVERRIDE(所有子节点自己的更改都无效) 、osg::StateAttribute::PROTECTED(不会受父节点影响)、osg::StateAttribute::INHERIT(强制子节
                                              点继承父节点状态,其效果是子节点的渲染状态被解除,而使用父节点的装填替代)
       例子:强制用线框模式渲染场景图形  osg::StateSet* state = root->getOrCreateStateSet();  osg::PolygonMode* pm = new osg::PolygonMode)  osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE );
                                                             state->setAttributeAndModes( pm,osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE );

这里面还有一个例子,这个例子将同一个Geode渲染了4次,它使用四个MatrixTransform节点来放置这个Geode,每个MatrixTransform节点都有自己的StateSet. P86
    其实这里面很好理解为什么MatrixTransfrom要被root添加进去,实际上它也是一个节点。作为Geode的父节点而已。

******************纹理映射
用户的代码需要遵循以下的步骤:
a. 指定用户几何体的纹理坐标。当你指定了纹理坐标之后,还要指定相应的纹理单元,OSG 使用纹理单元的值来实现多重纹理。
b. 创建纹理属性对象并保存纹理图形数据。
c. 为StateSet 设置合适的纹理属性和模式。
1. 纹理坐标
osg::ref_ptr<osg::Geometry> geom = new osg::Geometry;  osg::ref_ptr<osg::Vec2Array> tc = new osg::Vec2Array;//创建一个Vec2Array 对象以保存纹理单元0 的纹理坐标
geom->setTexCoordArray( 0, tc.get() ); tc->push_back( osg::Vec2( 0.f, 0.f ) ); tc->push_back( osg::Vec2( 1.f, 0.f ) );tc->push_back( osg::Vec2( 1.f, 1.f ) );tc->push_back( osg::Vec2( 0.f, 1.f ) );
osg::Geometry::setTexCoordArray()的第一个输入参数是纹理单元号,第二个
参数是纹理坐标数组。用户不需要使用类同osg::Geometry::setTexCoordBinding()
的函数输入点来绑定纹理数据。纹理坐标总是绑定到每个顶点的。
2. 基本2D纹理映射  osg::Image  osg::Texture2D
3. 其他
textureAttribute:  纹理状态,参数一是纹理单元,参数二有6种:sg::Texture1D,osg::Texture2D,osg::Texture3D,osg::TextureCubeMap、osg::TextureRectangle
                           还有osg::TexGen用于纹理坐标的生成
textureMode:  参数一是纹理单元、参数二有:GL_TEXTURE_1D,GL_TEXTURE_2D,GL_TEXTURE_3D,GL_TEXTURE_CUBE_MAP,GL_TEXTURE_RECTANGLE,GL_TEXTURE_GEN_Q,GL_TEXTURE_GEN_R,GL_TEXTURE_GEN_S,以
                        及GL_TEXTURE_GEN_T。
setTextureAttributesAndModes()

********************光照
光源会创建着色效果,但是并不创建阴影——osgShadow 可以用来创建阴影。
用户需要遵循下面的步骤:
a.  指定几何体法线。
b.  允许光照并设置光照状态。
c.  指定光源属性并关联到场景图形。
d.  指定表面材质属性。

1. 法线数据必须单位化以得到正确的结果。缩放会导致光照结果过于明亮或过于暗淡。解决方法是允许法线的重缩放模式
    osg::StateSet* state = geode->setOrCreateStateSet(); state->setMode( GL_RESCALE_NORMAL, osg::StateAttribute::ON );
    如果场景中的放缩变换是非均匀的,那么你可以允许法线归一化模式  osg::StateSet* state = geode->setOrCreateStateSet(); 
    state->setMode( GL_NORMALIZE, osg::StateAttribute::ON );  但归一化模式会耗费大量时间,编程时要避免。
2. 设置光照状态的2种方法
    a. osg::StateSet* state = root->getOrCreateStateSet(); state->setMode( GL_LIGHTING, osg::StateAttribute::ON ); state->setMode( GL_LIGHT0, osg::StateAttribute::ON );
        state->setMode( GL_LIGHT1, osg::StateAttribute::ON );  //允许光照,并为根节点允许两个光源
    b. osg::ref_ptr<osg::Light> light = new osg::Light;  light->setLightNum( 2 );
    osg::LightSource    osg::Light  OSG 程序开发师往往将LightSource 关联为MatrixTransform 的子节点,以控制灯光的位置
    ls->setReferenceFrame( osg::LightSource::ABSOLUTE_RF ); //忽略LightSource 的当前变换,而是把灯光的位置作为一个绝对值来看待
3. 材质属性
   用户首先要创建一个Material对象,设置颜色和其它参数,然后关联到场景图形的StateSet 中。
   例子:为一个几何图元的正面设置散射颜色、镜面反射颜色和镜面指数。
   osg::StateSet* state = node->getOrCreateStateSet();   osg::ref_ptr<osg::Material> mat = new osg::Material;  mat->setDiffuse( osg::Material::FRONT,
   osg::Vec4( .2f, .9f, .9f, 1.f ) );  mat->setSpecular( osg::Material::FRONT,osg::Vec4( 1.f, 1.f, 1.f, 1.f ) );  mat->setShininess( osg::Material::FRONT, 96.f );  state->setAttribute( mat.get() );
   此处镜面指数的值必须在1.0 到128.0 至间,除非用户指定了拓宽这一范围的方法
   直接设置材质属性可能会过于耗费资源。而一种名为颜色跟踪材质(color material)的特性,可以允许用户程序通过改变当
    前颜色的方法,自动改变某一特定的材质属性。osg::ref_ptr<osg::Material> mat = new osg::Material;  mat->setColorMode( osg::Material::AMBIENT_AND_DIFFUSE );  有一下几个选项:AMBIENT,DIFFUSE,SPECULAR,EMISSION,
                                                                       AMBIENT_AND_DIFFUSE 以及OFF。缺省OFF
   注意,根据颜色跟踪模式的取值不同,Material 类会自动允许或禁止GL_COLOR_MATERIAL。因此用户程序不需要调用setAttributeAndModes()来允许或禁止相关的模式值。
//*******************************************************************************************************************

//**********************************I/O************************************
osgDB::Registry::instance()->getDataFilePathList().push_back( newpath );  //添加指定的数据目录到数据文件路径表
如果因为某些原因OSG 不能写入/读取文件,上述函数将返回false。用户可以将OSG_NOTIFY_LEVEL 设置为WARN,并再次运行代码以观察操作失败的输出信息.
*******关于插件的搜索和注册
osgDB::Registry的构造函数包括了特定的代码来实现这类插件。Registry 类维护了一个扩展名的化名映射表来对应不同的文件格式和支持此类格式的插件。
OSG 不可能查找并加载所有的插件以获取它们支持的文件格式。这样在程序启动时将会是一笔很大的开销。因此,OSG使用职责链(Chain of Responsibility)的设计模式[Gamma95],以加载尽量少的插件。当用户程序尝试使用osgDB 读取
或写入文件时,OSG 将按照下面的步骤来查找合适的插件:
1、OSG 搜索已注册的插件列表,查找支持文件格式的插件。开始时已注册插件列表仅包含了Registry 类构造函数中注册的插件。如果OSG 找到了
可以支持此文件格式的插件,并成功执行了I/O 操作,那么它将返回相应的数据。
2、如果没有发现可以支持此格式的已注册插件,或者I/O 操作失败,那么OSG 将根据前述的文件命名规则创建插件文件的名称,并尝试读取相应的插件库。如果读取成功,OSG 将添加此插件到已注册插件列表中。
3、OSG 将重复执行步骤1。如果文件I/O 的操作再次失败,OSG 将返回失败信息。
******************osgText与osgFont
Font类用FreeType插件来读取字体文件。
如果要使用一种字体显示多行文字,只需要创建一个Font 对象,为每一段要显示的字符串建立一个Text 对象,把Font对象关联到Text对象中。
Text坐标位置:setPosition   文字方向setAxisAlignment 创建一个一直朝向视口的广告牌形式的文字,可以使用Text::SCREEN。text->setAxisAlignment( osgText::Text::SCREEN );
文字大小:setCharacterSize  缺省情况下,Text 将setCharacterSize()传入的参数视为物体的实际大小。不过Text 也允许用户指定字符在屏幕上显示的大小,而不是物体的真实坐标。使用Text::setCharacterSizeMode()方法可以指定使用屏幕坐标。
text->setCharacterSizeMode( osgText::Text::SCREEN_COORDS );
文字分辨率:setFontResolution

//***************************************************综合应用*****************************
如果你选择直接设置Camera 对象的矩阵值,那么就不要使用Viewer::run()函数,因为它不允许每帧都实时的改变视口的参数。你可以编写一个小的循环利用viewer.frame()来
代替这个函数,循环中可以反复更新视口并渲染单帧图像。
viewer.setClearColor(osg::Vec4(0.,0.,0.,1.))     //设置清屏颜色
viewer.getCamera()->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)    //清除颜色、深度、模版缓存
1. simpleViewer 类不会主动创建窗口或者设备上下文
2. Viewer 类只能在一个场景中添加一个视口(不过似乎可以使用一组摄像机来支持多通道渲染)
3. CompositeViewer 类可以支持一个或多个场景的多个视口显示,并允许用户程序指定其渲染顺序.可以支持渲染到纹理(render-to-texture,RTT)的操作
%%%%%%%%%%%%%%动态更改
osgViewer 库支持多线程模式,每一个线程均独立地运行拣选及绘制遍历。出于性能优化的考虑,OSG 并没有为了线程的安全性增设内存锁,而是要求用户程序只可在拣选及绘制遍历的时域之外修改场景图形。
方法有:
1.  用户可以通过设置Object 对象(Node,Drawable,StateSet 等)的数据变度(data variance)属性来完成这一工作。
2.  设置节点回调
3.  用户程序有时不能预知场景图形的哪一部分需要修改。这时需要搜索整个场景图形来查找特定的节点,或者由用户使用鼠标等输入设备来选择一个节点。
具体解释:
1.  osgViewer 支持的多线程模型允许用户程序主循环不必等到绘制遍历结束就可以继续运行。这就是说Viewer::frame()方法在绘制遍历仍未结束的时候就可以返回。换句话说,上一帧的绘制遍历可以与下一帧的更新遍历产生交叠。仔细考
     虑这一线程模型的实现的话,会发现它几乎很难避免与绘制遍历线程的冲突。不过,OSG 提供了osg::Object::DataVariance()方法作为这一问题的解决方案。
    [当用户开发了动态更改场景图形的代码时,可能会在修改场景
    图形时遇到程序崩溃或者段错误的情况。诸如此类的问题往往都是
    由于用户在拣选和绘制遍历过程中修改了场景图形的数据,而造成
    系统崩溃。]
    要设置一个Object 对象的数据变量,可以调用setDataVariance()并设置输入参数为Object::DataVariance 枚举量。初始状态下,变度的值是UNSPECIFIED。用户程序可以将数据变度更改为STATIC 或者DYNAMIC。OSG 将确保绘制遍历在所有的DYNAMIC 节点和
    数据处理完成后才会返回。同样,由于绘制遍历在函数返回后仍然可以继续渲染场景图形,OSG 将确保此时只有STATIC 数据可以继续进行图形渲染。如果用户的场景图形包含了很少的DYNAMIC 数据,那么绘制遍历可以很快返回,保证用户程序可以继续执行其它的任务。
    (这里可以联想到之前在设置节点回调的时候通常会看到node->setDataVariance(DYNAMIC); 就不难理解了);
2. a.  从NodeCallback 继承一个新的类。
    b. 重载NodeCallback::operator()方法。使用这个方法来实现场景图形的动态更改。
    c. 将用户从NodeCallback 继承的类实例化, 然后使用Node::setUpdateCallback()方法关联到将要修改的Node。
    在每个更新遍历过程中,OSG 都会调用派生类中的operator()方法,从而允许用户程序对Node 进行修改。
    回调示例代码中,Group 根节点有两个MatrixTransform 子节点,从而将Geode 中牛的模型变换到两个不同的位置。如图所示,其中一个MatrixTransform 对象设置了数据变度为DYNAMIC,而另一个由于不会被修改,因此使用了STATIC 数据变度。
3. NodeVisitor
    用户程序可以使用OSG 提供的任何NodeVisitor 派生类,也可以自己编写继承自NodeVisitor的类的代码, 重写apply() 函数来执行自己期望的节点操作。使用特定的名称来搜索节点(之前看到过的FindNameNode)也是一种简单而常用的操作。缺省情况下,NodeVisitor 基类禁止执行遍历。因此在你的派生
    类中,需要使用枚举量NodeVisotor::TRAVERSE_ALL_CHILDREN来初始化基类,以允许执行遍历。否则,OSG 将不会调用用户的apply()方法。
    你可以在任何一个节点上调用accept() ,NodeVisitor 将从那个节点开始遍历整个场景图形。

读OpenSceneGraph快速入门指导(Paul Martz著王锐钱学雷译)有感相关推荐

  1. osg自学笔记1——《OpenSceneGraph 快速入门指导》

    这里写自定义目录标题 <OpenSceneGraph Quick Start Guide>学习笔记 1. 1.3 运行 osgviewer 2.1.5 场景图形初步 3. 1.6 Open ...

  2. 串口转无线网模块:WizFi630 快速入门指导

    WIZnet研发的WizFi630,能有效实现串口转无线功能,它兼容 IEEE 802.11 b/g/n,支持3个以太网端口(10/100 高速以太网) 和2个UART口 ,内嵌全套网络协议栈和相关安 ...

  3. 一文读懂:快速入门机器学习,基础向

    [提前声明] 文章由作者:张耀峰 结合自己生产中的使用经验整理,最终形成简单易懂的文章 写作不易,转载请注明,谢谢! 代码案例地址: ?https://github.com/Mydreamandrea ...

  4. 计算机网络大白话的快速入门指导(一)

    目录 一.前言 二.对五层模型的整体观摩 三.物理层与数据链路层(网络接口层) 一.前言 大家好啊,我是小仙童,是一个计算机学生. 五一期间有一个CSDN的活动,发文即可参加. 主题的话就选择了计算机 ...

  5. BC28无线通信模块 NB-IOT模块 多频段小尺寸 NB-IOT模块快速入门指导

    产品描述: BC28是一款紧凑.高性能.低功耗的多频段NB-loT无线通信模块,支持B1/B3/B8/B5/B20/B28*频段.BC28在设计上兼容移远通信 GSM/GPRS系列的M26模块,方便客 ...

  6. Common Lisp 初学者快速入门指导

    看了<黑客与画家>,对Lisp语言比较好奇,于是就弄了本<Lisp使用教程>,有空的时候就学习一下.Lisp的实现有很多,我用的Emacs+sbcl+slime,因为网上资料比 ...

  7. CAT1模块EC200S 4G物联网模块串口透传MQTT协议 快速入门指导资料

    EC200S是广州斯迈尔特推出的一款工业级,小体积自带STM32CPU,引出串口.SPI\AD等常用接口,用户只要通电就能应用到自己的产品中.EC200S的版本已经完全可以支持UDP TCP PPP ...

  8. 【51单片机快速入门指南】2.3:GPIO读取矩阵键盘 8个IO读16键

    目录 硬知识 矩阵键盘介绍 测试程序 Key_Board.c Key_Board.h main.c 实验现象 普中51-单核-A2 STC89C52 Keil uVision V5.29.0.0 PK ...

  9. python新手教程 从零开始-Python零基础从零开始学习Python十分钟快速入门

    原标题:Python零基础从零开始学习Python十分钟快速入门 学习Python的,都知道Python 是一个高层次的结合了解释性.编译性.互动性和面向对象的脚本语言.Python是一种动态解释型的 ...

最新文章

  1. ARE YOU THE ONE?
  2. Maven -- group、artifact、package
  3. python tkinter库 密码实时显示_Python3 tkinter基础 Entry show textvariable 密码输入框
  4. python多线程同步与互斥_python多线程编程(3): 使用互斥锁同步线程
  5. ROS rqt、rviz
  6. [Mac入门]如何在Mac下显示Finder中的所有文件
  7. 阿里云Ubuntu16.04升级python3.6和pip
  8. 我的2009:知识管理篇
  9. ABB机器人紧凑型控制柜内部结构(图)
  10. b5纸尺寸_标准a2纸尺寸是多少厘米,设计宣传手册尺寸有哪些
  11. 2019年安徽大学ACM/ICPC实验室新生赛
  12. 直流输电模型基于pscad仿真软件的3端直流输电模型
  13. 智能车竞赛技术报告 | 全向行进组 - 东北林业大学- 进取号E
  14. 介绍一个成功的 Git 分支模型
  15. 如何在opencv 和 vs 2019 调整运行窗口的大小
  16. AUTOSAR开发技术手册
  17. 最优化理论中的方法概述
  18. python怎么画飞天小海龟_跟着 “小海龟” 畅游画图世界
  19. 巴菲特致股东的一封信:1982年
  20. 基于SpringBoot的健身房管理系统(提供源码)

热门文章

  1. 10个一般人不知道的小众网站,个个堪称神器,让你大开眼界
  2. iOS 9:四、设置信任
  3. 历史的1000+篇文章总结
  4. debian配置ip
  5. 【OpenPCDet】稀疏卷积SPConv-v1.2代码解读(5)
  6. 第十三届蓝桥杯C++B组国赛I题——齿轮 (AC)
  7. php解决缓慢http请求,php CURL 服务器响应慢的问题
  8. 阿里P8整理Mysql面试题答案,助你面试“脱颖而出”
  9. 爬取王者荣耀高清皮肤
  10. 那些10万变百万的矿工,都是从选对挖矿币种开始的!