Swift
复制代码
import UIKit
class Shader: NSObject {
var shaderProgram: GLuint = 0
private func loadShaderSource(from file: String) -> String? {
guard let path = Bundle.main.path(forResource: file, ofType: "glsl") else {
print("Failed to find shader file: \(file)")
return nil
}
do {
let source = try String(contentsOfFile: path, encoding: .utf8)
return source
} catch {
print("Failed to load shader file: \(file), error: \(error)")
return nil
}
}
func begin() {
glUseProgram(shaderProgram)
}
func compileShader(vert: String, frag: String) {
// 读取着色器源代码
guard let vertexSource = loadShaderSource(from: vert),
let fragmentSource = loadShaderSource(from: frag) else {
return
}
// 打印着色器源代码
print("Vertex Shader Source:\n\(vertexSource)")
print("Fragment Shader Source:\n\(fragmentSource)")
// 创建着色器程序
let vertexShader = glCreateShader(GLenum(GL_VERTEX_SHADER))
let fragmentShader = glCreateShader(GLenum(GL_FRAGMENT_SHADER))
// 将着色器源码附加到着色器对象上
vertexSource.withCString { ptr in
var p: UnsafePointer<GLchar>? = UnsafePointer<GLchar>(ptr)
glShaderSource(vertexShader, 1, &p, nil)
}
fragmentSource.withCString { ptr in
var p: UnsafePointer<GLchar>? = UnsafePointer<GLchar>(ptr)
glShaderSource(fragmentShader, 1, &p, nil)
}
// 编译顶点着色器
glCompileShader(vertexShader)
// 检查编译错误
var status: GLint = 0
glGetShaderiv(vertexShader, GLenum(GL_COMPILE_STATUS), &status)
if status == GL_FALSE {
var logLength: GLint = 0
glGetShaderiv(vertexShader, GLenum(GL_INFO_LOG_LENGTH), &logLength)
// Allocate buffer with an extra byte for the null terminator
let bufferLength = Int(logLength) + 1
var log = [GLchar](repeating: 0, count: bufferLength)
// Get the shader info log
glGetShaderInfoLog(vertexShader, logLength, nil, &log)
// Convert the buffer to a Swift string
if let logString = String(validatingUTF8: log) {
print("编译 顶点着色器 error: \(logString)")
} else {
print("编译 顶点着色器 error: Failed to retrieve log.")
}
return
}
// 编译片元着色器
glCompileShader(fragmentShader)
// 检查编译错误
glGetShaderiv(fragmentShader, GLenum(GL_COMPILE_STATUS), &status)
if status == GL_FALSE {
var logLength: GLint = 0
glGetShaderiv(fragmentShader, GLenum(GL_INFO_LOG_LENGTH), &logLength)
// Allocate buffer with an extra byte for the null terminator
let bufferLength = Int(logLength) + 1
var log = [GLchar](repeating: 0, count: bufferLength)
// Get the shader info log
glGetShaderInfoLog(fragmentShader, logLength, nil, &log)
// Convert the buffer to a Swift string
if let logString = String(validatingUTF8: log) {
print("编译 片元着色器 error: \(logString)")
} else {
print("编译 片元着色器 error: Failed to retrieve log.")
}
return
}
// 创建程序对象并链接着色器
shaderProgram = glCreateProgram()
glAttachShader(shaderProgram, vertexShader)
glAttachShader(shaderProgram, fragmentShader)
glLinkProgram(shaderProgram)
var linkStatus: GLint = 0
//获取链接状态
glGetProgramiv(shaderProgram, GLenum(GL_LINK_STATUS), &linkStatus)
if linkStatus == GL_FALSE {
NSLog("link error")
let message = UnsafeMutablePointer<GLchar>.allocate(capacity: 512)
glGetProgramInfoLog(shaderProgram, GLsizei(MemoryLayout<GLchar>.size * 512), nil, message)
let str = String(utf8String: message)
print("error = \(str ?? "没获取到错误信息")")
return
} else {
NSLog("link success")
}
// 删除着色器对象,因为它们已经链接到程序对象中
glDeleteShader(vertexShader)
glDeleteShader(fragmentShader)
}
}
Swift
复制代码
import UIKit
import GLKit
/**
渲染一个四边形
*/
class ViewController: UIViewController {
var eaglLayer: CAEAGLLayer!
var myContext: EAGLContext!
var shader = Shader()
var vao = GLuint()
var renderBuffer = GLuint()
var frameBuffer = GLuint()
var fbo = GLuint()
var fboTexture = GLuint()
override func viewDidLoad() {
super.viewDidLoad()
// 设置渲染显示区域
setupLayer()
// 初始化上下文
setupContext()
// 设置帧缓冲区
setupRenderBuffers()
setupFrameBuffer()
// 准备着色器
prepareShader()
prepareVAOAndVBO()
renderLayer()
}
func setupLayer() {
eaglLayer = CAEAGLLayer()
eaglLayer.frame = view.frame
eaglLayer.isOpaque = true
view.layer.addSublayer(eaglLayer)
}
func setupContext() {
if let context = EAGLContext(api: .openGLES3) {
EAGLContext.setCurrent(context)
myContext = context
print("Create context success")
} else {
print("Create context failed!")
}
}
// 生成和绑定渲染缓冲区对象,为渲染缓冲区分配存储空间,生成和绑定帧缓冲区对象,并将渲染缓冲区附加到帧缓冲区的颜色附件点
func setupRenderBuffers() {
//生成一个渲染缓冲区对象,并将其ID存储在,colorRenderBuffer变量中。
glGenRenderbuffers(1, &renderBuffer)
//绑定生成的渲染缓冲区对象,使其成为当前的渲染缓冲区
glBindRenderbuffer(GLenum(GL_RENDERBUFFER), renderBuffer)
}
func setupFrameBuffer() {
// 生成一个帧缓冲区对象,并将其ID存储在frameBuffer变量中
glGenFramebuffers(1, &frameBuffer)
// 将frameBuffer绑定到GL_FRAMEBUFFER目标上
glBindFramebuffer(GLenum(GL_FRAMEBUFFER), frameBuffer)
// 将渲染缓冲区附加到帧缓冲区的颜色附件点。
glFramebufferRenderbuffer(GLenum(GL_FRAMEBUFFER), GLenum(GL_COLOR_ATTACHMENT0), GLenum(GL_RENDERBUFFER), renderBuffer)
//方法为当前绑定的渲染缓冲区分配存储空间,并将其与 CAEAGLLayer 关联。
myContext.renderbufferStorage(Int(GL_RENDERBUFFER), from: eaglLayer)
}
func prepareShader() {
shader.compileShader(vert: "vertex", frag: "fragment")
}
func prepareVAOAndVBO() {
let positions: [GLfloat] = [
-0.5, -0.5, 0.0, // 左下角
0.5, -0.5, 0.0, // 右下角
-0.5, 0.5, 0.0, // 左上角
0.5, 0.5, 0.0 // 左上角
]
let colors: [GLfloat] = [
1.0, 0.2, 0.2, 1.0,
0.5, 1.0, 0.2, 1.0,
0.5, 0.5, 1.0, 1.0
]
let indices: [GLubyte] = [
0, 1, 2,3
]
var positionVBO = GLuint()
glGenBuffers(1, &positionVBO)
glBindBuffer(GLenum(GL_ARRAY_BUFFER), positionVBO)
glBufferData(GLenum(GL_ARRAY_BUFFER), MemoryLayout<GLfloat>.size * positions.count, positions, GLenum(GL_STATIC_DRAW))
var colorVBO = GLuint()
glGenBuffers(1, &colorVBO)
glBindBuffer(GLenum(GL_ARRAY_BUFFER), colorVBO)
glBufferData(GLenum(GL_ARRAY_BUFFER), MemoryLayout<GLfloat>.size * colors.count, colors, GLenum(GL_STATIC_DRAW))
var ebo = GLuint()
glGenBuffers(1, &ebo)
glBindBuffer(GLenum(GL_ELEMENT_ARRAY_BUFFER), ebo)
glBufferData(GLenum(GL_ELEMENT_ARRAY_BUFFER), MemoryLayout<GLubyte>.size * indices.count, indices, GLenum(GL_STATIC_DRAW))
glGenVertexArrays(1, &vao)
glBindVertexArray(vao)
glBindBuffer(GLenum(GL_ARRAY_BUFFER), positionVBO)
glVertexAttribPointer(0, 3, GLenum(GL_FLOAT), GLboolean(GL_FALSE), GLsizei(MemoryLayout<GLfloat>.size * 3), nil)
glEnableVertexAttribArray(0)
glBindBuffer(GLenum(GL_ARRAY_BUFFER), colorVBO)
glVertexAttribPointer(1, 4, GLenum(GL_FLOAT), GLboolean(GL_FALSE), GLsizei(MemoryLayout<GLfloat>.size * 4), nil)
glEnableVertexAttribArray(1)
glBindBuffer(GLenum(GL_ELEMENT_ARRAY_BUFFER), ebo)
glBindBuffer(GLenum(GL_ARRAY_BUFFER), 0)
glBindVertexArray(0)
}
func renderLayer() {
glClearColor(0.0, 0.0, 0.0, 1.0)
glClear(GLbitfield(GL_COLOR_BUFFER_BIT))
glViewport(GLint(0), GLint(0), GLsizei(view.frame.size.width), GLsizei(view.frame.size.height))
shader.begin()
// 解绑FBO
glBindFramebuffer(GLenum(GL_FRAMEBUFFER), 0)
// 渲染FBO内容到屏幕
glClearColor(0.0, 0.0, 0.0, 1.0)
glClear(GLbitfield(GL_COLOR_BUFFER_BIT))
// 绑定默认帧缓冲区
glBindFramebuffer(GLenum(GL_FRAMEBUFFER), frameBuffer)
// 使用FBO中的纹理进行后处理或直接绘制到屏幕
// 这里你需要一个简单的着色器来绘制纹理到屏幕
shader.begin()
// 绑定FBO纹理
glBindTexture(GLenum(GL_TEXTURE_2D), fboTexture)
// 绘制一个全屏四边形,将FBO纹理渲染到屏幕上
// 你需要设置适当的顶点和纹理坐标
// 这里假设你已经有一个VAO和VBO来绘制全屏四边形
glBindVertexArray(vao)
glDrawElements(GLenum(GL_TRIANGLE_STRIP), 4, GLenum(GL_UNSIGNED_BYTE), nil)
glBindVertexArray(0)
myContext.presentRenderbuffer(Int(GL_RENDERBUFFER))
}
}