Although the work uses only the basic java
and javascript
but has been more interested in golang, recently nothing else, wanted to write a game (also a blogger dream has always been) but if the direct effect on the game engine would not achieve the learning, so learn from scratch opengl
, golang
under the opengl
document is relatively small, the application does not seem wide, shining only C++
document Zhaomaohuahu the
main reference tutorial these two sites
learnOpenGl Chinese translation, use C++
implementation.
Go with OpenGL Tutorial unique in golang use opengl tutorials can be found, very early.
1. Related concepts
opengl
Developed by the Khronos Group and a maintenance specification (Specification). The specification defines how strictly the implementation of each function, and their output value. As for the interior of each specific function is how to achieve (Implement), will be the developer of OpenGL library discretion (translation: here the developer is the person to write OpenGL library). Because the details of OpenGL specification does not achieve a predetermined specific OpenGL library allows for different implementations, and as long as its function results matching the specification (i.e., as the user does not feel the difference in the function).
glfw
Used to create the window, context, and interfaces to receive input api and events.
shader(着色器)
Running applets on the GPU. These small programs to a specific part of the graphics rendering pipeline and run, the use of a C-like language called GLSL written, there is a vertex shaders and fragment shaders are two kinds of concrete doing is not very thorough I understand now only the door as he rendered image of a different phase of the tool?
program
After the merge multiple shader and final link to complete version.
Vertex Buffer Object (顶点缓冲区对象,简称vbo)
A plurality of objects stored vertices, a large number of one-time data transmission to the graphics card, it is easily understood that, if no buffer, make a vertex of each image are sent to the GPU, and the buffer is the same as the programming language thought.
Vertex Array Object(顶点数组对象,简称vao)
Vbo and save one or more corresponding vertex attributes, not only is there vbo rendered image directly, but also need to bind a variety of attributes, such as normals, color information, indexes, etc., after drawing each have the same configuration vao do not re-bind when vbo
Element Buffer Object(索引缓冲对象,简称ebo)
The concept here on the very clear, and not elaborated here
2. dependence
golang
In the country seems to be qiang, the good news opengl
and glfw
dependencies are posted github
on the configured gopath
directly using the system variable go get
command to download the dependencies. It is noted that the installation opengl
dependencies needed gcc
, if not, need to be installed mingw
or TDM-GCC
, as dependent on the installation command
go get -u github.com/go-gl/gl/v4.6-core/gl
go get github.com/go-gl/glfw/v3.2/glfw
3. Initialize window
import(
"github.com/go-gl/glfw/v3.2/glfw"
)
The introduction of dependence
if err := glfw.Init(); err != nil {
panic(err)
}
glfw.WindowHint(glfw.Resizable, glfw.False)
window, err := glfw.CreateWindow(width, height, "Conway's Game of Life", nil, nil)
if err != nil {
panic(err)
}
window.MakeContextCurrent()
Initialization and set the properties window, set the window size can not be changed here, to note is that GLFW
needs to be called in its thread after being initialized in
4. Preparation of shader programs and shader
The aforementioned use shader GLSL
language, studied the chain of responsibility pattern design students can shader understood as different parts of the chain of responsibility, and the output of the previous program is entering a program, we were to write a vertex shader and fragment shaders and write using a opengl
compiled function
import(
"github.com/go-gl/gl/v4.1-core/gl"
"strings"
"fmt"
)
const(
VertexShaderSource = `
#version 410
in vec3 vp;
void main(){
gl_Position = vec4(vp,1.0);
}
` + "\x00"
FragmentShaderSource = `
#version 410
out vec4 frag_colour;
uniform vec4 FragColor;
void main() {
frag_colour = FragColor;
}
` + "\x00"
)
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
}
Then we initialize shaders and shader added
if err := gl.Init(); err != nil {
panic(err)
}
version := gl.GoStr(gl.GetString(gl.VERSION))
log.Println("OpenGL version", version)
vertexShader, err := shader.CompileShader(shader.VertexShaderSource, gl.VERTEX_SHADER)
if err != nil {
panic(err)
}
fragmentShader, err := shader.CompileShader(shader.FragmentShaderSource, gl.FRAGMENT_SHADER)
if err != nil {
panic(err)
}
prog := gl.CreateProgram()
gl.AttachShader(prog, vertexShader)
gl.AttachShader(prog, fragmentShader)
gl.Viewport(0,0,width,height)
gl.LinkProgram(prog)
The construct an image, and a buffer
Define two slices
var (
vertices = []float32{
-0.5, -0.5, 0.0,
-0.5, 0.5, 0.0,
0.5, 0.5, 0.0,
0.5, -0.5, 0.0,
}
indices = []uint32{
0, 1, 2,
2, 3, 0,
}
)
Stored within the first slice of all the vertices constituting the two triangles are needed, since we will use ebo
, the two directly repeated vertices omitted, and each row of the second slice index of the previous section representing vertices, respectively corresponding triangular configuration.
Generate and bindvao
var vbo uint32
gl.GenBuffers(1, &vbo)
gl.BindBuffer(gl.ARRAY_BUFFER, vbo)
gl.BufferData(gl.ARRAY_BUFFER, 4*len(points), gl.Ptr(points), gl.STATIC_DRAW)
var vao uint32
gl.GenVertexArrays(1, &vao)
gl.BindVertexArray(vao)
gl.EnableVertexAttribArray(0)
gl.VertexAttribPointer(0, 3, gl.FLOAT, false, 0, gl.Ptr(nil))
var ebo uint32
gl.GenBuffers(2,&ebo)
gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER,ebo)
gl.BufferData(gl.ELEMENT_ARRAY_BUFFER,4*len(indices),gl.Ptr(indices),gl.STATIC_DRAW)
Finally main
draw function
for !window.ShouldClose() {
gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
timeValue := glfw.GetTime()
greenValue := float32(math.Sin(timeValue) / 2.0 + 0.5)
vertexColorLocation := gl.GetUniformLocation(prog,gl.Str("FragColor\x00"))
gl.UseProgram(prog)
glBindVertexArray(vao);
gl.Uniform4f(vertexColorLocation,0,greenValue,0,1)
gl.DrawElements(gl.TRIANGLES, 6, gl.UNSIGNED_INT, gl.PtrOffset(0))
glfw.PollEvents()
window.SwapBuffers()
}
The final operating results
complete code is as follows
package main
import(
"github.com/go-gl/glfw/v3.2/glfw"
"github.com/go-gl/gl/v4.1-core/gl"
"log"
"legend/shader"
"runtime"
"math"
"strings"
"fmt"
)
const (
width = 500
height = 500
VertexShaderSource = `
#version 410
in vec3 vp;
void main(){
gl_Position = vec4(vp,1.0);
}
` + "\x00"
FragmentShaderSource = `
#version 410
out vec4 frag_colour;
uniform vec4 FragColor;
void main() {
frag_colour = FragColor;
}
` + "\x00"
)
var (
vertices = []float32{
-0.5, -0.5, 0.0,
-0.5, 0.5, 0.0,
0.5, 0.5, 0.0,
0.5, -0.5, 0.0,
}
indices = []uint32{
0, 1, 2,
2, 3, 0,
}
)
func main() {
runtime.LockOSThread()
window := initGlfw()
defer glfw.Terminate()
program := initOpenGL()
vao := makeVao(vertices,indices)
for !window.ShouldClose() {
draw(vao, window, program)
}
glfw.Terminate()
}
func initGlfw() *glfw.Window {
if err := glfw.Init(); err != nil {
panic(err)
}
glfw.WindowHint(glfw.Resizable, glfw.False)
window, err := glfw.CreateWindow(width, height, "Conway's Game of Life", nil, nil)
if err != nil {
panic(err)
}
window.MakeContextCurrent()
return window
}
func initOpenGL() uint32 {
if err := gl.Init(); err != nil {
panic(err)
}
version := gl.GoStr(gl.GetString(gl.VERSION))
log.Println("OpenGL version", version)
vertexShader, err := shader.CompileShader(shader.VertexShaderSource, gl.VERTEX_SHADER)
if err != nil {
panic(err)
}
fragmentShader, err := shader.CompileShader(shader.FragmentShaderSource, gl.FRAGMENT_SHADER)
if err != nil {
panic(err)
}
prog := gl.CreateProgram()
gl.AttachShader(prog, vertexShader)
gl.AttachShader(prog, fragmentShader)
gl.Viewport(0,0,width,height)
gl.LinkProgram(prog)
return prog
}
func makeVao(points []float32,indices []uint32) uint32 {
var vbo uint32
gl.GenBuffers(1, &vbo)
gl.BindBuffer(gl.ARRAY_BUFFER, vbo)
gl.BufferData(gl.ARRAY_BUFFER, 4*len(points), gl.Ptr(points), gl.STATIC_DRAW)
var vao uint32
gl.GenVertexArrays(1, &vao)
gl.BindVertexArray(vao)
gl.EnableVertexAttribArray(0)
gl.VertexAttribPointer(0, 3, gl.FLOAT, false, 0, gl.Ptr(nil))
if(indices != nil){
var ebo uint32
gl.GenBuffers(2,&ebo)
gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER,ebo)
gl.BufferData(gl.ELEMENT_ARRAY_BUFFER,4*len(indices),gl.Ptr(indices),gl.STATIC_DRAW)
}
return vao
}
func draw(vao uint32, window *glfw.Window, program uint32) {
gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
timeValue := glfw.GetTime()
greenValue := float32(math.Sin(timeValue) / 2.0 + 0.5)
vertexColorLocation := gl.GetUniformLocation(program,gl.Str("FragColor\x00"))
gl.UseProgram(program)
gl.BindVertexArray(vao)
gl.Uniform4f(vertexColorLocation,0,greenValue,0,1)
//gl.DrawArrays(gl.TRIANGLES, 0, 4)
gl.DrawElements(gl.TRIANGLES, 6, gl.UNSIGNED_INT, gl.PtrOffset(0))
glfw.PollEvents()
window.SwapBuffers()
}
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
}