ios - 当我通过 OpenGLES 自定义 imageView 时出了什么问题?

标签 ios swift opengl-es

我想通过 OpenGLES 自定义一个 UIImageView。因为我不熟悉swift。也许某些代码是错误的,所以我无法显示我的图像。我已将名为 mepng 类型图像拖到 Assets.xcassets 中。我的代码如下:


import UIKit
import OpenGLES
import CoreGraphics

class DowImageView: UIView {

    private var mEaglLayer: CAEAGLLayer?
    private var mContext: EAGLContext?

    private var mColorRenderBuffer = GLuint()
    private var mColorFrameBuffer = GLuint()
    private var mprograme = GLuint()

    //How do you override layerClass in swift: https://stackoverflow.com/questions/24351102/how-do-you-override-layerclass-in-swift
    override class var layerClass: AnyClass {
        get {
            return CAEAGLLayer.self
        }
    }

    override func layoutSubviews() {
        setupLayer()
        setupContext()
        deleteRenderAndFrameBuffer()
        setupRenderBuffer()
        setupFrameBuffer()
        renderLayer()
    }

    private func setupLayer() {
        mEaglLayer = self.layer as? CAEAGLLayer
        self.contentScaleFactor = UIScreen.main.scale
        mEaglLayer?.drawableProperties = [kEAGLDrawablePropertyRetainedBacking: false,
                                                                  kEAGLDrawablePropertyColorFormat: kEAGLColorFormatRGBA8]
    }

    private func setupContext() {
        let context = EAGLContext(api: EAGLRenderingAPI.openGLES3)
        EAGLContext.setCurrent(context)
        mContext = context
    }


    private func deleteRenderAndFrameBuffer() {

        glDeleteBuffers(1, &mColorRenderBuffer)
        mColorRenderBuffer = 0
        glDeleteBuffers(1, &mColorFrameBuffer)
        mColorFrameBuffer = 0
    }

    private func setupRenderBuffer() {

        var buffer = GLuint()

        glGenRenderbuffers(1, &buffer)
        mColorRenderBuffer = buffer

        glBindRenderbuffer(GLenum(GL_RENDERBUFFER), mColorRenderBuffer)

        //https://developer.apple.com/documentation/opengles/eaglcontext/1622262-renderbufferstorage
        mContext?.renderbufferStorage(Int(GL_RENDERBUFFER), from: mEaglLayer)
    }

    private func setupFrameBuffer() {
        var buffer = GLuint()
        glGenFramebuffers(1, &buffer)
        mColorFrameBuffer = buffer
        glBindFramebuffer(GLenum(GL_FRAMEBUFFER), mColorFrameBuffer)
        glFramebufferRenderbuffer(GLenum(GL_FRAMEBUFFER), GLenum(GL_COLOR_ATTACHMENT0), GLenum(GL_RENDERBUFFER), mColorRenderBuffer)

    }

    private func renderLayer() {
        glClearColor(0.9, 0.8, 0.5, 1.0)
        glClear(GLbitfield(GL_COLOR_BUFFER_BIT))
        let scale = UIScreen.main.scale
        let frame = self.frame

        glViewport(GLint(frame.origin.x * scale), GLint(frame.origin.y * scale), GLsizei(frame.size.width * scale), GLsizei(frame.size.height * scale))

        let verFile = Bundle.main.path(forResource: "shaderv", ofType: "vsh")
        let fragFile = Bundle.main.path(forResource: "shaderf", ofType: "fsh")

        attachToProgram(with: verFile, fragFIle: fragFile)

        glLinkProgram(mprograme)
        var linkStatus = GLint()
        glGetProgramiv(mprograme, GLenum(GL_LINK_STATUS), &linkStatus)

        if linkStatus == GL_FALSE {
            var message = [GLchar]()
            glGetProgramInfoLog(mprograme, GLsizei(MemoryLayout<GLchar>.size * 512), nil, &message)
            let errorInfo = String(cString: message, encoding: .utf8)
            print(errorInfo)
            return
        }
        print("🍺🍻 link success")

        glUseProgram(mprograme)

        //坐标数据
        let attrArr: [GLfloat] = [
            0.5, -0.5, -1.0,     1.0, 0.0,
            -0.5, 0.5, -1.0,     0.0, 1.0,
            -0.5, -0.5, -1.0,    0.0, 0.0,

            0.5, 0.5, -1.0,      1.0, 1.0,
            -0.5, 0.5, -1.0,     0.0, 1.0,
            0.5, -0.5, -1.0,     1.0, 0.0,
        ]

        var attrBuffer = GLuint()
        glGenBuffers(1, &attrBuffer)
        glBindBuffer(GLenum(GL_ARRAY_BUFFER), attrBuffer)
        glBufferData(GLenum(GL_ARRAY_BUFFER), MemoryLayout<GLfloat>.size * 30, attrArr, GLenum(GL_DYNAMIC_DRAW))

        let position = glGetAttribLocation(mprograme, "position")

        glEnableVertexAttribArray(GLuint(position))

        glVertexAttribPointer(GLuint(position), 3, GLenum(GL_FLOAT), GLboolean(GL_FALSE), GLsizei(MemoryLayout<GLfloat>.size * 5), nil)

        let textCoor = glGetAttribLocation(mprograme, "textCoordinate")
        glEnableVertexAttribArray(GLuint(textCoor))
        glVertexAttribPointer(GLuint(textCoor), 2, GLenum(GL_FLOAT), GLboolean(GL_FALSE), GLsizei(MemoryLayout<GLfloat>.size * 5), BUFFER_OFFSET(3))

        loadTexture(with: "me")

        glUniform1i(glGetUniformLocation(mprograme, "colorMap"), 0)
        glDrawArrays(GLenum(GL_TRIANGLES), 0, 6)

        mContext?.presentRenderbuffer(Int(GL_RENDERBUFFER))
    }

    private func BUFFER_OFFSET(_ i: Int) -> UnsafeRawPointer? {
        return UnsafeRawPointer(bitPattern: i)
    }

    private func loadTexture(with name: String) {

        guard let spriteImage = UIImage(named: name)?.cgImage else { return }
        let width = spriteImage.width
        let height = spriteImage.height
        let spriteData = calloc(width * height * 4, MemoryLayout<GLubyte>.size)

        //https://stackoverflow.com/questions/24109149/cgbitmapcontextcreate-error-with-swift
        let spriteContext = CGContext(data: spriteData, width: width, height: height, bitsPerComponent: 8, bytesPerRow: width * 4, space: spriteImage.colorSpace!, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue)

        let rect = CGRect(x: 0, y: 0, width: width, height: height)
        spriteContext?.draw(spriteImage, in: rect)

        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), GL_CLAMP_TO_EDGE)
        glTexParameteri(GLenum(GL_TEXTURE_2D), GLenum(GL_TEXTURE_WRAP_T), GL_CLAMP_TO_EDGE)

        glTexImage2D(GLenum(GL_TEXTURE_2D), 0, GL_RGBA, GLsizei(width), GLsizei(height), 0, GLenum(GL_RGBA), GLenum(GL_UNSIGNED_BYTE), spriteData)
        free(spriteData)

    }

    private func attachToProgram(with verFile: String?, fragFIle: String?) {
        guard let verFile = verFile, let fragFIle = fragFIle else { return }
        var verShader = GLuint()
        var fragShader = GLuint()
        let program = glCreateProgram()
        compileshader(with: &verShader, type: GLenum(GL_VERTEX_SHADER), file: verFile)
        compileshader(with: &fragShader, type: GLenum(GL_FRAGMENT_SHADER), file: fragFIle)

        glAttachShader(program, verShader)
        glAttachShader(program, fragShader)

        glDeleteShader(verShader)
        glDeleteShader(fragShader)

        mprograme = program
    }

    private func compileshader(with  shader: inout GLuint,
                               type: GLenum,
                               file: String) {

        let content = try? String(contentsOfFile: file, encoding: String.Encoding.utf8)
        var source = UnsafePointer<GLchar>(content)

        shader = glCreateShader(type)

        glShaderSource(shader, 1,&source, nil)
        glCompileShader(shader)

    }
}

shaderv.vsh 的代码如下:

attribute vec4 position;
attribute vec2 textCoordinate;
varying lowp vec2 varyTextCoord;

void main() {
    varyTextCoord = textCoordinate;
    gl_Position = position;
}


shaderf.fsh 的代码如下:

varying lowp vec2 varyTextCoord;
uniform sampler2D colorMap;

void main() {
    gl_FragColor = texture2D(colorMap, varyTextCoord);
}

编译不显示错误信息,因此很难找到错误。你能帮我找到错误吗。

最佳答案

如果绑定(bind)了一个非零缓冲对象,那么 glVertexAttribPointer 的第5个参数被视为缓冲区对象数据存储中的字节偏移量

所以纹理坐标的偏移量是MemoryLayout<GLfloat>.size * 3 :

glVertexAttribPointer(..., BUFFER_OFFSET(3))

glVertexAttribPointer(GLuint(textCoor), 2, GLenum(GL_FLOAT), GLboolean(GL_FALSE),
   GLsizei(MemoryLayout<GLfloat>.size * 5), BUFFER_OFFSET(MemoryLayout<GLfloat>.size * 3))

关于ios - 当我通过 OpenGLES 自定义 imageView 时出了什么问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56535272/

相关文章:

ios - 用 Swift 语言显示 webImages 的 UITableView 似乎卡住了

iOS分享扩展,配置项(tableView)

ios - iOS 上的 OpenGL ES 三角形绘制错误

ios - 重新加载 UIPickerView

ios - 闭包元组不支持 Xcode 9 Swift 4 中的解构

swift - 在 Swift 中使用 C 字符串,或 : How to convert UnsafePointer<CChar> to CString

iOS 摄像头颜色实时识别 : Tracking a Ball

android - 如何在 Android OpenGL ES3.0 中向表面添加位图/图像纹理?

ios - 如何显示当前日期与过去日期之间的差异?

iphone - 设置对象的图层会导致内存问题吗?