the Fiddler's picture

OpenTK and WPF interoperation

Project:The Open Toolkit library
Version:all versions
Component:Code
Category:support request
Priority:normal
Assigned:Unassigned
Status:closed
Description

Right now, it is possible to create an OpenTK.GLControl and host it in a WPF using a WindowsFormsHost.

The question is: can we create an OpenGL context directly on a WPF window and do away with the host control?

The attached solution creates a WPF solution, obtains its handle and creates a GraphicsContext. This works without errors, however OpenGL rendering results in artifacts. The msdn entry for the OnRender method, notes that:

msdn wrote:

The rendering instructions for this element are not used directly when this method is invoked, and are instead preserved for later asynchronous use by layout and drawing.

This explains why the rendering artifacts appear: OpenGL tries to render to the window directly and does not participate into WPF composition.

One *could* use offscreen OpenGL rendering, perform a readback and present the results into the WPF window, but this is inefficient. It would be nice to find a better solution or confirm that it cannot be done.

Any ideas?

AttachmentSize
OpenTKWPF.zip1.81 MB

Comments

Comment viewing options

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

#21

There is a function named PixelZoom which does not affect ReadPixels. And it appears that you should flip image line by line

the Fiddler's picture

#22

Alternatively, try modifying your perspective projection to invert the y-axis (glFrustum or custom math, depending on whether you target OpenGL 2.1 or 3.0).

Edit: better link.

viewon01's picture

#23

Thanks for your ideas....

1) It sounds that PixelZoom does not affect glReadPixel !
2) The second solution is not acceptable, I want to create a control for the general usage and avoid them to have some "side effects", because using glScale can be easily overiden by normal drawing.

Can someone help me for the PBO problem ? I'm unable to draw on it and get an image using glReadPixel :-(

sharoz's picture

#24

I wrote an WPF OpenTK control for my own needs that may useful. It still wraps the wiforms control but it also has some WPF specific features for bindable shaders.
It also has an FBO class.

Here are a couple blog posts about it:
http://steveharoz.com/blog/?p=82
http://steveharoz.com/blog/?p=116

And here's the project site

Some aspects of it really need to be updated (especially the texture classes), but it's a spare time project.

-Steve

viewon01's picture

#25

Thanks steve,

But your control is not 100% WPF, so by example we cannout put other controls over this control !

The control I'm building is a 100% WPF control that follows the WPF rule and behavior.

Regards

-------------------------------------------------------------------------------------------------------------------------------------

So, I have find a working version based on FBO, the problem that remain is that the image sounds "Transparent" !!

Maybe the problem come from :
- Gl.glRenderbufferStorageEXT(Gl.GL_RENDERBUFFER_EXT, Gl.GL_RGBA8, width, height);
- Gl.glReadPixels(0, 0, _form.ClientSize.Width, _form.ClientSize.Height, Gl.GL_BGRA, Gl.GL_UNSIGNED_BYTE, _bitmapData.Scan0);

Can someone help me with this problem ?

The first is RGBA8 and the second is BGRA

Here I create the FBO :

            #region Render buffer
 
            Gl.glGenRenderbuffersEXT(1, out DepthRenderbuffer);
            Gl.glBindRenderbufferEXT(Gl.GL_RENDERBUFFER_EXT, DepthRenderbuffer);
            Gl.glRenderbufferStorageEXT(Gl.GL_RENDERBUFFER_EXT, Gl.GL_RGBA8, width, height);
            // GL_DEPTH_COMPONENT32, GL_RGBA8, RGBA, GL_RGBA, GL_BGRA
 
            #endregion
 
            #region Frame buffer
 
            // Creating the frame buffer
            Gl.glGenFramebuffersEXT(1, out FboHandle);
 
            // Binding an FBO :
            // - Makes given FBO current (all GL operations occur on attached images)
            // - target must be FRAMEBUFFER_EXT
            Gl.glBindFramebufferEXT(Gl.GL_FRAMEBUFFER_EXT, FboHandle);
 
            #endregion
 
            //---- Attaching Renderbuffers to a Framebuffer
            Gl.glFramebufferRenderbufferEXT(Gl.GL_FRAMEBUFFER_EXT, Gl.GL_COLOR_ATTACHMENT0_EXT, Gl.GL_RENDERBUFFER_EXT, DepthRenderbuffer);

Here I create the BitmapSource :

_bitmapData = _bitmap.LockBits(new System.Drawing.Rectangle(0, 0, _form.ClientSize.Width, _form.ClientSize.Height),
                                                System.Drawing.Imaging.ImageLockMode.ReadWrite,
                                                System.Drawing.Imaging.PixelFormat.Format32bppArgb);
 
                _oglImage.RequestRender();
 
                Gl.glFlush();
                Gl.glFinish();
 
                Gl.glReadBuffer(Gl.GL_COLOR_ATTACHMENT0_EXT);
                Gl.glReadPixels(0, 0, _form.ClientSize.Width, _form.ClientSize.Height, Gl.GL_BGRA, Gl.GL_UNSIGNED_BYTE, _bitmapData.Scan0);
 
                BitmapSource source = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(_bitmap.GetHbitmap(),
                                                                                IntPtr.Zero,
                                                                                Int32Rect.Empty,
                                                                                System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
 
                image.Source = source;
 
                _bitmap.UnlockBits(_bitmapData);
the Fiddler's picture

#26

Screenshot of the issue?

If the formats do not match, ReadPixels will convert its data to the format you specified. You'll take a (significant) speed hit but the results will be consistent (BGRA in this case).

Check your alpha values - maybe the result really *is* transparent? OpenGL doesn't take the alpha channel into account, unless you enable blending.

viewon01's picture

#27

Here, there is an image of an "opaque" cube :

http://picasaweb.google.com/viewon01/OpenGL#5382408228029550290

What is strange is that the color are correct, I have try Red cube, Green cube, Blue cube ... all are corrects... but it remain a transparency problem !

the Fiddler's picture

#28

Seems like your lighting equation is calculating alpha values. Quick sanity check: disable alpha writes and see if it works.

GL.ColorMask(true, true, true, false);

Edit: if this works, simply remove the alpha value from your light colors.

viewon01's picture

#29

Thanks...

But it doesn't work :-(

I use this :
glRenderbufferStorageEXT(Gl.GL_RENDERBUFFER_EXT, Gl.GL_RGBA8 ...

A lot of sample use "GL_DEPTH_COMPONENT32"... but I got a "Black" (empty) image with this !
And even , when I use GL_BGRA (like for glReadPixel...) I also got a black image :-(

the Fiddler's picture

#30

Drivers tend to be picky about DEPTH_COMPONENT formats. You should check whether the FBO is complete and try a different format if it is not.

It's also a good idea to check for OpenGL errors when running in debug mode. This can save you a lot of time in the long run.

Judging from the screenshot, I am pretty sure that this is an issue with the alpha values. Maybe WPF is expecting a RGBA image instead of BGRA? (Try changing the order in glReadPixels).

Another idea is to mask all color channels one by one and see if the rendered image looks correct on each step.

GL.ClearColor(1, 1, 1, 1); // White background, otherwise the last try would be completely invisible
 
// Test four times (one ColorMask call at a time) and check if the resulting image is correct.
GL.ColorMask(true, false, false, false); // Fully opaque, red
GL.ColorMask(false, true, false, false); // Fully opaque, green
GL.ColorMask(false, false, true, false); // Fully opaque, blue
GL.ColorMask(false, false, false, true); // Greyscale, alpha only