简体   繁体   English

Swift - 如何在OpenGL ES中绘制线条?

[英]Swift - How to draw line in OpenGL ES?

I'm trying to draw a black single line on GLKitView , using Swift , but it does not work. 我试图在GLKitView使用Swift绘制黑色单行,但它不起作用。 I can clear screen and I can fill it with any color, but I can't draw anything on it. 我可以清除屏幕,我可以用任何颜色填充它,但我不能在它上面画任何东西。 And I know, this question was asked lots of times, but I could not found any answer on Swift. 我知道,这个问题很多次被问过,但我找不到任何关于Swift的答案。 More over, there is no any info about using OpenGL ES with Swift, so I came here. 更重要的是,没有关于在Swift中使用OpenGL ES的任何信息,所以我来到这里。

Here is my code: 这是我的代码:

import GLKit

class MyGLKit: GLKView {
    override func drawRect(rect: CGRect) {
        glClearColor(0.8, 0.8, 0.8, 1.0)
        glClear(GLbitfield(GL_COLOR_BUFFER_BIT))

        glColor4f(0, 0, 0, 1)

        var line: [GLfloat] = [-1, 0, 1, 0]
        var len = line.count * sizeof(GLfloat)

        // Create an handle for a buffer object array
        var bufferObjectNameArray: GLuint = 0

        // Have OpenGL generate a buffer name and store it in the buffer object array
        glGenBuffers(1, &bufferObjectNameArray);

        // Bind the buffer object array to the GL_ARRAY_BUFFER target buffer
        glBindBuffer(GLbitfield(GL_ARRAY_BUFFER), bufferObjectNameArray);

        // Send the line data over to the target buffer in GPU RAM
        glBufferData(
        GLbitfield(GL_ARRAY_BUFFER),    // the target buffer
        len,                            // the number of bytes to put into the buffer
        line,                           // a pointer to the data being copied
        GLbitfield(GL_STATIC_DRAW));    // the usage pattern of the data

        glVertexPointer(2, GLbitfield(GL_FLOAT), 0, line);
        var programHandle: GLuint = glCreateProgram()
        glLinkProgram(programHandle)

        glDrawArrays(GLbitfield(GL_LINES), 0, 2);
    }
}

I'm not sure what this code doing, cause OpenGL ES seems insanely, after usual OpenGL. 我不确定这个代码在做什么,导致OpenGL ES看起来疯狂,在通常的OpenGL之后。 I mean, you need to write a lot of code just to draw a single line. 我的意思是,你需要编写很多代码来绘制一行。 Why does it work that way? 它为什么这样工作?

I have not used Swift, but based on code in OpenGL EXC_BAD_ACCESS when calling glDrawElements in Swift but not in Objective-C , your glVertexPointer() call should look like this: 我没有使用Swift,但是基于OpenGL EXC_BAD_ACCESS中的代码在Swift中调用glDrawElements而不是在Objective-C中 ,你的glVertexPointer()调用应该如下所示:

let bufferOffset: CConstVoidPointer = COpaquePointer(UnsafePointer<Int>(0))
glVertexPointer(2, GLbitfield(GL_FLOAT), 0, bufferOffset);

It also looks like you're not really building a shader program: 看起来你还没有真正构建着色器程序:

var programHandle: GLuint = glCreateProgram()
glLinkProgram(programHandle)

There's a bunch of things that need to go between here if you're using plain OpenGL. 如果您使用普通的OpenGL,那么需要介绍一些事情。 You need to create shader objects, give them code written in GLSL, make calls to compile the shaders, etc. I believe GLKit has functionality to use pre-baked shaders. 您需要创建着色器对象,为它们提供用GLSL编写的代码,调用以编译着色器等。我相信GLKit具有使用预烘焙着色器的功能。

As for why OpenGL is so "insane", that's beyond the scope of this site. 至于为什么OpenGL如此“疯狂”,这超出了本网站的范围。 And very subjective. 而且非常主观。 IMHO, the main point to keep in mind is that OpenGL is not designed to be a convenient API for programmers. 恕我直言,要记住的要点是,OpenGL并不是为程序员提供方便的API。 It is designed to provide a relatively thin generic abstraction for accessing graphics hardware. 它旨在为访问图形硬件提供相对较薄的通用抽象。 And the tendency for comparable APIs is actually to make the abstraction layer even thinner to reduce overhead (see eg DirectX 12). 类似API的趋势实际上是使抽象层更薄,以减少开销(参见例如DirectX 12)。

There's nothing stopping anybody from implementing more convenient higher level APIs on top of OpenGL. 没有什么可以阻止任何人在OpenGL之上实现更方便的更高级别的API。 These interfaces exist, and people use them. 这些接口存在,人们使用它们。

Looks like you need to add GLKBaseEffect 看起来你需要添加GLKBaseEffect

Anyway here is my working solution: To test, create a MyGLKit.swift file 无论如何这里是我的工作解决方案:要测试,创建一个MyGLKit.swift文件

import Foundation
import GLKit
import OpenGLES

struct OpenGLColor {
    var r: GLubyte = 0
    var g: GLubyte = 0
    var b: GLubyte = 0
    var a: GLubyte = 0
}

class MyGLKit: GLKView {

    var lineData: [GLfloat] = []
    var colorData: [GLubyte] = []
    var linesCount:Int = 0

    func setup(){
        self.context = EAGLContext(api: .openGLES2)!
        EAGLContext.setCurrent(self.context)

        //effect
        let effect: GLKBaseEffect = GLKBaseEffect()
        let projectionMatrix: GLKMatrix4 = GLKMatrix4MakeOrtho(-1.0, 1.0, -1.0, 1.0, 1.0, -1.0)
        effect.transform.projectionMatrix = projectionMatrix
        effect.prepareToDraw()


        //OPTIONAL > disable slow GL extensions
        glDisable(GLenum(GL_DEPTH_TEST))
        glDisable(GLenum(GL_BLEND))
        glDisable(GLenum(GL_DITHER))
        glDisable(GLenum(GL_STENCIL_TEST))
        glDisable(GLenum(GL_TEXTURE_2D))
        //

        glTexParameteri(GLenum(GL_TEXTURE_2D), GLenum(GL_TEXTURE_MAG_FILTER), GL_NEAREST)
        glTexParameteri(GLenum(GL_TEXTURE_2D), GLenum(GL_TEXTURE_MIN_FILTER), GL_NEAREST)
        glEnableVertexAttribArray(GLuint(GLKVertexAttrib.position.rawValue))
        glEnableVertexAttribArray(GLuint(GLKVertexAttrib.color.rawValue))

    }

    func drawLine(x:GLfloat, y:GLfloat, x2:GLfloat, y2:GLfloat, color: OpenGLColor){

        //suppport for retina
        var x = x
        var y = y
        var x2 = x2
        var y2 = y2
        x *= 2
        x2 *= 2
        y *= 2
        y2 *= 2

        //calculate position for opengl
        let w: GLfloat = GLfloat(self.bounds.size.width)
        let h: GLfloat = GLfloat(self.bounds.size.height)

        //coordinates x/y
        lineData.append(((1.0/w)*x)-1)
        lineData.append(1-((1.0/h)*y))
        lineData.append(0)
        lineData.append(((1.0/w)*x2)-1)
        lineData.append(1-((1.0/h)*y2))
        lineData.append(0)

        //color
        colorData.append(color.r)
        colorData.append(color.g)
        colorData.append(color.b)
        colorData.append(color.a)
        colorData.append(color.r)
        colorData.append(color.g)
        colorData.append(color.b)
        colorData.append(color.a)

        linesCount += 1

    }

    override func draw(_ rect: CGRect) {

        glLineWidth(1.0)
        glClearColor(0.8, 0.8, 0.8, 1.0)
        glClear(GLbitfield(GL_COLOR_BUFFER_BIT))

        //draw layer
        if (lineData.count > 0){
            glVertexAttribPointer(GLuint(GLKVertexAttrib.position.rawValue), 3, GLenum(GL_FLOAT), GLboolean(GL_FALSE), 0, lineData)
            glVertexAttribPointer(GLuint(GLKVertexAttrib.color.rawValue), 4, GLenum(GL_UNSIGNED_BYTE), GLboolean(GL_TRUE), 0, colorData)
            glDrawArrays(GLenum(GL_LINES), 0, GLsizei(linesCount*2))
        }
    }

}

Then use it for example in your UIViewController: 然后在你的UIViewController中使用它:

let g = MyGLKit()
        g.setup()
        g.frame = self.view.bounds
        self.view.addSubview(g)
        var color = OpenGLColor()
        color.r = 20
        color.b = 30
        color.g = 40
        color.a = 255
        g.drawLine(x: 10, y: 10, x2: GLfloat(g.frame.size.width), y2: 10, color: color)
        g.drawLine(x: 10, y: 50, x2: GLfloat(g.frame.size.width), y2: 50, color: color)
        g.setNeedsDisplay()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM