日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

【OpenGL4.0】GLSL渲染语言入门与VBO、VAO使用:绘制一个三角形

發布時間:2023/12/10 87 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【OpenGL4.0】GLSL渲染语言入门与VBO、VAO使用:绘制一个三角形 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

以前都是用Cg的,現在改用GLSL,又要重新學,不過兩種語言很多都是相通的。


下面的例子是實現繪制一個三角形的簡單程序。采用了VBO(veretx buffer object)、VAO(vertex array object)等OpenGL的一些新特性。越往后發展,可編程管線肯定是大勢所趨,OpenGL里原來的一些固定管線的內容肯定會被廢棄掉。所以從現在開始寫程序就要養成使用新特性、采用可編程管線技術的好習慣。


一、VAO、VBO介紹

隨著OpenGL狀態和固定管線模式的移除,我們不在用任何glEnable函數調用,而且也不會有glVertex、glColor等函數調用。這就意味著我們需要一種新的方式來將數據傳輸到圖形卡以渲染圖形。我們可以采用VBO,或者是在OpenGL3以上版本引入的新的特性,叫做VAO。通過它,我們可以把頂點數據和顏色存儲在不同的VBO中,但是在同一個VAO中。對于法線數據或者其他的頂點信息也是一樣。

VAO,是這樣一種方式:把對象信息直接存儲在圖形卡中,而不是在當我們需要的時候傳輸到圖形卡。這就是Direct3D所采用得方式,而在OpenGL中只有OpenGL3.X以上的版本中采用。這就意味著我們的應用程序不用將數據傳輸到圖形卡或者是從圖形卡輸出,這樣也就獲得了額外的性能提升。

使用VAO并不難。我們不需要大量的glVertex調用,而是把頂點數據存儲在數組中,然后放進VBO,最后在VAO中存儲相關的狀態。記住:VAO中并沒有存儲頂點的相關屬性數據。OpenGL會在后臺為我們完成其他的功能。

?

使用VAO的步驟:

1、產生VAO

void glGenVertexArrays(GLsizei n,
? GLuint *arrays);

n:要產生的VAO對象的數量。

arrays:存放產生的VAO對象的名稱。

2、綁定VAO

void glBindVertexArray(GLuint array);

array:要綁定的頂點數組的名字。

3、產生VBOs

void glGenBuffers(GLsizei ?n,
? GLuint * ? buffers);

產生緩沖區對象的名稱。

參數含義和glGenVertexArrays類似。

4、綁定VBOs

void glBindBuffer(GLenum ?target,
? GLuint ? buffer);

綁定一個緩沖區對象。

target可能取值是:GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER, GL_PIXEL_PACK_BUFFER, or GL_PIXEL_UNPACK_BUFFER.

當進行綁定之后,以前的綁定就失效了。

5、給VBO分配數據:

void glBufferData(?? GLenum? ??????? target,

??????? GLsizeiptr? ??? size,

??????? const GLvoid *? ????? data,

??????? GLenum? ??????? usage);

target可能取值為:GL_ARRAY_BUFFER(表示頂點數據), GL_ELEMENT_ARRAY_BUFFER(表示索引數據),GL_PIXEL_PACK_BUFFER(表示從OpenGL獲取的的像素數據), or GL_PIXEL_UNPACK_BUFFER(表示傳遞給OpenGL的像素數據).

參數含義:

size:緩沖區對象字節數

data:指針:指向用于拷貝到緩沖區對象的數據。或者是NULL,表示暫時不分配數據。

6、定義存放頂點屬性數據的數組:

首先需要啟用VAO中對應的頂點屬性數組:

void glEnableVertexAttribArray(????? GLuint? ? index);

index:指定了需要啟用的頂點屬性數組的索引

注意:它只在OpenGL2.0及其以上版本才有。

7、給對應的頂點屬性數組指定數據:

void glVertexAttribPointer(????? GLuint? ? index,

??????? GLint? ??? size,

??????? GLenum? ??????? type,

??????? GLboolean? ?? normalized,

??????? GLsizei? stride,

??????? const GLvoid *? ????? pointer);

index:要指定數據的頂點屬性數組的索引。

size:每個頂點屬性的數據個數。可能的取值是1、2、3或者4.初始值是4.

type:數組中每個數據的類型。可能的取值是:GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_INT, GL_UNSIGNED_INT, GL_FLOAT, or GL_DOUBLE。初始值是GL_FLOAT。

normalized:指定頂點數在被訪問的時候是否需要被歸一化。

注意:如果有個非零的緩沖對象綁定到GL_ARRAY_BUFFER,那么pointer就是對應的緩沖區對象的偏移量。

?stride:兩個連續頂點的屬性之間的偏移量。

pointer:指向數組中的第一個頂點屬性的第一個數據。

8、然后在進行渲染的時候,只需要綁定對應的VAO即可,操作起來十分方便。

glBindVertexArray(vaoHandle);

9、使用完畢之后需要清除綁定。

glBindVertexArray(0);


VAO參考資料:

VAO wiki

關于VAO的一篇博客

VAO

事實上,在這個簡單的程序中,不用VAO,只用VBO也一樣可以實現。只是采用VAO可以進一步提升性能,而且在較新版本的OpenGL中不用VAO的方式會被逐漸廢棄。


二、GLSL入門

關于GLSL,可以參考紅寶書的附錄,上面介紹了GLSL的入門知識。

這里也有一個很好的入門教程,英文的:

GLSL入門tutorial



三、程序實例

下面貼出源代碼(OpenGL,GLSL實現):

basic.vert:

  • //強制要求支持一個特定版本的GLSL版本
  • #version 400
  • in vec3 VertexPosition;
  • in vec3 VertexColor;
  • out vec3 Color;
  • void main()
  • {
  • Color =VertexColor;
  • gl_Position = vec4(VertexPosition,1.0);
  • }
  • basic.frag:

  • #version 400
  • in vec3 Color;
  • out vec4 FragColor;
  • void main()
  • {
  • FragColor = vec4(Color,1.0);
  • }
  • 主文件:

    main.cpp:

  • #pragma comment(lib,"glew32.lib")
  • #include <GL/glew.h>
  • #include "textfile.h"
  • #include <GL/glut.h>
  • #include <iostream>
  • using namespace std;
  • GLuint vShader,fShader;//頂點著色器對象
  • //頂點位置數組
  • float positionData[] = {
  • -0.8f, -0.8f, 0.0f,
  • 0.8f, -0.8f, 0.0f,
  • 0.0f, 0.8f, 0.0f };
  • //顏色數組
  • float colorData[] = {
  • 1.0f, 0.0f, 0.0f,
  • 0.0f, 1.0f, 0.0f,
  • 0.0f, 0.0f, 1.0f };
  • GLuint vaoHandle;//vertex array object
  • void initShader(const char *VShaderFile,const char *FShaderFile)
  • {
  • //1、查看GLSL和OpenGL的版本
  • const GLubyte *renderer = glGetString( GL_RENDERER );
  • const GLubyte *vendor = glGetString( GL_VENDOR );
  • const GLubyte *version = glGetString( GL_VERSION );
  • const GLubyte *glslVersion =
  • glGetString( GL_SHADING_LANGUAGE_VERSION );
  • GLint major, minor;
  • glGetIntegerv(GL_MAJOR_VERSION, &major);
  • glGetIntegerv(GL_MINOR_VERSION, &minor);
  • cout << "GL Vendor :" << vendor << endl;
  • cout << "GL Renderer : " << renderer << endl;
  • cout << "GL Version (string) : " << version << endl;
  • cout << "GL Version (integer) : " << major << "." << minor << endl;
  • cout << "GLSL Version : " << glslVersion << endl;
  • //2、編譯著色器
  • //創建著色器對象:頂點著色器
  • vShader = glCreateShader(GL_VERTEX_SHADER);
  • //錯誤檢測
  • if (0 == vShader)
  • {
  • cerr << "ERROR : Create vertex shader failed" << endl;
  • exit(1);
  • }
  • //把著色器源代碼和著色器對象相關聯
  • const GLchar *vShaderCode = textFileRead(VShaderFile);
  • const GLchar *vCodeArray[1] = {vShaderCode};
  • glShaderSource(vShader,1,vCodeArray,NULL);
  • //編譯著色器對象
  • glCompileShader(vShader);
  • //檢查編譯是否成功
  • GLint compileResult;
  • glGetShaderiv(vShader,GL_COMPILE_STATUS,&compileResult);
  • if (GL_FALSE == compileResult)
  • {
  • GLint logLen;
  • //得到編譯日志長度
  • glGetShaderiv(vShader,GL_INFO_LOG_LENGTH,&logLen);
  • if (logLen > 0)
  • {
  • char *log = (char *)malloc(logLen);
  • GLsizei written;
  • //得到日志信息并輸出
  • glGetShaderInfoLog(vShader,logLen,&written,log);
  • cerr << "vertex shader compile log : " << endl;
  • cerr << log << endl;
  • free(log);//釋放空間
  • }
  • }
  • //創建著色器對象:片斷著色器
  • fShader = glCreateShader(GL_FRAGMENT_SHADER);
  • //錯誤檢測
  • if (0 == fShader)
  • {
  • cerr << "ERROR : Create fragment shader failed" << endl;
  • exit(1);
  • }
  • //把著色器源代碼和著色器對象相關聯
  • const GLchar *fShaderCode = textFileRead(FShaderFile);
  • const GLchar *fCodeArray[1] = {fShaderCode};
  • glShaderSource(fShader,1,fCodeArray,NULL);
  • //編譯著色器對象
  • glCompileShader(fShader);
  • //檢查編譯是否成功
  • glGetShaderiv(fShader,GL_COMPILE_STATUS,&compileResult);
  • if (GL_FALSE == compileResult)
  • {
  • GLint logLen;
  • //得到編譯日志長度
  • glGetShaderiv(fShader,GL_INFO_LOG_LENGTH,&logLen);
  • if (logLen > 0)
  • {
  • char *log = (char *)malloc(logLen);
  • GLsizei written;
  • //得到日志信息并輸出
  • glGetShaderInfoLog(fShader,logLen,&written,log);
  • cerr << "fragment shader compile log : " << endl;
  • cerr << log << endl;
  • free(log);//釋放空間
  • }
  • }
  • //3、鏈接著色器對象
  • //創建著色器程序
  • GLuint programHandle = glCreateProgram();
  • if (!programHandle)
  • {
  • cerr << "ERROR : create program failed" << endl;
  • exit(1);
  • }
  • //將著色器程序鏈接到所創建的程序中
  • glAttachShader(programHandle,vShader);
  • glAttachShader(programHandle,fShader);
  • //將這些對象鏈接成一個可執行程序
  • glLinkProgram(programHandle);
  • //查詢鏈接的結果
  • GLint linkStatus;
  • glGetProgramiv(programHandle,GL_LINK_STATUS,&linkStatus);
  • if (GL_FALSE == linkStatus)
  • {
  • cerr << "ERROR : link shader program failed" << endl;
  • GLint logLen;
  • glGetProgramiv(programHandle,GL_INFO_LOG_LENGTH,
  • &logLen);
  • if (logLen > 0)
  • {
  • char *log = (char *)malloc(logLen);
  • GLsizei written;
  • glGetProgramInfoLog(programHandle,logLen,
  • &written,log);
  • cerr << "Program log : " << endl;
  • cerr << log << endl;
  • }
  • }
  • else//鏈接成功,在OpenGL管線中使用渲染程序
  • {
  • glUseProgram(programHandle);
  • }
  • }
  • void initVBO()
  • {
  • // Create and populate the buffer objects
  • GLuint vboHandles[2];
  • glGenBuffers(2, vboHandles);
  • GLuint positionBufferHandle = vboHandles[0];
  • GLuint colorBufferHandle = vboHandles[1];
  • //綁定VBO以供使用
  • glBindBuffer(GL_ARRAY_BUFFER,positionBufferHandle);
  • //加載數據到VBO
  • glBufferData(GL_ARRAY_BUFFER,9 * sizeof(float),
  • positionData,GL_STATIC_DRAW);
  • //綁定VBO以供使用
  • glBindBuffer(GL_ARRAY_BUFFER,colorBufferHandle);
  • //加載數據到VBO
  • glBufferData(GL_ARRAY_BUFFER,9 * sizeof(float),
  • colorData,GL_STATIC_DRAW);
  • glGenVertexArrays(1,&vaoHandle);
  • glBindVertexArray(vaoHandle);
  • glEnableVertexAttribArray(0);//頂點坐標
  • glEnableVertexAttribArray(1);//頂點顏色
  • //調用glVertexAttribPointer之前需要進行綁定操作
  • glBindBuffer(GL_ARRAY_BUFFER, positionBufferHandle);
  • glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, 0, (GLubyte *)NULL );
  • glBindBuffer(GL_ARRAY_BUFFER, colorBufferHandle);
  • glVertexAttribPointer( 1, 3, GL_FLOAT, GL_FALSE, 0, (GLubyte *)NULL );
  • }
  • void init()
  • {
  • //初始化glew擴展庫
  • GLenum err = glewInit();
  • if( GLEW_OK != err )
  • {
  • cout <<"Error initializing GLEW: " << glewGetErrorString(err) << endl;
  • }
  • initShader("basic.vert","basic.frag");
  • initVBO();
  • glClearColor(0.0,0.0,0.0,0.0);
  • //glShadeModel(GL_SMOOTH);
  • }
  • void display()
  • {
  • glClear(GL_COLOR_BUFFER_BIT);
  • 繪制一個三角形(使用普通方法)
  • //glBegin(GL_TRIANGLES);
  • //glColor3f(0.0f,1.0f,0.0f);
  • //glVertex3f(0.0f,1.0f,0.0f);
  • //glColor3f(0.0f,1.0f,0.0f);
  • //glVertex3f(-1.0f,-1.0f,0.0f);
  • //glColor3f(0.0f,0.0f,1.0f);
  • //glVertex3f(1.0f,-1.0f,0.0f);
  • //glEnd();
  • //使用VAO、VBO繪制
  • glBindVertexArray(vaoHandle);
  • glDrawArrays(GL_TRIANGLES,0,3);
  • glBindVertexArray(0);
  • glutSwapBuffers();
  • }
  • void keyboard(unsigned char key,int x,int y)
  • {
  • switch(key)
  • {
  • case 27:
  • glDeleteShader(vShader);
  • glUseProgram(0);
  • break;
  • }
  • }
  • int main(int argc,char** argv)
  • {
  • glutInit(&argc,argv);
  • glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
  • glutInitWindowSize(600,600);
  • glutInitWindowPosition(100,100);
  • glutCreateWindow("GLSL Test : Draw a triangle");
  • init();
  • glutDisplayFunc(display);
  • glutKeyboardFunc(keyboard);
  • glutMainLoop();
  • return 0;
  • }

  • 讀取shader文件的程序:

    textfile.h:

  • // textfile.h: interface for reading and writing text files
  • #ifndef TEXTFILE_H
  • #define TEXTFILE_H
  • #include <stdio.h>
  • #include <stdlib.h>
  • #include <string.h>
  • char *textFileRead(const char *fn);
  • int textFileWrite(char *fn, char *s);
  • unsigned char *readDataFromFile(char *fn);
  • #endif
  • textfile.cpp:
  • // textfile.cpp
  • // simple reading and writing for text files
  • #include "textfile.h"
  • unsigned char * readDataFromFile(char *fn)
  • {
  • FILE *fp;
  • unsigned char *content = NULL;
  • int count=0;
  • if (fn != NULL) {
  • fp = fopen(fn,"rb");
  • if (fp != NULL) {
  • fseek(fp, 0, SEEK_END);
  • count = ftell(fp);
  • rewind(fp);
  • if (count > 0) {
  • content = (unsigned char *)malloc(sizeof(unsigned char) * (count+1));
  • count = fread(content,sizeof(unsigned char),count,fp);
  • content[count] = '\0';
  • }
  • fclose(fp);
  • }
  • }
  • return content;
  • }
  • char *textFileRead(const char *fn) {
  • FILE *fp;
  • char *content = NULL;
  • int count=0;
  • if (fn != NULL) {
  • fp = fopen(fn,"rt");
  • if (fp != NULL) {
  • fseek(fp, 0, SEEK_END);
  • count = ftell(fp);
  • rewind(fp);
  • if (count > 0) {
  • content = (char *)malloc(sizeof(char) * (count+1));
  • count = fread(content,sizeof(char),count,fp);
  • content[count] = '\0';
  • }
  • fclose(fp);
  • }
  • }
  • return content;
  • }
  • int textFileWrite(char *fn, char *s) {
  • FILE *fp;
  • int status = 0;
  • if (fn != NULL) {
  • fp = fopen(fn,"w");
  • if (fp != NULL) {
  • if (fwrite(s,sizeof(char),strlen(s),fp) == strlen(s))
  • status = 1;
  • fclose(fp);
  • }
  • }
  • return(status);
  • }
  • 運行結果:

    總結

    以上是生活随笔為你收集整理的【OpenGL4.0】GLSL渲染语言入门与VBO、VAO使用:绘制一个三角形的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。