In this article, the main implementation is how to use OpenGL to draw a triangle and rectangle, I divided into the next few steps to illustrate:
- OpenGL language GLSL
- Compile the language of OpenGL
- Creating a vertex buffer
- Let me draw the graph
OpenGL language GLSL
It is similar to C in that you can declare variables (a_Position), have an entry function for main, and have built-in variables (gl_Position).
attribute vec3 a_Position;
void main(void) {
gl_Position = vec4(a_Position, 1.0);
}
Copy the code
Using the language OpenGL
Like our code, to use these GLSLS, you need to compile them and load them into memory. There are three steps in the loading and compiling process:
- Load the Shader string
- Creates a Shader object from a string
- Compile the Shader object
- (GLuint)compileShader:(NSString *)shaderName withType:(GLenum)shaderType {
// Load the shader string
NSString *shaderPath = [[NSBundle mainBundle] pathForResource:shaderName ofType:nil];
NSError *error;
NSString *shaderString = [NSString stringWithContentsOfFile:shaderPath encoding:NSUTF8StringEncoding error:&error];
if(! shaderString) {NSLog(@"Error loading shader: %@", error.localizedDescription);
return - 1;
}
//shader
GLuint shaderHandle = glCreateShader(shaderType);
// Convert the string code to shader
const char * shaderStringUTF8 = [shaderString UTF8String];
int shaderStringLength = (int)[shaderString length];
glShaderSource(shaderHandle, 1, &shaderStringUTF8, &shaderStringLength);
/ / compile a shader
glCompileShader(shaderHandle);
// Check the compilation result
GLint compileSuccess;
glGetShaderiv(shaderHandle, GL_COMPILE_STATUS, &compileSuccess);
if (compileSuccess == GL_FALSE) {
GLchar messages[256];
glGetShaderInfoLog(shaderHandle, sizeof(messages), 0, &messages[0]);
NSString *messageString = [NSString stringWithUTF8String:messages];
NSLog(@ "% @", messageString);
return - 1;
}
return shaderHandle;
}
Copy the code
Once compiled, we also need to create a pipe to pass the compiled stuff in memory to the GPU. The updated data from the CPU is sent to the GPU through this pipeline.
- (void)compileVertexShader:(NSString *)vertexShader
fragmentShader:(NSString *)fragmentShader {
GLuint vertexShaderName = [self compileShader:vertexShader
withType:GL_VERTEX_SHADER];
GLuint fragmentShaderName = [self compileShader:fragmentShader
withType:GL_FRAGMENT_SHADER];
/ / create the program
_programHandle = glCreateProgram();
// Bind shader
glAttachShader(_programHandle, vertexShaderName);
glAttachShader(_programHandle, fragmentShaderName);
glLinkProgram(_programHandle);
// Check the program result
GLint linkSuccess;
glGetProgramiv(_programHandle, GL_LINK_STATUS, &linkSuccess);
if (linkSuccess == GL_FALSE) {
GLchar messages[256];
glGetProgramInfoLog(_programHandle, sizeof(messages), 0, &messages[0]);
NSString *messageString = [NSString stringWithUTF8String:messages];
NSLog(@ "% @", messageString);
}
// Remove the shaders, they are already linked to our program and are no longer needed
glDeleteShader(vertexShaderName);
glDeleteShader(fragmentShaderName);
}
Copy the code
Creating a vertex buffer
We draw two graphs here, so we create two vertex buffers and store the corresponding vertex coordinates in the vertex buffers.
- (void)setupVBO {
GLfloat triangleVertices[] = {
0.4.0.0.0.0.0.0.0.4.0.0.0.5.0.0.0.0}; glGenBuffers(1, &_triangleVBO);
glBindBuffer(GL_ARRAY_BUFFER, _triangleVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(triangleVertices), triangleVertices, GL_STATIC_DRAW);
GLfloat rectangleVertices[] = {
0.4.0.4.0.0.0.4.0.8.0.0.0.4.0.8.0.0.0.4.0.4.0.0}; glGenBuffers(1, &_rectangleVBO);
glBindBuffer(GL_ARRAY_BUFFER, _rectangleVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(rectangleVertices), rectangleVertices, GL_STATIC_DRAW);
}
Copy the code
Let me draw the graph
We specify which channel to use, and then transfer data through that channel and display it.glEnableVertexAttribArray(0)
Represents the binding of the first parameter in the GLSL we wrote.glDrawArrays(GL_TRIANGLES, 0, 3)
Draw three points in a triangle.glDrawArrays(GL_TRIANGLE_FAN, 0, 4)
Draw four points in the form of a triangle ray and draw two triangles.
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
GLKView *glView = (GLKView *)self.view;
[EAGLContext setCurrentContext:glView.context];
glClearColor(0.0.0.1);
glClear(GL_COLOR_BUFFER_BIT);
[_triangleShader prepareToDraw];
glBindBuffer(GL_ARRAY_BUFFER, _triangleVBO);
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glDrawArrays(GL_TRIANGLES, 0.3);
[_rectangleShader prepareToDraw];
glBindBuffer(GL_ARRAY_BUFFER, _rectangleVBO);
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glDrawArrays(GL_TRIANGLE_FAN, 0.4);
}
Copy the code
Running the project, you can see a triangle and a rectangle, both red. Making the address