使用openTK绘图,保存到文件中,显示在屏幕上



我在earh地图上绘制多个图像,我在每个图像上使用透视正确的纹理链接。

我想将渲染图像存储到文件中(sorce文件为1280x760,在大多数情况下,渲染图像大约为160x90(。目前我正在使用GL.ReadPixels 进行此操作

int width = 1920;
int height = 1080;
using (Bitmap bitmap = new Bitmap(width, height))
{
System.Drawing.Imaging.BitmapData bits = bitmap.LockBits(new Rectangle(0, 0, width, height), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
GL.ReadPixels(0, (0, width, height, OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, bits.Scan0);
bitmap.UnlockBits(bits);
bitmap.RotateFlip(RotateFlipType.Rotate180FlipX);
bitmap.Save("output.png", System.Drawing.Imaging.ImageFormat.Png);
}

当我移动地图时,问题就出现了,渲染的图像在屏幕上不再可见,在这种情况下,GL.ReadPixels返回空像素。

即使当前未在屏幕上渲染,如何获得渲染图像?

额外的问题是,如果我使用帧缓冲区,结果是一样的,但使用帧缓冲区时,我从来没有在屏幕上看到图像,看起来帧缓冲区没有绘制在屏幕上,但GL.ReadPixels可以获得图像。在屏幕上绘制帧缓冲区需要哪几行代码?

知道吗?

我在帧缓冲区中添加了一些绘图代码,但结果是空图像。

int FBOHandle = 0;
int ColorTexture = 0;
int DepthTexture = 0;
public bool canRender = false;
public void onRender()
{
int zoom = (int)MainForm.mainMap.Zoom;
VideoMapOverlayBitmap pob = null;
lock (videoMapOverlayBitmapsSync)
videoMapOverlayBitmaps.TryGetValue(zoom, out pob);
if (pob == null)
return;
if (canRender)
{
canRender = false;
int fboWidth = 1920;
int fboHeight = 1080;
// Create Color Tex for framebuffer
GL.GenTextures(1, out ColorTexture);
GL.BindTexture(TextureTarget.Texture2D, ColorTexture);
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba8, fboWidth, fboHeight, 0, OpenTK.Graphics.OpenGL.PixelFormat.Rgba, PixelType.UnsignedByte, IntPtr.Zero);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.ClampToBorder);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.ClampToBorder);
// GL.Ext.GenerateMipmap( GenerateMipmapTarget.Texture2D );
// Create Depth Tex for framebuffer
GL.GenTextures(1, out DepthTexture);
GL.BindTexture(TextureTarget.Texture2D, DepthTexture);
GL.TexImage2D(TextureTarget.Texture2D, 0, (PixelInternalFormat)All.DepthComponent32, fboWidth, fboHeight, 0, OpenTK.Graphics.OpenGL.PixelFormat.DepthComponent, PixelType.UnsignedInt, IntPtr.Zero);
// things go horribly wrong if DepthComponent's Bitcount does not match the main Framebuffer's Depth
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.ClampToBorder);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.ClampToBorder);
// GL.Ext.GenerateMipmap( GenerateMipmapTarget.Texture2D );
// Create a FBO and attach the textures
GL.Ext.GenFramebuffers(1, out FBOHandle);
GL.Ext.BindFramebuffer(FramebufferTarget.FramebufferExt, FBOHandle);
GL.Ext.FramebufferTexture2D(FramebufferTarget.FramebufferExt, FramebufferAttachment.ColorAttachment0Ext, TextureTarget.Texture2D, ColorTexture, 0);
GL.Ext.FramebufferTexture2D(FramebufferTarget.FramebufferExt, FramebufferAttachment.DepthAttachmentExt, TextureTarget.Texture2D, DepthTexture, 0);
//check for errors on framebuffer
FramebufferErrorCode errorCode = GL.Ext.CheckFramebufferStatus(FramebufferTarget.Framebuffer);
if (errorCode != FramebufferErrorCode.FramebufferComplete)
{
if (errorCode == FramebufferErrorCode.FramebufferUnsupported)
Console.WriteLine("FramebufferUnsupported");
OnUnload();
return;
}
GL.ClearColor(0, 0, 0, 0);
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
/* 
//this corrupts my main screen
GL.ClearColor(Color.White);
GL.MatrixMode(MatrixMode.Projection);
GL.LoadIdentity();
GL.Ortho(0, fboWidth, fboHeight, 0, -1, 1);  // Up-left corner pixel has coordinate (0, 0)
GL.Viewport(0, 0, fboWidth, fboHeight);      // Use all of the glControl painting area   
*/
// Render all images
PureProjection proj = MainForm.mainMap.MapProvider.Projection;
List<VideoLogEntry> log = Log;
//go over all images in the loop
foreach (var videoEntry in log)
{
if (videoEntry == null)
continue;
if (videoEntry.projectedRectangleEmpty())
continue;
PointLatLng[] rect = videoEntry.getProjectedRectangle();
if (videoEntry.bmp != null)
videoEntry.createTexture();
GL.Enable(EnableCap.Texture2D);
GL.BindTexture(TextureTarget.Texture2D, videoEntry.texture);
//GL.Ext.FramebufferTexture2D(FramebufferTarget.FramebufferExt, FramebufferAttachment.ColorAttachment0Ext, TextureTarget.Texture2D, videoEntry.texture, 0);
//GL.DrawBuffers(1, new int[] { videoEntry.texture }); //compiler error
//Do the magick for "Perspective correct texturing"
// center point
GPoint localTargetPosition = MainForm.instance.gMapControl.FromLatLngToLocalWithOffset(videoEntry.target);
videoEntry.UpdatePolygonLocalPosition(videoEntry.projectedRectangle);
// determines distances to center for all vertexes
double dUL = Common.distance(new double[] { videoEntry.LocalPoints[0].X, videoEntry.LocalPoints[0].Y }, new double[] { localTargetPosition.X, localTargetPosition.Y });
double dUR = Common.distance(new double[] { videoEntry.LocalPoints[1].X, videoEntry.LocalPoints[1].Y }, new double[] { localTargetPosition.X, localTargetPosition.Y });
double dLR = Common.distance(new double[] { videoEntry.LocalPoints[2].X, videoEntry.LocalPoints[2].Y }, new double[] { localTargetPosition.X, localTargetPosition.Y });
double dLL = Common.distance(new double[] { videoEntry.LocalPoints[3].X, videoEntry.LocalPoints[3].Y }, new double[] { localTargetPosition.X, localTargetPosition.Y });
var texCoords = new[]
{
new Vector4(0, 0, 1, 1),
new Vector4(1, 0, 1, 1),
new Vector4(1, 1, 1, 1),
new Vector4(0, 1, 1, 1)
};
texCoords[0] *= (float)((dUL + dLR) / dLR);
texCoords[1] *= (float)((dUR + dLL) / dLL);
texCoords[2] *= (float)((dLR + dUL) / dUL);
texCoords[3] *= (float)((dLL + dUR) / dUR);
GL.Begin(PrimitiveType.Quads);
{
GL.TexCoord4(texCoords[0]); GL.Vertex4(videoEntry.LocalPoints[0].X, videoEntry.LocalPoints[0].Y, 1, 1); //UL  LocalPoints[0] gimbalUL
GL.TexCoord4(texCoords[1]); GL.Vertex4(videoEntry.LocalPoints[1].X, videoEntry.LocalPoints[1].Y, 1, 1); //UR  LocalPoints[1] gimbalUR
GL.TexCoord4(texCoords[2]); GL.Vertex4(videoEntry.LocalPoints[2].X, videoEntry.LocalPoints[2].Y, 1, 1); //LR  LocalPoints[2] gimbalLR
GL.TexCoord4(texCoords[3]); GL.Vertex4(videoEntry.LocalPoints[3].X, videoEntry.LocalPoints[3].Y, 1, 1); //LL  LocalPoints[3] gimbalLL
}
GL.End();
GL.Disable(EnableCap.Texture2D);
}
// Grab your screenshot
// draw FBO in to file
lock (pob.masterBitmapSync)
{
using (Bitmap mybitmap = new Bitmap(fboWidth, fboHeight))
{
//fill bitmal so we will see what ReadPixels draw
using (Graphics gfx = Graphics.FromImage(mybitmap))
using (SolidBrush brush = new SolidBrush(Color.FromArgb(0, 0, 255)))
{
gfx.FillRectangle(brush, 0, 0, mybitmap.Width, mybitmap.Height);
}
GPoint p = new GPoint(0, 0);
int outputWidth = mybitmap.Width;
int outputHeight = mybitmap.Height;
System.Drawing.Imaging.BitmapData bits = mybitmap.LockBits(new Rectangle(0, 0, mybitmap.Width, mybitmap.Height), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
GL.ReadPixels((int)p.X, (int)p.Y, outputWidth, outputHeight, OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, bits.Scan0);
mybitmap.UnlockBits(bits);
//mybitmap.RotateFlip(RotateFlipType.Rotate180FlipX);
mybitmap.Save(@"c:DownloadsaaaReadPixels_" + DateTime.Now.ToString("HHmmss_fff") + ".png", System.Drawing.Imaging.ImageFormat.Png);
pob.masterBitmap.Dispose();
pob.masterBitmap = null;
pob.masterBitmap = (Bitmap)mybitmap.Clone();
}
}
// Unload and dispose the frame buffer
GL.Ext.BindFramebuffer(FramebufferTarget.FramebufferExt, 0);

// Clean up what we allocated before exiting
if (ColorTexture != 0)
GL.DeleteTextures(1, ref ColorTexture);
ColorTexture = 0;
if (DepthTexture != 0)
GL.DeleteTextures(1, ref DepthTexture);
DepthTexture = 0;
if (FBOHandle != 0)
GL.Ext.DeleteFramebuffers(1, ref FBOHandle);
FBOHandle = 0;
}
}

即使当前未在屏幕上渲染,如何获得渲染图像?

创建一个新的帧缓冲区,绑定该帧缓冲区、设置视口、设置正交投影矩阵,将您想要的地图片段渲染到其中,调用GL.ReadPixels,保存屏幕截图,卸载并处理帧缓冲区。

以下是一些示例代码:

// Create framebuffer
int fboId = GL.GenFramebuffer();
GL.BindFramebuffer(FramebufferTarget.Framebuffer, fboId);
// Set up a framebuffer attachment here
int width = ...
int height = ...
int textureId = GL.GenTexture();
GL.BindTexture(TextureTarget.Texture2D, textureId);
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba8, width, height, 0, PixelFormat.Rgba, PixelType.Float, IntPtr.Zero);
GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, (FramebufferAttachment)fbAtt.AttachmentType, TextureTarget.Texture2D, textureId, 0);
GL.DrawBuffers(1, new int[] { textureId });
GL.Viewport(0, 0, width, height);
// Set up ortho modo. probably also want to disable depth testing and any active blend modes
....
// Render your map now
....
// Grab your screenshot
.... 
// Unload and dispose the frame buffer
...
// Reset everything (viewport, ortho mode, etc.) if you don't your normal map to flicker for a frame
....

你的另一个问题我不太理解

最新更新