基于OpenGL编写一个简易的2D渲染框架-04 绘制图片
阅读文章前需要了解的知识,纹理:https://learnopengl-cn.github.io/01%20Getting%20started/06%20Textures/
过程简述:利用 FreeImage 库加载图像数据,再创建 OpenGL 纹理,通过 Canvas2D 画布绘制,最后又 Renderer 渲染器渲染
本来想用 soil 库加载图像数据的,虽然方便,但是加载有些格式的图像文件时会出现一些问题。最后,改用 FreeImage 库来加载图像了。
添加 FreeImage 库到工程
解压 FreeImage.rar 文件后得到三个文件
将其分别拷贝到 debug文件夹、External 文件夹、Lib 文件夹中,再链接上 lib 库。
绘制图片
创建一个纹理结构,储存纹理索引、大小以及纹理坐标
struct DLL_export Texture
{
Rect size;
Vec2 texcoords[]; GLuint texture;
};
创建一个纹理管理器类 TextureManager,用于创建和管理纹理。
利用 FreeImage 库加载纹理
Texture* TexrureManager::createTexture(const char* filename)
{
GLuint texture = -;
std::string fullName = PathHelper::fullPath(filename); unsigned char* image_data = nullptr;
FIBITMAP* bmp = nullptr; /* 初始化 FreeImage */
FreeImage_Initialise(TRUE); /* 获取图像文件类型 */
FREE_IMAGE_FORMAT fif = FIF_UNKNOWN;
fif = FreeImage_GetFileType(fullName.c_str()); if ( fif == FIF_UNKNOWN ) {
fif = FreeImage_GetFIFFromFilename(fullName.c_str());
}
/* 加载所支持图像类型的图像 */
if ( (fif != FIF_UNKNOWN) && FreeImage_FIFSupportsReading(fif) ) {
bmp = FreeImage_Load(fif, fullName.c_str(), JPEG_DEFAULT);
}
if ( !bmp ) return nullptr; int w = FreeImage_GetWidth(bmp);
int h = FreeImage_GetHeight(bmp);
int pixel_count = w * h; int byte_per_pixel = FreeImage_GetLine(bmp) / w;
image_data = ( unsigned char* ) malloc(sizeof( unsigned char ) * pixel_count * ); unsigned char* bits = FreeImage_GetBits(bmp); int current_pixel = ;
if ( byte_per_pixel == ) {
for ( int i = ; i < pixel_count; i++ ) {
image_data[i * + ] = bits[current_pixel++];
image_data[i * + ] = bits[current_pixel++];
image_data[i * + ] = bits[current_pixel++];
image_data[i * + ] = bits[current_pixel++];
}
}
else {
for ( int i = ; i < pixel_count; i++ ) {
image_data[i * + ] = bits[current_pixel++];
image_data[i * + ] = bits[current_pixel++];
image_data[i * + ] = bits[current_pixel++];
image_data[i * + ] = ;
}
} if ( bmp ) FreeImage_Unload(bmp);
FreeImage_DeInitialise(); glGenTextures(, &texture);
glBindTexture(GL_TEXTURE_2D, texture); /* 设置纹理选项 */
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, , GL_RGBA, w, h, , GL_RGBA, GL_UNSIGNED_BYTE, image_data);
glBindTexture(GL_TEXTURE_2D, ); free(image_data); Texture* tex = new Texture();
tex->texture = texture;
tex->size.set(, , w, h);
tex->texcoords[].set(, );
tex->texcoords[].set(, );
tex->texcoords[].set(, );
tex->texcoords[].set(, ); return tex;
}
在函数中,使用 FreeImage 库加载纹理数据,然后创建 OpenGL 2D纹理,将创建的纹理保存到 Texture 结构中,并设置了纹理坐标。
在 Canvas2D 中绘制纹理
void Canvas2D::drawTexture(int x, int y, Texture* texture, Color& color)
{
int w = texture->size.w;
int h = texture->size.h; this->resizeVector(, );
vPositions[].set(x + , y + , );
vPositions[].set(x + , y + h, );
vPositions[].set(x + w, y + h, );
vPositions[].set(x + w, y + , ); vIndices[] = ;
vIndices[] = ;
vIndices[] = ;
vIndices[] = ;
vIndices[] = ;
vIndices[] = ; static RenderUnit unit;
unit.pPositions = &vPositions[];
unit.nPositionCount = ;
unit.pTexcoords = texture->texcoords;
unit.pIndices = &vIndices[];
unit.nIndexCount = ;
unit.color = color;
unit.texture = texture;
unit.renderType = RENDER_TYPE_TEXTURE; pRenderer->pushRenderUnit(unit);
}
函数很简单,设置了顶点数据并填充了 RenderUnit,再传到 渲染器中渲染。与绘制几何图形相比,多了纹理坐标,并把渲染类型设置为 渲染纹理。
渲染器 Renderer 渲染纹理
添加成员
std::map<Texture*, VertexData*> textureDatas;
每张纹理都有其相应的顶点数据,这样可以把多张相同纹理的顶点数据放到一个缓冲区中渲染,保证了渲染多张相同纹理时只使用使用一个 DrawCall(调用 函数 glDrawElements 进行绘制的次数),提高渲染效率。
在 pushRenderUnit 函数中
else if ( unit.renderType == RENDER_TYPE_TEXTURE ) {
auto it = textureDatas.find(unit.texture);
if ( it == textureDatas.end() ) {
vertexData = new VertexData();
vertexData->bHasTexcoord = true;
vertexData->renderType = RENDER_TYPE_TEXTURE;
textureDatas.insert(std::make_pair(unit.texture, vertexData));
}
else {
vertexData = it->second;
}
}
索引出纹理对应的 VertexData,然后填充数据。最后的渲染函数中添加填充纹理坐标代码
/* 设置纹理 */
if ( vertexData->bHasTexcoord ) {
glBindBuffer(GL_ARRAY_BUFFER, texcoordBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof( Vec2 ) * vertexData->nPositionCount, &vertexData->texcoords[], GL_DYNAMIC_DRAW); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texrure);
glUniform1i(glGetUniformLocation(shaderProgram, "defaulteTexture"), );
}
为了能够渲染纹理需要更改着色程序
顶点着色器
#version core layout(location = ) in vec3 Position;
layout(location = ) in vec2 Texcoord;
layout(location = ) in vec4 Color; out vec2 texcoord;
out vec4 color; uniform int bRenderTexture; void main()
{
gl_Position = vec4(Position, 1.0f);
color = Color; if( bRenderTexture != ){
texcoord = Texcoord;
}
}
片段着色器
#version core out vec4 Color; in vec2 texcoord;
in vec4 color; uniform sampler2D defaultTexture;
uniform int bRenderTexture; void main()
{
if( bRenderTexture != ){
Color = texture(defaultTexture, texcoord) * color * color.w;
}
else{
Color = color;
}
}
为了开启 Alpha 效果,设置OpenGL 的混合状态
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
在主函数中添加绘制图像的代码
Texture* texture = TexrureManager::instance()->getTexture("image.png");
Texture* texture1 = TexrureManager::instance()->getTexture("image.jpg");
canvas.drawTexture(, , texture1, Color(, , , ));
canvas.drawTexture(, , texture, Color(, , , 0.8));
程序的运行结果
这里绘制了 png 和 jpg 格式的图像
源码下载:http://pan.baidu.com/s/1skOmP21
基于OpenGL编写一个简易的2D渲染框架-04 绘制图片的更多相关文章
- 基于OpenGL编写一个简易的2D渲染框架-05 渲染文本
阅读文章前需要了解的知识:文本渲染 https://learnopengl-cn.github.io/06%20In%20Practice/02%20Text%20Rendering/ 简要步骤: 获 ...
- 基于OpenGL编写一个简易的2D渲染框架-06 编写一个粒子系统
在这篇文章中,我将详细说明如何编写一个简易的粒子系统. 粒子系统可以模拟许多效果,下图便是这次的粒子系统的显示效果.为了方便演示,就弄成了一个动图. 图中,同时显示了 7 种不同粒子效果,看上去效果挺 ...
- 基于OpenGL编写一个简易的2D渲染框架-01 创建窗口
最近正在学习OpenGL,我认为学习的最快方法就是做一个小项目了. 如果对OpenGL感兴趣的话,这里推荐一个很好的学习网站 https://learnopengl-cn.github.io/ 我用的 ...
- 基于OpenGL编写一个简易的2D渲染框架-03 渲染基本几何图形
阅读文章前需要了解的知识,你好,三角形:https://learnopengl-cn.github.io/01%20Getting%20started/04%20Hello%20Triangle/ 要 ...
- 基于OpenGL编写一个简易的2D渲染框架-02 搭建OpenGL环境
由于没有使用GLFW库,接下来得费一番功夫. 阅读这篇文章前请看一下这个网页:https://learnopengl-cn.github.io/01%20Getting%20started/02%20 ...
- 基于OpenGL编写一个简易的2D渲染框架-08 重构渲染器-整体架构
事实上,前面编写的渲染器 Renderer 非常简陋,虽然能够进行一些简单的渲染,但是它并不能满足我们的要求. 当渲染粒子系统时,需要开启混合模式,但渲染其他顶点时却不需要开启混合模式.所以同时渲染粒 ...
- 基于OpenGL编写一个简易的2D渲染框架-09 重构渲染器-Shader
Shader 只是进行一些简单的封装,主要功能: 1.编译着色程序 2.绑定 Uniform 数据 3.根据着色程序的顶点属性传递顶点数据到 GPU 着色程序的编译 GLuint Shader::cr ...
- 基于OpenGL编写一个简易的2D渲染框架-11 重构渲染器-Renderer
假如要渲染一个纯色矩形在窗口上,应该怎么做? 先确定顶点的格式,一个顶点应该包含位置信息 vec3 以及颜色信息 vec4,所以顶点的结构体定义可以这样: struct Vertex { Vec3 p ...
- 基于OpenGL编写一个简易的2D渲染框架-10 重构渲染器-Pass
Pass,渲染通路,一个渲染通路指的是一次像素处理和一次顶点处理,也就是指的是一次绘制.简单来说就是顶点数据在渲染管线中走一遍最后绘制. 渲染粒子系统的粒子时,需要开启 OpenGL 的混合模式,并使 ...
随机推荐
- 【python】实例-把两个无规则的序列连接成一个序列,并删除重复的元素,新序列按照升序排序
list_one=[3,6,2,17,7,33,11,7] list_two=[1,2,3,7,4,2,17,33,11] list_new=list_one+list_two list=[] i=0 ...
- 读书笔记:Sheldon.M.Ross:概率论基础教程:2014.01.22
贝叶斯公式与全概率公式 全概率公式:如果一件事情的发生有多个可能途径,那么这件事情的发生概率就是在不同途径下此事件发生的条件概率的加权平均.权值为各途径本身的发生概率. 贝叶斯公式:通过例子说明其含义 ...
- VS2010安装顽疾解决方法:error 25541 failed to open xml file
一.问题描述 因为之前(2012)对HDFS客户端Thrift接口的库文件封装使用的是VS2010,最近考虑做一个完整的网盘系统的客户端,就把该库文件使用起来,比较悲剧的是之前做过操作系统的还原.我的 ...
- Java网络编程(读书笔记)
部分片段: 早期web服务器由于Http链接短暂而有所掩盖,由于web页面和嵌入式的图片一般很小(至少与通常通过FTP获取软件包要小很多),由于web浏览器在获取各个文件后挂起连接,而不是一次保持数分 ...
- 学习笔记之Cloud computing
Cloud computing - Wikipedia https://en.wikipedia.org/wiki/Cloud_computing
- 学习笔记之数据库Database
SQL@Wiki http://en.wikipedia.org/wiki/SQL 一篇文章,掌握所有开源数据库的现状 - AI前线 https://mp.weixin.qq.com/s?__biz= ...
- 用linux的iconv函数 转换编码
inux shell 配置文件中默认的字符集编码为UTF-8 .UTF-8是unicode的一种表达方式,gb2312是和unicode都是字符的编码方式,所以说gb2312跟utf-8的概念应该不是 ...
- 1019 General Palindromic Number (20 分)
1019 General Palindromic Number (20 分) A number that will be the same when it is written forwards or ...
- 扫盲贴,802.11AD
早在去年,大家已经开始关注新的802.11ad规范,其高频高带宽低延迟的特性也让大家对将来的无线网络应用形态充满了期待,而今年的CES2016展会上,已经有不少的802.11ad产品出现,看来2016 ...
- Intellij IDEA 中如何查看maven项目中所有jar包的依赖关系图
Maven 组件界面介绍 如上图标注 1 所示,为常用的 Maven 工具栏,其中最常用的有: 第一个按钮:Reimport All Maven Projects 表示根据 pom.xml 重新载入项 ...