go gl 彩色的三角形

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)
    }
}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,273评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,349评论 3 398
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 167,709评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,520评论 1 296
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,515评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,158评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,755评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,660评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,203评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,287评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,427评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,122评论 5 349
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,801评论 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,272评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,393评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,808评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,440评论 2 359

推荐阅读更多精彩内容