go gl 彩色的三角形

栏目: 后端 · 发布时间: 7年前

内容简介:之前在网上想找一个能渲染颜色的go gl图形编程例子,,找了半天都是白色的三角形。。。于是自己研究了半天,大概是研究出来的样子,记录到这里来分享一下。1.
go gl 彩色的三角形

go 彩色三角形

之前在网上想找一个能渲染颜色的go gl图形编程例子,,找了半天都是白色的三角形。。。于是自己研究了半天,大概是研究出来的样子,记录到这里来分享一下。

作者用的是mac开发的,windows的go gl需要麻烦一点的操作,读者自行裁决吧。

配置

1. go下载

2.配置mac go环境请自行搜索一下。

3.IDE。作者用的是 goland ,破解的话,也请自行搜索一下。

go开发包

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

go gl 彩色的三角形

借助github的golang下载

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

go gl 彩色的三角形

配置

核心开发包

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Hackers

Hackers

Steven Levy / O'Reilly Media / 2010-5-30 / USD 21.99

This 25th anniversary edition of Steven Levy's classic book traces the exploits of the computer revolution's original hackers -- those brilliant and eccentric nerds from the late 1950s through the ear......一起来看看 《Hackers》 这本书的介绍吧!

SHA 加密
SHA 加密

SHA 加密工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具