manjian's picture

matrix to float[]

Err...I am looking for an effective way to transform the calculated matrix to float[] so that I can call glUniformMatrix{234}f to transfer the data to GLSL.Anybody helps?


Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
the Fiddler's picture

Use this:

Matrix4 matrix = new Matrix4();
UniformMatrix4(..., ref matrix.Row.X);

Not ideal, but there is no efficient way to convert a matrix to a float[] (as doing so would allocate memory).

I'll add overloads to the UniformMatrix* functions to make this simpler in the next release.

kanato's picture

I don't know if this is the best approach but I've used

unsafe
{
	GL.UniformMatrix4(loc, 16, false, (float*)&matrix);
}

At least, it compiles, but I haven't really tested it.

the Fiddler's picture

This should work, too.

manjian's picture

Oh,the sloution you guys introduce is completely anti-intuition .I hope the Fiddler add operator overload.
Here's another suggestion.Please write some wrapper class for ogl buffer object,array object,texture object,program object,frame buffer object,and shader object.Using the old,procedure-oriented way makes no sense,which slows down our coding speed.And referencing an object with an integral number is not type-safe,and error-prone.I know ogl prefers state machine way than object-oriented way,but I know you can hide that fact.

the Fiddler's picture

Indeed, this is not intuitive. This is always a problem when the API is generated by a tool (e.g. Mono's GTK# suffers from similar issues). On the other hand, the GL class contains something close to 5500 methods, which is just not possible to write by hand.

The solution that has worked so far is to add overloads by hand, whenever someone hits a not-so-intuitive method.

I agree that an object-oriented approach would be easier to use. Kamujin has written OOGL, which is an object-oriented wrapper for OpenGL (uses OpenTK internally), so take a look at that.

The problem with this approach (and the reason why OpenTK does not include OO wrappers) is that the OpenGL API is too large and the interactions between extensions too complex to write a meaningful OO wrapper without limiting functionality. A concrete example: you can use framebuffer objects either through extensions or through core functions (since OpenGL 3.0). The semantics of each approach are similar, but not identical (e.g. different error messages, slightly different tokens). Which implementation should the FrameBuffer class use? Or do you write two implementations and decide on the correct one at runtime? Now extrapolate that for the size of OpenGL (~1850 functions as of OpenGL 3.1)...

The crux of the problem is that you cannot write OO wrappers for OpenGL without some kind of tradeoff. For example, I've written several classes for internal consumption that work fine - if you have OpenGL 3.0. And while it is probably possible to find some kind of balance between the loss functionality and gain in usability (XNA seems to have hit a sweet spot), this is not the goal of OpenTK: as per the mission statement, OpenTK is a low-level binding to OpenGL with extra sauce, not a high-level wrapper! :)

In other words: try OOGL and see if it works for you.

manjian's picture

Thanks .I understand the intention of this toolkit more.

Kamujin's picture

Some code from OOGL. I hope this helps.

The way I use this is to pass the same float[] reference to that static each loop, this way the memory allocation is kept to a minimum.

PS. I completely agree with Fiddler. OOGL is not meant to be the end all and be all to OO wrappers. Honestly, I am just trying to give back some code that can help others consume OpenTK and write OpenGL apps.

Feel free to poach any useful ideas if you are lucky enough to find any.

		public static void ToOpenGL(Matrix4[] source, ref float[] destination)
		{
			if (destination == null || destination.Length != source.Length * 16)
			{
				destination = new float[source.Length * 16];
			}
			for(int i = 0; i < source.Length; i++)
			{
				int j = i * 16;
 
				destination[j + 00] = source[i].Column0.X;
				destination[j + 01] = source[i].Column1.X;
				destination[j + 02] = source[i].Column2.X;
				destination[j + 03] = source[i].Column3.X;
				destination[j + 04] = source[i].Column0.Y;
				destination[j + 05] = source[i].Column1.Y;
				destination[j + 06] = source[i].Column2.Y;
				destination[j + 07] = source[i].Column3.Y;
				destination[j + 08] = source[i].Column0.Z;
				destination[j + 09] = source[i].Column1.Z;
				destination[j + 10] = source[i].Column2.Z;
				destination[j + 11] = source[i].Column3.Z;
				destination[j + 12] = source[i].Column0.W;
				destination[j + 13] = source[i].Column1.W;
				destination[j + 14] = source[i].Column2.W;
				destination[j + 15] = source[i].Column3.W;
			}
		}
 
		public static void ToOpenGL(Matrix4 source, ref float[] destination)
		{
			if (destination == null || destination.Length != 16)
			{
				destination = new float[16];
			}
 
			destination[0] = source.Column0.X;
			destination[1] = source.Column1.X;
			destination[2] = source.Column2.X;
			destination[3] = source.Column3.X;
			destination[4] = source.Column0.Y;
			destination[5] = source.Column1.Y;
			destination[6] = source.Column2.Y;
			destination[7] = source.Column3.Y;
			destination[8] = source.Column0.Z;
			destination[9] = source.Column1.Z;
			destination[10] = source.Column2.Z;
			destination[11] = source.Column3.Z;
			destination[12] = source.Column0.W;
			destination[13] = source.Column1.W;
			destination[14] = source.Column2.W;
			destination[15] = source.Column3.W;
		}
 
		private static float[] matrixBuffer = new float[16];
		public static float[] ToOpenGL(Matrix4 source)
		{
			ToOpenGL(source, ref matrixBuffer);
			return matrixBuffer;
		}
the Fiddler's picture

The first two functions work fine, but the last one (float[] ToOpenGL(Matrix4)) will not give the expected results! Consider this:

float[] zero = ToOpenGL(Matrix4.Zero);
float[] identity = ToOpenGL(Matrix4.Identity);
 
if (zero[0] != identity[0])
    Console.WriteLine("Everything's fine.");
else
    Console.WriteLine("Oops, something's wrong.");

It is also not thread-safe.

In any case, if you come across any other functions that should have Matrix4 overloads, please say so and I'll add them.

Kamujin's picture

Oh, the last one is clearly not thread safe, but it's not advertised as thread safe.
The first 2 can be thread safe if you manage the access to the ref float[]'s that you pass.

I see your point about the 3rd form and I can see how it could be confusing. The intent is nothing more then a helper to pass Matrix4 to OpenGL. The use case you pointed out is not within the design considerations. I really don't expect people will adopt OOGL as is for their projects as it's too narrow. I think it's more likely to be picked apart for the nuggets of useful code in it.

the Fiddler's picture

Uniform* methods now contain Matrix4 / Vector[234] overloads (committed to rev. 1696).