reven's picture

Cg and OpenTK Matrix4

Hi, I'm currently having some troubles setting the parameters in a Cg Effect file with Cg.Tao. If this is the wrong place to ask the question, please direct me towards the right.

I would like to avoid using cgGlSetStateMatrixParameter and retrieving the matrices from the OpenGL set projection and modelview matrices. Instead, I'd like to manage my own matrices with OpenTK Matrix4 functions and then supply the matrices and uniform parameters.

I cannot, however, seem to make things work.

First I tried to set the matrix like this:

Matrix4 projectionMatrix = Matrix4.Identity * Matrix4.Perspective(90,800/600, 0.1f,100.0f); // this works right, cause it can be loaded with GL.LoadMatrix and displayed correctly..
IntPtr proj = Cg.cgGetEffectParameterBySemantic(effect, "Projection"); // retrieve projection matrix parameter 
 
// first try - did not work
Cg.cgSetMAtrixParameterfr(proj, out projectionMatrix.Row0.X);   
 
// second try - did not work either
CgGl.cgGLSetMAtrixParameterArrayfr(proj, 0,1, (IntPtr) projectionMatrix.Row0);
 
// Third:
float[] matrix = new float[]
{
   projectionMatrix.Row0.X,
   projectionMatrix.Row0.Y,  
   projectionMatrix.Row0.Z,
   ..
   ..
   projectionMatrix.Row3.W
}
 
Cg.cgSetMatrixPArameterfr(proj, out matrixA[0]);
 
// fourth
CgGl.cgGLSetMAtrixParameterArrayfr(proj, 0,1, matrix);

None of these seemed to work. Any ideas of what might be wrong?


Comments

Comment viewing options

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

The 'out' keyword tells that your parameter is written to by the function (which is probably not what SetMatrixParameter is supposed to do), use 'ref' instead. Imho the Cg binding is incorrect there, if Cg.cgSetMAtrixParameterfr(proj, out projectionMatrix.Row0.X); compiles.

To obtain a pointer to the first element of the Matrix4 struct, use MyMatrix.Row0.X, not MyMatrix.Row0

I don't know anything about Tao.Cg - that's why you got no answer for your other Cg related problem - but you should be warned that passing pointers to Tao bindings often requires you to pin the associated array manually.

reven's picture

Thanks for the answer.

The 'out' keyword tells that your parameter is written to by the function (which is probably not what SetMatrixParameter is supposed to do), use 'ref' instead. Imho the Cg binding is incorrect there, if Cg.cgSetMAtrixParameterfr(proj, out projectionMatrix.Row0.X); compiles.

The Tao.Cg binding requires the out keyword - I found it odd as well. I cannot compile with ref.

To obtain a pointer to the first element of the Matrix4 struct, use MyMatrix.Row0.X, not MyMatrix.Row0
As you can see, in the first try i did pass it as Cg.cgSetMatrixparameterfr(proj, out projectionMatrix.Row0.X), so I did try to obtain the pointer to the first element of the Matrix4 struct that way. It works with parameter functions taking floats as argument with myVector3.X, so I find it odd that it does not with the matrix.

I don't know anything about Tao.Cg - that's why you got no answer for your other Cg related problem - but you should be warned that passing pointers to Tao bindings often requires you to pin the associated array manually.

What do you mean by that? I'm still fairly new to C#.

Entropy's picture

If you need to learn a little about pointers and unsafe code in C#, then take a look at this page to see how pointers work: http://www.softsteel.co.uk/tutorials/cSharp/lesson5.html

I'm not too hot at this myself either, but if you specify a block of code as unsafe, you can fix ("pin") fields in memory, so that they won't get moved around by the garbage collector, something like this:

        public static unsafe void setTheta1Degrees(ref Vector2 vector, float angleInDegrees)
        {
            while(angleInDegrees > 360)
                angleInDegrees -= 360;
 
            fixed (Vector2* V2 = &vector)
            {
                float l = (*V2).Length;
                (*V2).X = l * (float)Math.Cos((double)Functions.DegreesToRadians(angleInDegrees));
                (*V2).Y = l * (float)Math.Sin((double)Functions.DegreesToRadians(angleInDegrees));
            }
        }

This was something I wrote ages ago when I'd just started learning C#, before I realised that passing structs using the "ref" keyword lets you change the original object (rather than just copying the data, which is how they are usually passed). It's a pretty redundant (or even highly inefficient) way of using pointers in C#, but I wrote it after reading the page I've posted above, and it serves as a decent example of unsafe code and fixed objects.

Hope that helps, and I'm sorry if it's much more info than you needed! :-)

Inertia's picture
unsafe
{
  fixed( float* MyPtr = &MyMatrix.Row0.X )
  {
    // now it's guaranteed not to be moved by GC until end of block 
    CgGl.cgGLSetMAtrixParameterArrayfr(proj, 0,1, MyPtr); // assuming there's a float* overload
  } 
}

You should look up unsafe and fixed on MSDN, obviously you use it at your own risk ;)

reven's picture

Thanks for the info so far. I actually did not know I could use pointers like I do in C++ in C#.

Even though I have now tried working with pointers, I still does not work. I figure that it is more of a Tao.Cg or Cg problem than OpenTK. What I have done now is:

//  First: I do not fix, since the projectionMatrix.Row0.X is "already a fixed expression". I have also tried to declare this within the unsafe block.
unsafe
{    
    CgGl.cgGLSetMAtrixParameterArrayfr(proj, 0,1, &projectionMatrix.Row0.X); // assuming there's a float* overload
 
} 
 
// second using the normal float[] array as showed earlier
unsafe
{ 
    fixed (float* MyPtr = &array)
    {  
        CgGl.cgGLSetMAtrixParameterArrayfr(proj, 0,1, MyPtr); // assuming there's a float* overload
    }   
}
 
// Third the same deal with Cg.cgSetMatrixParameterfr(proj, out *MyPtr)

Any ideas?

Inertia's picture
unsafe
{
  fixed( float* MyPtr = &MyMatrix.Row0.X )
  {
    CgGl.cgGLSetMAtrixParameterArrayfr(proj, 0,16, MyPtr);
  }
}

Note the '16'

reven's picture

I have tried that with no luck either. :\

Inertia's picture

Cg uses column or row major matrices (OpenTK uses the later)? Besides that I cannot help you any further, the pinning should not be the problem now.

reven's picture

The CgGl.cgGLSetMatrixParameterArrayfr function means that it uses rows - hence the r appended. It has a CgGl.cgGLSetMatrixParameterArrayfc equivalent as well. So this should not be a problem :\

Thanks so far.

reven's picture

Jesus. I now just tried a lot of different things, and i finally found what I currently regard as a solution to the problem:

I had to pass my ROW OpenTK Matrix4 to cgSetMAtrixPArameterfc which - according to the officialt documentation - takes a column matrix. I guess that there might be a mistake in the Tao.Cg binding?

For the curious, this is what was needed:

Matrix4 projectionMatrix = Matrix4.Identity * Matrix4.Perspective(90,800/600, 0.1f,100.0f); 
IntPtr proj = Cg.cgGetEffectParameterBySemantic(effect, "Projection"); 
 
Cg.cgSetMatrixParamterfc(proj, out projectionMatrix.Row0.X);

Notice that it does require the out keyword and that the c at the end of the function is needed, contrary to human logic and the official documentation. This must either be a mistake at Cg, Tao.Cg or OpenTK.

Thanks for all the help. I learned something new. :)