美文网首页
go gl 彩色的三角形

go gl 彩色的三角形

作者: 甚解_4703 | 来源:发表于2019-02-08 15:41 被阅读0次
    go 彩色三角形

    之前在网上想找一个能渲染颜色的go gl图形编程例子,,找了半天都是白色的三角形。。。于是自己研究了半天,大概是研究出来的样子,记录到这里来分享一下。
    作者用的是mac开发的,windows的go gl需要麻烦一点的操作,读者自行裁决吧。

    配置

    1.go下载
    2.配置mac go环境请自行搜索一下。
    3.IDE。作者用的是goland,破解的话,也请自行搜索一下。

    go开发包

    由于国内的墙比较严重,建议用github上的镜像下载,然后本地配置一下。


    借助github的golang下载

    下载下来之后把包拖动到指定的目录,比如golang.org中:


    配置

    核心开发包

    "github.com/go-gl/gl/v4.1-core/gl"
    "github.com/go-gl/glfw/v3.2/glfw"
    

    go get github.com/go-gl

    开发

    新建一个go项目。

    初始化调用。
    func init() {
        // This is needed to arrange that main() runs on main thread.
        // See documentation for functions that are only allowed to be called from the main thread.
        runtime.LockOSThread()
    }
    
    初始化我们的gl窗口
    // initGlfwTest 初始化 glfw 并且返回一个可用的窗口。
    func initGlfwTest() *glfw.Window {
        if err := glfw.Init(); err != nil {
            panic(err)
        }
        glfw.WindowHint(glfw.Resizable, glfw.False)
        glfw.WindowHint(glfw.ContextVersionMajor, 4) // OR 2
        glfw.WindowHint(glfw.ContextVersionMinor, 1)
        glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile)
        glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.True)
        window, err := glfw.CreateWindow(widthTest, heightTest, "Test", nil, nil)
        if err != nil {
            panic(err)
        }
        window.MakeContextCurrent()
        return window
    }
    
    初始化我们的opengl
    // initOpenGLTest 初始化 OpenGL 并且返回一个初始化了的程序。
    func initOpenGLTest() uint32 {
        if err := gl.Init(); err != nil {
            panic(err)
        }
        version := gl.GoStr(gl.GetString(gl.VERSION))
        log.Println("OpenGL version", version)
    
        vertexShader, err := compileShaderTest(vertexShaderSourceTest, gl.VERTEX_SHADER)
        if err != nil {
            panic(err)
        }
        fragmentShader, err := compileShaderTest(fragmentShaderSourceTest, gl.FRAGMENT_SHADER)
        if err != nil {
            panic(err)
        }
        prog := gl.CreateProgram()
        gl.AttachShader(prog, vertexShader)
        gl.AttachShader(prog, fragmentShader)
        gl.LinkProgram(prog)
    
        return prog
    }
    

    编译着色器的代码:

    func compileShaderTest(source string, shaderType uint32) (uint32, error) {
        shader := gl.CreateShader(shaderType)
        csources, free := gl.Strs(source)
        gl.ShaderSource(shader, 1, csources, nil)
        free()
        gl.CompileShader(shader)
        var status int32
        gl.GetShaderiv(shader, gl.COMPILE_STATUS, &status)
        if status == gl.FALSE {
            var logLength int32
            gl.GetShaderiv(shader, gl.INFO_LOG_LENGTH, &logLength)
            log := strings.Repeat("\x00", int(logLength+1))
            gl.GetShaderInfoLog(shader, logLength, nil, gl.Str(log))
            return 0, fmt.Errorf("failed to compile %v: %v", source, log)
        }
        return shader, nil
    }
    

    着色器以及窗口宽高的设定:

    const (
        widthTest  = 1280
        heightTest = 720
    
        vertexShaderSourceTest = `
        #version 410
        in vec3 vp;
        in vec4 vs_color;
    
        out vec4 fs_color; //传给片段着色器
        void main() {
            fs_color = vs_color;
            gl_Position = vec4(vp, 1.0);
        }
    ` + "\x00"
        fragmentShaderSourceTest = `
        #version 410
        in vec4 fs_color;//从定点着色器过来的值
        out vec4 frag_colour;
        void main() {
            //frag_colour = vec4(1, 1, 1, 1);
            frag_colour = fs_color;
        }
    ` + "\x00"
    )
    

    网上的教程都是直接用了:
    frag_colour = vec4(1, 1, 1, 1);
    上面这样写只能渲染出一个白色的三角形。它不能读取我们输入的颜色,当然你可以改写这颜色值,得到不一样的颜色,但是跟我们的五彩斑斓的三角形还是不一样的。
    这样就要求我们传入的顶点需要包含颜色值。

    定义顶点

    var (
        vertexPosColor = []float32{
            0, 0.5, 0, 1.0, 0.0, 0.0, 1.0,     // top
            -0.5, -0.5, 0, 0.0, 1.0, 0.0, 1.0, // left
            0.5, -0.5, 0, 0.0, 0.0, 1.0, 1.0,  // right
        }
    )
    

    前面3个值就是定点的x,y,z,后面4个就是颜色值啦~,对应rgba

    创建我们的VBO(顶点缓存对象),VAO(顶点数组对象)

    func makeVboVao() (uint32, uint32) {
        var vbo uint32
        gl.GenBuffers(1, &vbo)
    
        var vao uint32
        gl.GenVertexArrays(1, &vao)
    
        return vbo, vao
    }
    

    绑定VBO,VAO

    // makeVaoTest2 把我们的顶点数据推入到显卡中
    func makeVaoTest2(points []float32, vbo, vao, verPos, verColor uint32) {
        singleBytes := int(unsafe.Sizeof(points[0]))
    
        //var vbo uint32
        //gl.GenBuffers(1, &vbo)
        gl.BindBuffer(gl.ARRAY_BUFFER, vbo)
        gl.BufferData(gl.ARRAY_BUFFER, singleBytes*len(points), gl.Ptr(points), gl.STATIC_DRAW)
        //fmt.Println("makeVaoTest=",unsafe.Sizeof(points[0]))
    
        //var vao uint32
        //gl.GenVertexArrays(1, &vao)
        gl.BindVertexArray(vao)
    
        gl.VertexAttribPointer(verPos, 3, gl.FLOAT, false, int32(singleBytes)*7, nil)
        gl.EnableVertexAttribArray(verPos)
    
        gl.VertexAttribPointer(verColor, 4, gl.FLOAT, false, int32(singleBytes)*7, gl.PtrOffset(singleBytes*3))
        gl.EnableVertexAttribArray(verColor)
    }
    
    

    最后是我们的主函数

    func main() {
        //init() //init是不会被申明的,所以这里调用会报错
    
        window := initGlfwTest()
        defer glfw.Terminate()
        program := initOpenGLTest()
    
        //这里是去获取到我们的着色器中顶点位置 vp
        attVertex := uint32(gl.GetAttribLocation(program, gl.Str("vp\x00")))
        //获取我们的顶点着色器中顶点颜色 vs_color
        attColor := uint32(gl.GetAttribLocation(program, gl.Str("vs_color\x00")))
        fmt.Println("main 1 =", attVertex, attColor)
    
        //vaoVertex := makeVaoTest(triangle, attVertex, 3)
        //makeVaoTest(triangle, attVertex, 3)
        //vaoColor := makeVaoTest(vertexColor, attColor, 4)
        //makeVaoTest(vertexColor, attVertex, 4)
        //fmt.Println("main 2 =", vaoVertex, vaoColor)
    
        //vaoVertex := makeVaoTest(triangle, 3)
    
        vbo, vao := makeVboVao()
        //gl.BindBuffer(gl.ARRAY_BUFFER, vaoVertex)
        //gl.EnableVertexAttribArray(attVertex)
        //gl.VertexAttribPointer(attVertex, 3, gl.FLOAT, false, 0, nil)
        var step float32 = 0.01
        var nowUnix = time.Now().UnixNano() / 1000000
        for !window.ShouldClose() {
            makeVaoTest2(vertexPosColor, vbo, vao, attVertex, attColor)
    
            drawTest(window, program)
    
            //让我们的顶点动起来
            vertexPosColor[0] += step
            if vertexPosColor[0] > 1.0 {
                step = -0.01
            } else if vertexPosColor[0] < -1.0 {
                step = 0.01
            }
    
            //计算fps
            preUnix := nowUnix
            nowUnix = time.Now().UnixNano() / 1000000
            var fps = fmt.Sprintf("FPS:%.2v", 1000.0/(nowUnix-preUnix))
            fmt.Println(fps)
            //显示在窗口的title中
            window.SetTitle(fps)
        }
    }
    

    最后附上项目的完整代码:

    package main
    
    import (
        "fmt"
        "github.com/go-gl/gl/v4.1-core/gl"
        "github.com/go-gl/glfw/v3.2/glfw"
        "log"
        "runtime"
        "strings"
        "time"
        "unsafe"
    )
    
    const (
        widthTest  = 1280
        heightTest = 720
    
        vertexShaderSourceTest = `
        #version 410
        in vec3 vp;
        in vec4 vs_color;
    
        out vec4 fs_color; //传给片段着色器
        void main() {
            fs_color = vs_color;
            gl_Position = vec4(vp, 1.0);
        }
    ` + "\x00"
        fragmentShaderSourceTest = `
        #version 410
        in vec4 fs_color;//从定点着色器过来的值
        out vec4 frag_colour;
        void main() {
            //frag_colour = vec4(1, 1, 1, 1);
            frag_colour = fs_color;
        }
    ` + "\x00"
    )
    
    //init 函数
    /*
    为了使用导入的包,首先必须将其初始化。初始化总是以单线程执行,并且按照包的依赖关系顺序执行。这通过Golang的运行时系统控制,如所示:
    初始化导入的包(递归导入)
    对包块中声明的变量进行计算和分配初始值
    执行包中的init函数
    
    
    init()函数会在每个包完成初始化后自动执行,并且执行优先级比main函数高。init 函数通常被用来:
    对变量进行初始化
    检查/修复程序的状态
    注册
    运行一次计算
     */
    func init() {
        // This is needed to arrange that main() runs on main thread.
        // See documentation for functions that are only allowed to be called from the main thread.
        runtime.LockOSThread()
    }
    
    // initGlfwTest 初始化 glfw 并且返回一个可用的窗口。
    func initGlfwTest() *glfw.Window {
        if err := glfw.Init(); err != nil {
            panic(err)
        }
        glfw.WindowHint(glfw.Resizable, glfw.False)
        glfw.WindowHint(glfw.ContextVersionMajor, 4) // OR 2
        glfw.WindowHint(glfw.ContextVersionMinor, 1)
        glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile)
        glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.True)
        window, err := glfw.CreateWindow(widthTest, heightTest, "Test", nil, nil)
        if err != nil {
            panic(err)
        }
        window.MakeContextCurrent()
        return window
    }
    
    // initOpenGLTest 初始化 OpenGL 并且返回一个初始化了的程序。
    func initOpenGLTest() uint32 {
        if err := gl.Init(); err != nil {
            panic(err)
        }
        version := gl.GoStr(gl.GetString(gl.VERSION))
        log.Println("OpenGL version", version)
    
        vertexShader, err := compileShaderTest(vertexShaderSourceTest, gl.VERTEX_SHADER)
        if err != nil {
            panic(err)
        }
        fragmentShader, err := compileShaderTest(fragmentShaderSourceTest, gl.FRAGMENT_SHADER)
        if err != nil {
            panic(err)
        }
        prog := gl.CreateProgram()
        gl.AttachShader(prog, vertexShader)
        gl.AttachShader(prog, fragmentShader)
        gl.LinkProgram(prog)
    
        return prog
    }
    
    var (
        triangle = []float32{
            0, 0.5, 0,     // top
            -0.5, -0.5, 0, // left
            0.5, -0.5, 0,  // right
        }
        // 保存顶点的颜色情报的数组
        vertexColor = []float32{
            1.0, 0.0, 0.0, 1.0,
            0.0, 1.0, 0.0, 1.0,
            0.0, 0.0, 1.0, 1.0,
        }
    
        vertexPosColor = []float32{
            0, 0.5, 0, 1.0, 0.0, 0.0, 1.0,     // top
            -0.5, -0.5, 0, 0.0, 1.0, 0.0, 1.0, // left
            0.5, -0.5, 0, 0.0, 0.0, 1.0, 1.0,  // right
        }
    )
    
    // makeVaoTest 执行初始化并从提供的点里面返回一个顶点数组
    func makeVaoTest(points []float32, index, size int32) uint32 {
        var vbo uint32
        gl.GenBuffers(1, &vbo)
        gl.BindBuffer(gl.ARRAY_BUFFER, vbo)
        gl.BufferData(gl.ARRAY_BUFFER, int(unsafe.Sizeof(points[0]))*len(points), gl.Ptr(points), gl.STATIC_DRAW)
        //fmt.Println("makeVaoTest=",unsafe.Sizeof(points[0]))
        var vao uint32
        gl.GenVertexArrays(1, &vao)
        gl.BindVertexArray(vao)
        gl.EnableVertexAttribArray(uint32(index))
        gl.VertexAttribPointer(uint32(index), size, gl.FLOAT, false, 0, nil)
    
        return vao
    }
    
    func makeVboVao() (uint32, uint32) {
        var vbo uint32
        gl.GenBuffers(1, &vbo)
    
        var vao uint32
        gl.GenVertexArrays(1, &vao)
    
        return vbo, vao
    }
    
    // makeVaoTest2 把我们的顶点数据推入到显卡中
    func makeVaoTest2(points []float32, vbo, vao, verPos, verColor uint32) {
        singleBytes := int(unsafe.Sizeof(points[0]))
    
        //var vbo uint32
        //gl.GenBuffers(1, &vbo)
        gl.BindBuffer(gl.ARRAY_BUFFER, vbo)                                                     //绑定顶点缓存对象
        gl.BufferData(gl.ARRAY_BUFFER, singleBytes*len(points), gl.Ptr(points), gl.STATIC_DRAW) //把顶点数据推入到缓存
        //fmt.Println("makeVaoTest=",unsafe.Sizeof(points[0]))
    
        //var vao uint32
        //gl.GenVertexArrays(1, &vao)
        gl.BindVertexArray(vao) //绑定到我们的顶点数组对象
    
        //3表示我们的顶点只有3个float,然后一个顶点的大小是 8字节*7(3维顶点,4维颜色)
        gl.VertexAttribPointer(verPos, 3, gl.FLOAT, false, int32(singleBytes)*7, nil)
        gl.EnableVertexAttribArray(verPos)
    
        //4表示我们的顶点只有4个float,然后一个顶点的大小是 8字节*7(3维顶点,4维颜色)
        gl.VertexAttribPointer(verColor, 4, gl.FLOAT, false, int32(singleBytes)*7, gl.PtrOffset(singleBytes*3))
        gl.EnableVertexAttribArray(verColor)
    }
    
    func compileShaderTest(source string, shaderType uint32) (uint32, error) {
        shader := gl.CreateShader(shaderType)
        csources, free := gl.Strs(source)
        gl.ShaderSource(shader, 1, csources, nil)
        free()
        gl.CompileShader(shader)
        var status int32
        gl.GetShaderiv(shader, gl.COMPILE_STATUS, &status)
        if status == gl.FALSE {
            var logLength int32
            gl.GetShaderiv(shader, gl.INFO_LOG_LENGTH, &logLength)
            log := strings.Repeat("\x00", int(logLength+1))
            gl.GetShaderInfoLog(shader, logLength, nil, gl.Str(log))
            return 0, fmt.Errorf("failed to compile %v: %v", source, log)
        }
        return shader, nil
    }
    
    //这里我们调用了 `makeVaoTest` ,从我们之前定义的 `triangle` 顶点中获得 `vao` 引用,将它作为一个新的参数传递给 `drawTest` 函数:
    func drawTest(window *glfw.Window, program uint32) {
        //清除画布颜色缓存和深度缓存
        gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
        //使用什么着色器
        gl.UseProgram(program)
        //0是指从顶点buffer的什么位置开始,count表示我们画3个顶点
        gl.DrawArrays(gl.TRIANGLES, 0, 3)
        //传递事件
        glfw.PollEvents()
        //交换缓存到显卡
        window.SwapBuffers()
    }
    
    func main() {
        //init() //init是不会被申明的,所以这里调用会报错
    
        window := initGlfwTest()
        defer glfw.Terminate()
        program := initOpenGLTest()
    
        //这里是去获取到我们的着色器中顶点位置 vp
        attVertex := uint32(gl.GetAttribLocation(program, gl.Str("vp\x00")))
        //获取我们的顶点着色器中顶点颜色 vs_color
        attColor := uint32(gl.GetAttribLocation(program, gl.Str("vs_color\x00")))
        fmt.Println("main 1 =", attVertex, attColor)
    
        //vaoVertex := makeVaoTest(triangle, attVertex, 3)
        //makeVaoTest(triangle, attVertex, 3)
        //vaoColor := makeVaoTest(vertexColor, attColor, 4)
        //makeVaoTest(vertexColor, attVertex, 4)
        //fmt.Println("main 2 =", vaoVertex, vaoColor)
    
        //vaoVertex := makeVaoTest(triangle, 3)
    
        vbo, vao := makeVboVao()
        //gl.BindBuffer(gl.ARRAY_BUFFER, vaoVertex)
        //gl.EnableVertexAttribArray(attVertex)
        //gl.VertexAttribPointer(attVertex, 3, gl.FLOAT, false, 0, nil)
        var step float32 = 0.01
        var nowUnix = time.Now().UnixNano() / 1000000
        for !window.ShouldClose() {
            makeVaoTest2(vertexPosColor, vbo, vao, attVertex, attColor)
    
            drawTest(window, program)
    
            //让我们的顶点动起来
            vertexPosColor[0] += step
            if vertexPosColor[0] > 1.0 {
                step = -0.01
            } else if vertexPosColor[0] < -1.0 {
                step = 0.01
            }
    
            //计算fps
            preUnix := nowUnix
            nowUnix = time.Now().UnixNano() / 1000000
            var fps = fmt.Sprintf("FPS:%.2v", 1000.0/(nowUnix-preUnix))
            fmt.Println(fps)
            //显示在窗口的title中
            window.SetTitle(fps)
        }
    }
    
    

    相关文章

      网友评论

          本文标题:go gl 彩色的三角形

          本文链接:https://www.haomeiwen.com/subject/mhxosqtx.html