rucuriousyet
rucuriousyet

Reputation: 41

Go go-gl OpenGL Rendering Issues

I have a program that was originally working completely fine that would draw a triangle using the go-gl OpenGL wrapper for Go. In the process of playing with the code things started to get weird. Sometimes the shape would be rendered, and then it just wouldn't. Sometimes saving the file then running the code again would work, sometimes that also failed. In this process there were no changes to made to the file from working to broken. The glfw window still shows up with a background color and the vertices array I use is populated. I am not sure whether this is a simple error in my code or if its something hardware related.

Not sure if this helps, but I am using the latest Atom editor with the Go-Plus plugin.

package main

import (
    "fmt"
    "log"
    "runtime"

    "github.com/go-gl/gl/v4.1-core/gl"
    "github.com/go-gl/glfw/v3.1/glfw"
)

const vertexSource = `
#version 330
in vec2 position;
void main() {
    gl_Position = vec4(position,0.0, 1.0);
}
` + "\x00"

const fragmentSource = `
#version 330
uniform vec3 triangleColor;
out vec4 outputColor;
void main() {
    outputColor = vec4(triangleColor,1.0);
}
` + "\x00"

var vao, vbo uint32
var vertices = []float32{
    0.0, 0.5,
    0.5, -0.5,
    -0.5, -0.5,
}

func init() {
    runtime.LockOSThread()
}

func main() {
    if err := glfw.Init(); err != nil {
        log.Fatalln("failed to initalize GL window:", err)
    }
    defer glfw.Terminate()

    glfw.WindowHint(glfw.Resizable, glfw.True)
    glfw.WindowHint(glfw.ContextVersionMajor, 4)
    glfw.WindowHint(glfw.ContextVersionMinor, 1)
    glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile)
    glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.True)

    windowHeight := 800
    windowWidth := 800

    window, err := glfw.CreateWindow(windowWidth, windowHeight, "HelloGL2.0", nil, nil)
    if err != nil {
        panic(err)
    }
    window.MakeContextCurrent()

    if err := gl.Init(); err != nil {
        panic(err)
    } else {
        fmt.Println("OpenGL Version:", gl.GoStr(gl.GetString(gl.VERSION)))
    }

    gl.GenVertexArrays(1, &vao)
    gl.BindVertexArray(vao)

    gl.GenBuffers(1, &vbo)

    gl.BindBuffer(gl.ARRAY_BUFFER, vbo)
    gl.BufferData(gl.ARRAY_BUFFER, len(vertices), gl.Ptr(vertices), gl.STREAM_DRAW)

    vertexShader := gl.CreateShader(gl.VERTEX_SHADER)
    vcsources, free := gl.Strs(vertexSource)
    gl.ShaderSource(vertexShader, 1, vcsources, nil)
    free()
    gl.CompileShader(vertexShader)
    fragmentShader := gl.CreateShader(gl.FRAGMENT_SHADER)
    fcsources, free := gl.Strs(fragmentSource)
    gl.ShaderSource(fragmentShader, 1, fcsources, nil)
    gl.CompileShader(fragmentShader)

    shaderProgram := gl.CreateProgram()
    gl.AttachShader(shaderProgram, vertexShader)
    gl.AttachShader(shaderProgram, fragmentShader)
    gl.BindFragDataLocation(shaderProgram, 0, gl.Str("outputColor\x00"))
    gl.LinkProgram(shaderProgram)
    gl.UseProgram(shaderProgram)

    posAttrib := uint32(gl.GetAttribLocation(shaderProgram, gl.Str("position\x00")))
    gl.EnableVertexAttribArray(posAttrib)
    gl.VertexAttribPointer(posAttrib, 2.0, gl.FLOAT, false, 0.0, gl.PtrOffset(0))

    gl.GetUniformLocation(shaderProgram, gl.Str("triangleColor\x00"))

    //GL_STATIC_DRAW: The vertex data will be uploaded once and drawn many times (e.g. the world).
    //GL_DYNAMIC_DRAW: The vertex data will be changed from time to time, but drawn many times more than that.
    //GL_STREAM_DRAW: The vertex data will change almost every time it's drawn (e.g. user interface).

    for !window.ShouldClose() {
        //gl.Uniform3f(uniColor, 2.0, 0.0, 1.0)

        gl.ClearColor(0.9, 1.0, 0.3, 1.0)
        gl.Clear(gl.COLOR_BUFFER_BIT)

        gl.DrawArrays(gl.TRIANGLES, 0, 3)

        window.SwapBuffers()
        glfw.PollEvents()
    }

    gl.DeleteProgram(shaderProgram)
    gl.DeleteShader(fragmentShader)
    gl.DeleteShader(vertexShader)
    gl.DeleteBuffers(1, &vbo)
    gl.DeleteVertexArrays(1, &vao)

    fmt.Println("Exiting!")

    window.Destroy()

}

Upvotes: 1

Views: 429

Answers (2)

Will
Will

Reputation: 1098

For the triangle to appear, BufferData size parameter needs the len(vertices) times float32 size (4):

gl.BufferData(gl.ARRAY_BUFFER, len(vertices)*4, gl.Ptr(vertices), gl.STREAM_DRAW)

For the triangle to show a color, there are two changes to make.

Put the uniColor variable in the left side of the GetUniformLocation triangleColor line:

uniColor := gl.GetUniformLocation(shaderProgram, gl.Str("triangleColor\x00"))

Uncomment the line to set the color:

gl.Uniform3f(uniColor, 2.0, 0.0, 1.0)

Minor things:

The BindFragDataLocation line with outputColor can be removed. Even if GetUniformLocation replaced the line, it won't work between the AttachShader and LinkProgram lines.

It's recommended to do the following after LinkProgram to free up resources:

gl.DetachShader(shaderProgram, vertexShader)
gl.DetachShader(shaderProgram, fragmentShader)
gl.DeleteShader(vertexShader)
gl.DeleteShader(fragmentShader)

Upvotes: 0

Alandroid
Alandroid

Reputation: 31

Your code gives me:

./gl.go:76: undefined: gl.Strs
./gl.go:81: undefined: gl.Strs

Consider using my code for loading and compiling your shaders:

func NewProgram(vertexShaderSource, fragmentShaderSource string) (uint32, error) {
    vertexShader, err := CompileShader(vertexShaderSource, gl.VERTEX_SHADER)
    if err != nil {
        return 0, err
    }

    fragmentShader, err := CompileShader(fragmentShaderSource, gl.FRAGMENT_SHADER)
    if err != nil {
        return 0, err
    }

    program := gl.CreateProgram()

    gl.AttachShader(program, vertexShader)
    gl.AttachShader(program, fragmentShader)
    gl.LinkProgram(program)

    var status int32
    gl.GetProgramiv(program, gl.LINK_STATUS, &status)
    if status == gl.FALSE {
        var logLength int32
        gl.GetProgramiv(program, gl.INFO_LOG_LENGTH, &logLength)

        log := strings.Repeat("\x00", int(logLength+1))
        gl.GetProgramInfoLog(program, logLength, nil, gl.Str(log))

        return 0, errors.New(fmt.Sprintf("failed to link program: %v", log))
    }

    gl.DeleteShader(vertexShader)
    gl.DeleteShader(fragmentShader)

    return program, nil
}

func CompileShader(source string, shaderType uint32) (uint32, error) {
    shader := gl.CreateShader(shaderType)

    csource := gl.Str(source)
    gl.ShaderSource(shader, 1, &csource, nil)
    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
}

Upvotes: 0

Related Questions