内容简介:之前在网上想找一个能渲染颜色的go gl图形编程例子,,找了半天都是白色的三角形。。。于是自己研究了半天,大概是研究出来的样子,记录到这里来分享一下。1.
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) } }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- CSS三角形和饼图
- 【Leetcode】120.三角形最小路径和
- 【WPF】用三角形网格构建三维图形
- 音视频之opengl绘制三角形
- C++数字三角形问题与DP算法
- 蓝桥杯 ADV-135 算法提高 三角形面积
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。