Posts
Search
Contact
Cookies
About
RSS

Go 3d with G3N (a rather nice 3d engine for golang)

Added 31 May 2018, 12:26 a.m. edited 18 Jun 2023, 7:31 p.m.

I've had my eye on Go for a while, the last time I had a good look at it I was generally satisfied, but a little bit disappointed with the surrounding ecosystem, especially relating to 3D graphics. Its not taken too long for this to be addressed and looking through github I found a rather nice 3d engine written in and for the Go language. Despite being a relative novice at coding with Go I was able to take the quick start code from the read me and not only get it running but to add and change things with ease.

My initial investigations did lead me to an interesting "feature" in Go, namely that shadowing variables is allowed and as Go doesn't do warnings, it can cause a nasty bug. You can run go vet -shadow and if I ever need anything more complex than go build then I'll be certainly be adding that command in there... The issue is best explained by looking at a little code...

package main

import "fmt"

var x int

func main() {
    x := 24
    fmt.Println("x =",x)
    showX()
}

func showX() {
    fmt.Println("x =",x)
}
The problem here is the accidental declarative assignment at the start of main(), this can be exacerbated by using a text editor with a default font that has colons with sub microscopic dots, but my disappointments with KDE 5 are better left for another day (if I can be bring myself to blog about it *sigh*) A common pattern in Go seems to be to use a declarative assignment usually with an error value as well as the item you're creating. Its all to easy to decide you want to use a global and forget to change the deceleration to a simple assignment. Yet another reason global variables are usually best done without! and I'm not too sure this shouldn't be an error... That aside Go is a nice language and the compiler is easy to live with, if C++ will shoot your foot off and the Rust compiler forces you to shoot your foot off, then Go feels like the safety is on and the rabbit jumped into your bag where it died peacefully in its sleep. Before you can even open a window with G3n you need to create a "window manager" this had been done to provide an easy place to encapsulate different tool kits, there is only GLFW at the moment by I can definitely live with that, having happily relied on it a number of times when working in C. It does follow a very similar pattern to using GLFW even allowing low level access to OpenGL, you only really need to access to OpenGL for things like setting the background colour and viewport settings. While arguably these type of things could be bundled up into the window manager object, it is actually nice to have low level access when you need it.

Lets look at adding a textured 3d object - while you can load wavefront obj or collada files there are a useful set geometric shapes that can be created on the fly

tx, err := texture.NewTexture2DFromImage("./doh.png")
if err != nil {
    panic(err)
}

geom := geometry.NewTorus(1, .6, 16, 32, math.Pi*2)
mat := material.NewPhong(math32.NewColor("White"))
mat.AddTexture(tx)
shape := graphic.NewMesh(geom, mat)
scene.Add(shape)
It really is that simple, the material in concert with and image provides the geometry with a "skin", both the geometry and material together make up a mash. The scene variable is a normal scene node provided by the engine, you parent everything to a node and then tell the renderer what scene you want to render. Hierarchies like this are very powerful allowing you to swap in whole scene when you need to change things about. For example while in an elevator scene you could be loading and setting up another scene and just swap in the new level when you're ready for it. Its worth looking at the engines godoc although some of the descriptions could be a little more verbose and give hints on usage, if you get really stuck the codes just there, not just the various demo's but the engine code itself. Go is a very clean language and doesn't look like someone has vomited ascii all over your screen and the code base for the engine is organised in a reasonably logical manner, so you can usually work out what you need to do to get things going. Callbacks are used as you'd expect in any other GLFW application, you can use anonymous functions which is fine for two to three liners, but much more and it can clutter your code, obviously if you have a window size callback you're going to have to access OpenGL and the camera, for ease I'm just using globals (hence the shadow discovery) and this is less than ideal and doesn't feel particularly idiomatic Go. We'll be addressing this at a later date, by using the engines application singleton, because for sure I'll be investigating this project closer, in the mean time you can download my version of the hello world app for g3n