OSG编程指南<十四>:OSG纹理渲染之普通纹理、多重纹理、Mipmap多级渐远纹理及TextureRectangle矩阵纹理

news2024/11/18 1:33:16

1、纹理映射介绍

  物体的外观不仅包括形状,不同物体表面有着不同的颜色和图案。一个简单而有效地实现这种特性的方法就是使用纹理映射。在三维图形中,纹理映射(Texture Mapping)的方法运用广泛,使用该技术可以大大提高物体的真实感。

  OSG 是对底层 OpenGL API 的封装,OpenGL 本身有非常标准而高效的纹理机制。OSG 全面支持OpenGL 的纹理映射机制,因此,在 OSG 中使用纹理映射机制非常简单。纹理映射主要包括一维纹理、二维纹理、三维纹理、凸凹纹理、多重纹理、Mipmap 纹理、压缩纹理和立方纹理等。本文主要针对一维纹理、二维纹理、三维纹理、多重纹理、Mipmap 纹理和立方纹理等经常使用的几种纹理加以解释说明。

下面讲解一些纹理的基础知识,这些对于熟悉 OpenGL 的朋友来说,应该都是再基础不过了。

(1)纹理坐标:

enum WrapParameter
{
WRAP_S, //x 轴
WRAP_T, //y 轴
WRAP_R //z 轴
};

(2)纹理的包装模式:

enum WrapMode
{
CLAMP = GL_CLAMP, //截取
CLAMP_TO_EDGE = GL_CLAMP_TO_EDGE,//边框始终被忽略
CLAMP_TO_BORDER = GL_CLAMP_TO_BORDER_ARB, //它使用的纹理取自图像的边框,没有边框就使用
常量边框颜色
REPEAT = GL_REPEAT, //纹理的重复映射
MIRROR = GL_MIRRORED_REPEAT_IBM //纹理镜像的重复映射
};

(3)纹理过滤方法:

enum FilterParameter
{
MIN_FILTER, //用于缩小
MAG_FILTER //用于放大
};

(4)纹理的过滤处理:

enum FilterMode
{
LINEAR= GL_LINEAR, //以周围 4 个像素的平均值作为纹理
LINEAR_MIPMAP_LINEAR= GL_LINEAR_MIPMAP_LINEAR,//使用线性均和计算两个纹理的值
LINEAR_MIPMAP_NEAREST= GL_LINEAR_MIPMAP_NEAREST,//线性地改写临近的纹理单元值
NEAREST= GL_NEAREST, //取比较接近的像素作为纹理
NEAREST_MIPMAP_LINEAR= GL_NEAREST_MIPMAP_LINEAR,//在两个纹理中选择最临近的纹理,并取它
们之间的线性均和值
NEAREST_MIPMAP_NEAREST= GL_NEAREST_MIPMAP_NEAREST //选择最临近的纹理单元值
};

(5)纹理映射模式(处理纹理图像数据与物体本身的融合):

enum Mode
{
DECAL= GL_DECAL, //贴花
MODULATE= GL_MODULATE, //调整
BLEND= GL_BLEND, //混合
REPLACE= GL_REPLACE, //替换,覆盖
ADD= GL_ADD //添加
};

(6)纹理坐标的自动生成模式:

enum Mode
{
OBJECT_LINEAR= GL_OBJECT_LINEAR,//物体线性,纹理贴图与移动物体保持固定
EYE_LINEAR= GL_EYE_LINEAR,//产生移动物体的动态轮廓线
SPHERE_MAP= GL_SPHERE_MAP,//球体贴图
NORMAL_MAP= GL_NORMAL_MAP_ARB, //法线贴图,用于立方图纹理
REFLECTION_MAP = GL_REFLECTION_MAP_ARB//反射贴图
};

(7)贴图坐标:

enum Coord
{
S, //x
T, //y
R, //z
Q //w
};

(8)纹理的内部格式:

enum InternalFormatMode
{
USE_IMAGE_DATA_FORMAT, //使用贴图本身的格式
USE_USER_DEFINED_FORMAT,//使用用户自定义的格式,如 GL_R3G3B3 等格式
USE_ARB_COMPRESSION, //使用 ARB 协会出的贴图压缩格式
USE_S3TC_DXT1_COMPRESSION,//使用 S3TC_DXT1 压缩格式
USE_S3TC_DXT3_COMPRESSION,//使用 S3TC_DXT3 压缩格式
USE_S3TC_DXT5_COMPRESSION //使用 S3TC_DXT5 压缩格式
};

2、二维纹理

2.1 纹理坐标和纹理数据

  在所有的纹理映射中,二维纹理映射的过程最简单,也非常容易理解。在用户应用程序中创建二维纹理的步骤如下:

(1)指定用户几何体的纹理坐标。
(2)创建纹理属性对象并保存纹理图形数据。
(3)为 StateSet 设置合适的纹理属性和模式。

1.纹理坐标
  在前面几何体的绘制时已经提到用一个二维的向量数据来保存纹理坐标。设置纹理坐标比较简单,纹理坐标是与顶点一一对应的,很像数学中的映射。
  下面的代码段创建了一个 osg::Vec2Array 数组,用于保存纹理坐标,同时将其关联到 Geometry 实例的纹理单元 0。如果要对单一的 Geometry 设置多个纹理,只需要将多个纹理坐标数组关联到Geometry,并针对不同的数组指定不同的纹理单元即可。

//创建一个 Geometry 几何体对象
osg::ref_ptr<osg::Geometry> geom = new osg::Geometry;
//创建一个 Vec2Array 对象以保存纹理单元 0 的纹理坐标,并将其关联到 geom
osg::ref_ptr<osg::Vec2Array> tc = new osg::Vec2Array;
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()的函数输入点来绑定纹理数据。纹理坐标总是绑定到每个顶点的。在这里有一点要注意,OpenGL 的早期版本并不支持多重纹理,而加入多重纹理的特性之后,OpenGL 仍然支持非多重纹理的函数接口,以实现向下兼容。从本质上说,此时 OpenGL 将非多重纹理接口解释为使用纹理单元 0 对应所有纹理数据。与 OpenGL 不同,OSG 并不支持非多重纹理接口。因此,用户程序必须指定一个纹理单元,以对应纹理坐标数据和纹理状态。如果要使用单一纹理,只需要指定到纹理单元 0 即可。

2.纹理数据
  在大多数应用程序中,纹理数据都是从外部导入的图像文件。当没有必要导入图像时,可以生成一幅纹理数据贴图。这里使用从外部导入的纹理数据图形的方法。读取图像需要使用一个新类——osg::Image。osg::Image 继承自 osg::Object 类。面的代码将实现如何读取图像:

osg::ref_ptr<osg::Image> image = new osg::Image;
image->setFileName( "tree.rgb" );

  在读取一个图像后,需要创建一个纹理对象来关联图像。osg::Texture2D 属于 osg::StateAttribute 的派生类,用于管理 OpenGL 纹理对象,而 Image 用于管理图像像素数据。如果要使用 2D 图像文件作为纹理映射的图形,只要将文件名赋给 Image 对象并将 Image 关联到 Texture2D 即可。osg::Texture2D 继承自 osg::Texture。下面的代码将实现将图像关联到 2D 纹理对象上:

//将图像关联到 Texture2D 对象
osg::ref_ptr<osg::Texture2D> tex = new osg::Texture2D;
tex->setImage( image.get() );

  在关联图像以后,可以直接关联到渲染状态。值得注意的是:大量使用纹理贴图的程序往往需要实现更紧凑的内存管理。Image 类继承自 Referenced 类,而 Texture2D 内部保存了一个指向 Image 的ref_ptr<>指针。在第一次渲染时,OSG 创建了用于保存图像数据的 OpenGL 纹理对象,其结果是产生了两个纹理图像的副本,一个是 Image 对象,另一个由 OpenGL 拥有。简单的单环境(single-context)场景渲染中,读者可以通过设置 Texture2D 解除对 Image 的引用来降低内存损耗。如果当前引用 Image对象的只有 Texture2D 对象,那么 OSG 将释放 Image 及其内存空间。下面的代码演示了设置 Texture2D解除对 Image 引用的方法:

//创建 OpenGL 纹理对象后,释放内部的 ref_ptr<Image>,删除 Image 图像
tex->setUnRefImageDataAfterApply( true );

  默认情况下,Texture2D 不会自动释放对 Image 的引用。在多环境(multi-context)场景渲染中,这是一种期望行为,前提是纹理对象并没有在各环境中共享。

3.纹理状态
  用户程序可以使用纹理状态函数接口为每个纹理单元指定渲染状态。纹理状态函数接口与非纹理状态的接口类似。用户可以使用 osg::StateSet::setTextureAttribute()将一个纹理属性关联到 StateSet 对象。setTextureAttribute()的第一个参数是纹理单元,第二个参数是继承自 StateAttribute 类的一种纹理属性。

  合法的纹理属性类共有 6 种,其中包括 5 种纹理类型(osg::Texture1D、osg::Texture2D、osg::Texture3D、
osg::TextureCubeMap 和 osg::TextureRectangle)和一个用于纹理坐标的生成的类(osg::TexGen)。

  下面的代码将根据给定的 Texture2D 属性对象 tex 和渲染状态 StateSet 将 tex 关联到渲染状态,并设置使用纹理单元 0。

//创建一个 Texture2D 属性
Osg::ref_ptr<osg::Texture2D> tex = new osg::Texture2D;
//关联材质属性到材质单元 0
state->setTextureAttribute( 0, tex.get() );

  与上面的程序类似,用户可以调用 osg::StateSet::setTextureMode()方法来设置材质渲染模式,这个方法与 setMode()方法类似。用户可以使用 setTextureMode()来设置 GL_TEXTURE_1D、GL_TEXTURE_2D、GL_TEXTURE_3DGL_TEXTURE_CUBE_MAP、GL_TEXTURE_RECTANGLE、GL_TEXTURE_GEN_Q、GL_TEXTURE_GEN_R、GL_TEXTURE_GEN_S 以及 GL_TEXTURE_GEN_T 模式。

  与 setTextureAttribute()相似,setTextureMode()的第一个参数表示纹理单元。下面的代码段将禁止纹理单元 1 的 2D 纹理映射:

state->setTextureMode( 1, GL_TEXTURE_2D, osg::StateAttribute::OFF );

  当然,用户也可以使用 osg::StateSet::setTextureAttributesAndModes()来关联纹理渲染属性到StateSet,同时允许相应的纹理模式。如果属性是一个 TexGen 对象,那么 setTextureAttributesAndModes()将设置相应的坐标生成模式 GL_TEXTURE_GEN_Q、GL_TEXTURE_GEN_R、GL_TEXTURE_GEN_S和 GL_TEXTURE_GEN_T。对于其他纹理属性来说,这一模式是隐含的。例如,下面的代码中,由于第二个参数传入了一个 Texture2D 对象作为纹理属性,setTextureAttributesAndModes()将允许GL_TEXTURE_2D 模式:

//创建一个 Texture2D 属性对象
osg::ref_ptr<osg::Texture2D> tex = new osg::Texture2D;
//在纹理单元 0 上,关联 2D 纹理属性并许可 GL_TEXTURE_2D 模式
state->setTextureAttributeAndModes( 0, tex );

  setTextureAttributeAndModes() 的 第 三 个 参 数 的 默 认 值 为 ON , 即 允 许 纹 理 渲 染 模 式 。 与
setAttributeAndModes()类似,读者可以对这个参数使用位或操作包括 OVERRIDE、PROTECTED 和INHERIT,以修改纹理属性的继承特性。读者还可以通过修改 setTextureMode()和 setTextureAttribute()的第三个参数来指定这个继承标志。

2.2 示例效果

2.2.1 普通示例

  备注:osg默认会被图片大小非2的n次方的图片进行缩放处理。后续可与矩阵纹理进行对比

在这里插入图片描述

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

#include <windows.h>
#include <osgViewer/Viewer>

#include <osg/Node>
#include <osg/Geode>
#include <osg/Group>
#include <osg/Geometry>
#include <osg/Image>
#include <osg/TexGen>
#include <osg/Texture1D>
#include <osg/TexEnv>
#include <osg/StateSet>
#include <osg/PrimitiveSet>
#include <osgDB/ReadFile>
#include <osgDB/WriteFile>
#include <osgViewer/ViewerEventHandlers> //事件监听
#include <osgGA/StateSetManipulator> //事件响应类,对渲染状态进行控制
#include <osgUtil/Simplifier> //简化几何体

#include <osgUtil/Optimizer>

#pragma comment(lib, "OpenThreadsd.lib")
#pragma comment(lib, "osgd.lib")
#pragma comment(lib, "osgDBd.lib")
#pragma comment(lib, "osgUtild.lib")
#pragma comment(lib, "osgGAd.lib")
#pragma comment(lib, "osgViewerd.lib")
#pragma comment(lib, "osgTextd.lib")

//创建一个四边形节点
osg::ref_ptr<osg::Node> createNode()
{
	osg::ref_ptr<osg::Geode> geode = new osg::Geode();

	osg::ref_ptr<osg::Geometry> geom = new osg::Geometry();

	//设置顶点
	osg::ref_ptr<osg::Vec3Array> vc = new osg::Vec3Array();
	vc->push_back(osg::Vec3(0.0f, 0.0f, 0.0f));
	vc->push_back(osg::Vec3(1.0f, 0.0f, 0.0f));
	vc->push_back(osg::Vec3(1.0f, 0.0f, 1.0f));
	vc->push_back(osg::Vec3(0.0f, 0.0f, 1.0f));

	geom->setVertexArray(vc.get());

	//设置纹理坐标
	osg::ref_ptr<osg::Vec2Array> vt = new osg::Vec2Array();
	vt->push_back(osg::Vec2(0.0f, 0.0f));
	vt->push_back(osg::Vec2(1.0f, 0.0f));
	vt->push_back(osg::Vec2(1.0f, 1.0f));
	vt->push_back(osg::Vec2(0.0f, 1.0f));

	geom->setTexCoordArray(0, vt.get());

	//设置法线
	osg::ref_ptr<osg::Vec3Array> nc = new osg::Vec3Array();
	nc->push_back(osg::Vec3(0.0f, -1.0f, 0.0f));

	geom->setNormalArray(nc.get());
	geom->setNormalBinding(osg::Geometry::BIND_OVERALL);

	//添加图元
	geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, 4));

	//绘制
	geode->addDrawable(geom.get());

	return geode.get();
}

//创建二维纹理状态对象
osg::ref_ptr<osg::StateSet> createTexture2DState(osg::ref_ptr<osg::Image> image)
{
	//创建状态集对象
	osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet();

	//创建二维纹理对象
	osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D();
	texture->setDataVariance(osg::Object::DYNAMIC);

	//设置贴图
	texture->setImage(image.get());

	stateset->setTextureAttributeAndModes(0, texture.get(), osg::StateAttribute::ON);

	return stateset.get();
}

int main()
{
	osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer();

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

	//读取贴图文件
	osg::ref_ptr<osg::Image> image = osgDB::readImageFile("Images/primitives.gif");

	osg::ref_ptr<osg::Node> node = createNode();

	//创建状态集对象
	osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet();
	stateset = createTexture2DState(image.get());

	//使用二维纹理
	node->setStateSet(stateset.get());

	root->addChild(node.get());

	//优化场景数据
	osgUtil::Optimizer optimizer;
	optimizer.optimize(root.get());

	//方便查看在多边形之间切换,以查看三角网
	viewer->addEventHandler(new osgGA::StateSetManipulator(viewer->getCamera()->getOrCreateStateSet()));
	viewer->addEventHandler(new osgViewer::StatsHandler());
	viewer->addEventHandler(new osgViewer::WindowSizeHandler());
	viewer->setSceneData(root.get());
	viewer->setUpViewInWindow(600, 600, 1000, 800);
	return viewer->run();
}
2.2.2 光照和混合模式示例

在这里插入图片描述

在这里插入图片描述

//创建二维纹理状态对象
osg::ref_ptr<osg::StateSet> createTexture2DState(osg::ref_ptr<osg::Image> image)
{
	//创建状态集对象
	osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet();

	//创建二维纹理对象
	osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D();
	texture->setDataVariance(osg::Object::DYNAMIC);

	//设置贴图
	texture->setImage(image.get());

	//关联Texture2D纹理对象,第三个参数默认为ON
	stateset->setTextureAttributeAndModes(0, texture.get(), osg::StateAttribute::ON);

	//启用混合
	stateset->setMode(GL_BLEND, osg::StateAttribute::ON);

	//关闭光照
	stateset->setMode(GL_LIGHTING, osg::StateAttribute::ON);

	return stateset.get();
}
2.2.3 光照关闭示例

在这里插入图片描述

//创建二维纹理状态对象
osg::ref_ptr<osg::StateSet> createTexture2DState(osg::ref_ptr<osg::Image> image)
{
	//创建状态集对象
	osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet();

	//创建二维纹理对象
	osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D();
	texture->setDataVariance(osg::Object::DYNAMIC);

	//设置贴图
	texture->setImage(image.get());

	//关联Texture2D纹理对象,第三个参数默认为ON
	stateset->setTextureAttributeAndModes(0, texture.get(), osg::StateAttribute::ON);

	//启用混合
	stateset->setMode(GL_BLEND, osg::StateAttribute::ON);

	//关闭光照
	stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF);

	return stateset.get();
}

3、多重纹理

  在进行标准的二维纹理映射处理时,一次把一幅纹理图像应用到一个多边形上。多重纹理允许应用几个纹理,在纹理操作管线中把它们逐个应用到同一个多边形上。多重纹理存在一系列的纹理单元,每个纹理单元执行单独的纹理操作,并把它的结果传递给下一个纹理单元,直到所有纹理单元的操作完成为止,最终显示处理后的效果。

  多重纹理映射非常广泛,它能实现一些高级的渲染技巧,如光照、贴花、合成和细节纹理等。在OSG 中实现三维纹理主要有以下几个步骤:
(1)指定用户几何体的纹理坐标。
(2)创建多个纹理属性对象并保存纹理多个图形数据。
(3)为 StateSet 设置合适的纹理属性和模式。

  看起来和二维纹理映射的区别不大,简单地说就是多个二维纹理映射的叠加。但这里需要注意的是,对于不同的纹理属性对象需要指定不同的纹理单元及纹理坐标,否则就不会启用该纹理单元,或者该纹理单元会被覆盖。

2.2 示例效果

  原书上给的示例感觉不太合适不具备说明性,因此自己参照learnopengl实现了多重纹理混合示例。

在这里插入图片描述

2.2 源码

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

#include <windows.h>
#include <osgViewer/Viewer>

#include <osg/Node>
#include <osg/Geode>
#include <osg/Group>
#include <osg/Geometry>
#include <osg/Image>
#include <osg/TexGen>
#include <osg/Texture1D>
#include <osg/TexEnv>
#include <osg/StateSet>
#include <osg/PrimitiveSet>
#include <osgDB/ReadFile>
#include <osgDB/WriteFile>
#include <osgViewer/ViewerEventHandlers> //事件监听
#include <osgGA/StateSetManipulator> //事件响应类,对渲染状态进行控制
#include <osgUtil/Simplifier> //简化几何体

#include <osgUtil/Optimizer>

#pragma comment(lib, "OpenThreadsd.lib")
#pragma comment(lib, "osgd.lib")
#pragma comment(lib, "osgDBd.lib")
#pragma comment(lib, "osgUtild.lib")
#pragma comment(lib, "osgGAd.lib")
#pragma comment(lib, "osgViewerd.lib")
#pragma comment(lib, "osgTextd.lib")

//创建一个四边形节点
osg::ref_ptr<osg::Node> createNode()
{
	osg::ref_ptr<osg::Geode> geode = new osg::Geode();

	osg::ref_ptr<osg::Geometry> geom = new osg::Geometry();

	//设置顶点
	osg::ref_ptr<osg::Vec3Array> vc = new osg::Vec3Array();
	vc->push_back(osg::Vec3(0.0f, 0.0f, 0.0f));
	vc->push_back(osg::Vec3(1.0f, 0.0f, 0.0f));
	vc->push_back(osg::Vec3(1.0f, 0.0f, 1.0f));
	vc->push_back(osg::Vec3(0.0f, 0.0f, 1.0f));

	geom->setVertexArray(vc.get());

	//设置纹理坐标
	osg::ref_ptr<osg::Vec2Array> vt = new osg::Vec2Array();
	vt->push_back(osg::Vec2(0.0f, 0.0f));
	vt->push_back(osg::Vec2(1.0f, 0.0f));
	vt->push_back(osg::Vec2(1.0f, 1.0f));
	vt->push_back(osg::Vec2(0.0f, 1.0f));

	geom->setTexCoordArray(0, vt.get());
	geom->setTexCoordArray(1, vt.get());

	//设置法线
	osg::ref_ptr<osg::Vec3Array> nc = new osg::Vec3Array();
	nc->push_back(osg::Vec3(0.0f, -1.0f, 0.0f));

	geom->setNormalArray(nc.get());
	geom->setNormalBinding(osg::Geometry::BIND_OVERALL);

	//添加图元
	geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, 4));

	//绘制
	geode->addDrawable(geom.get());

	return geode.get();
}

//创建二维纹理状态对象
osg::ref_ptr<osg::StateSet> createTexture2DState()
{
	//读取贴图文件
	osg::ref_ptr<osg::Image> image2 = osgDB::readImageFile("awesomeface.png");
	osg::ref_ptr<osg::Image> image1 = osgDB::readImageFile("container.jpg");

	//创建状态集对象
	osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet();

	//创建二维纹理对象
	osg::ref_ptr<osg::Texture2D> texture1 = new osg::Texture2D();
	texture1->setDataVariance(osg::Object::DYNAMIC);
	//设置贴图
	texture1->setImage(image1.get());
	//关联Texture2D纹理对象,第三个参数默认为ON
	stateset->setTextureAttributeAndModes(0, texture1.get(), osg::StateAttribute::ON);

	//创建二维纹理对象
	osg::ref_ptr<osg::Texture2D> texture2 = new osg::Texture2D();
	texture2->setDataVariance(osg::Object::DYNAMIC);
	//设置贴图
	texture2->setImage(image2.get());
	//关联Texture2D纹理对象,第三个参数默认为ON
	stateset->setTextureAttributeAndModes(1, texture2.get(), osg::StateAttribute::ON);

	//启用混合
	stateset->setMode(GL_BLEND, osg::StateAttribute::ON);

	//关闭光照
	stateset->setMode(GL_LIGHTING, osg::StateAttribute::ON);

	return stateset.get();
}

int main()
{
	osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer();

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

	osg::ref_ptr<osg::Node> node = createNode();

	//创建状态集对象
	osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet();
	stateset = createTexture2DState();

	//使用二维纹理
	node->setStateSet(stateset.get());

	root->addChild(node.get());

	//优化场景数据
	osgUtil::Optimizer optimizer;
	optimizer.optimize(root.get());

	//方便查看在多边形之间切换,以查看三角网
	viewer->addEventHandler(new osgGA::StateSetManipulator(viewer->getCamera()->getOrCreateStateSet()));
	viewer->addEventHandler(new osgViewer::StatsHandler());
	viewer->addEventHandler(new osgViewer::WindowSizeHandler());
	viewer->setSceneData(root.get());
	viewer->setUpViewInWindow(600, 600, 1000, 800);
	return viewer->run();
}

4、Mipmap多级渐远纹理

  在一个动态的场景中,当一个纹理对象迅速远离视点时,纹理图像必须随着被投影的图像一起缩小。为了实现这种效果,可以通过对纹理图像进行过滤,适当对它进行缩小,以使它映射到物体的表面时不会产生抖动或者闪烁的效果。但这时还存在一个问题,就是当视点距离速度变大时,单个纹理缩小为单个像素之前,在经过一些过渡点时,经过过滤的纹理图像会变化非常明显。同时,也没有必要使用一张那么大的纹理数据了;当使用一个很大的、包含很多贴图的场景时,对渲染效率的影响是相当大的。

  为了避免这种突然变化的现象及不必要的渲染负担,可以预先指定一系列分辨率递减的纹理图像。使用 Mipmap 纹理映射必须指定全系列大小为 2 的整数次方的纹理图像,其范围为从最大值到 1×1 的纹理单元。例如,如果最高的纹理分辨率为 32×32,那么必须指定的纹理图像为 32×32、16×16、8×8、4×4、2×2、1×1。通常来说,较小的纹理图像是上一级分辨率的纹理图像的 4 个纹理单元的平均值。当然,这里也没有确定的计算方法,一般是这样计算的。

在 OSG 中使用 Mipmap 纹理映射主要包括下面几个步骤:

(1)将各层的纹理图像数据按照从大到小的顺序(且尺寸必须为 2 的幂次)依次存放到 unsigned char*数组中,将这个数组使用 setImage 送入 Image 对象。
(2)将各层纹理数据在数组中的偏移地址记录到一个 osg::Image::MipmapDataType 列表中,用于选择正确的层次细节纹理图像。
(3)使用 setMipmapLevels()将 MipmapDataType 送入 Image 对象。注意,这一步的次序和 setImage不能颠倒,否则可能无法正确显示各级别的纹理图像。

  在示例程序中,可以看到清晰的纹理图像的各个层次级别细节的明显过渡,这里用颜色代替了纹理。

备注:OpenGL描述如下:当调用glTexImage2D时,当前绑定的纹理对象就会被附加上纹理图像。然而,目前只有基本级别(Base-level)的纹理图像被加载了,如果要使用多级渐远纹理,我们必须手动设置所有不同的图像(不断递增第二个参数)。或者,直接在生成纹理之后调用glGenerateMipmap。这会为当前绑定的纹理自动生成所有需要的多级渐远纹理。生成了纹理和相应的多级渐远纹理后,释放图像的内存并解绑纹理对象是一个很好的习惯。

4.1 示例效果

在这里插入图片描述

4.2 源码

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

#include <windows.h>
#include <osgViewer/Viewer>

#include <osg/Node>
#include <osg/Geode>
#include <osg/Group>
#include <osg/Geometry>
#include <osg/Image>
#include <osg/TexGen>
#include <osg/Texture1D>
#include <osg/TexEnv>
#include <osg/StateSet>
#include <osg/PrimitiveSet>
#include <osgDB/ReadFile>
#include <osgDB/WriteFile>
#include <osgViewer/ViewerEventHandlers> //事件监听
#include <osgGA/StateSetManipulator> //事件响应类,对渲染状态进行控制
#include <osgUtil/Simplifier> //简化几何体

#include <osgUtil/Optimizer>

#pragma comment(lib, "OpenThreadsd.lib")
#pragma comment(lib, "osgd.lib")
#pragma comment(lib, "osgDBd.lib")
#pragma comment(lib, "osgUtild.lib")
#pragma comment(lib, "osgGAd.lib")
#pragma comment(lib, "osgViewerd.lib")
#pragma comment(lib, "osgTextd.lib")

//创建一个四边形
osg::ref_ptr<osg::Geode> createQuad()
{
	osg::ref_ptr<osg::Geode> geode = new osg::Geode();

	osg::ref_ptr<osg::Geometry> geom = new osg::Geometry();
	geode->addDrawable(geom.get());

	//设置顶点
	osg::ref_ptr<osg::Vec3Array> vec = new osg::Vec3Array;
	vec->push_back(osg::Vec3(-10.0f, 0.0f, -10.0f));
	vec->push_back(osg::Vec3(-10.0f, 0.0f, 10.0f));
	vec->push_back(osg::Vec3(10.0f, 0.0f, 10.0f));
	vec->push_back(osg::Vec3(10.0f, 0.0f, -10.0f));

	geom->setVertexArray(vec.get());

	//设置法线
	osg::ref_ptr<osg::Vec3Array> nor = new osg::Vec3Array;
	nor->push_back(osg::Vec3f(0.0f, -1.0f, 0.0f));

	geom->setNormalArray(nor.get());
	geom->setNormalBinding(osg::Geometry::BIND_PER_PRIMITIVE_SET);


	//设置纹理坐标
	osg::ref_ptr<osg::Vec2Array> tex = new osg::Vec2Array;
	tex->push_back(osg::Vec2f(0.0f, 0.0f));
	tex->push_back(osg::Vec2f(0.0f, 1.0f));
	tex->push_back(osg::Vec2f(1.0f, 1.0f));
	tex->push_back(osg::Vec2f(1.0f, 0.0f));

	geom->setTexCoordArray(0, tex.get());

	geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, 4));

	return geode.get();
}

static void fillImage(unsigned char* ptr, unsigned int size)
{
	//黑色
	if (size == 1)
	{
		float r = 0.5f;
		osg::Vec4 color(0.0f, 0.0f, 0.0f, 1.0f);
		*ptr++ = (unsigned char)((color[0]) * 255.0f);
		*ptr++ = (unsigned char)((color[1]) * 255.0f);
		*ptr++ = (unsigned char)((color[2]) * 255.0f);
		*ptr++ = (unsigned char)((color[3]) * 255.0f);
	}

	//白色
	if (size == 2)
	{
		osg::Vec4 color(1.0f, 1.0f, 1.0f, 1.0f);
		for (unsigned int r = 0; r < size; ++r)
		{
			for (unsigned int c = 0; c < size; ++c)
			{
				*ptr++ = (unsigned char)((color[0]) * 255.0f);
				*ptr++ = (unsigned char)((color[1]) * 255.0f);
				*ptr++ = (unsigned char)((color[2]) * 255.0f);
				*ptr++ = (unsigned char)((color[3]) * 255.0f);
			}
		}
	}

	//黄色
	if (size == 4)
	{
		osg::Vec4 color(0.0f, 1.0f, 0.0f, 1.0f);
		for (unsigned int r = 0; r < size; ++r)
		{
			for (unsigned int c = 0; c < size; ++c)
			{
				*ptr++ = (unsigned char)((color[0]) * 255.0f);
				*ptr++ = (unsigned char)((color[1]) * 255.0f);
				*ptr++ = (unsigned char)((color[2]) * 255.0f);
				*ptr++ = (unsigned char)((color[3]) * 255.0f);
			}
		}
	}

	//红色
	if (size == 8)
	{
		osg::Vec4 color(1.0f, 0.0f, 0.0f, 1.0f);
		for (unsigned int r = 0; r < size; ++r)
		{
			for (unsigned int c = 0; c < size; ++c)
			{
				*ptr++ = (unsigned char)((color[0]) * 255.0f);
				*ptr++ = (unsigned char)((color[1]) * 255.0f);
				*ptr++ = (unsigned char)((color[2]) * 255.0f);
				*ptr++ = (unsigned char)((color[3]) * 255.0f);
			}
		}
	}

	//粉红色
	if (size == 16)
	{
		osg::Vec4 color(1.0f, 0.0f, 1.0f, 1.0f);
		for (unsigned int r = 0; r < size; ++r)
		{
			for (unsigned int c = 0; c < size; ++c)
			{
				*ptr++ = (unsigned char)((color[0]) * 255.0f);
				*ptr++ = (unsigned char)((color[1]) * 255.0f);
				*ptr++ = (unsigned char)((color[2]) * 255.0f);
				*ptr++ = (unsigned char)((color[3]) * 255.0f);
			}
		}
	}

	//黄色
	if (size == 32)
	{
		osg::Vec4 color(1.0f, 1.0f, 0.0f, 1.0f);
		for (unsigned int r = 0; r < size; ++r)
		{
			for (unsigned int c = 0; c < size; ++c)
			{
				*ptr++ = (unsigned char)((color[0]) * 255.0f);
				*ptr++ = (unsigned char)((color[1]) * 255.0f);
				*ptr++ = (unsigned char)((color[2]) * 255.0f);
				*ptr++ = (unsigned char)((color[3]) * 255.0f);
			}
		}
	}

	//蓝绿色
	if (size == 64)
	{
		osg::Vec4 color(0.0f, 1.0f, 1.0f, 1.0f);
		for (unsigned int r = 0; r < size; ++r)
		{
			for (unsigned int c = 0; c < size; ++c)
			{
				*ptr++ = (unsigned char)((color[0]) * 255.0f);
				*ptr++ = (unsigned char)((color[1]) * 255.0f);
				*ptr++ = (unsigned char)((color[2]) * 255.0f);
				*ptr++ = (unsigned char)((color[3]) * 255.0f);
			}
		}
	}

	//灰白色
	if (size == 128)
	{
		osg::Vec4 color(0.5f, 0.5f, 0.5f, 1.0f);
		for (unsigned int r = 0; r < size; ++r)
		{
			for (unsigned int c = 0; c < size; ++c)
			{
				*ptr++ = (unsigned char)((color[0]) * 255.0f);
				*ptr++ = (unsigned char)((color[1]) * 255.0f);
				*ptr++ = (unsigned char)((color[2]) * 255.0f);
				*ptr++ = (unsigned char)((color[3]) * 255.0f);
			}
		}
	}

	//蓝色
	if (size == 256)
	{
		osg::Vec4 color(0.0f, 0.0f, 1.0f, 1.0f);
		for (unsigned int r = 0; r < size; ++r)
		{
			for (unsigned int c = 0; c < size; ++c)
			{
				*ptr++ = (unsigned char)((color[0]) * 255.0f);
				*ptr++ = (unsigned char)((color[1]) * 255.0f);
				*ptr++ = (unsigned char)((color[2]) * 255.0f);
				*ptr++ = (unsigned char)((color[3]) * 255.0f);
			}
		}
	}
}

int main()
{
	osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer();

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

	//创建一个平面
	osg::ref_ptr<osg::Geode> geode = createQuad();

	osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet();

	osg::ref_ptr<osg::Image> image = new osg::Image();

	//创建一个MipmapDataType列表,用来各层图片数据的偏移地址
	osg::Image::MipmapDataType mipmapData;

	//纹理的尺寸的最大值,必须为2的幂次
	unsigned int s = 256;

	//计算所需分配的数组的大小
	unsigned int totalSize = 0;

	for (unsigned int i = 0; s > 0; s >>= 1, ++i)
	{
		if (i > 0)
		{
			mipmapData.push_back(totalSize);
		}

		totalSize += s * s * 4;
	}

	//申请一个数据
	unsigned char* ptr = new unsigned char[totalSize];

	//设置image的尺寸大小,数据及数据格式
	image->setImage(256, 256, 256, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, ptr, osg::Image::USE_NEW_DELETE, 1);

	//将偏移地址传入imge对象
	image->setMipmapLevels(mipmapData);

	//向image中填充各层数据
	s = 256;
	for (unsigned int i = 0; s > 0; s >>= 1, ++i)
	{
		fillImage(ptr, s);

		ptr += s * s * 4;
	}

	//创建一个二维纹理对象
	osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D;
	//设置贴图
	texture->setImage(0, image.get());
	//设置边界处理为REPEATE
	texture->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
	texture->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);
	//设置滤波
	texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::NEAREST_MIPMAP_NEAREST);
	texture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::NEAREST);
	//启用二维纹理对象
	stateset->setTextureAttributeAndModes(0, texture.get(), osg::StateAttribute::ON);

	geode->setStateSet(stateset.get());

	root->addChild(geode.get());

	//优化场景数据
	osgUtil::Optimizer optimizer;
	optimizer.optimize(root.get());

	//方便查看在多边形之间切换,以查看三角网
	viewer->addEventHandler(new osgGA::StateSetManipulator(viewer->getCamera()->getOrCreateStateSet()));
	viewer->addEventHandler(new osgViewer::StatsHandler());
	viewer->addEventHandler(new osgViewer::WindowSizeHandler());
	viewer->setSceneData(root.get());
	viewer->setUpViewInWindow(600, 600, 1000, 800);
	return viewer->run();
}

5、TextureRectangle矩阵纹理

  TextureRectangle 纹理映射是在 OpenGL 后来版本中的一个扩展——ARB_texture_rectangle,它也是一种二维纹理映射,但它与前面介绍的二维映射有很大的区别。
在这里插入图片描述

  使用 TextureRectangle 纹理映射时有以下几点需要注意:

纹理环绕模式。它并不支持所有的纹理包装模式,只能使用 CLAMP、CLAMP_TO_EDGE 或CLAMP_TO_BORDER,并不支持 REPEAT。
纹理滤波。它只支持NEAREST或者LINEAR,不支持Mipmap滤波,使用它时不能实现Mipmap纹理。
不支持纹理边框。

  对于没有图形学基础的开发人员来说,TextureRectangle 比较容易理解,也非常容易上手,可以简单理解为一个矩形纹理。

5.1 示例效果

在这里插入图片描述

5.2 源码

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

#include <windows.h>
#include <osgViewer/Viewer>

#include <osg/Node>
#include <osg/Geode>
#include <osg/Group>
#include <osg/Geometry>
#include <osg/Image>
#include <osg/TexGen>
#include <osg/Texture1D>
#include <osg/TexEnv>
#include <osg/TextureRectangle>
#include <osg/TexMat>
#include <osg/StateSet>
#include <osg/PrimitiveSet>
#include <osgDB/ReadFile>
#include <osgDB/WriteFile>
#include <osgViewer/ViewerEventHandlers> //事件监听
#include <osgGA/StateSetManipulator> //事件响应类,对渲染状态进行控制
#include <osgUtil/Simplifier> //简化几何体

#include <osgUtil/Optimizer>

#pragma comment(lib, "OpenThreadsd.lib")
#pragma comment(lib, "osgd.lib")
#pragma comment(lib, "osgDBd.lib")
#pragma comment(lib, "osgUtild.lib")
#pragma comment(lib, "osgGAd.lib")
#pragma comment(lib, "osgViewerd.lib")
#pragma comment(lib, "osgTextd.lib")

//创建一个四边形节点
osg::ref_ptr<osg::Node> createNode()
{
	osg::ref_ptr<osg::Geode> geode = new osg::Geode();

	osg::ref_ptr<osg::Geometry> geom = new osg::Geometry();

	//设置顶点
	osg::ref_ptr<osg::Vec3Array> vc = new osg::Vec3Array();
	vc->push_back(osg::Vec3(0.0f, 0.0f, 0.0f));
	vc->push_back(osg::Vec3(1.0f, 0.0f, 0.0f));
	vc->push_back(osg::Vec3(1.0f, 0.0f, 1.0f));
	vc->push_back(osg::Vec3(0.0f, 0.0f, 1.0f));

	geom->setVertexArray(vc.get());

	//设置纹理坐标
	osg::ref_ptr<osg::Vec2Array> vt = new osg::Vec2Array();
	vt->push_back(osg::Vec2(0.0f, 0.0f));
	vt->push_back(osg::Vec2(1.0f, 0.0f));
	vt->push_back(osg::Vec2(1.0f, 1.0f));
	vt->push_back(osg::Vec2(0.0f, 1.0f));

	geom->setTexCoordArray(0, vt.get());

	//设置法线
	osg::ref_ptr<osg::Vec3Array> nc = new osg::Vec3Array();
	nc->push_back(osg::Vec3(0.0f, -1.0f, 0.0f));

	geom->setNormalArray(nc.get());
	geom->setNormalBinding(osg::Geometry::BIND_OVERALL);

	//添加图元
	geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, 4));

	//绘制
	geode->addDrawable(geom.get());

	return geode.get();
}

//创建二维纹理状态对象
osg::ref_ptr<osg::StateSet> createTexture2DState(osg::ref_ptr<osg::Image> image)
{
	//创建状态集对象
	osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet();

	//创建二维纹理对象
	osg::ref_ptr<osg::TextureRectangle> texture = new osg::TextureRectangle();
	texture->setDataVariance(osg::Object::DYNAMIC);
	//设置贴图
	texture->setImage(image.get());

	//设置纹理矩阵,并设置为根据矩阵纹理(TextureRectangle)的大小自动缩放
	//从而允许应用一个矩形纹理到一个纹理坐标不在0-1上
	osg::ref_ptr<osg::TexMat> texmat = new osg::TexMat;
	texmat->setScaleByTextureRectangleSize(true);

	//启用纹理及纹理矩阵
	stateset->setTextureAttributeAndModes(0, texmat.get(), osg::StateAttribute::ON);
	stateset->setTextureAttributeAndModes(0, texture.get(), osg::StateAttribute::ON);

	//关闭光照
	stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF);

	return stateset.get();
}

int main()
{
	osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer();

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

	//读取贴图文件
	osg::ref_ptr<osg::Image> image = osgDB::readImageFile("Images/primitives.gif");

	osg::ref_ptr<osg::Node> node = createNode();

	//创建状态集对象
	osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet();
	stateset = createTexture2DState(image.get());

	//使用二维纹理
	node->setStateSet(stateset.get());

	root->addChild(node.get());

	//优化场景数据
	osgUtil::Optimizer optimizer;
	optimizer.optimize(root.get());

	//方便查看在多边形之间切换,以查看三角网
	viewer->addEventHandler(new osgGA::StateSetManipulator(viewer->getCamera()->getOrCreateStateSet()));
	viewer->addEventHandler(new osgViewer::StatsHandler());
	viewer->addEventHandler(new osgViewer::WindowSizeHandler());
	viewer->setSceneData(root.get());
	viewer->setUpViewInWindow(600, 600, 1000, 800);
	return viewer->run();
}

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

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

相关文章

BatchOutput PDF for Mac(PDF 批量处理软件)

BatchOutput PDF是一款适用于 Mac 的 PDF 批量处理软件。它可以帮助用户将多个 PDF 文件进行异步处理&#xff0c;提高工作效率。 BatchOutput PDF 可以自动化执行许多任务&#xff0c;包括 PDF 文件的打印、转换、分割、压缩、加密、重命名等&#xff0c;而且它还可以将自定义…

公有云频繁宕机引发思考:超越灾难,跨云容灾的未来

近期&#xff0c;阿里云全球服务器和可用区的故障事件导致所有依赖其服务的应用在三个小时内无法使用&#xff0c;这一事件凸显了单一云服务依赖的风险。成千上万的企业和服务瞬间陷入混乱&#xff0c;这不仅仅是技术故障的问题&#xff0c;而是关乎信任、安全和业务连续性的危…

【蓝桥杯选拔赛真题49】python英文转换 青少年组蓝桥杯python 选拔赛STEMA比赛真题解析

目录 python英文转换 一、题目要求 1、编程实现 2、输入输出 二、算法分析

私家车位共享APP-计算机毕业设计源码24384

目 录 摘要 1 绪论 1.1 课题的研究背景 1.2研究内容与研究目标 1.3ssm框架 1.4论文结构与章节安排 2 2 私家车位共享APP系统分析 2.1 可行性分析 2.2 系统流程分析 2.2.1 数据增加流程 2.2.2 数据修改流程 2.2.3数据删除流程 2.3 系统功能分析 2.3.1功能性分析 2…

使用Java将properties转为yaml,保证顺序、实测无BUG版本

使用Java将properties转为yaml 一 前言1.1 顺序错乱的原因1.2 遗漏子节点的原因 二、优化措施三、源码 一 前言 浏览了一圈网上的版本&#xff0c;大多存在以下问题&#xff1a; 转换后顺序错乱遗漏子节点 基于此进行了优化&#xff0c;如果只是想直接转换&#xff0c;可直接…

golang—kafka架构原理快速入门以及自测环境搭建(docker单节点部署)

kafka Apache Kafka 是一个分布式的流处理平台。它具有以下特点&#xff1a; 支持消息的发布和订阅&#xff0c;类似于 RabbtMQ、ActiveMQ 等消息队列支持数据实时处理能保证消息的可靠性投递支持消息的持久化存储&#xff0c;并通过多副本分布式的存储方案来保证消息的容错高…

【代码】考虑区域多能源系统集群协同优化的联合需求侧响应模型(完美复现)

程序名称&#xff1a;考虑区域多能源系统集群协同优化的联合需求侧响应模型 实现平台&#xff1a;matlab-yalmip-cplex/gurobi 代码简介&#xff1a;风电、光伏发电等波动电源接入比例不断提高&#xff0c;使得区域多能源系统中能量转化和协调能力减弱。基于此&#xff0c;该…

orvibo旗下的VS30ZW网关分析之一

概述 从官网的APP支持的智能中枢来看,一共就两种大类: MixPad系列和网关系列 排除MixPad带屏网关外,剩余的设备如下图: 目前在市场上这四种网关已经下市,官方已经宣布停产。所以市场上流通的也几乎绝迹。 从闲鱼市场上可以淘到几个,拿来分析一下,这里我手头有如下的两…

简单字符串处理

答案&#xff1a; #include <stdio.h> #include <string.h> #define MAX 51 //该定义宏为字符串最大长度 int main() {char arr[MAX] { 0 }; gets(arr); //读取存给arrint len 0, i 0, num 0;len strlen(arr); //len代表字符串长度for (i 0; i &l…

【实战教程】PHP如何轻松对接阿里云直播?

1. 配置阿里云直播的推流地址和播放地址 使用阿里云直播功能前&#xff0c;首先需要在阿里云控制台中创建直播应用&#xff0c;然后获取推流地址和播放地址。 推流地址一般格式为&#xff1a; rtmp://{Domain}/{AppName}/{StreamName}?auth_key{AuthKey}-{Timestamp}-{Rand…

Docker安装Elasticsearch以及ik分词器

Elasticsearch 是一个分布式、RESTful 风格的搜索和数据分析引擎&#xff0c;能够解决不断涌现出的各种用例。作为 Elastic Stack 的核心&#xff0c;Elasticsearch 会集中存储您的数据&#xff0c;让您飞快完成搜索&#xff0c;微调相关性&#xff0c;进行强大的分析&#xff…

微服务中配置Nacos热更新

启动Nacos startup.cmd -m standalone 在IDE中启动服务 打开nacos管理后台并选择配置列表 创建配置(这里以日期格式为例) 因为这里配置的是userservice的服务,所以在userservice服务的pom文件中引入依赖 配置一个bootstrap.yml文件 注意这里bootstrap文件中配置过的内容,在app…

一起学docker系列之十五深入了解 Docker Network:构建容器间通信的桥梁

目录 1 前言2 什么是 Docker Network3 Docker Network 的不同模式3.1 桥接模式&#xff08;Bridge&#xff09;3.2 Host 模式3.3 无网络模式&#xff08;None&#xff09;3.4 容器模式&#xff08;Container&#xff09; 4 Docker Network 命令及用法4.1 docker network ls4.2 …

Web安全漏洞分析-XSS(中)

随着互联网的迅猛发展&#xff0c;Web应用的普及程度也愈发广泛。然而&#xff0c;随之而来的是各种安全威胁的不断涌现&#xff0c;其中最为常见而危险的之一就是跨站脚本攻击&#xff08;Cross-Site Scripting&#xff0c;简称XSS&#xff09;。XSS攻击一直以来都是Web安全领…

(动手学习深度学习)第13章 实战kaggle竞赛:树叶分类

文章目录 实战kaggle比赛&#xff1a;树叶分类1. 导入相关库2. 查看数据格式3. 制作数据集4. 数据可视化5. 定义网络模型6. 定义超参数7. 训练模型8. 测试并提交文件 竞赛技术总结1. 技术分析2. 数据方面模型方面3. AutoGluon4. 总结 实战kaggle比赛&#xff1a;树叶分类 kagg…

目标检测常用评价指标

1 基本概念 1.1 IOU(Intersection over Union) 1.2 TP TN FP FN 2. 各种率 3. PR曲线 4. mAP的计算 4.1 AP的计算 4.2 mAP 4.3 mAP0.5和mAP0.5:0.95 1.1 IOU(Intersection over Union) 1.2 TP TN FP FN TP(Truth Positive)&#xff1a; 预测正类&#xff0c;实际正类&#x…

JIT精益理念下SMT物料配送模式的智能化创新

纬湃汽车电子&#xff0c;作为现代汽车电子行业的佼佼者&#xff0c;专注于为全球汽车制造商提供高品质的电子组件。公司致力于通过采用最先进的技术和流程&#xff0c;持续提升产品质量和生产效率。在这一背景下&#xff0c;纬湃汽车电子的SMT车间的转型升级尤为引人关注。 项…

【C++高阶(六)】哈希的应用--位图布隆过滤器

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:C从入门到精通⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习C   &#x1f51d;&#x1f51d; 哈希的应用 1. 前言2. 位图的概念以及定义3. 位…

WEB渗透—反序列化(九)

Web渗透—反序列化 课程学习分享&#xff08;课程非本人制作&#xff0c;仅提供学习分享&#xff09; 靶场下载地址&#xff1a;GitHub - mcc0624/php_ser_Class: php反序列化靶场课程&#xff0c;基于课程制作的靶场 课程地址&#xff1a;PHP反序列化漏洞学习_哔哩哔_…

yolov8 原木识别模型

一、模型介绍 模型基于 yolov8数据集采用SKU-110k&#xff0c;这数据集太大了十几个 G&#xff0c;所以只训练了 10 轮左右就拿来微调了原木数据微调&#xff1a;纯手工标注 200 张左右原木图片&#xff0c;训练 20 轮的效果 PS&#xff1a;因为训练时间比较长 Google 的 Cola…