返回
OpenGL ES 入门:点亮金字塔——色彩、纹理、混合与 GLKit 实现
IOS
2023-12-15 10:31:52
在本文中,我们将深入浅出地探讨 OpenGL ES 的世界,通过创建一个金字塔模型并赋予其色彩、纹理和混合效果,逐步揭开其渲染管线的奥秘。我们将使用 GLKit 这个易于使用的框架,简化 OpenGL ES 的使用。准备好开启这段激动人心的渲染之旅了吗?
渲染管线:从顶点到片段
OpenGL ES 的渲染管线是一个多阶段的过程,将原始顶点数据转换为屏幕上的像素。该管线的主要阶段包括:
- 顶点着色器: 处理顶点数据,进行变换、照明和其它顶点级操作。
- 片段着色器: 处理单个像素,计算其颜色、深度和其它片段级属性。
- 光栅化: 将顶点组装成原始片段。
- 混合: 根据混合规则,将片段颜色与帧缓冲中的现有颜色混合。
绘制金字塔
让我们开始创建我们的金字塔模型。首先,我们需要定义顶点数据:
const float vertices[] = {
// 前面
0.0f, 1.0f, 0.0f,
-1.0f, -1.0f, 1.0f,
1.0f, -1.0f, 1.0f,
// 右面
0.0f, 1.0f, 0.0f,
1.0f, -1.0f, 1.0f,
1.0f, -1.0f, -1.0f,
// 后面
0.0f, 1.0f, 0.0f,
1.0f, -1.0f, -1.0f,
-1.0f, -1.0f, -1.0f,
// 左面
0.0f, 1.0f, 0.0f,
-1.0f, -1.0f, -1.0f,
-1.0f, -1.0f, 1.0f
};
接下来,我们需要定义用于应用于顶点的颜色数据:
const float colors[] = {
// 前面
1.0f, 0.0f, 0.0f, 1.0f,
0.0f, 1.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f, 1.0f,
// 右面
1.0f, 0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f, 1.0f,
0.0f, 1.0f, 0.0f, 1.0f,
// 后面
1.0f, 0.0f, 0.0f, 1.0f,
0.0f, 1.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f, 1.0f,
// 左面
1.0f, 0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f, 1.0f,
0.0f, 1.0f, 0.0f, 1.0f
};
使用 GLKit
GLKit 是一个 Apple 提供的框架,可以简化 OpenGL ES 的使用。它提供了高层次的接口,使我们能够轻松配置渲染状态、创建缓冲区和加载着色器。
首先,我们需要创建一个 GLKView,这是 OpenGL ES 的视图类:
let glkView = GLKView(frame: self.view.bounds)
然后,我们需要将视图添加到我们的视图控制器并设置其委托:
self.view.addSubview(glkView)
glkView.delegate = self
顶点着色器
顶点着色器用于变换和处理每个顶点数据。我们使用 GLKit 的 GLKMatrix4
类来定义模型视图投影矩阵:
var modelViewProjectionMatrix: GLKMatrix4!
在 glkView(_:drawIn:)
方法中,我们更新矩阵并设置 uniform 变量:
modelViewProjectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(60.0), Float(self.view.bounds.width / self.view.bounds.height), 0.1, 100.0)
顶点着色器代码如下:
#version 300 es
in vec4 position;
in vec4 sourceColor;
uniform mat4 modelViewProjectionMatrix;
out vec4 vColor;
void main() {
gl_Position = modelViewProjectionMatrix * position;
vColor = sourceColor;
}
片段着色器
片段着色器用于计算每个片段的颜色。它接收顶点着色器输出的 vColor
变量并混合纹理颜色:
#version 300 es
precision mediump float;
in vec4 vColor;
uniform sampler2D texture;
out vec4 fragColor;
void main() {
fragColor = texture2D(texture, gl_PointCoord) * vColor;
}
纹理和混合
为了给金字塔添加纹理,我们需要加载图像并创建纹理对象:
let texture = try! GLKTextureLoader.textureWithContentsOfFile("texture.png", options: nil)
在 glkView(_:drawIn:)
方法中,我们启用纹理并设置 uniform 变量:
glEnable(GLenum(GL_TEXTURE_2D))
glBindTexture(GLenum(GL_TEXTURE_2D), texture.name)
glUniform1i(uniforms["texture"], 0)
混合使我们能够将纹理颜色与顶点颜色进行混合。我们使用 GLKit 的 GLKMesh
类来渲染网格并启用混合:
let mesh = GLKMesh(vertexCount: vertices.count, vertices: vertices, textureCoordinates: nil, colors: colors, indices: nil)
glkView.enable(GLKView.EAGLContext.GLES2.GLKViewDrawableColorFormat.RGBA8888, forTextureOf: mesh)
完整代码
以下是完整代码:
import GLKit
class ViewController: UIViewController {
var glkView: GLKView!
var modelViewProjectionMatrix: GLKMatrix4!
var uniforms: [String: GLint] = [:]
override func viewDidLoad() {
super.viewDidLoad()
glkView = GLKView(frame: self.view.bounds)
self.view.addSubview(glkView)
glkView.delegate = self
}
override func glkView(_ view: GLKView, drawIn rect: CGRect) {
glClearColor(0.0, 0.0, 0.0, 1.0)
glClear(GLbitfield(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT))
glEnable(GLenum(GL_DEPTH_TEST))
let program = GLKProgram()
let vertexShader = try! loadShader("VertexShader.glsl", type: GL_VERTEX_SHADER)
let fragmentShader = try! loadShader("FragmentShader.glsl", type: GL_FRAGMENT_SHADER)
program.attachShader(vertexShader)
program.attachShader(fragmentShader)
program.link()
glUseProgram(program.program)
modelViewProjectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(60.0), Float(self.view.bounds.width / self.view.bounds.height), 0.1, 100.0)
uniforms["modelViewProjectionMatrix"] = glGetUniformLocation