OpenGl 顯示2D圖像

  • Opengl的認識

Opengl 顯示2D圖像相對於在平臺採用接口的方式,效率上是高一些的,因爲使用了較少的CPU運行時間。

學習Opengl時間不長,僅僅對管道的方法有所瞭解,Shade的方法有時間再去學習;Opengl的 版本有比較多,Qt對Opengl有相應的模塊,不過使用起來和常見的Win32程序有所區別,在Qt中包含了兩個窗口類來支持Opengl,QGLWidget和QOpenglWidget,前者是較爲老的版本,後者是更爲新的類,其實都差別不大。

void initializeGL();用於初始化,
void paintGL();用於繪製各種圖元以及紋理貼圖

  • 紋理貼圖的方法

初始化紋理尺寸的代碼:

unsigned char* image_data = nullptr;
	int pixel_count = CImageW * CImageH;
	DATA_SIZE = pixel_count * 4;
	DATA_SIZE3 = pixel_count * 3;
	image_data = (unsigned char*)malloc(sizeof(unsigned char) * DATA_SIZE);
	for (int i = 0; i < pixel_count; i++) {
		image_data[i * 4 + 0] = 255;
		image_data[i * 4 + 1] = 255;
		image_data[i * 4 + 2] = 255;
		image_data[i * 4 + 3] = 255;
	}
	glGenTextures(1, &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, 0, GL_BGRA, CImageW, CImageH, 0, GL_BGRA, GL_UNSIGNED_BYTE, image_data);
	free(image_data);
	

如果採用交換緩存區的方法來紋理貼圖,還需要進一步綁定兩個“乒乓”buffer,相關知識點:http://www.songho.ca/opengl/gl_pbo.html

glGenBuffersARB(2, pboIds);
	glBindBufferARB(GL_PIXEL_UNPACK_BUFFER, pboIds[0]);
	glBufferDataARB(GL_PIXEL_UNPACK_BUFFER, DATA_SIZE3, 0, GL_STREAM_DRAW);
	glBindBufferARB(GL_PIXEL_UNPACK_BUFFER, pboIds[1]);
	glBufferDataARB(GL_PIXEL_UNPACK_BUFFER, DATA_SIZE3, 0, GL_STREAM_DRAW);
	glBindBufferARB(GL_PIXEL_UNPACK_BUFFER, 0);

實際上測試,並沒有官方說的提高得很明顯,儘管glTexImage2D函數幾乎不耗時,綁定緩存的效率也並非很高。

另外有一些筆記本電腦的顯卡好像是不支持的這中方法的,也就是glTexImage2D函數的調用依然很耗時。

顯示函數代碼:

如果是簡單的直接顯示

glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, (GLsizei)HwManager.getImageWidth(), (GLsizei)HwManager.getImageHeight(), GL_BGR, GL_UNSIGNED_BYTE, pGLBuffer);
GLenum result = glGetError();
qDebug() << "GLenum:" << result;
GLdouble viewMatrix[16];
glGetDoublev(GL_MODELVIEW_MATRIX, viewMatrix);
GLdouble projectionMatrix[16];
glGetDoublev(GL_PROJECTION_MATRIX, projectionMatrix);
GLint    viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);


glBindTexture(GL_TEXTURE_2D, texture);
glBindBufferARB(GL_PIXEL_UNPACK_BUFFER, pboIds[index]);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, (GLsizei)HwManager.getImageWidth(), (GLsizei)HwManager.getImageHeight(), GL_BGR, GL_UNSIGNED_BYTE, 0);
// start to modify pixel values ///////////////////
// bind PBO to update pixel values
glBindBufferARB(GL_PIXEL_UNPACK_BUFFER, pboIds[nextIndex]);
// map the buffer object into client's memory
// Note that glMapBuffer() causes sync issue.
// If GPU is working with this buffer, glMapBuffer() will wait(stall)
// for GPU to finish its job. To avoid waiting (stall), you can call
// first glBufferData() with NULL pointer before glMapBuffer().
// If you do that, the previous data in PBO will be discarded and
// glMapBuffer() returns a new allocated pointer immediately
// even if GPU is still working with the previous data.
glBufferDataARB(GL_PIXEL_UNPACK_BUFFER, DATA_SIZE3, 0, GL_STREAM_DRAW);
ptr = (GLubyte*)glMapBufferARB(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);
if (ptr)
{
	//
	if (pGLBuffer != NULL)
	{
		mutex.lock();
		memcpy(ptr, pGLBuffer, DATA_SIZE3);
		//ptr = pGLBuffer;
		mutex.unlock();
	}
	glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER);  // release pointer to mapping buffer
}
glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER);  // release pointer to mapping buffer
// measure the time modifying the mapped buffer
// it is good idea to release PBOs with ID 0 after use.
// Once bound with 0, all pixel operations behave normal ways.
glBindBufferARB(GL_PIXEL_UNPACK_BUFFER, 0);

Qt 中使用拓展函數需要窗口類區繼承一些Qt的封裝類。

class myQtOpenglWindow :public QGLWidget,protected QOpenGLFunctions, protected QOpenGLExtension_ARB_vertex_buffer_object
{
...

}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章