BradLarson / GPUImage2

GPUImage 2 is a BSD-licensed Swift framework for GPU-accelerated video and image processing.
BSD 3-Clause "New" or "Revised" License
4.85k stars 605 forks source link

Framebuffer method cannot render the texture image. #318

Closed junyng closed 4 years ago

junyng commented 4 years ago

I have created a custom object that conforms to ImageSource protocol like CircleGenerator I ran the method activateFramebufferForRendering() like a generator. This seems to bind the framebuffer and run a render-to-texture.

Like CircleGenerator, My custom generator draws shapes was successful. However, when loading the texture image, it was not reflected in the view.

Below is a part of the custom class source.

How can I bind a frame buffer and work with render-to-texture from a texture image? I need help.

class TextureGenerator: ImageSource {

static private let vertexShader = """
attribute vec4 position;
attribute vec2 inputTextureCoordinate;
varying vec2 textureCoordinate;

void main(void) {
    gl_Position = position;
    textureCoordinate = inputTextureCoordinate;
}
"""

static private let fragmentShader = """
varying highp vec2 textureCoordinate;
uniform sampler2D inputImageTexture;

void main()
{
    gl_FragColor = texture2D(inputImageTexture, textureCoordinate);
}
"""

let vertices: [Float] = [
    -0.5, 0.5, 0.0, 0.0, 1.0,
    -0.5, -0.5, 0.0, 0.0, 0.0,
    0.5, -0.5, 0.0, 1.0, 0.0,
    0.5, 0.5, 0.0, 1.0, 1.0
]

let indices: [GLubyte] = [
    0, 1, 2,
    2, 3, 0
]

var size: Size
let targets = TargetContainer()

var imageFramebuffer: Framebuffer!
let shader: ShaderProgram

var vbo = GLuint()
var ebo = GLuint()
var texture = GLuint()
var colorRenderbuffer = GLuint()

init(size: Size) {
    self.size = size
    self.shader = try! ShaderProgram(vertexShader: TextureGenerator.vertexShader, fragmentShader: TextureGenerator.fragmentShader)

    do {
        imageFramebuffer = try Framebuffer(context: sharedImageProcessingContext, orientation: .portrait, size: GLSize(size))
    } catch {
        fatalError("Could not construct framebuffer of size: \(size), error:\(error)")
    }
}

func renderTexture() {
    let image = UIImage(imageLiteralResourceName: "textureImage.png")
    guard let contextImage = image.cgImage else {
        return
    }
    let width = contextImage.width
    let height = contextImage.height

    let imageData = calloc(width * height * 4, MemoryLayout<GLubyte>.size)
    let spriteContext = CGContext(data: imageData,
                                  width: width,
                                  height: height,
                                  bitsPerComponent: 8,
                                  bytesPerRow: width * 4,
                                  space: CGColorSpaceCreateDeviceRGB(),
                                  bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue)
    spriteContext?.draw(contextImage, in: CGRect(x: 0, y: 0, width: width, height: height))

    glGenTextures(1, &texture)
    glActiveTexture(GLenum(GL_TEXTURE3))
    glBindTexture(GLenum(GL_TEXTURE_2D), texture)
    glTexParameteri(GLenum(GL_TEXTURE_2D), GLenum(GL_TEXTURE_MIN_FILTER), GL_NEAREST)
    glTexImage2D(GLenum(GL_TEXTURE_2D), 0, GL_RGBA, GLsizei(width), GLsizei(height), 0, GLenum(GL_RGBA), GLenum(GL_UNSIGNED_BYTE), imageData)
    glBindTexture(GLenum(GL_TEXTURE_2D), 0)

    imageFramebuffer.activateFramebufferForRendering()

    guard let positionAttribute = shader.attributeIndex("position"),
        let inputTextureCoordinates = shader.attributeIndex("inputTextureCoordinate") else { fatalError("A position attribute was missing from the shader program during rendering.") }

    glClearColor(0.0, 0.0, 0.0, 0.0)
    glClear(GLbitfield(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT))

    shader.use()

    glGenBuffers(1, &vbo)
    glBindBuffer(GLenum(GL_ARRAY_BUFFER), vbo)
    glBufferData(GLenum(GL_ARRAY_BUFFER), MemoryLayout<Float>.size * vertices.count, vertices, GLenum(GL_STATIC_DRAW))

    glGenBuffers(1, &ebo)
    glBindBuffer(GLenum(GL_ELEMENT_ARRAY_BUFFER), ebo)
    glBufferData(GLenum(GL_ELEMENT_ARRAY_BUFFER), indices.count, indices, GLenum(GL_STATIC_DRAW))

    glVertexAttribPointer(positionAttribute, 3, GLenum(GL_FLOAT), GLboolean(GL_FALSE), GLsizei(MemoryLayout<Float>.size * 5), UnsafePointer(bitPattern: 0))
    glEnableVertexAttribArray(positionAttribute)
    glVertexAttribPointer(inputTextureCoordinates, 2, GLenum(GL_FLOAT), GLboolean(GL_FALSE), GLsizei(MemoryLayout<Float>.size * 5), UnsafePointer(bitPattern: 3 * MemoryLayout<Float>.size))
    glEnableVertexAttribArray(inputTextureCoordinates)

    glBindTexture(GLenum(GL_TEXTURE_2D), texture)
    if let uniform = shader.uniformIndex("inputImageTexture") {
        glUniform1i(uniform, 3)
    }

    glDrawElements(GLenum(GL_TRIANGLES), GLsizei(indices.count), GLenum(GL_UNSIGNED_BYTE), nil)

    glDisableVertexAttribArray(positionAttribute)
    glDisableVertexAttribArray(inputTextureCoordinates)
    glDeleteBuffers(1, &vbo)
    glDeleteBuffers(1, &ebo)

    notifyTargets()
    }
}
junyng commented 4 years ago

This was caused by different texture wrapping values. Solved the problem.