Previously, CG was used. Now, glsl is used and learning is required again. However, many of the two languages are the same.
The following example is a simple program for drawing a triangle. Some new OpenGL features such as VBO (veretx buffer object) and VAO (vertex array object) are used. More and more development in the future, the programmable pipeline will certainly be the trend of the times. The contents of some of the original fixed pipelines in OpenGL will certainly be discarded. Therefore, from now on, writing programs should develop a good habit of using new features and programmable pipeline technology.
1. Introduction to VAO and VBO
With the removal of OpenGL status and fixed pipeline mode, we do not use any glable function call, nor do we have function calls such as glvertex and glcolor. This means we need a new way to transfer data to the graphics card to render the image. We can use VBO or a new feature introduced in opengl3 or later, called VAO. Through it, we can store vertex data and color in different VBO, but in the same VAO. The same is true for normal data or other vertex information.
VAO directly stores the object information in the graphics card, rather than transmitting it to the graphics card as needed. This is the method used by direct3d, which is used in OpenGL only in opengl3.x and later versions. This means that our applications do not need to transmit data to the graphics card or output data from the graphics card, which leads to additional performance improvements.
It is not difficult to use VAO. Instead of calling glvertex, we store vertex data in an array, put it into VBO, and finally store relevant States in VAO. Remember: VAO does not store vertex-related attribute data. OpenGL will complete other functions for us in the background.
Steps for using VAO:
1. Generate VAO
Void glgenvertexarrays (glsizei N,
Gluint * arrays );
N: Number of VAO objects to be generated.
Arrays: name of the generated VAO object.
2. Bind VAO
Void glbindvertexarray (gluint array );
Array: the name of the vertex array to be bound.
3. Generate VBOs
Void glgenbuffers (glsizei
N,
Gluint *
Buffers );
Name of the buffer object generated.
The parameter description is similar to that of glgenvertexarrays.
4. Bind VBOs
Void glbindbuffer (glenum
Target,
Gluint
Buffer );
Bind a buffer object.
The target value may be gl_array_buffer, gl_element_array_buffer, gl_pixel_pack_buffer, or gl_pixel_unpack_buffer.
After binding, the previous binding will become invalid.
5. Allocate data to VBO:
Void glbufferdata (glenum target,
Glsizeiptr size,
Const glvoid * data,
Glenum usage );
The target value may be gl_array_buffer (indicating vertex data), gl_element_array_buffer (indicating index data), and gl_pixel_pack_buffer (indicating pixel data obtained from OpenGL ), or gl_pixel_unpack_buffer (indicating the pixel data passed to OpenGL ).
Parameter description:
Size: number of bytes of the buffer object
Data: pointer: point to the data used to copy to the buffer object. Or null, indicating that no data is allocated.
6. Define an array for storing vertex attribute data:
First, you must enable the corresponding vertex attribute array in VAO:
Void glenablevertexattribarray (gluint index );
Index: Specifies the index of the vertex attribute array to be enabled.
Note: It is available only in opengl2.0 and later versions.
7. specify data for the corresponding vertex attribute array:
Void glvertexattribpointer (gluint index,
Glint size,
Glenum type,
Glboolean normalized,
Glsizei stride,
Const glvoid * pointer );
Index: Index of the array of the vertex attribute of the data to be specified.
Size: the number of data records for each vertex attribute. The possible values are 1, 2, 3, or 4. The initial value is 4.
Type: the type of each data in the array. Possible values: gl_byte, gl_unsigned_byte, gl_short, gl_unsigned_short, gl_int, gl_unsigned_int, gl_float, or gl_double. The initial value is gl_float.
Normalized: Specifies whether the number of vertices needs to be normalized when accessed.
Note: If a non-zero buffer object is bound to gl_array_buffer, pointer is the offset of the corresponding buffer object.
Stride: the offset between two consecutive vertex attributes.
Pointer: point to the first data of the first vertex attribute in the array.
8. Then, when performing rendering, you only need to bind the corresponding VAO to facilitate the operation.
Glbindvertexarray (vaohandle );
9. after use, clear the binding.
Glbindvertexarray (0 );
VAO references:
VAO Wiki
A blog about VAO
VAO
In fact, in this simple program, VAO is not required, and VBO can be used only. The use of VAO can further improve performance, and the use of VAO in later versions of OpenGL will be gradually discarded.
Ii. Getting started with glsl
For details about glsl, refer to the appendix of hongbao, which describes the introduction of glsl.
There is also a good getting started tutorial in English:
Getting started with glsl tutorial
3. program instance
Below is the source code (implemented by OpenGL and glsl ):
Basic. Vert:
// It is required to support a specific version of glsl # version 400in vec3 vertexposition; In vec3 vertexcolor; out vec3 color; void main () {color = vertexcolor; gl_position = vec4 (vertexposition, (1.0 );}
Basic. Frag:
#version 400in vec3 Color;out vec4 FragColor;void main(){FragColor = vec4(Color,1.0);}
Main file:
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; // Vertex coloring machine object // float positiondata array [] = {-0.8f,-0.8f, 0.0f, 0.8f,-0.8f, 0.0f, 0.0f, 0.8f, 0.0f}; // color array float colordata [] = {1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f}; gluint vaohandle; // vertex array objectvoid initshader (const char * Haderfile, const char * fshaderfile) {// 1. view the glsl and OpenGL versions. Const glubyte * Renderer = glgetstring (gl_renderer); const glubyte * vendor = glgetstring (gl_vendor ); const glubyte * version = glgetstring (gl_version); const glubyte * glslversion = glgetstring (signature); glint major, minor; glgetintegerv (signature, & major); getglintegerv (signature, & 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. Compile the shader // to create the shader object: vertex shader vshader = glcreateshader (gl_vertex_shader); // If (0 = vshader) {cerr <"error: Create vertex shader failed" <Endl; exit (1);} // set the source code and the color. Object const glchar * vshadercode = textfileread (vshaderfile); const glchar * vcodearray [1] = {vshadercode}; glshadersource (vshader, 1, vcodearray, null ); // compile the colorator object glcompileshader (vshader); // check whether the compilation is successful glint compileresult; glgetshaderiv (vshader, gl_compile_status, & compileresult); If (gl_false = compileresult) {glint loglen; // obtain the length of the compiled log glgetshaderiv (vshader, gl_info_log_length, & loglen); If (loglen> 0) {char * log = (CH Ar *) malloc (loglen); glsizei written; // obtain the log information and output glgetshaderinfolog (vshader, loglen, & written, log); cerr <"vertex shader compile log: "<Endl; cerr <log <Endl; free (log); // release space} // create a coloring er object: fragment shader fshader = glcreateshader (gl_fragment_shader); // Error Detection If (0 = fshader) {cerr <"error: Create fragment shader failed" <Endl; exit (1);} // associate the source code and the object of the shader with const glchar * fshadercode = textfileread (fshaderfile); Const glchar * fcodearray [1] = {fshadercode}; glshadersource (fshader, 1, fcodearray, null); // compile the shader object glcompileshader (fshader ); // check whether the compilation is successful. glgetshaderiv (fshader, gl_compile_status, & compileresult); If (gl_false = compileresult) {glint loglen; // obtain the length of the compiled log, & loglen); If (loglen> 0) {char * log = (char *) malloc (loglen); glsizei written; // obtain the log information and output glgetshaderinfolog (fshader, logl En, & written, log); cerr <"fragment shader compile log:" <Endl; cerr <log <Endl; free (log ); // release space} // 3. link the shader object // create the shader program gluint programhandle = glcreateprogram (); If (! Programhandle) {cerr <"error: Create program failed" <Endl; exit (1) ;}// link the shader program to glattachshader (programhandle, vshader); glattachshader (programhandle, fshader); // link these objects into an executable program gllinkprogram (programhandle); // query the result of the link glint linkstatus; glgetprogramiv (programhandle, gl_link_status, & linkstatus); If (gl_false = linkstatus) {cerr <"error: link shader program failed" <Endl; glint loglen; glgetprogram IV (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 // link successful, use the rendering program {gluseprogram (programhandle) ;}} void initvbo () {// create and populate the buffer objectsgluint vbohandles [2]; glgenbuffers (2, vbohandles) in the OpenGL pipeline ); gluint position Bufferhandle = vbohandles [0]; gluint colorbufferhandle = vbohandles [1]; // bind a VBO to use the callback (callback, positionbufferhandle); // load data to vboglbufferdata (gl_array_buffer, 9 * sizeof (float), positiondata, callback); // bind VBO for glbindbuffer (gl_array_buffer, colorbufferhandle); // load data to vboglbufferdata (gl_array_buffer, 9 * sizeof (float), colordata, gl_static_draw); glgenvertexarrays (1, & vaohandle); glbindve Rtexarray (vaohandle); vertex (0); // vertex coordinate glablevertexattribarray (1); // vertex color // before calling the vertex, You need to bind glbindbuffer (gl_array_buffer, positionbufferhandle ); round (0, 3, gl_float, gl_false, 0, (glubyte *) null); glbindbuffer (gl_array_buffer, colorbufferhandle); Round (1, 3, gl_float, gl_false, 0, (glubyte *) null);} void Init () {// initialize the glew extension library glenum E RR = 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 ); //// draw a triangle (using the normal method) // 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 (); // use VAO and VBO to draw glbindvertexarray (vaohandle); gldrawarrays (gl_triangles ); glbindvertexarray (0); fig ();} void keyboard (unsigned char key, int X, int y) {Switch (key) {Case 27: gldeleteshader (vshader ); gluseprogram (0); break;} int main (INT argc, char ** argv) {gluinit (& argc, argv); gluinitdisplaymode (glu_double | glu_rgb ); gluinitwindowsize (600,600); gluinitwindowposition (100,100); glucreatewindow ("glsl test: Draw a triangle"); Init (); gludisplayfunc (Display); glukeyboardfunc (keyboard); glumainloop (); return 0 ;}
The program that reads the shader file:
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);}
Running result: