Math module?

On the source force page, it's mentioned that OpenTK contains a maths module. Is this accurate? I don't see it anywhere.


Comments

No, it´s not accurate, but
posted by the Fiddler.

No, it´s not accurate, but the library still is in alpha stages ;) If you have an immediate need for a math library, I think there is one in Mono .Xna (http://code.google.com/p/monoxna/).

What functionality do you actually need? The plan for OpenTK is to have some simple vector, matrix and quaternion math and probably some noise generation functions. There will be a fully managed implementation (with horrible performance) which will be sped it up with unmanaged hand-optimized plugins. I´ve been holding back until I can find a way to detect and use available plugins without incurring a large speed penalty (if you have any ideas how to do this they´d be appreciated!)

I have no immediate need, I
posted by george

I have no immediate need, I was just curious.
A set of classes that match the directx vector/matrix stuff would be useful, especially if the opengl interface could be extended to use them.

As for the performace of a managed implementation, a lot of operations are so small (vector arithmetic, cross/dot product etc) the cost of managed->unmanaged conversion and back probably outweighs any speed gains you might get.

A set of classes that match
posted by the Fiddler.

A set of classes that match the directx vector/matrix stuff would be useful, especially if the opengl interface could be extended to use them.
That's the idea - the opengl bindings are written in a way that allows overloads to be easily added.

I've started checking in code for the math module. It won't be ready for some time still, but (thankfully) it's a straightforward thing to write - a nice contrast to the platform-specific code.

Thanks for adding a Math
posted by Inertia

Thanks for adding a Math library :) I've started building my own yesterday, because the lack of such a library really started to annoy me. Yours seems rather complete, i'll try to help where I can.

I've gone through most of yours (basically Vector3 and Matrix, because that is what I built yesterday and is fresh in memory), and got some suggestions:

1) Is there a reason why Normalize and Divide in the Vector3 class don't try{} for a division by 0 exception? I see you want the methods to operate at fast as possible, but this will crash applications badly when not caught.

2) Couldn't find any comparison helper for floats. Maybe you could add this to the Functions.cs (refactor and change accessibility as you wish):

private const float FLOATEQUALITYTHRESHOLD = 0.000001f;

private static bool IsFloatEqual( float f1, float f2 )
{
  return ( Math.Abs( f1 - f2 ) <= FLOATEQUALITYTHRESHOLD );
}

The reason for this is that precision issues could lead to a == comparision result in "false", although the compared floats should be considered equal and the result be "true".

3) I believe you will be better off with having less duplicate code. e.g. the implementation of Cross(3 params) would imho be safer to have like this:

public static void Cross(ref Vector3 left, ref Vector3 right, out Vector3 result)
{
  Vector3 result = new Vector3(left)
  result = Cross(result, right);
}

else there could be problems if result is null when calling the method.

4) Regarding the operator overloads, there's always manipulation of the left parameter. I've chosen to implement it in a way that only the Struct's Add(), Sub(), Mult(), Div() Methods manipulates it's instance, while all operator overloads and static functions will always allocate memory and return a new instance. I believe I see the reason why you chose this, writing VectorA += VectorB sure is nice, but not if you write VectorC = VectorA + VectorB you have changed VectorC and VectorA.
I guess that topic is kinda like the holy Linux vs. Windows war and both sides have their points. I just thought it should be mentioned before building more overloads (I'll definitely add some if I may).

5) I belive to have found a nice way to deal with Constructors for Vectors. Here's copy&paste of some of my code, I've used an float[3] to index the Vector's components to avoid unsafe, but you should get the idea of what my point is:

public void SetTo( float x, float y, float z )
        {
            this.elements[0] = x;
            this.elements[1] = y;
            this.elements[2] = z;
        }

        public void SetTo( double x, double y, double z )
        {
            this.elements[0] = (float) x;
            this.elements[1] = (float) y;
            this.elements[2] = (float) z;
        }

        public void SetTo( Vector3 v )
        {
            this.elements[0] = v.X;
            this.elements[1] = v.Y;
            this.elements[2] = v.Z;
        }

        public Vector3( )
        {
            this.elements = new float[3];
            this.SetTo( Vector3.Zero );
        }

        public Vector3( float x, float y, float z )
        {
            this.elements = new float[3];
            this.SetTo( x, y, z );
        }

        public Vector3( double x, double y, double z )
        {
            this.elements = new float[3];
            this.SetTo( x, y, z );
        }

        public Vector3( Vector3 v )
        {
            this.elements = new float[3];
            this.SetTo( v );
        }

The nice thing about this is that you can make a copy of another vector's values with the SetTo function, without creating a new instance.

That's all for now, please don't take this as destructive critique. I like your work and am very impressed of the Quaternion bit, always considered it very hard to visualize and debug.

Edit: mhmm should probably have started a new topic instead.

One good CSharp math class
posted by JTalton

One good CSharp math class is Sharp3D Math.
http://www.codeplex.com/Wiki/View.aspx?ProjectName=Sharp3D
It has not been updated in a while.

I ended up writing my own Vector, TexCoord, and Matrix classes. I found it useful to make the vectors such that they could never have their values changed. I had been running into problems where I had a dictionary whose keys were vectors, and if the vectors changed at some point, the dictionary would not work right. Not sure it is a great design, but I found it useful and like it very much.

On the subject of using generics, the C5 Generic Collection Library is a little nicer than the .NET Generics.
http://www.itu.dk/research/c5/

Thanks for the links, the C5
posted by the Fiddler.

Thanks for the links, the C5 Generic Collection is superb!

I'd really like the Vectors
posted by objarni

I'd really like the Vectors etc. to be immutable, ie. values _cannot_ change. It makes easier programming - decrease aliasing problems like the dictionary trouble mentioned above - and the C# allocation routine is insanely fast ...

What would be really great is to do a "real" comparison between a mutable an immutable Vector3 class in C# ... anyone did that? If the difference is less than 10% in speed I'd say it's not worth the trouble having mathematical entities changeable = mutable.

I usually go by the rule "if I need those extra 10% I'd hard-code everything inside the algorithm anyway" and make the general APIs, well, general and robust. Also, thinking of how vectors are used is rewarding -- spitting 3d models made up of relatively static vectors won't burden the gc very much (and we'll use vertex arrays or similar in GL anyway, right?), if that is the concern regarding the immutable/mutable controversy. Is that the controversy?

I think, and here I hazard, that the general use of a Vector3 class would be more of a "do precomputations/small amount of computations comfortably"-kind-of-thing than "I will use Vector3 in every single leaf of my grand world".

Of course, there is a third less-elegant (?) solution too -- and that is to have two different sets of classes for mathematical entities. One mutable (Vector3m?) and one immutable (Vector3). With all the hassle that will bring ..

Wow this got longer than I first thought :) guess it is not such a clear-cut case.

my 2 cc

Forgive my stupid question,
posted by Inertia

Forgive my stupid question, but what is your problem storing all your immutable Vectors in one place, make sure you have no references from outside left to that place and just leave them be? Some people might want to implement a particle system, collision detection, etc., where building 1000s of immutable Vectors per frame will inevitably flood memory and degrade performance.

4.b) It seems in the Quaternion class the operator overloads aren't all used in a consistent way with the vector class. This will inevitably lead to the situation where bugs are introduced because some functions update the "left" parameter while others don't.

> Forgive my stupid
posted by objarni

> Forgive my stupid question, but what is your problem storing all your immutable Vectors in one place, make sure you have no r
I take it you mean mutable here.

> references from outside left to that place and just leave them be? Some people might want to implement a particle system,
> collision detection, etc., where building 1000s of immutable Vectors per frame will inevitably flood memory and degrade performance.
Well as I said it is not a clear-cut question. If you want those 10% extra, you'll have to go to C, I am the first to admin!

In your multi-thousand-particle case, I would recommend using fixed-length arrays of floats or something like that to maximize cache coherence and minimize gc work. But is that case enough to "bloat" general mathematical entities of the OpenTK? Do you know how much optimization work has gone into the "new" of .NET? A lot I tell you. It is WAY faster than malloc/new of C/C++.

When you are using mutable types, you are also "buying into" a less mathematically sane program with a higher probability of bugs. This is not such a problem if you are a lone hacker and can keep your project in your head all the time. It gets a lot worse when you build projects for any longer time, say several months or with several people involved. Eg.: which vector-arrays are "untouchable"? which can I mess around with? when do I have to clone the vector I am using and when can I change it safely? If you have ever coded any larger project in C, you know what I mean and what a fuzz the mutable char*-"strings" are.

I know this question is "sensitive" -- I just wanted to state my experience with this thing. I have given it quite some thought through the years. Basically, I think the way of the future is immutable types as much as we can, and mutable types for "inner loops" as Michael Abrash once put it IIRC. Remember Knuths famous words of wisdom: premature optimization is the root of all evil.

Cya (and I will still like OpenTK if you end up with mutable Vectors! :)

It isn't strange that object
posted by the Fiddler.

It isn't strange that object allocation is faster in .Net (or Java for example) than in C/C++, as they are garbage collected environments - allocation is little more than a plain addition there, an amortized O(1) operation. C/C++ have to traverse lists and run heuristics to find the best-fit hole in memory.

The problem with creating temporary objects in these mathematical operations isn't so much the memory allocation itself (a temp object on the stack isn't that bad), but the inevitable copy (8-16 bytes for a Vector struct). Operating on the vector members themselves may allow everything to stay in registers - performing a copy probably throws us to the L1 cache.

Yes, I know this is a premature optimization, but there really is no alternative here. We cannot go back and change the implementation afterwards, if it doesn't perform as it should - once released, we are stuck with it for eternity. At least, if you have a mutable type you can force immutable behavior out of it (for example by encapsulating it and providing a readonly property), but you cannot do the reverse and maintain performance.

When you are using mutable types, you are also "buying into" a less mathematically sane program with a higher probability of bugs.
Wait, aren't mathematical vectors *always* mutable?

The problem with creating
posted by objarni

The problem with creating temporary objects in these mathematical operations isn't so much the memory allocation itself (a temp object on the stack isn't that bad), but the inevitable copy (8-16 bytes for a Vector struct). Operating on the vector members themselves may allow everything to stay in registers - performing a copy probably throws us to the L1 cache.

Exactly; there is no reason to be "afraid" of new in C#!

About the inevitable copy of immutable types. If you do v += u; I don't see how you could get rid of the copy operation :) The copy is there whether vectors are mutable or immutable.

Yes, I know this is a premature optimization, but there really is no alternative here. We cannot go back and change the implementation afterwards, if it doesn't perform as it should - once released, we are stuck with it for eternity. At least, if you have a mutable type you can force immutable behavior out of it (for example by encapsulating it and providing a readonly property), but you cannot do the reverse and maintain performance.

There is no problem encapsulating an immutable type with a mutable one. Just keep a local (immutable) field, and when you want to do your += operation just create a new instance. But I'm not saying that is the best thing to do today.

The case where you want to update a single component, say x -- in that case the mutable += of is faster than "v = v + new Vector3(dx,0,0);". But really - how often do you update just a single component? This is a really odd operation..

Regardless of whether Vector3 become immutable or mutable, integrating it with the OpenTK GL methods, which I guess is one of the feats' driving the implementations of the math lib, is it such a great breaking change going from immutable to mutable or vice versa? The type is used in the interface if I'm not mistaken. Not by intricate algorithms, in which case it might have been a big change. And they way I see it, OpenTK is more of a wrapper-library than an algorithm library!


When you are using mutable types, you are also "buying into" a less mathematically sane program with a higher probability of bugs.
Wait, aren't mathematical vectors *always* mutable?

Umm. This is the same as saying, given some arithmetic expression say 1+2, "Isn't integers *always* changeable?" That is just madness in mathematics (you cannot *change* the value of the integer 2!). This is the distinction between mutable and immutable types.

Wow, lots of stuff here,
posted by the Fiddler.

Wow, lots of stuff here, I'll try to address everything bit by bit.

@objarni:
I'd really like the Vectors etc. to be immutable, ie. values _cannot_ change. It makes easier programming - decrease aliasing problems like the dictionary trouble mentioned above - and the C# allocation routine is insanely fast ...

What would be really great is to do a "real" comparison between a mutable an immutable Vector3 class in C# ... anyone did that? If the difference is less than 10% in speed I'd say it's not worth the trouble having mathematical entities changeable = mutable.
To find out the performance impact of allocations, I timed 10^8 Vector3 additions. I made sure that the methods were JITed first, and that the whole loop wasn't optimized-out by the compiler. Here are the results (ns per iteration, 3.2GHz Core 2 Duo):

Noop                                    0,00440376ns
Vector3.Add(ref a, ref b, out res)      0,03766322ns
Add(a, b, out res)                      0,08392346ns
res = Add(ref a, ref b)                 0,09454702ns
res = Add(a, b)                         0,11466584ns

Noop establishes the baseline performance of an empty loop to ensure the rest of the results make sense. The first two functions do not allocate memory, but show the relative cost of using pass-by-value vs pass-by-reference. The last two allocate a new Vector3 on the stack, something that brings a relatively significant performance hit - an immutable version of this struct would take this hit on every operation.

In any case, this is a micro-benchmark which might not be indicative of real-world performance. I do think, however, that mutable structs are more useful in normal use cases - what would you use Vectors for? Probably to calculate object physics, setup vertex arrays and, less likely, for vertex animation. In all these cases, an immutable struct would be less efficient. I really can't think of a normal use-case where immutability would be preferrable (no, using Vectors as keys in a dictionary isn't very normal! :) ) And if the need arise, one could always avoid calling operators on the structs that should stay unchanged.

@Inertia:
1) They don't catch DivideByZero exceptions, because there is no meaningful way to respond to such an error. The best we can do is inform the user that his program has a problem and hope for the best. If he is careless his application will crash, yes, but that's better than hiding the bug under the carpet and having him wonder why his 3d model suddenly turned invisible :)

2) Oops, yes that's needed! Generally, I prefer the cast-to-integer-and-compare approach than using a set epsilon (although both have their uses). I haven't tried the integer-comparison method in C#, but I think it should work inside an unsafe and unchecked block.

3) Good catch, that's a left-over function from a previous version (deletes).

4) You might be looking at an earlier revision, as we have removed all instance members in the latest version :) We decided that there's no good reason to have both instance and static methods to do the same thing - instance methods would hardly ever be utilized. IIRC, XNA has static methods too.

5) I am not sure I see what the advantage of this method is?

       public Vector3( Vector3 v )
        {
            this.elements = new float[3];
            this.SetTo( v );
        }

vs
       public Vector3(Vector3 v)
        {
            X = v.X;
            Y = v.Y;
            Z = v.Z;
        }

Seems the same to me, although the second method avoids an allocation. You only need unsafe code to apply indexing (unless you use a C# 'union' but that's another can of worms entirely), and there's no reason why to apply indexing in the first place. In any case, the unsafe code needn't be exposed to the user.

(*)By indexing I mean sth like:

       public float get(int index)
        {
            unsafe
            {
                fixed (float* ptr = &this.X)
                    return *(ptr + index);
            }
        }

but even that can be written to avoid unsafe code:
       public float get(int index)
       {
            switch (index)
            {
                case 0: return X; break;
                case 1: return Y; break;
                case 2: return Z; break;
                default: throw new ArgumentOutOfRangeException("index", index, "Should be 0, 1 or 2.");
            }
        }

Edit:
4b) The math stuff isn't fully baked yet, these will be fixed before the release.

Noop
posted by objarni

Noop 0,00440376ns
Vector3.Add(ref a, ref b, out res) 0,03766322ns
Add(a, b, out res) 0,08392346ns
res = Add(ref a, ref b) 0,09454702ns
res = Add(a, b) 0,11466584ns

Judging from this it seems what really matters (0,038->0.084) is pass-by-reference or pass-by-value, which makes me think your Vectors are structs and not classes? Is that the case? What are these numbers if you switch from struct to class (or class to struct)?

These are structs. I
posted by the Fiddler.

These are structs. I followed Rico Mariani's advice, who knows much more on performance topics than I ever would:
The main reason goes right back to data density. There is a strong expectation that this class will be embedded in other classes such as Vertex and you can imagine many others. It is likely that there will be temporaries of this type, and importantly arrays of this type. Using a value type will make it so that walking through sets of related points does not require following multiple pointers and therefore data density is likely to be enhanced. And of course, there is storage overhead for classes -- the object header and the method table pointer -- these will be absent in packed arrays of structures.

Contrariwise the usual benefits of being a class are not especially valuable. Will we be subtyping? No. Sychronizing? No. Do we want point "identity" (e.g. the canonical instance of point (1,2,-1)? No.

Just out of curiosity, could
posted by objarni

Just out of curiosity, could you run your performance test changing struct to class and post it here? It would be interesting to know..

I'll try to do that tonight.
posted by the Fiddler.

I'll try to do that tonight. I expect performance will be similar to the (ref, ref, out) overload in microbenchmarks, but worse in larger cases.

I wrote a simple
posted by objarni

I wrote a simple test-program to measure the performance of a struct-vector versus a class-vector:

int times = 100000000;
VClass v = new VClass(3, 1, 2);
VClass w = new VClass(0, 0, 0);
for (int i = 0; i < times; i++)
{
  w = w + v;
}

versus

int times = 100000000;
VStruct v = new VStruct(3, 1, 2);
VStruct w = new VStruct(0, 0, 0);
for (int i = 0; i < times; i++)
{
  VStruct.Add(ref v, ref w, out w);
}

This gave me approximately 2,0 seconds running time for the first loop and 0,7 seconds on the second. (Release build on a WinXp AMD Athlon 64 Dual Core 3800+ machine, experiment repeated like 5 times for each loop)

So there is quite a difference! Structs is the way to go, even though the syntax isn't that good-looking! :)

A third variation I tried was using operator + on the struct:

int times = 100000000;
VStruct v = new VStruct(3, 1, 2);
VStruct w = new VStruct(0, 0, 0);
for (int i = 0; i < times; i++)
{
  w = w + v;
}

This gave me a running time of 3,3 seconds! The most expensive alternative..

2) Thanks for the link,
posted by Inertia

2) Thanks for the link, interesting approach of the problem

4) True, in your implementation it didn't make a difference. In what I've written, instance members never allocate new memory and overwrite their values with the result instead, and only the static methods allocate new memory (the later is like XNA). Regarding XNA's vector math library: People complained about it because it returned a new instance every single call, at some point the GC kicked in and their applications froze.

But please, If you really must overwrite one of the parameters, PLEASE do not name them "left" and "right". Please refactor the one that's values are overwritten with "result" or something more obvious which parameter will be left untouched. (With whip-cream and sugar ontop!)

5) Just that the SetTo() method avoids duplicate code and allows to set XYZ to a desired value with a single call and without creating a new instance.
I've just used an array because it was the easiest way to feed Vectors to glVertex3fv etc.. There was this idea for a future optimization to use unmanaged C++ to malloc 3 floats from system memory for the Vectors at the initialization stage, to prevent pinning.

P.S. I take it you will use the math library also for future GL 3.0/OpenAL in OpenTK?

4) We've tried to avoid
posted by the Fiddler.

4) We've tried to avoid excessive memory allocations: static methods with "out" parameters (e.g. Vector3.Add(ref Vector3, ref Vector3, out Vector3) do not allocate memory. Only static methods that return results (e.g. Vector3 Vector3.Add(Vector3, Vector3)), do.

But please, If you really must overwrite one of the parameters, PLEASE do not name them "left" and "right".
No parameter named left or right will be overwritten, ever! Mutable parameters will be named "result" and have an 'out' flow direction. Some older SVN revisions had instance members that mutated the 'left' parameter, but this was just an experiment - no trace of that will make its way in a release!

5) You may know that already, but C# can allocate memory on the stack through the stackalloc keyword. The framework can also allocate heap memory with the Marshal.AllocHGlobal method. Neither of these is subject to garbage collection, and they should provide a measurable benefit in some cases (e.g. maintaining large client-side data structures for OpenGL, like vertex arrays).

P.S. I take it you will use the math library also for future GL 3.0/OpenAL in OpenTK?
Unless the rest of the Tao developers agree to add a math library to Tao, I'll probably keep this one around. If worse comes to worst, we can try to to find a middle ground with OpenAL.Net, to ensure interoperability (Tao.Ode is, I think, officially dead - superseded by Ode.Net). In any case, future GL 3.0/OpenAL, as well as current GL 2.1 make trivial use of the math library (just a few function overloads), so they will be easy to change, at least before the API freeze.

4) Then obviously I've been
posted by Inertia

4) Then obviously I've been browsing the wrong directory, thought it was the correct one since the files were only ~20 hours old. Thank god, didn't really like interface as you probably noticed ;P

5) It was just an optimization consideration, I'll probably switch from Tao to OpenTK when OpenGL 3.0 specs/drivers are available so I'll rather help getting your math library bug-free than continuing my solution. From what I've read GL3 will be very nice to use in an object oriented design and due to the API changes it will probably be necessary to rewrite most of my helpers anyway.

Tbh I doubt there will be such a change in Tao. Most of the bindings do not require permanent maintenance and I believe to have read a similar suggestion (well, it was about making Tao more object oriented IIRC) before the forum wipe, which was rather clear about Tao will very likely stay at the bindings level and no step further. You had a good point there, before GL3 is released (and most likely GLFW, FreeGLUT, SDL and DevIL will all require updates) would be a good point of time to deal with this (if at all).

Then you did browse the
posted by the Fiddler.

Then you did browse the correct directory, but overlooked a tiny little thing in the code:

public static Vector3 Add(Vector3 a, Vector3 b)
{
        a.X += b.X;
        a.Y += b.Y;
        a.Z += b.Z;
        return a;
}

Seems dangerous but it really isn't! The change to 'a' won't be reflected to the caller, because 'a' is a struct and we pass by value.

Moreover, the compiler will complain bitterly if you try to pass a null reference to:

public static void Add(ref Vector3 a, ref Vector3 b, out Vector3 result)

so this is safe too (in response to point (3) above).

I'm looking for ways to break the implementation, if you can think of any say it!

Ok, I think most things have
posted by george

Ok, I think most things have been answered, but I might as well explain some more, just to clear up any confusion.

Generally the functions have two versions. One that looks like this:

public static Vector3 Operation(Vector3 a, Vector3 b)

in which the operands are passed by value (they're structs), that is they are copied onto the stack. we reuse one of those copies to hold the result so we don't need to call new and make a third copy. this is then returned by value, ie copied back.

The second version looks like this:

publci static void Operation(ref Vector3 a, ref Vector3 b, out Vector3 result)

here the operands are passed by reference. no copy is made on the stack (so it's a little bit faster), the result can't possibly be null (it's a struct remember), so we can just write the result into it. no temporary copies are made and nothing is copied back to the caller.

the operator overloads are basically the same as the first version (ie pass by value).

To answser Inertia's original point 3:
There's no chance of the result parameter being null so we don't need to call new, and the function bodys are so trivial that the small amount of code duplication is preferable to making a function call and relying on the jit to inline it. The definition of a cross product is not likely to change any time soon :) same goes for the operator overloads.

hope that clears things up.

1) If you decide to let the
posted by Inertia

1) If you decide to let the programmer handle special cases like this, please throw an Exception("Matrix is singular and cannot be inverted.") or something like that at Matrix4.cs Line: 437. The code block is currently:

435  if (pivot == 0.0f)
436  {
437     return mat;
438  }

4) Doh. Yes, you are absolutely right and I have to apoligize for wasting your time. I had used classes and derived Vector2/3/4 from a Vector base class to avoid duplicate functions, and was so excited about your announcement that I didn't really look at your definition and jumped right into the implementation part. Please consider 4) void and null. I think your decision to use structs is better in this case, the amount of duplicate code is still manageable and the complexity of the Vector structs is limited.

I'll download and work with the math library a bit before making any further comments, promised ;)

Good catch, corrected!
posted by the Fiddler.

Good catch, corrected!

Just a question is public
posted by Axelill

Just a question is

public void Normalize()
        {
            float scale = 1.0f / this.Length;
            X *= scale;
            Y *= scale;
            Z *= scale;
        }

better than

public void Normalize()
        {
            float scale =  this.Length;
            X /= scale;
            Y /= scale;
            Z /= scale;
        }

Is multiply quicker than divide ?

Anyway, this is really a good work.

If people want to use their own implementation, it 's easy to rewrite the part and compile to get exactly what you want and need.

I'm really happy with this structures (at least the vector 2,3 and 4 (have not looked the matrix)) and should do the job that 90% of the users want.

Axel.

edit : now, I've checked the matrix structure and I have two questions :
- first why 4 vector instead of float[16] (reuse code of vecotr4 ?) it would have been better for a GL.LoadMatrix(ref Matrix4 m) or something. I'm sure there is a reason why using 4 vector but I can't find why ? ;)
- second why 4 ROW vector :
I though opengl was using column matrix :
http://www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/...
now, let's check the quaternions.

Yes, multiply is generally a
posted by george

Yes, multiply is generally a lot faster than divide. enough to make it worthwhile to precompute the reciprocal and multiply if you're doing more than one.

as for the matrix, arrays aren't value types in c# so having an array of matrices wouldn't lay them out how you want. It makes the implementation simpler as well. They could have been rows or columns, but the row layout is more common I think.

Not an array of matrices but
posted by Axelill

Not an array of matrices but more something like :

struct Matrix
{
private float[] m_matrix = new float[16];
....
}

If you use the column matrix (opengl) instead of the row matrix(most used), then it is easy to overload Gl.LoadMAtrix(Matrix m) (normaly glLoadMAtrix(const float*)in C)
because the 4 vector will be aligned in the memory instead with row vector the memory allocation is no good(not good for opengl).

DIrectX use row matrix because every function in directx is made for row matrix.
Opengl use collumn matrix so it would give more possibilities of improvement for the future.

Correct me if i'm wrong.

PS : and there is a lot of function in opengl that use the const float* as a matrix;

Axel.

OpenGL can use row-major
posted by the Fiddler.

OpenGL can use row-major matrices too, with glLoadTransposeMatrix, so the choice of one over the other has little impact. It's been some time before I touched matrix code, but I think some things can be implemented easier with row-major matrices (but don't quote me on this :) )

About const float * parameters, it makes no difference if you declare an array of 16 floats vs 4 Vector4's, as long as long as the layout in memory is the same (and it is, since Matrix4 is declared with the the StructLayout(LayoutKind.Sequential) attribute). Both cases will (should) work if you pass the address of the first element.

Yes, true the problem with
posted by Axelill

Yes, true the problem with transposeMatrix is if the matrix is not normalised (not often) it's just a pain in the ass for the computer to use it and even tranpose matrix, i think ( but do not quote me for this ;)) that he just move the value to fit what opengl works with (column matrix).

From The openGl Bible (opengl programming guide sixth version page 116 bottom page) :

"glLoadTransposeMatrix(m) has the same effect as glLoadMtrix(transpose(t))."

So lot of useless calculation. Need to be verified but it might be the case. If someone knows more about opengl matrix management, that would be appreciated.

Axel.

I just read (but didn't
posted by the Fiddler.

I just read (but didn't verify) that the ATI SDK works with row-major matrices, which might indicate that these work better on ATI hardware. The OpenSceneGraph also uses row-major matrices (the have an interesting discussion), if that means anything.

In any case, I am not going to rewrite matrix functions (don't break something that works!) and probably noone else will. It's way too much work for the benefit of using one OpenGL function over another. :)