GithubHelp home page GithubHelp logo

go3d's Introduction

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: https://pkg.go.dev/github.com/ungerik/go3d

go3d's People

Contributors

alexozer avatar bitdeli-chef avatar chran554 avatar codelingobot avatar gmlewis avatar hubues avatar iopred avatar panmari avatar targodan avatar ungerik avatar yashyash avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

go3d's Issues

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

vec2.Angle works only for normalized vectors.

The function vec2.Angle(a, b _vec2.T) works only for normalized vectors.
By definition it's: a * b = |a| * |b| * cos(phi)
Solved to phi that is: acos((a_b) / (|a| * |b|))
Will open up a pull request in a second.

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.

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.

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?

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

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.

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;
}

Bug in mat4.Quaternion()

Hi,
thanks a lot for filling this gap in golang!
Lets get to it: I think there is a problem in mat4.Quaternion()
A. for calculating the trace only the part of the rotation matrix should be taken (Trace3) not the tracec of the full mat4
B. IMO you need to switch on the sign of the trace to account for ambiguities, right (see f.e. eigen quaternions line 822 following....)

Best
Johannes

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.

Angle is NaN for certain vectors.

I came across another problem with vec*.Angle(a, b vec*.T):
For certain vectors it results in NaN because math.Acos(x) is NaN for x < -1 or x > 1 (see godocs).

In my case it happened for (-3.015463917525773; 3.340206185567011) and (-3.015463917525773; 3.3402061855670104) which resulted in math.Acos(1.0000000000000002) = NaN

Pull request coming up in a second.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.