sgl

package module
v0.0.0-...-27c5885 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 17, 2022 License: MIT Imports: 11 Imported by: 0

README

SimpleGL

SimpleGL is a simple Go wrapper for modern OpenGL.
It's a pure Go repo and is fully compatible with go-gl ecosystem.

NOTICE

This package is still in early stages and might have incompatible updates!

SimpleGL uses the packages below:

SimpleGL provides Object, Group, Viewpoint, LightSource, some common shapes and some routine functions to make modern OpenGL development more easily and fast.
It could be seen as a lightweight wrapper just to simplify the OpenGL routines and organize the code, so developers can get rid of those verbose routines and focus on shaders, vertices and business logics.

Installation

go get github.com/burwei/sgl

Quick Start

Let's get start with the hello cube program. It shows a rotating cube.
This program is the modified version of go-gl/example/gl41core-cube example.

package main

import (
	"math"

	"github.com/burwei/sgl"
	"github.com/go-gl/glfw/v3.3/glfw"
	"github.com/go-gl/mathgl/mgl32"
)

const (
	width  = 800
	height = 600
	title  = "SimpleGL"
)

func main() {
	window := sgl.Init(width, height, title)
	defer sgl.Terminate()

	vp := sgl.NewViewpoint(width, height)
	ls := sgl.NewLightSrc()
	mt := sgl.NewMaterial()

	cube := sgl.NewSimpleObj()
	cube.SetProgVar(sgl.SimpleObjVar{
		Red:   1,
		Green: 0.3,
		Blue:  0.3,
		Vp:    &vp,
		Ls:    &ls,
		Mt:    &mt,
	})
	cube.SetVertices(sgl.NewCube(200))
	cube.SetModel(mgl32.Translate3D(0, 0, 0))

	angle := 0.0
	previousTime := glfw.GetTime()
	rotateY := mgl32.Rotate3DY(-math.Pi / 6).Mat4()

	sgl.BeforeMainLoop(window, &vp)
	for !window.ShouldClose() {
		sgl.BeforeDrawing()

		// make the cube rotate
		time := glfw.GetTime()
		elapsed := time - previousTime
		previousTime = time
		angle += elapsed
		cube.SetModel(rotateY.Mul4(
			mgl32.Rotate3DX(float32(angle) / 5).Mat4(),
		))

		// Render
		cube.Render()

		sgl.AfterDrawing(window)
	}
}

result:

Usage

To use SimpleGL, developers should know how to develop modern OpenGL.
LeanOpenGL.com is a good place to get started if one is not so familiar with OpenGL.

The good news is, developers with Go programming skills and zero OpenGL knowledge might still able to learn some basic OpenGL directly from SimpleGL, since it organizes the code to make it easier to use and understand.

The usage introduction contains the contents below:

  • OpenGL program struture
  • Object
  • Shape
  • Viewpoint & Coordinate system
  • LightSource & Material
  • Group
  • STL
OpenGL Program structure

Modern OpenGL program can be roughly divided into two parts, CPU program and GPU programs.

The CPU program contains two parts, setup and main loop.
In setup part we call sgl.Init(), which will lock the current thread and init OpenGL and GLFW. GLFW is the library that handles the graphics output and device input, such as window, keyboard, mouse, joystick and so on. Variable assignment, input callback settings and all things we should prepared before starting the main loop will be in the setup part.
The main loop is the for !window.ShouldClose() {} loop. We render the objects in main loop. Before and after the rendering, we call sgl.BeforeDrawing() and sgl.AfterDrawing() to clean, swap buffers and poll events.

The GPU programs contains also two parts, Program Object and shaders. Program Object is used in render operation and it's also the "Program" that SimpleGL refers to when calling APIs like sgl.MakeProgram() and slg.SetProgVar() and so on. SimpleGL sees each Program Object as a final all-in-one program for each sgl.Object, so all varialbes of shaders attached to the Program Object are also seen as the variables of the "Program". Shaders are written in GLSL, and are used to determine how to draw the vertices.
One Program Object can combine multiple shaders to do the rendering job, but we only attach a vertex shader and a fragment shader on it in SimpleGL (so far). Vertex shader calculates the positions of vertices and fragment shader calculates the colors of fragments.

The above is just a simplified introduction. To know more about how OpenGL works, see OpenGL rendering pipeline overview.

Object

sgl.Object is an interface that represents a object with a specific Project Object that can be render on the window after it gets the program variables and vertex array it needs.

sgl.Object + program variables + vertex array = visuable object

sgl.SimpleObj is the object with basic lighting, and it's able to draw any shape (any vertex array that contains 3*n float32 values). Developers can implement their own sgl.Object to create some cool objects. By implement sgl.Object, the object could be more easiy to use and be able to move together as a group.

// create a sgl.Object with its program
cube := sgl.NewSimpleObj()

// set shader program variables and bind them to the program
cube.SetProgVar(sgl.SimpleObjVar{
	Red:   1,
	Green: 0.3,
	Blue:  0.3,
	Vp:    &vp,
	Ls:    &ls,
	Mt:    &mt,
})

// set the vetex array
cube.SetVertices(sgl.NewCube(200))

// set the initial position and rotation of the object
// we set the posisition to (0, 0, 0) without any rotation
cube.SetModel(mgl32.Translate3D(0, 0, 0))

// render the object (in main loop)
cube.Render()
Shape

Shapes are described by vertex arrays, which are 1-D float32 arrays. The most basic vertex arrays are those who use 3 float32 values to represent a vertex's X,Y,Z position. Sometimes vertex array will contains some meta data such as the direction of the texture.

For instance, sgl.NewCube() is a vertex array that use 3 float32 to represent a vertex and form a cube with a user-defined side length.

cube.SetVertices(sgl.NewCube(200))
Viewpoint & Coordinate system

sgl.Viewpoint provides a default camera (eye) position on (X, Y, Z) = (0, 0, 1000) and default target position on (X, Y, Z) = (0, 0, 0). The default top direction of the camera is positive Y and the default projection is perspective projection.

Before we read the code, we should understand the position of the camera as well as the coordinate systems.

There are four coordinate systems here:

  1. local coordinate
  2. world-space coordinate
  3. view-space coordinate
  4. clip-space coordinate

The usage of sgl.Viewpoint is simple. Just new one with the width and height of the window. Although there's no strong restrictions, all sgl.Object should contain a sgl.Viewpoint to make the object appear in view-space and clip-space coordinate correctly.

vp := sgl.NewViewpoint(width, height)

cube := sgl.NewSimpleObj()
cube.SetProgVar(sgl.SimpleObjVar{
	Red:   1,
	Green: 0.3,
	Blue:  0.3,
	Vp:    &vp,
	Ls:    &ls,
	Mt:    &mt,
})
LightSource & Material

sgl.LightSource and agl.Material provides a default light source and default material. These two are essential for those sgl.Object that render the lighting effect.

sgl.LightSource contains 3 attributes: light position, light color and light intensity. All of them are easy to understand.

sgl.Material contains 4 attributes: ambient, diffuse, specular and shininess. Ambient determines what color does the material reflects under ambient lighting; diffuse determines what color does the material reflects under diffuse lighting; specular determines the color of the material's specular highligh; and shininess determines the scattering/radius of the specular highlight.

ls := sgl.NewLightSrc()
mt := sgl.Material{
	Ambient: mgl32.Vec3{0.1, 0.1, 0.1},
	Diffuse: mgl32.Vec3{0.6, 0.6, 0.6},
	Specular: mgl32.Vec3{1.5, 1.5, 1.5},
	Shininess: 24,
}

cube := sgl.NewSimpleObj()
cube.SetProgVar(sgl.SimpleObjVar{
	Red:   1,
	Green: 0.3,
	Blue:  0.3,
	Vp:    &vp,
	Ls:    &ls,
	Mt:    &mt,
})
Group

sgl.Group collects mutiple sgl.Object and make them move together like a bigger object. Besides making sgl.Object move together, sgl.Group can also move any collected sgl.Object individually.

// before main loop
group := sgl.NewGroup()
group.AddObject("cube1", &cube1)

// in main loop
group.SetObjectModel("cube1", rotateY.Mul4(
	mgl32.Rotate3DX(float32(angle)/5).Mat4(),
))
group.SetGroupModel(
	mgl32.Translate3D(0, float32(tr), 0).Mul4(
		mgl32.Rotate3DY(float32(angle)/5).Mat4(),
	),
)
group.Render()
STL

STL is a common file format for 3D models.
SimpleGL also provides some APIs to read STL files and turn them into vertex arrays.

The below shows how to read a STL file and create a object with it.
The STL file is download from a free STL platform called cults3d.com, and the link is here.

// free stl source: https://cults3d.com/en/3d-model/game/iron-man-bust_by-max7th-kimjh
// read binary STL file and shift it to the center
stlVertices := sgl.ReadBinaryStlFile("ironman_bust_max7th_bin.stl")
stl := sgl.NewBaseObj()
stl.SetProgVar(sgl.BaseObjVar{Vp: &vp})
stl.SetVertices(&stlVertices)
stl.SetModel(mgl32.Translate3D(0, 0, 0))
	

// read binary STL file without shifting
stlVertices := sgl.ReadBinaryStlFileRaw("ironman_bust_max7th_bin.stl")

// read binary STL file and shift it to a specific center
stlVertices := sgl.ReadBinaryStlFileWithCenter("ironman_bust_max7th_bin.stl", 50, 100, 20)

result:

Examples

For more examples, see the example folder.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AddNormal

func AddNormal(vertices []float32) []float32

func AfterDrawing

func AfterDrawing(window *glfw.Window)

func BeforeDrawing

func BeforeDrawing()

func BeforeMainLoop

func BeforeMainLoop(window *glfw.Window, vp *Viewpoint)

func Init

func Init(windowWidth int, windowHeight int, windowTitle string) *glfw.Window

func InitGlfwAndOpenGL

func InitGlfwAndOpenGL(width int, height int, title string) *glfw.Window

func MakeProgram

func MakeProgram(vertexShaderSource, fragmentShaderSource string) uint32

func MakeProgramFromFile

func MakeProgramFromFile(vertPath string, fragPath string) uint32

func NewCube

func NewCube(l float32) *[]float32

NewSimpleCube will return vertices of a cube with side length l.

func NewPlane

func NewPlane(l float32) *[]float32

func NewUniTexCube

func NewUniTexCube(l float32) *[]float32

NewUniTexCube will return vertices of a cube with side length l. The vertices contains custom data (texture vector)

func ReadBinaryStlFile

func ReadBinaryStlFile(file string) []float32

func ReadBinaryStlFileRaw

func ReadBinaryStlFileRaw(file string) []float32

func ReadBinaryStlFileWithCenter

func ReadBinaryStlFileWithCenter(
	file string,
	centerX float32,
	centerY float32,
	centerZ float32,
) []float32

func Terminate

func Terminate()

Types

type BaseObj

type BaseObj struct {
	// Program is the shader program of the object.
	Program uint32

	// Vao stands for "Vertex Array Object", and it contains
	// one or more "Vertex Buffer Object" which is a memory
	// buffer that contains the data of vertices
	Vao uint32

	// Vertices are points that form the shape of the object.
	Vertices *[]float32

	// Model keeps translation/rotation info of the object.
	Model mgl32.Mat4

	// Uniform is the map of the name of uniform variables in
	// shader program and itself.
	Uniform map[string]int32

	// ProgVar is the customizes struct that contains all the uniform
	// variables that will be used in the shader program of a certain object.
	// Developer should implement their own ProgVar and put it here to shadow
	// this BaseObjVar type of ProgVar
	ProgVar BaseObjVar
}

BaseObj is an Object that keeps the basic info of a Object which will render a wireframe object. BaseObj could be embedded into other Object struct to provide common methods like GetProgram(), GetProgVar(), GetVertices(), GetModel() and SetProgram(). So when we're developing a new Object struct, we only need to implement SetProgVar(), SetVertices() and Render().

func (*BaseObj) GetModel

func (obj *BaseObj) GetModel() mgl32.Mat4

func (*BaseObj) GetProgVar

func (obj *BaseObj) GetProgVar() interface{}

func (*BaseObj) GetProgram

func (obj *BaseObj) GetProgram() uint32

func (*BaseObj) GetVertices

func (obj *BaseObj) GetVertices() *[]float32

func (*BaseObj) Render

func (obj *BaseObj) Render()

func (*BaseObj) SetModel

func (obj *BaseObj) SetModel(model mgl32.Mat4)

func (*BaseObj) SetProgVar

func (obj *BaseObj) SetProgVar(progVar interface{})

func (*BaseObj) SetProgram

func (obj *BaseObj) SetProgram(program uint32)

func (*BaseObj) SetVertices

func (obj *BaseObj) SetVertices(vertices *[]float32)

type BaseObjVar

type BaseObjVar struct {
	Vp *Viewpoint
}

BaseObjVar is the program variable struct for BaseObj. Every Object struct will have it's own program variable struct.

type Group

type Group struct {
	// contains filtered or unexported fields
}

func NewGroup

func NewGroup() Group

func (*Group) AddObject

func (g *Group) AddObject(name string, obj Object)

func (*Group) Render

func (g *Group) Render()

func (*Group) SetGroupModel

func (g *Group) SetGroupModel(newModel mgl32.Mat4)

func (*Group) SetObjectModel

func (g *Group) SetObjectModel(name string, newModel mgl32.Mat4)

type LightSrc

type LightSrc struct {
	Pos       mgl32.Vec3
	Color     mgl32.Vec3
	Intensity float32
}

func NewLightSrc

func NewLightSrc() LightSrc

type Material

type Material struct {
	Ambient   mgl32.Vec3
	Diffuse   mgl32.Vec3
	Specular  mgl32.Vec3
	Shininess float32
}

func NewMaterial

func NewMaterial() Material

type Object

type Object interface {
	// GetProgram gets the program of the object.
	GetProgram() uint32

	// SetProgram sets the program of the object using an existing program.
	SetProgram(program uint32)

	// GetProgram gets the program variables of the object.
	// The return value should be a program variable struct.
	// Program variable struct is the customizes struct that contains all
	// the uniform variables that will be used in the shader program of a
	// certain object.
	GetProgVar() interface{}

	// SetProgram sets the program variables of the object.
	// The binding of uniform variables to the program should be set here.
	SetProgVar(progVar interface{})

	// GetVertices gets the vertices of the object.
	GetVertices() *[]float32

	// SetVertices sets the vertices of the object.
	// VAO, VBO and EBO should be set here if needed.
	SetVertices(vertices *[]float32)

	// GetModel gets the model of the object.
	GetModel() mgl32.Mat4

	// SetModel sets the model of the object.
	SetModel(model mgl32.Mat4)

	// Render refreshes uniform variables and draw the object.
	// All references of the variables that would change the
	// object's states in the main loop (i.e. uniform variables)
	// should have already been prepared when calling SetProgVar().
	Render()
}

Object is the basic interface of every renderable object.

func NewBaseObj

func NewBaseObj() Object

NewBaseObj return a BaseObj instance with its program. Each Object usually only be able to use one kind of program, so it's a nice practice to use NewXXX() to create an Object instance that contains the default program. However, we could always use SetProgram() to set the program if there is an existing program which is already been compiled.

func NewSimpleObj

func NewSimpleObj() Object

NewSimpleObj returns a SimpleObj instance with its program.

type SimpleObj

type SimpleObj struct {
	BaseObj
	// contains filtered or unexported fields
}

SimpleObj is the Object struct that will render a mono color object which has certain material properties. The mono color object will reflect the light from a single light source.

func (*SimpleObj) Render

func (obj *SimpleObj) Render()

func (*SimpleObj) SetProgVar

func (obj *SimpleObj) SetProgVar(progVar interface{})

func (*SimpleObj) SetVertices

func (obj *SimpleObj) SetVertices(vertices *[]float32)

type SimpleObjVar

type SimpleObjVar struct {
	Red   float32
	Green float32
	Blue  float32
	Vp    *Viewpoint
	Ls    *LightSrc
	Mt    *Material
}

SimpleObjVar is the program variable struct for SimpleObj.

type Viewpoint

type Viewpoint struct {
	Projection mgl32.Mat4
	Fovy       float32
	Aspect     float32
	Near       float32
	Far        float32
	Camera     mgl32.Mat4
	Eye        mgl32.Vec3
	Target     mgl32.Vec3
	Top        mgl32.Vec3
}

func NewViewpoint

func NewViewpoint(width int, height int) Viewpoint

Directories

Path Synopsis
demo
stl

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL