A performance oriented 2D/3D math package for Go

Package go3d is a performance oriented vector and matrix math package for 2D and 3D graphics.

Every type has its own sub-package and is named T. So vec3.T is the 3D vector type. For every vector and matrix type there is a String() method and a Parse() function. Besides methods of T there are also functions in the packages, like vec3.Dot(a, b).

Packages under the float64 directory are using float64 values instead of float32.

Matrices are organized as arrays of columns which is also the way OpenGL expects matrices. DirectX expects "arrays of rows" matrices, use the Transpose() to convert.

Methods that don't return a specific value, return a pointer to the struct to allow method call chaining.

Example:

a := vec3.Zero
b := vec3.UnitX
a.Add(&b).Scale(5)

Method names in the past tense return a copy of the struct instead of a pointer to it.

Example:

a := vec3.UnitX
b := a.Scaled(5) // a still equals vec3.UnitX

Note that the package is designed for performance over usability where necessary. This is the reason why many arguments are passed by pointer reference instead of by value. Sticking either to passing and returning everything by value or by pointer would lead to a nicer API, but it would be slower as demonstrated in mat4/mat4_test.go

cd mat4
go test -bench=BenchmarkMulAddVec4_PassBy*

Documentation: http://godoc.org/github.com/ungerik/go3d

Bitdeli Badge

Owner
Erik Unger
CTO & Co-Founder DOMONDA GmbH, Software & Aerospace Enthusiast
Erik Unger
Comments
  • Feature request: T.Array()

    Feature request: T.Array()

    The methods T.Slice() returns a slice to access the single fields, but this is incompatible with functions such as from go-gl on the UniformLocation type to specify some matrix values. Theses methods have arrays in their signature:

    func (location UniformLocation) UniformMatrix4fv(transpose bool, list ...[16]float32) {
    

    as seen here

    There is already one copy operation per field going on, I'd like to avoid having a second operation to copy the slice to a compatible array. Hence I'd like to propose the feature to add T.Array(), such as mat4.Array() [16]float32.

    Do you see this as a suitable addition to the library? Would you want to do this on your own or via pull request?

  • In place variants for matrix*vector

    In place variants for matrix*vector

    Heyhey

    For speed reasons, it would be nice to have an in place variant for transforming a vector with a matrix, i.e.

    v' = M * v

    with v' directly saved into v. My proposal would be to rename the existing MulVec3 etc. methods to MuledVec3 and implement the in place variant under the name MulVec3. This breaks all code using this, though.

    An alternative could be to provide the in place method under another name, e.g, TransformVec3.

  • Rotating vector by quaternion, normalizes it

    Rotating vector by quaternion, normalizes it

    Rotating anything by identity shouldn't change anything. vec := vec3.T{1,1,1} fmt.Printf("%v rotating by identity gives %v\n", vec,quaternion.Ident.RotatedVec3(&vec))

    [1 1 1] rotating by identity gives [0.5773503 0.5773503 0.5773503]

    Quaternion rotation converts input to another quaternion and multiply it.

    Normalizing quaternions is itself wise idea, but this vector normalization side-efect isn't so nice.

  • Extension/bugfixes on my fork

    Extension/bugfixes on my fork

    Hey there!

    I'm using a fork of your package for a ray tracer I'm implementing right now. In the process of developing it, I found some bugs, wrote some tests and implemented additional stuff (determinant of a mat4, inverse of a mat4...) Would you be interested in merging some of the changes? I must admit though that my tests/commits are not too clean...

    see https://github.com/panmari/go3d

  • vec3.Add() and similar should return a pointer

    vec3.Add() and similar should return a pointer

    The functions with names in the past tense that operate on more than one object (like vec3.Add()) should (imo) return a pointer to the result, not a normal object. This makes these functions consistent with their corresponding methods on the datatypes and makes it much easier to chain vector operations.

    For example, let's say I have three points (vec3.T) and want to find the area of the triangle whose vertices are the points.

    pt1 := vec3.T{0, 0, 0}
    pt2 := vec3.T{3, 5, 1}
    pt3 := vec3.T{6, 2, -1}
    

    To calculate the area without modifying pt1, pt2, or pt3, I would have to do this:

    v1 := vec.Sub(&pt2, &pt1)
    v2 := vec.Sub(&pt3, &pt2)
    areaVec := vec.Cross(&v1, &v2)
    return areaVec.Length()
    

    But if all functions that operate on vec3's return a pointer, it's simpler:

    return vec.Cross(vec.Sub(&pt2, &pt1), vec.Sub(&pt3, &pt2)).Length()
    

    I'm sure you came across this dilemma when designing go3d initially, but I'd like to at least hear your rationale for this design decision if nothing more.

  • Include copy of fmath with fix for archs other than amd64

    Include copy of fmath with fix for archs other than amd64

    Imported package github.com/barnex/fmath does not compile on other architectures than amd64:

    $ GOOS=linux GOARCH=arm go build
    # github.com/barnex/fmath
    /Users/hugues/go/pkg/mod/github.com/barnex/[email protected]/sqrtf_decl.go:7:6: missing function body
    
    

    fmath package provides float32 wrappers for standard math package float64 functions. It as (only) one optimization in assembly code for sqrt function, for architecture amd64. This optimization is implemented in two files: sqrtf_amd64.s and sqrtf_decl.go. That later file must be compiled only for amd64 arch because its function body is empty and implemented in sqrtf_amd64.s. Currently it is included in builds for all archs, leading to the error reported above. To fix that, it should be renamed or include a build flag:

    // +build amd64
    

    This pull request proposes to include (copy) fmath package code from github.com/barnex/fmath into go3d, and remove the dependency to github.com/barnex/fmath. One could argue that github.com/barnex/fmath could be fixed instead, but that project shows no activity since 6 years. In addition, it is very simply made of generated wrapper code from a simple bash script (see codegen.bash). The only optimisation is within sqrtf function, that works only for amd64. Hence a pragmatic approach is to embed the fixed fmath functions into go3d (just my humble opinion).

  • multiplying vector by float

    multiplying vector by float

    Can we add this feature to vec3? I suggest

    a := vec3.Zero
    b := 5.0
    a.MulFloat(b)
    
    func (vec) MulFloat(f float64) {
        vec[0] *= f
        vec[1] *= f
        vec[2] *= f
    

    Thank you

  • Fix function comments based on best practices from Effective Go

    Fix function comments based on best practices from Effective Go

    Hi, we updated some exported function comments based on best practices from Effective Go. It’s admittedly a relatively minor fix up. Does this help you?

  • MulVec3 is broken

    MulVec3 is broken

    Hi, This code in float64/mat3/mat3.go is broken:

    func (mat *T) MulVec3(v *vec3.T) vec3.T {
    return vec3.T{
    mat[0][0]*v[0] + mat[1][0]*v[1] + mat[2][0]*v[2],
    mat[0][1]*v[1] + mat[1][1]*v[1] + mat[2][1]*v[2],
    mat[0][2]*v[2] + mat[1][2]*v[1] + mat[2][2]*v[2],
    }
    }
    

    It should read (pay special attention to the first column):

    func (mat *T) MulVec3(v *vec3.T) vec3.T {
    return vec3.T{
    mat[0][0]*v[0] + mat[1][0]*v[1] + mat[2][0]*v[2],
    mat[0][1]*v[0] + mat[1][1]*v[1] + mat[2][1]*v[2],
    mat[0][2]*v[0] + mat[1][2]*v[1] + mat[2][2]*v[2],
    }
    }
    

    Looks like a cut-n-paste error, because TransformVec3 is correct.

  • Added normals (2D vec), and copying calculation functions (2D & 3D).

    Added normals (2D vec), and copying calculation functions (2D & 3D).

    Add Abs, and Absed (vec2 float64 float32) Add Normal, and NormalCCW (vec2 float64 float32) Add Added, Subed, and Muled (vec2 float64 float32) Add Added, Subed, and Muled (vec3 float64 float32) Add Add(a, b) function (vec3 float64 float32)

  • Fixed bug in Invert mat3, added invert to mat2

    Fixed bug in Invert mat3, added invert to mat2

    Add PracticallyEquals (vec2 vec3 mat2 mat3 for both float32 float64) to compare if vectors and matrices are equal within a tolerance threshold. Add invert to mat2 (float32 float64). Unroll Mul function (mat3 float32 float64) Unroll Transpose (mat3 float32 float64) Unroll Adjugate (mat3 float32 float64) Fix bug in Invert function (mat3 float32 float64)

  • Some new additions, some leaner implementations and one breaking change(!)

    Some new additions, some leaner implementations and one breaking change(!)

    Breaking change(!) cross function vec2 (float32 float64) now return a scalar value, not a new vector. Cross-product in 2D is not well-defined but it is changed to the 2D version stated at https://mathworld.wolfram.com/CrossProduct.html .

    Add Sinus and Cosine for angle between vectors (vec2 vec3 float64 float32) Changed implementation for Angle (vec2 vec3 float32 float64) to utilize Cosine implementation (with math.Acos). Changed implementation for left and right winding (vec2 float32 float64)

    Duplicated test file for quaternion (float32 float64)

  • mat4.AssignPerspectiveProjection?

    mat4.AssignPerspectiveProjection?

    It appears AssignPerspectiveProjection is creating a Frustum.

    go3d:

    // AssignPerspectiveProjection assigns a perspective projection transformation.
    func (mat *T) AssignPerspectiveProjection(left, right, bottom, top, znear, zfar float32) *T {
    	near2 := znear + znear
    	ooFarNear := 1 / (zfar - znear)
    
    	mat[0][0] = near2 / (right - left)
    	mat[1][0] = 0
    	mat[2][0] = (right + left) / (right - left)
    	mat[3][0] = 0
    
    	mat[0][1] = 0
    	mat[1][1] = near2 / (top - bottom)
    	mat[2][1] = (top + bottom) / (top - bottom)
    	mat[3][1] = 0
    
    	mat[0][2] = 0
    	mat[1][2] = 0
    	mat[2][2] = -(zfar + znear) * ooFarNear
    	mat[3][2] = -2 * zfar * znear * ooFarNear
    
    	mat[0][3] = 0
    	mat[1][3] = 0
    	mat[2][3] = -1
    	mat[3][3] = 0
    
    	return mat
    }
    

    https://github.com/g-truc/glm/blob/416fa93e42f8fe1d85a93888a113fecd79e01453/glm/ext/matrix_clip_space.inl#L159-L171

    template<typename T>
    GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumRH_NO(T left, T right, T bottom, T top, T nearVal, T farVal)
    {
    	mat<4, 4, T, defaultp> Result(0);
    	Result[0][0] = (static_cast<T>(2) * nearVal) / (right - left);
    	Result[1][1] = (static_cast<T>(2) * nearVal) / (top - bottom);
    	Result[2][0] = (right + left) / (right - left);
    	Result[2][1] = (top + bottom) / (top - bottom);
    	Result[2][2] = - (farVal + nearVal) / (farVal - nearVal);
    	Result[2][3] = static_cast<T>(-1);
    	Result[3][2] = - (static_cast<T>(2) * farVal * nearVal) / (farVal - nearVal);
    	return Result;
    }
    

    https://github.com/g-truc/glm/blob/416fa93e42f8fe1d85a93888a113fecd79e01453/glm/ext/matrix_clip_space.inl#L238-L252

    template<typename T>
    GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveRH_NO(T fovy, T aspect, T zNear, T zFar)
    {
    	assert(abs(aspect - std::numeric_limits<T>::epsilon()) > static_cast<T>(0));
    
    	T const tanHalfFovy = tan(fovy / static_cast<T>(2));
    
    	mat<4, 4, T, defaultp> Result(static_cast<T>(0));
    	Result[0][0] = static_cast<T>(1) / (aspect * tanHalfFovy);
    	Result[1][1] = static_cast<T>(1) / (tanHalfFovy);
    	Result[2][2] = - (zFar + zNear) / (zFar - zNear);
    	Result[2][3] = - static_cast<T>(1);
    	Result[3][2] = - (static_cast<T>(2) * zFar * zNear) / (zFar - zNear);
    	return Result;
    }
    
Dabulang is an interpreted object-oriented programming language aimed towards game development.

Dabulang (ダブ言語) Dabulang is an interpreted object-oriented programming language aimed towards game development. The language's standard library has a

Sep 14, 2022
Lightweight, facility, high performance golang based game server framework
Lightweight, facility, high performance golang based game server framework

Nano Nano is an easy to use, fast, lightweight game server networking library for Go. It provides a core network architecture and a series of tools an

Jan 1, 2023
High performance lib for mmorpg game

lib_chaos create a awesome fast lib to support make game in future. what's in th

May 27, 2022
chess package for go
chess package for go

chess Introduction chess is a set of go packages which provide common chess utilities such as move generation, turn management, checkmate detection, P

Dec 26, 2022
high performance fixed decimal place math library for Go

Summary A fixed place numeric library designed for performance. All numbers have a fixed 7 decimal places, and the maximum permitted value is +- 99999

Dec 6, 2022
A pure Go 3D math library.

MathGL This is a Go matrix and vector math library specialized for Open GL graphics capabilities. This package is made primarily with code generation

Dec 24, 2022
GoStats is a go library for math statistics mostly used in ML domains, it covers most of the statistical measures functions.

GoStats GoStats is an Open Source Go library for math statistics mostly used in Machine Learning domains, it covers most of the Statistical measures f

Nov 10, 2022
Plot 3D math equation z=f(x, y) with SVG format.
Plot 3D math equation z=f(x, y) with SVG format.

plot-function-svg Plot 3D math equation z=f(x, y) with SVG format. Some codes are referred from https://github.com/adonovan/gopl.io licensed under a C

Dec 30, 2021
Golang-module-references - A reference for how to setup a Golang project with modules - Task Management + Math Examples

Golang Module Project The purpose of this project is to act as a reference for setting up future Golang projects using modules. This project has a mat

Jan 2, 2022
RundQuiz-Game - This is a Go exercise that implements and builds a quiz game from a list of math questions in a CSV file.

Go RundQuiz Game Exercise details This exercise is broken into two parts to help simplify the process of explaining it as well as to make it easier to

Jan 5, 2022
Sunrise/Noon/Sunset math in Go

Sunrise/Noon/Sunset math in Go

Feb 10, 2022
Dynamic object-oriented programming support for the Go language

Goop Description The Goop (Go Object-Oriented Programming) package provides support for dynamic object-oriented programming constructs in Go, much lik

Oct 13, 2022
Kratos is a microservice-oriented governance framework implements by golang
Kratos is a microservice-oriented governance framework implements by golang

Kratos is a microservice-oriented governance framework implements by golang, which offers convenient capabilities to help you quickly build a bulletproof application from scratch.

Dec 27, 2022
Document-oriented, embedded SQL database

Genji Document-oriented, embedded, SQL database Table of contents Table of contents Introduction Features Installation Usage Using Genji's API Using d

Jan 1, 2023
An application-oriented unified storage layer for Golang.

storage An application-oriented unified storage layer for Golang. Goal Production ready High performance Vendor agnostic Features Widely services supp

Dec 21, 2022
Kratos is a microservice-oriented governance framework implements by golang,
Kratos is a microservice-oriented governance framework implements by golang,

Kratos is a microservice-oriented governance framework implements by golang, which offers convenient capabilities to help you quickly build a bulletproof application from scratch.

Dec 31, 2022
Zadig is a cloud native, distributed, developer-oriented continuous delivery product.

Zadig Developer-oriented Continuous Delivery Product English | 简体中文 Table of Contents Zadig Table of Contents What is Zadig Quick start How to use? Ho

Jan 8, 2023
Dabulang is an interpreted object-oriented programming language aimed towards game development.

Dabulang (ダブ言語) Dabulang is an interpreted object-oriented programming language aimed towards game development. The language's standard library has a

Sep 14, 2022
Zadig is a cloud native, distributed, developer-oriented continuous delivery product.

Zadig Developer-oriented Continuous Delivery Product ⁣ English | 简体中文 Table of Contents Zadig Table of Contents What is Zadig Quick start How to use?

May 12, 2021
A cutting edge (haha), prototype, object-oriented and highly modular slash command handler for Discordgo.
A cutting edge (haha), prototype, object-oriented and highly modular slash command handler for Discordgo.

ken ⚠️ Disclaimer This package is still in a very early state of development and future updates might include breaking changes to the API until the fi

Dec 12, 2022