Glu NURBS Curve and Surface example

I had the need to start working with Glu.Nurbs curves and surfaces this week.

To get a handle on the structures and procedures involved, I created a simple OpenTK example for using Glu.NurbsCurves and Glu.NurbsSurfaces. It's built using the example framework and the SVN revision 1324 of OpenTK. The Curve and surface data is from a RedBook example, if this is a problem, I can change the data.

Please consider this as my first contribution to OpenTK.

djk

[Edit] I started to add trimming curves to the surface and the parameter GLU_MAP1_TRIM_2 is missing from the MapTarget enum.

[Edit2] It looks like the GLU_MAP1_TRIM_2 is actually a NurbsTrim.Map1Trim2, the Glu.NurbsCurve does not have a signature that is compatible with a NurbsTrim. I have not figured out how to add the missing overload.

I have updated the drawing code to allow trimming and commented out the trimming operation, its in the rev1 zip file.

AttachmentSize
W06_GluNurbs_rev6.zip7.46 KB

Comments

Thanks! I've ported the Quadrics example from the redbook aswell, it's not on svn because of the very same copyright question. The email sent to clarify this couldn't be delivered.

Since the redbook is mirrored online by several universities and other GL pages, I kinda believe it's ok to add it's ported C# code to OpenTK. There might be legal consequences if you try to put OpenTK on a CD/DVD and sell that (they might want a piece of that pie), but for non-commercial/educational use I see no reason why this could become a problem.

The example is evolving and I will replace the few bits that are left from the RedBook with orignal work over the next few days.

I am still stuck on the trimming curve issue, I added the Map1Trim2 enum to the MapTarget enum. When I apply the trimming curve it blows up deep in the bowels of OpenTK. Could you and/or fiddler take a look at rev2 and let me know if the trimmed surface error I am getting is fundamentally the same issue as that faced by the vertex array. I am starting to think that the trimmed surface process is using both client and graphics memory.

[Edit] Below is the temporary addition I made to MapTarget enum

   public enum MapTarget
    {
        GeometryDeformationSgix = ((int)0X8194),
        Map1Color4 = ((int)0X0D90),
        Map1Index = ((int)0X0D91),
        Map2Index = ((int)0X0Db1),
        Map1Vertex4 = ((int)0X0D98),
        TextureDeformationSgix = ((int)0X8195),
        Map1Vertex3 = ((int)0X0D97),
        Map1Normal = ((int)0X0D92),
        Map2Vertex4 = ((int)0X0Db8),
        Map2Color4 = ((int)0X0Db0),
        Map2Vertex3 = ((int)0X0Db7),
        Map2Normal = ((int)0X0Db2),
        Map1TextureCoord4 = ((int)0X0D96),
        Map1TextureCoord2 = ((int)0X0D94),
        Map1TextureCoord3 = ((int)0X0D95),
        Map2TextureCoord2 = ((int)0X0Db4),
        Map2TextureCoord3 = ((int)0X0Db5),
        Map2TextureCoord1 = ((int)0X0Db3),
        Map1TextureCoord1 = ((int)0X0D93),
        Map2TextureCoord4 = ((int)0X0Db6),
        Map1Trim2 = 100210
    }

I have added some controls for exploring the tesselation parameters of the Glu Nurbs surface and curves in rev3.

The problem is related to the delegate:

internal unsafe delegate void NurbsCurve(IntPtr nurb, Int32 knotCount, [Out] float* knots, Int32 stride, [Out] float* control, Int32 order, MapTarget type);

both [Out] keywords are marshaling data in the wrong direction. PlwCurve() should work without modifications.

In rev3 I fixed part of the problem, I had to many control points to the specified knot vector. The problem now seems to be in the EndSurface method that is called right after the trim curve is closed.

Rev4 uses PwlCurve, and PwlCurve or the NurbsCurve gives me the same error:

if (_trimSurface)
{
     Glu.BeginTrim(_theNurb);
     //Glu.NurbsCurve(_theNurb, 8, _trimKnots, 2, _trimControlPoints, 4, MapTarget.Map1Trim2); // trim curve is a foil shape.
     Glu.PwlCurve(_theNurb,4, _trimControlPoints, 2, NurbsTrim.Map1Trim2); // trim curve is a diamond shape
     Glu.EndTrim(_theNurb);
}

Error message: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

Stack Trace: at OpenTK.Graphics.Glu.Imports.EndSurface(IntPtr nurb)
at OpenTK.Graphics.Glu.EndSurface(IntPtr nurb) in C:\Documents and Settings\dkingsley\My Documents\Visual Studio 2005\Projects\OpenGLControls\OpenTK\OpenTk-0.9.1\Source\OpenTK\Graphics\Glu\Glu.cs:line 269
at Examples.WinForms.W06_GluNurbs.NurbsSurface.Draw() in C:\Documents and Settings\dkingsley\My Documents\Visual Studio 2005\Projects\OpenGLControls\OpenTK\OpenTk-0.9.1\Source\Examples\WinForms\W06_GluNurbs.cs:line 321

Mhmm I'm unable to reproduce the error, so it's very likely - as you said earlier - that this is similar to the "Vertex Array" problem. My guess is the pointer to the controlpoints isn't used before Glu.EndSurface() is called, so pinning the ControlPoints (maybe adding a GL.Finish before releasing the pin too) should give the desired result.
I'm not familiar with the math for Nurbs - no idea if the points are specified correctly - but the example draws the very same surface no matter if including the trim or not. I recall reading somewhere that the control points have to be clamped to uv space [0f..1f] but not entirely sure if that is an issue hereby.

I tried to pin the data with no success. I am quite comfortable working with nurbs data. The trim curve is defined in the uv range of [0f..1f].

djk

Well, I finally figured out the problem; I don't seem to be able to tell the difference between clockwise and counter-clockwise.

NurbsCurve still needs to have a set of overloads that takes a NurbsTrim.Map1Trim2.

To make rev5 work, the MapTarget enum has to be temporarily modified as above to add Map1Trim2.

djk

I'll test this on Mono, then add it to the examples. Thanks!

Good job :) Btw. is there any reason why you did not wrap the Nurbs into display lists? That would pretty much work around the issue with pinning except at display list compile time, which is imo desireable. Since you don't allow the control points to be changed through the form it would probably be best practice to do this, assuming display lists can wrap whatever the Glu functions do call in GL.

Today when I began implementing the NurbsSurface object in our application I wrapped the glu calls for the nurbs surface into a display list and it works well.

I also found an issue with the stride for non-square grids of control points, I am at this moment testing an algorithm for computing the stride from the Nurbs data.

I will back these items into the example later tonight and update the zip file.

Trimming curves do not seem to work in a display list, I am researching to see if this is by design.

I fixed the stride issues for non-square grids of control points.

I noticed this afternoon that when the tessellation parameter is set to path length the tessellation of the surface is dependent on the current view transformation. Using the domain distance (ie number of u and v divisions) the tessellation is independent of the view transformation.

I have posted a cleaned up rev6.