Introduction to OpenGL ES on Xcode
OpenGL ES (Embedded Systems) is a cross-platform API for rendering 2D and 3D graphics. It is widely used in mobile devices, including iOS and Android platforms. In this article, we will explore how to create a 3D sphere and apply texture to it using OpenGL ES on Xcode.
Prerequisites
Before diving into the code, make sure you have:
- Xcode installed on your Mac
- A basic understanding of Objective-C programming language
- A familiarity with iOS development
Setting Up the Project
Create a new project in Xcode and select “Application” under the template selection page. In the next step, choose “iOS App” as the product type.
Next, create an empty file named Shader.m
and write the following code:
#import <Foundation/Foundation.h>
@interface Shader : NSObject {
NSString *vertexShaderSource;
NSString *fragmentShaderSource;
}
@property (nonatomic, copy) NSString *vertexShaderSource;
@property (nonatomic, copy) NSString *fragmentShaderSource;
@end
@implementation Shader
@synthesize vertexShaderSource = _vertexShaderSource;
@synthesize fragmentShaderSource = _fragmentShaderSource;
- (instancetype)init {
self = [super init];
if (self) {
// Initialize shaders here
}
return self;
}
- (void)setVertexShaderSource:(NSString *)vertexShaderSource {
_vertexShaderSource = vertexShaderSource;
}
- (void)setFragmentShaderSource:(NSString *)fragmentShaderSource {
_fragmentShaderSource = fragmentShaderSource;
}
@end
Creating a Sphere
To create a sphere, we will use the GLKMatrix4
class to define a 4x4 matrix. The sphere’s position and radius are defined using this matrix.
Firstly, add the following code in your ViewController.m
file:
#import <GLKit/GLKit.h>
@interface ViewController () {
GLKMatrix4 modelMatrix;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Initialize sphere model matrix here
}
Next, write a function to create the sphere model matrix:
- (GLKMatrix4)sphereModelMatrix:(float)radius {
GLKMatrix4 sphereModel = GLKMatrix4MakeIdentity();
sphereModel.m00 = 1 / radius;
sphereModel.m11 = -1 / radius;
sphereModel.m22 = 1 / radius;
sphereModel.m33 = (float)sqrt(1 - (float)pow(radius, 2));
sphereModel.m02 = 0.0;
sphereModel.m13 = 0.0;
return sphereModel;
}
Now, create a function to draw the sphere:
- (void)drawSphere {
GLKMatrix4 modelMatrix = [self sphereModelMatrix:100.0f];
// Set up vertex data for the sphere
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 3, NULL);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 3, (void*)(&modelMatrix.m00));
// Create and set up the shader
Shader *shader = [[Shader alloc] init];
[shader setVertexShaderSource:@"#version 150\nin vec4 vertexPosition;\nout vec2 texCoord0;\nvoid main() {\n gl_Position = projectionMatrix * modelViewMatrix * vertexPosition;\n texCoord0 = (vertexPosition.xy - vec2(1.0, 1.0)) / vec2(-1.0, -1.0);\n}"];
[shader setFragmentShaderSource:@"#version 150\nin vec2 texCoord0;\nout vec4 fragColor;\nvoid main() {\n fragColor = texture(iResolution.xy, texCoord0) * 0.5 + 0.5;\n}"];
// Set up the view matrix
GLKMatrix4 viewMatrix = GLKMatrix4MakeTranslation(0, -100, -400);
// Create and set up the model-view-projection matrix
GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspectiveFOV(GL_PI / 2.0f, GLKMatrix4Identity(), 0.1f, 10000.0f);
GLKMatrix4 projectionViewMatrix = GLKMatrix4Multiply(projectionMatrix, viewMatrix);
// Set up the model-view matrix
GLKMatrix4 modelViewMatrix = GLKMatrix4Multiply(modelMatrix, GLKMatrix4MakeTranslation(0, -100, -400));
// Create and set up the uniform matrices
glUniformMatrix4fv(glGetUniformLocation(shader.shaderProgram, "projection"), 1, GL_FALSE, projectionViewMatrix.data);
glUniformMatrix4fv(glGetUniformLocation(shader.shaderProgram, "model"), 1, GL_FALSE, modelViewMatrix.data);
}
Applying Texture
To apply a texture to the sphere, we will use the GLKVector2
class to define the UV coordinates for each face of the sphere.
Firstly, write an OpenGL ES code snippet in your ViewController.m file:
- (void)drawSphere {
// ... existing drawSphere function
// Set up vertex data for the texture coordinates
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 6, NULL);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 6, (void*)(&modelMatrix.m00));
}
Next, write an OpenGL ES code snippet to create the texture map:
- (void)drawSphere {
// ... existing drawSphere function
// Set up vertex data for the texture coordinates
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 6, NULL);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 6, (void*)(&modelMatrix.m00));
// Create and set up the shader
Shader *shader = [[Shader alloc] init];
[shader setVertexShaderSource:@"#version 150\nin vec4 vertexPosition;\nout vec2 texCoord0;\nvoid main() {\n gl_Position = projectionMatrix * modelViewMatrix * vertexPosition;\n texCoord0 = (vertexPosition.xy - vec2(1.0, 1.0)) / vec2(-1.0, -1.0);\n}"];
[shader setFragmentShaderSource:@"#version 150\nin vec2 texCoord0;\nout vec4 fragColor;\nvoid main() {\n // Calculate the UV coordinates based on the vertex position
float u = (texCoord0.x + 0.5) / 1;
float v = (texCoord0.y + 0.5) / 1;
// Apply a texture to the sphere
vec4 textureValue = texture2D(iResolution, vec2(u, v));
fragColor = textureValue * 0.5 + 0.5;\n}"];
// Set up the view matrix
GLKMatrix4 viewMatrix = GLKMatrix4MakeTranslation(0, -100, -400);
// Create and set up the model-view-projection matrix
GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspectiveFOV(GL_PI / 2.0f, GLKMatrix4Identity(), 0.1f, 10000.0f);
GLKMatrix4 projectionViewMatrix = GLKMatrix4Multiply(projectionMatrix, viewMatrix);
// Set up the model-view matrix
GLKMatrix4 modelViewMatrix = GLKMatrix4Multiply(modelMatrix, GLKMatrix4MakeTranslation(0, -100, -400));
// Create and set up the uniform matrices
glUniformMatrix4fv(glGetUniformLocation(shader.shaderProgram, "projection"), 1, GL_FALSE, projectionViewMatrix.data);
glUniformMatrix4fv(glGetUniformLocation(shader.shaderProgram, "model"), 1, GL_FALSE, modelViewMatrix.data);
}
Using a Texture
To use the generated texture map, create and set up the texture object in your ViewController.m file:
- (void)drawSphere {
// ... existing drawSphere function
// Create and set up the shader
Shader *shader = [[Shader alloc] init];
[shader setVertexShaderSource:@"#version 150\nin vec4 vertexPosition;\nout vec2 texCoord0;\nvoid main() {\n gl_Position = projectionMatrix * modelViewMatrix * vertexPosition;\n texCoord0 = (vertexPosition.xy - vec2(1.0, 1.0)) / vec2(-1.0, -1.0);\n}"];
[shader setFragmentShaderSource:@"#version 150\nin vec2 texCoord0;\nout vec4 fragColor;\nvoid main() {\n // Calculate the UV coordinates based on the vertex position
float u = (texCoord0.x + 0.5) / 1;
float v = (texCoord0.y + 0.5) / 1;
// Load the texture
vec4 textureValue = texture2D(iResolution, vec2(u, v));
// Apply a texture to the sphere
fragColor = textureValue * 0.5 + 0.5;\n}"];
// Set up the view matrix
GLKMatrix4 viewMatrix = GLKMatrix4MakeTranslation(0, -100, -400);
// Create and set up the model-view-projection matrix
GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspectiveFOV(GL_PI / 2.0f, GLKMatrix4Identity(), 0.1f, 10000.0f);
GLKMatrix4 projectionViewMatrix = GLKMatrix4Multiply(projectionMatrix, viewMatrix);
// Set up the model-view matrix
GLKMatrix4 modelViewMatrix = GLKMatrix4Multiply(modelMatrix, GLKMatrix4MakeTranslation(0, -100, -400));
// Create and set up the uniform matrices
glUniformMatrix4fv(glGetUniformLocation(shader.shaderProgram, "projection"), 1, GL_FALSE, projectionViewMatrix.data);
glUniformMatrix4fv(glGetUniformLocation(shader.shaderProgram, "model"), 1, GL_FALSE, modelViewMatrix.data);
}
Conclusion
This article provided a basic example of how to create a 3D sphere and apply texture using OpenGL ES on Xcode. It covered the creation of the sphere model matrix, setting up vertex data for the sphere, creating and setting up shaders, and applying textures.
It’s worth noting that this is just a basic example and there are many ways to improve it, such as by adding more complex geometry or using other rendering techniques like instancing or deferred shading.
For any questions or comments please don’t hesitate to reach out.
Last modified on 2024-01-12