使用语言是Swift
效果图:
步骤
与绘制图片的步骤基本一致,所以引用了上一篇文章中步骤图。
自定义顶点着色器和片元着色器
顶点着色器
文件名:shaderv.glsl
attribute vec4 position;
attribute vec4 positionColor;
attribute vec2 textCoordinate;
uniform mat4 projectionMatrix;
uniform mat4 modelViewMatrix;
varying lowp vec4 varyColor;
varying lowp vec2 varyTextCoord;
void main(){
varyColor = positionColor;
varyTextCoord = textCoordinate;
vec4 vpos;
vpos = projectionMatrix * modelViewMatrix * position;
gl_Position = vpos;
}
片元着色器
文件名:shaderf.glsl
precision highp float;
varying lowp vec4 varyColor;
varying lowp vec2 varyTextCoord;
uniform sampler2D colorMap;
void main(){
vec4 weakMask = texture2D(colorMap,varyTextCoord);
vec4 weak = varyColor;
float alpha = 0.5;
vec4 tempColor = weak * (1.0 - alpha) + weakMask * alpha;
gl_FragColor = tempColor;
}
设置View
属性与定时器
class meView: UIView {
fileprivate var meLayer : CAEAGLLayer!
fileprivate var meContext : EAGLContext!
fileprivate var meColorReaderBuffer : GLuint = GLuint()
fileprivate var meColorFrameBuffer : GLuint = GLuint()
fileprivate var meProgram : GLuint = GLuint()
fileprivate var meVertices : GLuint = GLuint()
fileprivate var xDegree : Float = 0.0
fileprivate var yDegree : Float = 0.0
fileprivate var zDegree : Float = 0.0
fileprivate var bX :Bool = false
fileprivate var bY :Bool = false
fileprivate var bZ :Bool = false
fileprivate var timer: Timer?
override class var layerClass : AnyClass{
return CAEAGLLayer.self
}
override func layoutSubviews() {
self.setupLayer()
self.setContext()
self.setClearBuffer()
self.setReaderBuffer()
self.setFrameBuffer()
self.renderLayer()
}
@IBAction func clickX(_ sender: Any) {
if timer == nil {
timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(reDegree), userInfo: nil, repeats: true)
}
bX = !bX
}
@IBAction func clickY(_ sender: Any) {
if timer == nil {
timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(reDegree), userInfo: nil, repeats: true)
}
bY = !bY
}
@IBAction func clickZ(_ sender: Any) {
if timer == nil {
timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(reDegree), userInfo: nil, repeats: true)
}
bZ = !bZ
}
@objc private func reDegree(){
xDegree += (bX ? 1 : 0) * 0.5
yDegree += (bY ? 1 : 0) * 0.5
zDegree += (bZ ? 1 : 0) * 0.5
self.renderLayer()
}
}
准备工作与绘制
extension meView{
//1、创建图层
fileprivate func setupLayer(){
self.meLayer = self.layer as? CAEAGLLayer
guard self.meLayer != nil else {
return
}
self.contentScaleFactor = UIScreen.main.scale
self.meLayer.drawableProperties = [kEAGLDrawablePropertyColorFormat : kEAGLColorFormatRGBA8,kEAGLDrawablePropertyRetainedBacking: false]
}
// 2、创建上下文
fileprivate func setContext(){
let context = EAGLContext(api: .openGLES3)
guard EAGLContext.setCurrent(context) else {
return
}
self.meContext = context!
}
// 3、清空缓存区
fileprivate func setClearBuffer(){
glDeleteBuffers(1, &meColorFrameBuffer)
self.meColorFrameBuffer = 0
glDeleteBuffers(1, &meColorReaderBuffer)
self.meColorReaderBuffer = 0
}
// 4、设置RenderBuffer
fileprivate func setReaderBuffer(){
var buffer : GLuint = GLuint()
glGenRenderbuffers(1, &buffer)
self.meColorReaderBuffer = buffer
glBindRenderbuffer(GLenum(GL_RENDERBUFFER), self.meColorReaderBuffer)
meContext.renderbufferStorage(Int(GL_RENDERBUFFER), from: self.meLayer)
}
// 5、设置FrameBuffer
fileprivate func setFrameBuffer(){
var buffer : GLuint = GLuint()
glGenFramebuffers(1, &buffer)
self.meColorFrameBuffer = buffer
glBindFramebuffer(GLenum(GL_FRAMEBUFFER), self.meColorFrameBuffer)
glFramebufferRenderbuffer(GLenum(GL_FRAMEBUFFER), GLenum(GL_COLOR_ATTACHMENT0), GLenum(GL_RENDERBUFFER), self.meColorReaderBuffer)
}
// 6、开始绘制
fileprivate func renderLayer(){
glClearColor(1, 0.9, 0.4, 1)
glClear(GLbitfield(GL_COLOR_BUFFER_BIT))
//
let scale = UIScreen.main.scale
glViewport(GLint(self.frame.origin.x), GLint(self.frame.origin.y), GLsizei(self.frame.size.width * scale), GLsizei(self.frame.size.height * scale))
let vertFile = Bundle.main.path(forResource: "shaderv", ofType: "glsl") ?? ""
let fragFile = Bundle.main.path(forResource: "shaderf", ofType: "glsl") ?? ""
print("vertFile: \(vertFile)")
print("fragFile: \(fragFile)")
guard let program = self.loaderShader(vertFile, fragFile) else {
print("program is nil")
return
}
//
self.meProgram = program
glLinkProgram(self.meProgram)
var linkStatus = GLint()
glGetProgramiv(self.meProgram, GLenum(GL_LINK_STATUS), &linkStatus)
if linkStatus == GLint(GL_FALSE){
let count = 1024
let message = UnsafeMutablePointer<GLchar>.allocate(capacity: count)
message.initialize(repeating: GLchar(0), count: count)
glGetProgramInfoLog(self.meProgram, GLsizei(MemoryLayout<GLchar>.size * count), nil, message)
defer{
message.deinitialize(count: count)
message.deallocate()
}
print("error:\(message)")
return
}
glUseProgram(self.meProgram)
let attArr : [GLfloat] = [
-0.5, 0.5, 0.0, 1.0, 0.0, 1,0.5, 0.0,1.0, //左上0
0.5, 0.5, 0.0, 1.0, 0.0, 1,0.5, 1.0,1.0,//右上1
-0.5, -0.5, 0.0, 1.0, 1.0, 1,0.5, 0.0,0.0, //左下2
0.5, -0.5, 0.0, 1.0, 1.0, 1,0.5, 1.0,0.0,//右下3
0.0, 0.0, 1.0, 0.0, 1.0, 1,0.5, 0.5,1.0,//顶点4
]
let indices : [GLuint] = [
0, 3, 2,
0, 1, 3,
0, 2, 4,
0, 4, 1,
2, 3, 4,
1, 4, 3,
]
if self.meVertices == 0{
glGenBuffers(1, &self.meVertices)
}
glBindBuffer(GLenum(GL_ARRAY_BUFFER), self.meVertices)
glBufferData(GLenum(GL_ARRAY_BUFFER), MemoryLayout<GLfloat>.size*attArr.count, attArr, GLenum(GL_DYNAMIC_DRAW))
let position = glGetAttribLocation(self.meProgram, "position")
glEnableVertexAttribArray(GLuint(position))
glVertexAttribPointer(GLuint(position), GLint(3), GLenum(GL_FLOAT), GLboolean(GL_FALSE), GLsizei(MemoryLayout<GLfloat>.size * 9), UnsafeRawPointer.init(bitPattern: 0))
let positionColor = glGetAttribLocation(self.meProgram, "positionColor")
glEnableVertexAttribArray(GLuint(positionColor))
glVertexAttribPointer(GLuint(positionColor), GLint(4), GLenum(GL_FLOAT), GLboolean(GL_FALSE), GLsizei(MemoryLayout<GLfloat>.size * 9), UnsafeRawPointer(bitPattern: MemoryLayout<GLfloat>.size * 3))
let textCoordinate = glGetAttribLocation(self.meProgram, "textCoordinate")
glEnableVertexAttribArray(GLuint(textCoordinate))
glVertexAttribPointer(GLuint(textCoordinate), GLint(2), GLenum(GL_FLOAT), GLboolean(GL_FALSE), GLsizei(MemoryLayout<GLfloat>.size * 9), UnsafeRawPointer(bitPattern: MemoryLayout<GLfloat>.size * 7))
let projectionMatrix = glGetUniformLocation(self.meProgram, "projectionMatrix")
let modelViewMatrix = glGetUniformLocation(self.meProgram, "modelViewMatrix")
let width: Float = Float(self.frame.size.width)
let height: Float = Float(self.frame.size.height)
let aspect = width / height
var _projectionMatrix : GLKMatrix4 = GLKMatrix4Identity
_projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(35), aspect, 1, 200)
let count = MemoryLayout.size(ofValue: _projectionMatrix.m) / MemoryLayout.size(ofValue: _projectionMatrix.m.0)
withUnsafePointer(to: &_projectionMatrix.m) { (pointer) in
pointer.withMemoryRebound(to: GLfloat.self, capacity: count, { (pon) in
glUniformMatrix4fv((projectionMatrix), GLsizei(1), GLboolean(GL_FALSE), pon)
})
}
var _modelViewMatrix = GLKMatrix4Identity,_rotationMatrix = GLKMatrix4Identity
_modelViewMatrix = GLKMatrix4Translate(_modelViewMatrix, 0, 0, -10.0)
_rotationMatrix = GLKMatrix4RotateX(_rotationMatrix, xDegree)
_rotationMatrix = GLKMatrix4RotateY(_rotationMatrix, yDegree)
_rotationMatrix = GLKMatrix4RotateZ(_rotationMatrix, zDegree)
_modelViewMatrix = GLKMatrix4Multiply(_modelViewMatrix,_rotationMatrix )
let modelCount = MemoryLayout.size(ofValue: _modelViewMatrix.m) / MemoryLayout.size(ofValue: _modelViewMatrix.m.0)
withUnsafePointer(to: &_modelViewMatrix.m) { (pointer) in
pointer.withMemoryRebound(to: GLfloat.self, capacity: modelCount, { (pon) in
glUniformMatrix4fv((modelViewMatrix), GLsizei(1), GLboolean(GL_FALSE), pon)
})
}
// glEnable(GLenum(GL_DEPTH_TEST))
glEnable(GLenum(GL_CULL_FACE))
glEnable(GLenum(GL_BLEND))
glBlendFunc(GLenum(GL_SRC_ALPHA), GLenum(GL_ONE_MINUS_SRC_ALPHA));
self.setupTexture("108")
glDrawElements(GLenum(GL_TRIANGLES), GLsizei(MemoryLayout<GLuint>.size*indices.count / MemoryLayout<GLuint>.size), GLenum(GL_UNSIGNED_INT), indices)
self.meContext.presentRenderbuffer(Int(GL_RENDERBUFFER))
}
//加载纹理
fileprivate func setupTexture(_ fileName: String){
guard let image = UIImage(named: fileName)?.cgImage else {
print("image is nil")
return
}
let height = image.height
let width = image.width
let count = MemoryLayout<GLubyte>.size * height * width * 4
let spriteData = UnsafeMutablePointer<GLubyte>.allocate(capacity: count)
UIGraphicsBeginImageContext(CGSize(width: width, height: height))
let spriteContext = CGContext(data: spriteData, width: width, height: height, bitsPerComponent: 8, bytesPerRow: width * 4, space: image.colorSpace!, bitmapInfo: image.bitmapInfo.rawValue)
let rect = CGRect(x: 0, y: 0, width: width, height: height)
spriteContext?.translateBy(x: rect.origin.x, y: rect.origin.y)
spriteContext?.translateBy(x: 0, y: rect.size.height)
spriteContext?.scaleBy(x: 1, y: -1)
spriteContext?.translateBy(x: -rect.origin.x, y: -rect.origin.y)
spriteContext?.draw(image, in: rect)
UIGraphicsEndImageContext()
glBindTexture(GLenum(GL_TEXTURE_2D), 0)
glTexParameteri(GLenum(GL_TEXTURE_2D), GLenum(GL_TEXTURE_MIN_FILTER), GL_LINEAR)
glTexParameteri(GLenum(GL_TEXTURE_2D), GLenum(GL_TEXTURE_MAG_FILTER), GL_LINEAR)
glTexParameteri(GLenum(GL_TEXTURE_2D), GLenum(GL_TEXTURE_WRAP_S), GLint(GL_CLAMP_TO_EDGE))
glTexParameteri(GLenum(GL_TEXTURE_2D), GLenum(GL_TEXTURE_WRAP_T), GLint(GL_CLAMP_TO_EDGE))
glTexImage2D(GLenum(GL_TEXTURE_2D), GLint(0), GLint(GL_RGBA), GLsizei(width), GLsizei(height), GLint(0), GLenum(GL_RGBA), GLenum(GL_UNSIGNED_BYTE), spriteData)
free(spriteData)
// defer {
// spriteData.deinitialize(count: count)
// spriteData.deallocate()
// }
}
}
生成shander program
extension meView{
fileprivate func loaderShader(_ vert : String, _ frag : String) -> GLuint?{
let programe : GLuint = glCreateProgram();
guard let vertShader = compileShader(GLenum(GL_VERTEX_SHADER), vert) else {
print("顶点着色器获取为空")
return nil
}
guard let frag = self.compileShader(GLenum(GL_FRAGMENT_SHADER), frag) else{
print("片元着色器为空")
return nil
}
glAttachShader(programe, vertShader)
glAttachShader(programe, frag)
glDeleteShader(vertShader)
glDeleteShader(frag)
return programe
}
fileprivate func compileShader(_ type : GLenum, _ file : String) -> GLuint?{
let shader = glCreateShader(type)
guard let fileContent = try? String(contentsOfFile: file, encoding: .utf8) else {
print("文件读取为空")
return nil
}
fileContent.withCString { (str) in
var pon : UnsafePointer<GLchar>? = str
glShaderSource(shader, 1, &pon, nil)
}
glCompileShader(shader)
return shader
}
}