iOS版。 OpenGL的。同时有几个观点

时间:2016-09-22 12:00:59

标签: ios audio opengl-es shader

在我询问filling space between two curve lines with gradient之前的几天。 因为我在我的代码中改变了很多 - 现在我使用着色器。结果几乎就像我需要的那样。但!同样,我在一个控制器中同时使用多个OpenGL视图时遇到问题,但它们必须在彼此之间完全独立。 所以,感谢来自raywenderlich.comcode example from bradley的令人难以置信的教程,我有下一个情况:

  • 类SoundWaveView.swift的两个自定义对象(从bradley的OpenGLView.swift改进);
  • openglView对象的顶点/片段着色器;
  • 控制器,我创建并添加两个SoundWaveView对象(具有相同的上下文!!!!!):

C

override func viewDidLoad() {
    super.viewDidLoad()


    let context = EAGLContext(API: EAGLRenderingAPI.OpenGLES2)

    let viewPos1: CGRect = CGRectMake(0, 150, UIScreen.mainScreen().bounds.size.width, 150);
    let view1 = SoundWaveView(frame: viewPos1, fileName: "Personal Jesus", fileExtention: "mp3", c: context)
    view1.backgroundColor = UIColor.grayColor()
    self.view.addSubview(view1)


    let viewPos2: CGRect = CGRectMake(0, 350, UIScreen.mainScreen().bounds.size.width, 150);
    let view2 = SoundWaveView(frame: viewPos2, fileName: "Imagine", fileExtention: "mp3", c: context)
    view2.backgroundColor = UIColor.blackColor()
    self.view.addSubview(view2)
}

每个SoundWaveView对象都会编译着色器,如上面的教程所示:

    func compileShaders() {

    let vertexShader = compileShader("SimpleVertex", shaderType: GLenum(GL_VERTEX_SHADER))
    let fragmentShader = compileShader("SimpleFragment", shaderType: GLenum(GL_FRAGMENT_SHADER))

    let programHandle: GLuint = glCreateProgram()
    glAttachShader(programHandle, vertexShader)
    glAttachShader(programHandle, fragmentShader)
    glLinkProgram(programHandle)

    var linkSuccess: GLint = GLint()
    glGetProgramiv(programHandle, GLenum(GL_LINK_STATUS), &linkSuccess)
    if (linkSuccess == GL_FALSE) {
        var message = [CChar](count: 256, repeatedValue: CChar(0))
        var length = GLsizei(0)
        glGetProgramInfoLog(programHandle, 256, &length, &message)
        print("Failed to create shader program! : \( String(UTF8String: message) ) ")
        exit(1);
    }

    glUseProgram(programHandle)

    .  .  .  .  .
    shaderPeakId = glGetUniformLocation(programHandle, "peakId")

    shaderWaveAmp = glGetUniformLocation(programHandle, "waveAmp");

    glEnableVertexAttribArray(positionSlot)
    glEnableVertexAttribArray(colorSlot)

    glUniform1f(shaderSceneWidth!,  Float(self.frame.size.width));
    glUniform1f(shaderSceneHeight!, Float(self.frame.size.height));
    glUniform1i(shaderPeaksTotal!,  GLint(total));
    glUniform1i(shaderPeakId!,      GLint(position));

}

为了渲染音频波,需要传递到着色器值作为A)振幅(我从avaudioplayer得到它们 - 它工作得很完美,对于我在控制器中创建的两个对象,我对两个不同的轨道有不同的振幅)和B)波数字(又名peakId /位置)。

因此,对于第一个创建的对象(灰色),位置等于1,此波必须为红色并放置在屏幕的左侧部分。对于第二个对象(黑色)位置为3,波形为蓝色并放置在右侧部分。 /位置2是屏幕中心,现在不使用/

每次音频更新都会导致更新opengl:

var waveAmp :Float = 0

.    .    .    .    . 

func updateMeters(){

    player!.updateMeters()
    var normalizedValue = normalizedPowerLevelFromDecibels(player!.averagePowerForChannel(0))

    waveAmp = normalizedValue!
}

func render(displayLink: CADisplayLink?) {

        glBlendFunc(GLenum(GL_ONE), GLenum(GL_ONE_MINUS_SRC_ALPHA))
        glEnable(GLenum(GL_BLEND))

        //            glClearColor(0, 104.0/255.0, 55.0/255.0, 1.0)
        glClearColor(0, 0, 0, 0)
        glClear(GLenum(GL_COLOR_BUFFER_BIT) | GLenum(GL_DEPTH_BUFFER_BIT))
        glEnable(GLenum(GL_DEPTH_TEST))

        glViewport(0, 0, GLsizei(self.frame.size.width), GLsizei(self.frame.size.height))

        glBindBuffer(GLenum(GL_ARRAY_BUFFER), vertexBuffer)
        glBindBuffer(GLenum(GL_ELEMENT_ARRAY_BUFFER), indexBuffer)

        glVertexAttribPointer(positionSlot, 3, GLenum(GL_FLOAT), GLboolean(UInt8(GL_FALSE)), GLsizei(sizeof(Vertex)), nil)
        glVertexAttribPointer(colorSlot, 4, GLenum(GL_FLOAT), GLboolean(UInt8(GL_FALSE)), GLsizei(sizeof(Vertex)), UnsafePointer<Void>(bitPattern: (sizeof(Float) * 3)))

        glDrawElements(GLenum(GL_TRIANGLE_FAN), GLsizei(Indices.size()), GLenum(GL_UNSIGNED_BYTE), nil)

        glVertexAttribPointer(positionSlot, 3, GLenum(GL_FLOAT), GLboolean(UInt8(GL_FALSE)), GLsizei(sizeof(Vertex)), nil);
        glVertexAttribPointer(colorSlot, 4, GLenum(GL_FLOAT), GLboolean(UInt8(GL_FALSE)), GLsizei(sizeof(Vertex)), UnsafePointer<Void>(bitPattern: (sizeof(Float) * 3)));

        context.presentRenderbuffer(Int(GL_RENDERBUFFER))


    print("position=\(position)  waveAmp=\(waveAmp)")
    glUniform1i(shaderPeakId!,  GLint(position));
    glUniform1f(shaderWaveAmp!, waveAmp);
}

使用print()进行记录 - 功能:

position=1  waveAmp=0.209313
position=3  waveAmp=0.47332
position=1  waveAmp=0.207556
position=3  waveAmp=0.446235
position=1  waveAmp=0.20769
position=3  waveAmp=0.446235
position=1  waveAmp=0.246206
position=3  waveAmp=0.430118

我希望我会有两个矩形 - 一个灰色,左边有红色波浪,一个黑色,右边有蓝色线条。 但是我有下一个麻烦!渲染发生在一个(最后)视图中并按顺序更改:

enter image description here enter image description here

请任何人!如何同时使用两个glView? 或者我可能需要在一个视图中使用两个着色器?

我想完成这个音频波任务并与大家分享。但我仍然不明白这个问题

1 个答案:

答案 0 :(得分:0)

查看您发布的SoundWaveView类的代码,看起来该视图处理初始化上下文,上下文的帧缓冲,以及更多。由于您向两个视图发送相同的EAGLContext,这意味着正在初始化相同的上下文,然后可能由第二个视图重新初始化。这对我来说似乎不对。如果您只为另一个视图创建一个单独的上下文,它实际上可能正常工作,并且GPU将在这两个视图之间进行渲染时进行上下文切换,并将它们视为单独的应用程序。

但这不是应该如何设计这么简单的应用程序。如果你想同时在屏幕上绘制两个对象,那当然并不意味着你需要两个不同的视图。您必须构建一个系统来处理从每个波形中获取信息并将其自动转换为适当的绘制调用。这将作为您的应用程序的迷你绘图引擎。通过这种方法,您可以进一步支持更酷的技术和绘图...可能有更多的波形,每种波形,不同的纹理/颜色,酷效果等。