1. 简述
根据OpenGL版本的不同,在场景中绘制几何体的方式和使用的OpenGL函数有很大的差别,概括起来包括:
OpenGL模式 | 方式 | 备注 |
---|---|---|
LegecyOpenGL | 立即模式 | |
LegecyOpenGL | DispalyList(显示列表) | |
LegecyOpenGL | VertexArray的方式 | |
LegecyOpenGL | VBO方式 | 可以忽略VAO |
CoreProfile | VBO方式 | 必须使用VAO |
CoreProfile | VBO方式-DSA(>=4.5) | 使用DSA(Direct State Access)扩展的接口 |
针对表中Legecy OpenGL的几种方式,可以参考:《VA、VAO和VBO API备忘》
2. 基本绘制
三角形的顶点可以使用golang中的切片来定义:
var vertices = []float32{
-0.5,-0.5,0.0, 0.5,-0.5,0.0,0.5,}
如果使用OpenGL 2.1版本,可以使用立即模式来快速绘制三角形(调用glVertex*这样的函数)
func draw() {
gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
gl.Color3f(1.0,0.5,0.2)
gl.Begin(gl.TRIANGLES)
gl.Vertex3f(vertices[0],vertices[1],vertices[2])
gl.Vertex3f(vertices[3],vertices[4],vertices[5])
gl.Vertex3f(vertices[6],vertices[7],vertices[8])
gl.End()
}
3. VBO方式绘制(3.3)
在OpenGL 3.3以后的版本,绘制几何体需要使用VBO的方式。由于在3.3以后的版本OpenGL必须使用Shader来绘制,代码中会存在很多shader处理相关的代码,主要包括:
1. shader文件读取
2. shader的源码编译
3. program链接shader和使用program
func compileShader(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
}
绘制的代码需要创建VBO和VAO,同时使用接口将数据传输到VBO中,代码如下
var vbo uint32
gl.GenBuffers(1,&vbo)
gl.BindBuffer(gl.ARRAY_BUFFER,vbo)
gl.BufferData(gl.ARRAY_BUFFER,4*len(vertices),gl.Ptr(vertices),gl.STATIC_DRAW)
gl.GenVertexArrays(1,&vao)
gl.BindVertexArray(vao)
gl.VertexAttribPointer(0,3,gl.FLOAT,false,0,gl.PtrOffset(0))
gl.EnableVertexAttribArray(0)
gl.BindVertexArray(0)
gl.BindBuffer(gl.ARRAY_BUFFER,0)
vertexShader,err := compileShader(vertexShaderSourceCode,gl.VERTEX_SHADER)
if err != nil {
panic(err)
}
fragmentShader,err := compileShader(fragmentShaderSourceCode,gl.FRAGMENT_SHADER)
if err != nil {
panic(err)
}
program = gl.CreateProgram()
gl.AttachShader(program,vertexShader)
gl.AttachShader(program,fragmentShader)
gl.LinkProgram(program)
完成设置之后,绘制三角形
func draw() {
gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
gl.UseProgram(program)
gl.BindVertexArray(vao)
gl.DrawArrays(gl.TRIANGLES,int32(len(vertices)/3))
}
Shader部分非常简单,顶点shader直接读入数据并赋值给gl_Position,片元Shader直接设置颜色(需要注意golang中的跨行字符串格式)
var vertexShaderSourceCode = `
#version 330 core
layout (location=0) in vec3 pos;
void main() {
gl_Position = vec4(pos.x,pos.y,pos.z,1.0);
}
` + "\x00"
var fragmentShaderSourceCode = `
#version 330 core
out vec4 color;
void main() {
color = vec4(1.0,0.2,1.0);
}
` + "\x00"
3. VBO方式绘制(4.5 DSA)
OpenGL 4.5中的代码和3.3大体相同,不过由于DSA引入有部分接口略有差别,一个主要的区别是不需要在写很多gl.Bind函数了,主要的修改如下:
var vbo uint32
// 3.3
//gl.GenBuffers(1,&vbo)
//gl.BindBuffer(gl.ARRAY_BUFFER,vbo)
//gl.BufferData(gl.ARRAY_BUFFER,//4*len(vertices),gl.STATIC_DRAW)
// 4.5 DSA
gl.CreateBuffers(1,&vbo)
gl.Ptr(vertices),0)
//gl.GenVertexArrays(1,&vao)
//gl.BindVertexArray(vao)
//4.5 DSA
gl.CreateVertexArrays(1,&vao)
gl.BindVertexArray(vao)
gl.BindBuffer(gl.ARRAY_BUFFER,vbo)
gl.VertexAttribPointer(0,gl.PtrOffset(0))
gl.EnableVertexAttribArray(0)