osg::DrawElements*系列函数及GL_QUAD_STRIP、GL_QUADS绘制四边形效率对比

news2025/4/22 6:24:10

目录

1. 前言

2. osg::DrawElements*系列函数用法说明

3. GL_QUADS、GL_QUAD_STRIP用法及不同点

4. 效率对比

5. 总结

6. 参考资料


1. 前言

      利用osg绘制图元,如:三角形、四边形等,一般用osg::PrimitiveSet类。其派生出了很多子类,如下图所示:

图1 

在开发中,用DrawElements*系列函数和osg::DrawArrays函数绘制图元比较多,本文以绘制四边形为例子,以osg::DrawElementsUShort、osg::DrawArrays来讲解怎样绘制四边形,及GL_QUAD_STRIP、GL_QUAD的不同、它们之间的效率。

2. osg::DrawElements*系列函数用法说明

      osg::DrawElements*系列函数osg::DrawElementsUShort、osg::DrawElementsUBye、osg::DrawElementsUIntosg::DrawElements派生,而osg::DrawElements对应OPenGL的glDrawElements函数,关于glDrawElements函数用法,请参考:

《glDrawElements用法说明》。

   osg::DrawArrays 类在直接从数组读取顶点数据时效果很好,没有间隙。 但是,当同一个顶点可以属于一个对象的多个面时,它就不那么有效了。 考虑这个例子:

图2 

一个立方体有八个顶点。 然而,从图中可以看出(我们正在考虑将一个立方体扫到一个平面上),一些顶点属于多个面。 如果我们构建一个包含 12 个三角形面的立方体(注:虽然是绘制四边形,但GPU等硬件在真正绘制时,是用两个三角形来拼出一个四边形的对于硬件来说绘制2个三角形比直接一个四边形效率更高,故6个四边形其实内部绘制是12个三角形绘制的),那么这些顶点将重复,而不是 8 个顶点的数组,我们将得到 36 个顶点的数组,其中大部分实际上是相同的顶点! 

      在OSG中,有类 osg::DrawElementsUInt、 osg::DrawElementsUByte和 osg::DrawElementsUShort,它们使用顶点索引数组作为数据,旨在解决上述问题。 索引数组存储描述几何体的面和其他元素的图元顶点的索引。 将这些类应用于立方体时,存储八个顶点的数据就足够了,这些顶点通过索引数组与面相关联。

   osg::DrawElements* 类型的类的设计方式与标准 std::vector 类的设计方式相同。 此代码可用于添加索引。如:

osg::ref_ptr<osg::DrawElementsUInt> de = new osg::DrawElementsUInt(GL_TRIANGLES);
de->push_back(0); 
de->push_back(1); 
de->push_back(2);
de->push_back(3); 
de->push_back(0); 
de->push_back(2); 

此代码定义图2中所示的立方体的正面。考虑另一个说明性的例子——八面体。

图3 

很有趣,因为它只包含六个顶点,但每个顶点已经在四个三角形面中了! 我们可以使用 osg::DrawArrays 创建一个包含 24 个顶点的数组来显示所有八个面。 然而,我们将采取不同的方式——我们将顶点存储在一个包含六个元素的数组中,并使用类 osg::DrawElementsUInt 生成面。

main.h

#ifndef     MAIN_H
#define     MAIN_H
#include<osg/Geometry>
#include<osg/Geode>
#include<osgUtil/SmoothingVisitor>
#include<osgViewer/Viewer>
#endif

 main.cpp

#include"main.h"
int main(int argc, char *argv[]){
    
    osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array(6);
    (*vertices)[0].set( 0.0f,  0.0f,  1.0f);
    (*vertices)[1].set(-0.5f, -0.5f,  0.0f);
    (*vertices)[2].set( 0.5f, -0.5f,  0.0f);
    (*vertices)[3].set( 0.5f,  0.5f,  0.0f);
    (*vertices)[4].set(-0.5f,  0.5f,  0.0f);
    (*vertices)[5].set( 0.0f,  0.0f, -1.0f);
    
    osg::ref_ptr<osg::DrawElementsUInt> indices = new osg::DrawElementsUInt(GL_TRIANGLES, 24);
    (*indices)[ 0] = 0; (*indices)[ 1] = 1; (*indices)[ 2] = 2;
    (*indices)[ 3] = 0; (*indices)[ 4] = 4; (*indices)[ 5] = 1;
    (*indices)[ 6] = 4; (*indices)[ 7] = 5; (*indices)[ 8] = 1;
    (*indices)[ 9] = 4; (*indices)[10] = 3; (*indices)[11] = 5;
    (*indices)[12] = 3; (*indices)[13] = 2; (*indices)[14] = 5;
    (*indices)[15] = 1; (*indices)[16] = 5; (*indices)[17] = 2;
    (*indices)[18] = 3; (*indices)[19] = 0; (*indices)[20] = 2;
    (*indices)[21] = 0; (*indices)[22] = 3; (*indices)[23] = 4;
    
    osg::ref_ptr<osg::Geometry> geom = new osg::Geometry;
    geom->setVertexArray(vertices.get());
    geom->addPrimitiveSet(indices.get());
    
    osgUtil::SmoothingVisitor::smooth(*geom);
    
    osg::ref_ptr<osg::Geode> root = new osg::Geode;
    root->addDrawable(geom.get());
    
    osgViewer::Viewer viewer;
    viewer.setSceneData(root.get());
    
    return viewer.run();
}

上述代码先创建一个有六个顶点的数组,然后使用指针解引用操作和 operator [] 操作符寻址其坐标向量 赋值。别忘了 osg::Array 是 std::vector 的派生类。然后为面创建为顶点索引列表。面将是三角形的,共有 8 个,这意味着索引列表应包含 24 个元素。 面索引按顺序进入此数组:例如,面 0 由顶点 0、1 和 2 组成; 面 1 - 顶点 0、4 和 1; 面 2 - 顶点 4、5 和 1,依此类推。 顶点按逆时针顺序列出,如果你看正面(见图3)。

3. GL_QUADS、GL_QUAD_STRIP用法及不同点

      GL_QUADS:绘制一系列四边形,首先使用顶点V0、V1、V2、V3绘制第1个四边形,然后是V4、V5、V6、V7绘制第2个四边形,接下来以次类推,如果顶点个数n不是4的倍数,最后1个、2个、3个顶点被忽略。注意:如果四边形之间的顶点坐标不相同,则这些四边形是分离的,如下:

图4 

GL_QUAD_STRIP:绘制一系列四边形,首先使用顶点V0、V1、V3、V2绘制第1个四边形,接着是V2、V3、V5、V4,然后是V4、V5、V7、V6。以此类推。顶点个数n至少要大于4,否则不会绘制任何四边形。如果n是奇数,最后一点顶点就被忽略。如下:

图5 

GL_QUAD_STRIP画出一组共享边的四边形。对于较小的模型,共享边的差异可以忽略不计;对于较大的模型,使用GL_QUAD_STRIP意味着显著地节省了计算次数。从第一对顶点开始,相邻的两对定点被定义成一个四边形。定点 2n-1、2n、2n+2和2n+1定义了第n个四边形。有|V|/2-1个四边形将被绘制,|V|代表顶点的个数,如果|V|小于4,OpenGL将不会绘制任何图形。所有四边形将以逆时针顺序排列,互相连接形成四边形带。注意用来构成四边形的顶点顺序和使用GL_QUADS时的顺序是不同的,每一个四边形的第二对定点被逆向使用,以使每一个四边形顶点能被一致地定义。  

图6 

4. 效率对比

       本节以osg::DrawElements*系列函数及GL_QUAD_STRIP、GL_QUADS绘制四边形,以看看它们之间的效率差别。绘制10个连接的立方体如下:

图7

代码如下:

// QUAD_STRIP.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include<osgViewer/Viewer>
#include<osgViewer/ViewerEventHandlers>
#include<osg/PolygonMode>
#include<iostream>
//const auto g_quadCount = 1000000;
const auto g_quadCount = 10;

osg::ref_ptr<osg::Geode> createQuads3()
{
	osg::ref_ptr<osg::Geode> spGeode = new osg::Geode;// Geode是Node的派生类,为了绘制图元的管理类

	osg::ref_ptr<osg::Geometry> spGeometory = new osg::Geometry;
	spGeode->addChild(spGeometory);

	osg::ref_ptr<osg::Vec3Array> spCoordsArray = new osg::Vec3Array;
	auto offset = 0;
    int nGeomeryCount = 0;
   while (true)
   {
	   // 前面
	   spCoordsArray->push_back(osg::Vec3d(-1.0, -1.0 + offset, -1.0));  // 前左下顶点  V1
	   spCoordsArray->push_back(osg::Vec3d(1.0, -1.0 + offset, -1.0));   // 前右下顶点  V2
	   spCoordsArray->push_back(osg::Vec3d(-1.0, -1.0 + offset, 1.0));   // 前左上顶点  V3。注意:前左上顶点才是第3个顶点,而不是前右上顶点 
	   spCoordsArray->push_back(osg::Vec3d(1.0, -1.0 + offset, 1.0));    // 前右上顶点  V4
	   
	   spCoordsArray->push_back(osg::Vec3d(-1.0, 1.0 + offset, 1.0));    // V5
	   spCoordsArray->push_back(osg::Vec3d(1.0, 1.0 + offset, 1.0));     // V6
	   spCoordsArray->push_back(osg::Vec3d(-1.0, 1.0 + offset, -1.0));   // V7
	   spCoordsArray->push_back(osg::Vec3d(1.0, 1.0 + offset, -1.0));    // V8

	   spCoordsArray->push_back(osg::Vec3d(-1.0, -1.0 + offset, -1.0));    // V9
	   spCoordsArray->push_back(osg::Vec3d(1.0, -1.0 + offset, -1.0));    // V10
	   
	   offset += 2; // y轴方向上宽度为2
	   nGeomeryCount++;
	   if (g_quadCount == nGeomeryCount)
	   {
		   break;
	   }
   }

   spGeometory->setVertexArray(spCoordsArray);
   spGeometory->addPrimitiveSet(new osg::DrawArrays(GL_QUAD_STRIP, 0, spCoordsArray->size()));

   return spGeode;
}

osg::ref_ptr<osg::Geode> createQuads2()
{
	osg::ref_ptr<osg::Geode> spGeode = new osg::Geode;// Geode是Node的派生类,为了绘制图元的管理类

	osg::ref_ptr<osg::Geometry> spGeometory = new osg::Geometry;
	spGeode->addChild(spGeometory);
	//spGeode->addDrawable(spGeometory);// 可以将addChild替换为这句。
	
	osg::ref_ptr<osg::Vec3Array> spCoordsArray = new osg::Vec3Array;
	auto totalVertCount = g_quadCount * 8;
	osg::DrawElementsUShort* pDrawElemt = new osg::DrawElementsUShort(GL_QUADS, 24 * g_quadCount); // 立方体共8个顶点,每个顶点重复了3次

	auto iVertCount = 0;
	for (auto offset = 0; ; offset += 2)
	{
		spCoordsArray->push_back(osg::Vec3d(1.0, -1.0 + offset, -1.0));  // 0
		spCoordsArray->push_back(osg::Vec3d(1.0, -1.0 + offset, 1.0));   // 1
		spCoordsArray->push_back(osg::Vec3d(-1.0, -1.0 + offset, 1.0));    // 2
		spCoordsArray->push_back(osg::Vec3d(-1.0, -1.0 + offset, -1.0));   // 3

		iVertCount += 4;
		if (iVertCount >= totalVertCount)
		{
			break;
		}
	}
	
	for (auto guadIndex = 0; guadIndex < g_quadCount; ++guadIndex)
	{
		auto nElementIndex = guadIndex * 24;

		// 右侧面
		auto temp = 4 * guadIndex;
		(*pDrawElemt)[0 + nElementIndex] = 0 + temp;
		(*pDrawElemt)[1 + nElementIndex] = 4 + temp;
		(*pDrawElemt)[2 + nElementIndex] = 5 + temp;
		(*pDrawElemt)[3 + nElementIndex] = 1 + temp;

		// 前面
		if (0 == guadIndex % 2)// 前一个立方体的后面和后一个立方体的前面重合,故只绘制一个
		{
			(*pDrawElemt)[4 + nElementIndex] = 0 + temp;
			(*pDrawElemt)[5 + nElementIndex] = 1 + temp;
			(*pDrawElemt)[6 + nElementIndex] = 2 + temp;
			(*pDrawElemt)[7 + nElementIndex] = 3 + temp;
		}

		// 左侧面
		(*pDrawElemt)[8 + nElementIndex] = 3 + temp;
		(*pDrawElemt)[9 + nElementIndex] = 7 + temp;
		(*pDrawElemt)[10 + nElementIndex] = 6 + temp;
		(*pDrawElemt)[11 + nElementIndex] = 2 + temp;

		// 上面
		(*pDrawElemt)[12 + nElementIndex] = 1 + temp;
		(*pDrawElemt)[13 + nElementIndex] = 5 + temp;
		(*pDrawElemt)[14 + nElementIndex] = 6 + temp;
		(*pDrawElemt)[15 + nElementIndex] = 2 + temp;

		// 后面
		(*pDrawElemt)[16 + nElementIndex] = 4 + temp;
		(*pDrawElemt)[17 + nElementIndex] = 5 + temp;
		(*pDrawElemt)[18 + nElementIndex] = 6 + temp;
		(*pDrawElemt)[19 + nElementIndex] = 7 + temp;

		// 底面
		(*pDrawElemt)[20 + nElementIndex] = 0 + temp;
		(*pDrawElemt)[21 + nElementIndex] = 4 + temp;
		(*pDrawElemt)[22 + nElementIndex] = 7 + temp;
		(*pDrawElemt)[23 + nElementIndex] = 3 + temp;

	}

	spGeometory->setVertexArray(spCoordsArray);
	spGeometory->addPrimitiveSet(pDrawElemt);
	
	return spGeode;
}

osg::Geode* createQuads1()
{
	auto pGeode = new osg::Geode;

	auto pGeomery = new osg::Geometry;
	pGeode->addChild(pGeomery);
	auto spCoordsArray = new osg::Vec3Array;
	auto offset = 0;
	int nGeomeryCount = 0;
	while (true)
	{
		// 右侧面
		spCoordsArray->push_back(osg::Vec3d(1.0, -1.0 + offset, -1.0));  // 前右下顶点
		spCoordsArray->push_back(osg::Vec3d(1.0, 1.0 + offset, -1.0));   // 后右下顶点
		spCoordsArray->push_back(osg::Vec3d(1.0, 1.0 + offset, 1.0));    // 后右上顶点 
		spCoordsArray->push_back(osg::Vec3d(1.0, -1.0 + offset, 1.0));   // 前右上顶点

		// 前面
		spCoordsArray->push_back(osg::Vec3d(1.0, -1.0 + offset, -1.0));  // 右下顶点
		spCoordsArray->push_back(osg::Vec3d(1.0, -1.0 + offset, 1.0));   // 右上顶点
		spCoordsArray->push_back(osg::Vec3d(-1.0, -1.0 + offset, 1.0));  // 左上顶点 
		spCoordsArray->push_back(osg::Vec3d(-1.0, -1.0 + offset, -1.0)); // 左下顶点

		// 左侧面
		spCoordsArray->push_back(osg::Vec3d(-1.0, -1.0 + offset, -1.0));  // 前左下顶点
		spCoordsArray->push_back(osg::Vec3d(-1.0, -1.0 + offset, 1.0));   // 前左上顶点
		spCoordsArray->push_back(osg::Vec3d(-1.0, 1.0 + offset, 1.0));    // 后左上顶点 
		spCoordsArray->push_back(osg::Vec3d(-1.0, 1.0 + offset, -1.0));   // 后左下顶点

		// 后面
		spCoordsArray->push_back(osg::Vec3d(1.0, 1.0 + offset, -1.0));    // 后下顶点
		spCoordsArray->push_back(osg::Vec3d(1.0, 1.0 + offset, 1.0));     // 后上顶点
		spCoordsArray->push_back(osg::Vec3d(-1.0, 1.0 + offset, 1.0));    // 左上顶点 
		spCoordsArray->push_back(osg::Vec3d(-1.0, 1.0 + offset, -1.0));   // 左下顶点

		// 上面
		spCoordsArray->push_back(osg::Vec3d(1.0, -1.0 + offset, 1.0));     // 前右顶点
		spCoordsArray->push_back(osg::Vec3d(1.0, 1.0 + offset, 1.0));      // 后右顶点
		spCoordsArray->push_back(osg::Vec3d(-1.0, 1.0 + offset, 1.0));     // 后左顶点 
		spCoordsArray->push_back(osg::Vec3d(-1.0, -1.0 + offset, 1.0));    // 前左顶点

		// 底面
		spCoordsArray->push_back(osg::Vec3d(1.0, -1.0 + offset, -1.0));     // 前右顶点
		spCoordsArray->push_back(osg::Vec3d(1.0, 1.0 + offset, -1.0));     // 后右顶点
		spCoordsArray->push_back(osg::Vec3d(-1.0, 1.0 + offset, -1.0));    // 后左顶点 
		spCoordsArray->push_back(osg::Vec3d(-1.0, -1.0 + offset, -1.0));   // 前左顶点
		
		offset += 2; // y轴方向上宽度为2
		nGeomeryCount++;
		if (g_quadCount == nGeomeryCount)
		{
			break;
		}
	}
	
	pGeomery->setVertexArray(spCoordsArray);
	pGeomery->addPrimitiveSet(new osg::DrawArrays(GL_QUADS, 0, spCoordsArray->size()));
	
	return pGeode;
}

int main()
{
    auto pRoot = new osg::Group;

	auto pGeode = createQuads3();
	pGeode->getOrCreateStateSet()->setAttribute(
		new osg::PolygonMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE));
	pGeode->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);

	pRoot->addChild(pGeode);
	
	auto pViewer = new osgViewer::Viewer;
	auto pStatsHander = new osgViewer::StatsHandler;
	pViewer->addEventHandler(pStatsHander);
	pViewer->setSceneData(pRoot);
	pViewer->run();
}

 当g_quadCount为10时,把第195行代码分别换成createQuads1、createQuads2、createQuads3,在视景器窗体中连续按4次键盘小写s键时,createQuads1函数即用osg::DrawArrays及GL_QUADS各性能指标如下:

图8 osg::DrawArrays及GL_QUADS绘制10个立方体时的各性能指标

createQuads2函数即用osg::DrawElementsUShort及GL_QUADS各性能指标如下:

图9 osg::DrawElementsUShort及GL_QUADS绘制10个立方体时的各性能指标 

createQuads3函数即用osg::DrawArrays及GL_QUAD_STRIP各性能指标如下: 

图10 osg::DrawArrays及GL_QUAD_STRIP绘制10个立方体时的各性能指标  

当绘制的立方体个数为10即立方体个数很少时,这三者在GPU占用、帧率、绘制、裁剪等方面差别不是很大。

当将g_quadCount改为1000000时, createQuads1函数即用osg::DrawArrays及GL_QUADS各性能指标如下:

图11 osg::DrawArrays及GL_QUADS绘制1000000个立方体时的各性能指标 

createQuads2函数即用osg::DrawElementsUShort及GL_QUADS各性能指标如下: 

图12 osg::DrawElementsUShort及GL_QUADS绘制1000000个立方体时的各性能指标  

createQuads3函数即用osg::DrawArrays及GL_QUAD_STRIP各性能指标如下: 

图13 osg::DrawArrays及GL_QUAD_STRIP绘制100000个立方体时的各性能指标  

当要绘制的立方体很多时, 采用osg::DrawArrays和GL_QUAD_STRIP明显比osg::DrawElementsUShort及osg::DrawArrays和GL_QUADS效率高很多、GPU占用大大减少、帧率高;而osg::DrawElementsUShort和GL_QUADS比osg::DrawArrays和GL_QUADS效率高一些,因为osg::DrawElementsUShort采取的是点的索引,剔除了重复,所以效率会高点。

5. 总结

  • osg::DrawElements*系列函数采用点的索引绘制图元,而osg::DrawArrays采用点的数组来绘制图元,当点个数很多时,前者效率高些。
  • 当点个数是巨大量时,GL_QUAD_STRIP比采用GL_QUADS效率高很多。同样地GL_TRIANGLE_STRIP绘制三角形时效率比GL_TRIANGLES高。
  • 上述代码main函数中用到了统计和性能相关的各项参数的osgViewer::StatsHandler类,关于该类的用法,请参考:浅谈osgViewer::StatsHandler、osg::Stats类的用法

6. 参考资料

【1】:OpenGL编程指南(原书第7版)。

【2】:理解GL_QUAD_STRIP。

【3】:OSG几何开发快速教程。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1346224.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【网络安全 | Misc】miss_01 太湖杯

解压时提示输入密码&#xff1a; 如果 frFlags 或 deFlags 不为0会导致zip的伪加密 将deFlags的值修改为0 将9改为0&#xff0c;另存为123.zip&#xff1a; 即可绕过加密&#xff1a; 得到一个zip一个docx&#xff0c;但zip需要密码&#xff1a; 因此看docx有无敏感信息&#x…

面向对象基础-类与对象-封装

1、类与对象 1.1 概念 类&#xff1a;类是一个抽象的概念&#xff0c;用于描述一类对象的特点。 对象&#xff1a;根据类的概念所创造的实体。 【思考】一个对象可以没有对应的类嘛&#xff1f; 不可以&#xff0c;因为必须现有类才能创建对象。 1.2 类的内容 类中最基础的内容…

x-cmd pkg | fzf - 命令行模糊查找器

目录 简介首次用户功能特点竞品和相关作品进一步阅读 简介 fzf 是一个由 Go 编写的命令行模糊搜索工具&#xff0c;用于在大量文本数据中快速定位和选择内容&#xff0c;可以与任何列表一起使用&#xff08;e.g. 文件、命令历史记录、进程、主机名、书签、git 提交等&#xff…

鲲志说:向我乘风破浪,好事多磨的2023致敬!(感恩有礼,感谢有你)

伴随着2023最后一个工作日的结束&#xff0c;也终于要给一年的工作划上一个结尾了&#xff0c;当然&#xff0c;也要给自己一个交代&#xff0c;给自己一个年度总结 2023年&#xff0c;大的挫折也是有的&#xff0c;但我相信好事多磨&#xff0c;总的来说是事业型的一年&#x…

华为ensp网络设计期末测试题-复盘

网络拓扑图 地址分配表 vlan端口分配表 需求 The device is running!<Huawei>sys Enter system view, return user view with CtrlZ. [Huawei]un in en Info: Information center is disabled. [Huawei]sys S1 [S1]vlan 99 [S1-vlan99]vlan 100 [S1-vlan100]des IT [S1-…

关于“Python”Django 管理网站的核心知识点整理大全52

目录 注意 18.2.2 激活模型 settings.py 18.2.3 Django 管理网站 1. 创建超级用户 注意 2. 向管理网站注册模型 admin.py 注意 3. 添加主题 Climbing。 18.2.4 定义模型 Entry models.py 18.2.5 迁移模型 Entry 18.2.6 向管理网站注册 Entry admin.py 往期快速…

十三:爬虫-Scrapy框架(下)

一&#xff1a;各文件的使用回顾 1.items的使用 items 文件主要用于定义储存爬取到的数据的数据结构&#xff0c;方便在爬虫和 Item Pipeline 之间传递数据。 items.pyimport scrapyclass TencentItem(scrapy.Item):# define the fields for your item here like:title scr…

c++简易AI

今天小编一时雅兴大发&#xff0c;做了一个c的简易AI&#xff0c;还是很垃圾的&#xff01; 题外话&#xff08;每期都会有&#xff09;&#xff1a;我的蛋仔名叫酷影kuying&#xff0c;大家能加我好友吗&#xff1f; 上代码咯&#xff01; #include<bits/stdc.h> #in…

2023年终总结丨很苦,很酷!

文章目录 个人简介丨了解博主写在前面丨博主介绍年终总结丨博主成就年终总结丨博主想说年终总结丨学习芝士年终总结丨未来展望写在后面丨新年快乐 个人简介丨了解博主 主页地址&#xff1a;https://blog.csdn.net/m0_68111267 荣誉身份 ⭐2022年度CSDN 社区之星 Top6 ⭐2023年…

基于NASM搭建一个能编译汇编语言的汇编软件工具环境(利用NotePad++)

文章目录 一、创建汇编语言源程序二、Notepad的下载、安装、使用三、下载和安装编译器NASM3.1 下载NASM编译器3.2 安装并配置环境变量 四、编译汇编语言源程序&#xff08;使用命令&#xff09;五、下载和使用配套源码及工具六、将编译功能集成到Notepad 一、创建汇编语言源程序…

vue3中pinia的使用及持久化(详细解释)

解释一下pinia&#xff1a; Pinia是一个基于Vue3的状态管理库&#xff0c;它提供了类似Vuex的功能&#xff0c;但是更加轻量化和简单易用。Pinia的核心思想是将所有状态存储在单个store中&#xff0c;并且将store的行为和数据暴露为可响应的API&#xff0c;从而实现数据&#…

[设计模式 Go实现] 创建型~工厂方法模式

工厂方法模式使用子类的方式延迟生成对象到子类中实现。 Go中不存在继承 所以使用匿名组合来实现 代码实现 package factorymethod//Operator 是被封装的实际类接口 type Operator interface {SetA(int)SetB(int)Result() int }//OperatorFactory 是工厂接口 type OperatorF…

国图公考:研究生可以考选调生吗?

研究生可以报考选调生吗?当然是可以的&#xff0c;但是同样需要满足一定的条件才可以。 除本科生外&#xff0c;具有硕士、博士学位的考生均可申请考试。但是&#xff0c;除了满足应届毕业生的身份&#xff0c;还需要满足年龄限制。一般来说&#xff0c;本科生不超过25岁&…

文件批量整理,文件归类整理,文件批量归类

我们每天都要面对无数的文件&#xff0c;从工作报告、个人照片到电影和音乐。如何有效地管理和归类这些文件&#xff0c;成为了我们日常生活和工作中所要处理的。今天&#xff0c;小编就给大家介绍一款简单易用的工具——文件批量改名高手&#xff0c;助你轻松实现文件批量归类…

基于DBNetpp的文本检测的仪表盘读数识别

一个不知名大学生&#xff0c;江湖人称菜狗 original author: Jacky Li Email : 3435673055qq.com Time of completion&#xff1a;2023.12.31 Last edited: 2023.12.31 祝自己生日快乐啦&#xff01;&#xff01;&#xff01;&#xff01; 目录 算法设计 &#xff08;1&…

【逗老师的无线电】ICOM IC-705终端模式Terminal Mode直连反射器配置-内置网关IP直连篇

各位友台大家好呀&#xff0c;逗老师最近整了一台IC-705&#xff0c;最吸引人的莫过于这玩意可以IP直连反射器。下面简单介绍一下这个功能和其配置方法 目录 一、功能二、依赖条件三、配置3.1、IC-705连接WIFI3.2、配置Terminal Mode3.2.1、点击MENU进入菜单&#xff0c;翻到第…

数据库的学习笔记——第一篇

SQL通用语法 SQL语句 DDL 数据定义 数据库、表字段 DML 数据操作 增删改 DQL 数据查询 查询表中记录 DCL 数据控制 创建用户、控制用户权限 DLL语句——数据库操作 SHOW DATABASES; # 查询数据库SELECT DATABASE(); # 查询当前数据库CREATE DATABASE [IF …

简单几步制作翻页电子画册

翻页电子画册是一种非常流行的电子书形式&#xff0c;它能够以生动、美观、有趣的方式展示您的内容。如果您想要制作自己的翻页电子画册&#xff0c;以下是一些简单的步骤&#xff0c;可以帮助您轻松上手。 首先&#xff0c;你需要一款在线制作电子杂志平台。比如FLBOOK&#x…

[NCTF 2022]calc

[NCTF 2022]calc 考点&#xff1a;python环境变量注入 打开题目&#xff0c;F12有hint 访问一下得到源码 app.route("/calc",methods[GET]) def calc():ip request.remote_addrnum request.values.get("num")log "echo {0} {1} {2}> ./tmp/log…

DragonEnglish:COCA20000+单词+释义

去年的时候接触到了 COCA20000 单词&#xff0c;对这种给单词特定顺序的方式蛮感兴趣的。因为我当时接触的版本只有单词或者单词释义的版本&#xff0c;所以我直接通过各种方式给它搭配了音标例句发音&#xff0c;然后每100个切割成1份&#xff0c;分成了 202 个文件来学习&…