OpenGL进行简单的通用计算实例
博主作为OpenGL新手,最近要用OpenGL进行并行的数据计算,突然发现这样的资料还是很少的,大部分资料和参考书都是讲用OpenGL进行渲染的。好不容易找到一本书《GPGPU编程技术,从OpenGL、CUDA到OpenCL》,里面对并行处理的发展进行了系统性的介绍,还是很不错的。小白博主很兴奋,看完书中第三章后恍然大悟了很多,就贴出书中代码3-3的例子,实现一番,并用一副图片数据做了实现。
实现环境:Window7 32bit, VS2013+OpenGL3.3+GLEW+GLFW。
OpenGL用来进行通用数据计算的流程如下图,数据从CPU(应用程序)中通过“用绘制来调用”发送到纹理缓存,以纹理映射的方式给到着色器,最后经过片段着色器的计算(GLSL语言)后,再将结果输出到纹理缓存,最后CPU(应用程序)再从纹理缓存中读取结果数据,至此计算完成。

1.书中代码3-3,输入一组数据到纹理缓存,然后再从纹理缓存中读取这组数据,代码以及实验结果如下:
数据类型就设置为float,将数据发送至纹理缓存要用这个函数glTexSubImage2D( );
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#define GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.h>
using namespace std;
#define WIDTH 2
#define HEIGHT 3
int main(int argc, char** argv)
{
int nWidth=(int)WIDTH;
int nHeight=(int)HEIGHT;
int nSize=(int)nWidth*nHeight; //创建输入数据
float* pfInput=new float[*nSize];
float* pfOutput=new float[*nSize];
for (int i=; i<nSize*; i++)
{
pfInput[i]= (float)(i + 1.2345);
}
//初始化并设置GLFW
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, );
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, );
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
//创建GLFW窗口
GLFWwindow* window = glfwCreateWindow(, , "LearnOpenGL", nullptr, nullptr);
glfwMakeContextCurrent(window);
//初始化GLEW
//glewExperimental = GL_TRUE;
glewInit(); //创建FBO并绑定
GLuint fb;
glGenFramebuffersEXT(, &fb);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb); //创建纹理对象并绑定
GLuint tex;
glGenTextures(, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
//设置纹理参数
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); //将纹理关联到FBO
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, tex, ); //将纹理数据设置为单精度浮点数
glTexImage2D(GL_TEXTURE_2D, , GL_RGBA_FLOAT32_ATI, nWidth, nHeight,, GL_RGBA, GL_FLOAT, NULL);
//将数据传至输入纹理缓存
//glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, nWidth, nHeight, 0, GL_RGBA, GL_FLOAT, pfInput);
glTexSubImage2D(GL_TEXTURE_2D, , , , nWidth, nHeight, GL_RGBA, GL_FLOAT, pfInput); //从输出纹理缓存中读出数据
glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
glReadPixels(,, nWidth, nHeight, GL_RGBA, GL_FLOAT, pfOutput); //打印并检查结果
bool bCap=true;
for (int i=; i<nSize*; i++)
{
cout<<i<<":\t"<<pfInput[i]<<'\t'<<pfOutput[i]<<endl;
if (pfInput[i]!=pfOutput[i]) bCap=false;
} if (bCap) cout<<"Round trip complete!"<<endl;
else cout<<"Round trip failed!" <<endl; delete pfInput;
delete pfOutput;
glDeleteFramebuffers(, &fb);
glDeleteTextures(, &tex); system("pause"); return ;
}

2.读取一幅图像,写入纹理缓存并从纹理缓存读出,配合OpenCV使用。代码如下(原理差不多):
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#define GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <opencv.hpp>
using namespace std;
using namespace cv;
#define WIDTH 2
#define HEIGHT 3
int main(int argc, char** argv)
{
//读取图像
Mat srcImg=imread("./lena.jpg");
Mat dstImg=Mat::zeros(srcImg.size(), srcImg.type()); int nWidth=srcImg.cols;
int nHeight=srcImg.rows;
int nSize=(int)nWidth*nHeight; //BGR转换到RGB空间
cvtColor(srcImg, srcImg, CV_BGR2RGB);
cvtColor(dstImg, dstImg, CV_BGR2RGB); //获取图像数据指针
uchar* puInput=srcImg.data;
uchar* puOutput=dstImg.data; //初始化并设置GLFW
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, );
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, );
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
//创建GLFW窗口
GLFWwindow* window = glfwCreateWindow(, , "LearnOpenGL", nullptr, nullptr);
glfwMakeContextCurrent(window);
//初始化GLEW
glewExperimental = GL_TRUE;
glewInit(); //创建FBO并绑定
GLuint fb;
glGenFramebuffersEXT(, &fb);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb); //创建纹理对象并绑定
GLuint tex;
glGenTextures(, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
//设置纹理参数
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
//将纹理关联到FBO
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, ); //将数据传至输入纹理缓存
glTexImage2D(GL_TEXTURE_2D, , GL_RGB, nWidth, nHeight, , GL_RGB, GL_UNSIGNED_BYTE, puInput); //从输出纹理缓存中读出数据
glReadPixels(,, nWidth, nHeight, GL_RGB, GL_UNSIGNED_BYTE, puOutput); //保存输出图像
imwrite("./LenaIsBack.jpg", dstImg); glDeleteFramebuffers(, &fb);
glDeleteTextures(, &tex); system("pause"); return ;
}
数据类型要设置为unsigned_byte,将数据送至纹理缓存要用这个函数glTexImage2D();最终保存出来的结果我没有再转换到BGR空间,所以输入的Lena和输出的Lena将会下面这样(仅供参考,哈哈)~:

其实最好设置两个纹理缓存对象,一个用于输入,一个用于输出,把输出的纹理缓存绑定的FBO(帧缓冲对象)。用GLSL语言在着色器中写出需要进行计算的算法就可以实现通用数据的处理了。对了,渲染的窗口还是要建立的,这样OpenGL以为它是在进行渲染到屏幕的操作,其实我们通过帧缓冲和纹理缓冲实现的是通用数据计算的过程。
今天就到这里,我继续去看书了,每天进步一点点点点。
OpenGL进行简单的通用计算实例的更多相关文章
- 审核流(3)低调奢华,简单不凡,实例演示-SNF.WorkFlow--SNF快速开发平台3.1
下面我们就从什么都没有,结合审核流进行演示实例.从无到有如何快速完美的实现,然而如此简单.低调而奢华,简单而不凡. 从只有数据表通过SNF.CodeGenerator代码生成器快速生成单据并与审核流进 ...
- 初学redux笔记,及一个最简单的redux实例
categories: 笔记 tags: react redux 前端框架 把初学redux的一些笔记写了下来 分享一个入学redux很合适的demo, 用redux实现计数器 这是从阮一峰老师git ...
- HTML与CSS简单页面效果实例
本篇博客实现一个HTML与CSS简单页面效果实例 index.html <!DOCTYPE html> <html> <head> <meta charset ...
- Java Tread多线程(0)一个简单的多线程实例
作者 : 卿笃军 原文地址:http://blog.csdn.net/qingdujun/article/details/39341887 本文演示,一个简单的多线程实例,并简单分析一下线程. 编程多 ...
- 使用ssm(spring+springMVC+mybatis)创建一个简单的查询实例(三)(错误整理篇)
使用ssm(spring+springMVC+mybatis)创建一个简单的查询实例(一) 使用ssm(spring+springMVC+mybatis)创建一个简单的查询实例(二) 以上两篇已经把流 ...
- 使用ssm(spring+springMVC+mybatis)创建一个简单的查询实例(二)(代码篇)
这篇是上一篇的延续: 用ssm(spring+springMVC+mybatis)创建一个简单的查询实例(一) 源代码在github上可以下载,地址:https://github.com/guoxia ...
- 使用ssm(spring+springMVC+mybatis)创建一个简单的查询实例(一)
梳理下使用spring+springMVC+mybatis 整合后的一个简单实例:输入用户的 ID,之后显示用户的信息(此次由于篇幅问题,会分几次进行说明,此次是工程的创建,逆向生成文件以及这个简单查 ...
- 使用JAVA实现的一个简单IOC注入实例
https://blog.csdn.net/echoshinian100/article/details/77977823 欲登高而望远,勿筑台于流沙 RSS订阅 原 使用JAVA实现的一个简单IOC ...
- Qt5.9一个简单的多线程实例(类QThread)(第一种方法)
Qt开启多线程,主要用到类QThread.有两种方法,第一种用一个类继承QThread,然后重新改写虚函数run().当要开启新线程时,只需要实例该类,然后调用函数start(),就可以开启一条多线程 ...
随机推荐
- 再谈javascript面向对象编程
前言:虽有陈皓<Javascript 面向对象编程>珠玉在前,但是我还是忍不住再画蛇添足的补上一篇文章,主要是因为javascript这门语言魅力.另外这篇文章是一篇入门文章,我也是才开始 ...
- JavaScript的DOM编程--05--获取文本节点
获取文本节点: 1). 步骤: 元素节点 --> 获取元素节点的子节点 2). 若元素节点只有文本节点一个子节点, 例如 <li id="bj" name=" ...
- Python并发实践_03_并发实战之一
16S数据质控流程,一次下机lane包括很多的项目,每个项目有独立的合同号,一个项目可能包含16S或者ITS两种,通过一个完整的pipeline,将上游拆分好的数据全部整理成可以直接分析的数据.原本这 ...
- 利用layer实现MVC页面数据互交提示弹框
需求说明: 一个表单页面,点击提交之后,进入后台进行一系列数据交互,然后将交互信息返回至页面中,并以弹框形式展示 应用场景: 添加.修改.删除数据后,返回数据操作是否成功,以及一些其他信息 前期准备: ...
- Head First设计模式之解释器模式
一.定义 给定一个语言,定义它的文法表示,并定义一个解释器,这个解释器使用该标识来解释语言中的句子. 主要解决:对于一些固定文法构建一个解释句子的解释器. 何时使用:如果一种特定类型的问题发生的频率足 ...
- Tempdb总结
Tempdb 系统数据库是一个全局资源,可供连接到 SQL Server 实例的所有用户使用,并可用于保存下列各项: 显式创建的临时用户对象,例如全局或局部临时表.临时存储过程.表变量或游标. SQL ...
- Maven构建项目比较慢的解决办法
[前言] Intellij IDEA下Maven构建项目时,构建项目速度比较慢.需要等好久才能构建好一个项目,有时候一下午也还在提示进度. [问题描述] 使用Maven构建项目时: 设置好各种参数,然 ...
- windows 纤程
纤程本质上也是线程,是多任务系统的一部分,纤程为一个线程准并行方式调用多个不同函数提供了一种可能,它本身可以作为一种轻量级的线程使用.它与线程在本质上没有区别,它也有上下文环境,纤程的上下文环境也是一 ...
- windows平台调用函数堆栈的追踪方法
在windows平台,有一个简单的方法来追踪调用函数的堆栈,就是利用函数CaptureStackBackTrace,但是这个函数不能得到具体调用函数的名称,只能得到地址,当然我们可以通过反汇编的方式通 ...
- ReSharper 全教程
Resharper系列 更多关于Resharper的介绍 参考我之前的文章: Resharper 详细教程 提升ReSharper和Visual Studio的性能 Visual Studio中使用R ...