C# 在C中使用DirectX11和SlimDX的Nvidia 3d视频#
你好, 我正在尝试使用nvidia 3DVision和两个IP摄像头显示实时立体视频。我对DirectX完全陌生,但我尝试过在这个网站和其他网站上完成一些教程和其他问题。现在,我正在为左眼和右眼显示两个静态位图。一旦我的程序的这一部分开始工作,这些将被我相机中的位图所取代。 这个问题对我帮助很大,但我仍在努力让我的程序正常工作。我发现我的快门眼镜开始正常工作,但只显示右眼的图像,而左眼保持空白(除了鼠标光标) 以下是生成立体图像的代码:C# 在C中使用DirectX11和SlimDX的Nvidia 3d视频#,c#,nvidia,direct3d,directx-11,slimdx,C#,Nvidia,Direct3d,Directx 11,Slimdx,你好, 我正在尝试使用nvidia 3DVision和两个IP摄像头显示实时立体视频。我对DirectX完全陌生,但我尝试过在这个网站和其他网站上完成一些教程和其他问题。现在,我正在为左眼和右眼显示两个静态位图。一旦我的程序的这一部分开始工作,这些将被我相机中的位图所取代。 这个问题对我帮助很大,但我仍在努力让我的程序正常工作。我发现我的快门眼镜开始正常工作,但只显示右眼的图像,而左眼保持空白(除了鼠标光标) 以下是生成立体图像的代码: using System; using System.Co
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using SlimDX;
using SlimDX.Direct3D11;
using SlimDX.Windows;
using SlimDX.DXGI;
using Device = SlimDX.Direct3D11.Device; // Make sure we use DX11
using Resource = SlimDX.Direct3D11.Resource;
namespace SlimDxTest2
{
static class Program
{
private static Device device; // DirectX11 Device
private static int Count; // Just to make sure things are being updated
// The NVSTEREO header.
static byte[] stereo_data = new byte[] {0x4e, 0x56, 0x33, 0x44, //NVSTEREO_IMAGE_SIGNATURE = 0x4433564e;
0x00, 0x0F, 0x00, 0x00, //Screen width * 2 = 1920*2 = 3840 = 0x00000F00;
0x38, 0x04, 0x00, 0x00, //Screen height = 1080 = 0x00000438;
0x20, 0x00, 0x00, 0x00, //dwBPP = 32 = 0x00000020;
0x02, 0x00, 0x00, 0x00}; //dwFlags = SIH_SCALE_TO_FIT = 0x00000002
[STAThread]
static void Main()
{
Bitmap left_im = new Bitmap("Blue.png"); // Read in Bitmaps
Bitmap right_im = new Bitmap("Red.png");
// Device creation
var form = new RenderForm("Stereo test") { ClientSize = new Size(1920, 1080) };
var desc = new SwapChainDescription()
{
BufferCount = 1,
ModeDescription = new ModeDescription(1920, 1080, new Rational(120, 1), Format.R8G8B8A8_UNorm),
IsWindowed = false, //true,
OutputHandle = form.Handle,
SampleDescription = new SampleDescription(1, 0),
SwapEffect = SwapEffect.Discard,
Usage = Usage.RenderTargetOutput
};
SwapChain swapChain;
Device.CreateWithSwapChain(DriverType.Hardware, DeviceCreationFlags.Debug, desc, out device, out swapChain);
RenderTargetView renderTarget; // create a view of our render target, which is the backbuffer of the swap chain we just created
using (var resource = Resource.FromSwapChain<Texture2D>(swapChain, 0))
renderTarget = new RenderTargetView(device, resource);
var context = device.ImmediateContext; // set up a viewport
var viewport = new Viewport(0.0f, 0.0f, form.ClientSize.Width, form.ClientSize.Height);
context.OutputMerger.SetTargets(renderTarget);
context.Rasterizer.SetViewports(viewport);
// prevent DXGI handling of alt+enter, which doesn't work properly with Winforms
using (var factory = swapChain.GetParent<Factory>())
factory.SetWindowAssociation(form.Handle, WindowAssociationFlags.IgnoreAll);
form.KeyDown += (o, e) => // handle alt+enter ourselves
{
if (e.Alt && e.KeyCode == Keys.Enter)
swapChain.IsFullScreen = !swapChain.IsFullScreen;
};
form.KeyDown += (o, e) => // Alt + X -> Exit Program
{
if (e.Alt && e.KeyCode == Keys.X)
{
form.Close();
}
};
context.ClearRenderTargetView(renderTarget, Color.Green); // Fill Screen with specified colour
Texture2DDescription stereoDesc = new Texture2DDescription()
{
ArraySize = 1,
Width = 3840,
Height = 1081,
BindFlags = BindFlags.None,
CpuAccessFlags = CpuAccessFlags.Write,
Format = SlimDX.DXGI.Format.R8G8B8A8_UNorm,
OptionFlags = ResourceOptionFlags.None,
Usage = ResourceUsage.Staging,
MipLevels = 1,
SampleDescription = new SampleDescription(1, 0)
};
// Main Loop
MessagePump.Run(form, () =>
{
Texture2D texture_stereo = Make3D(left_im, right_im); // Create Texture from two bitmaps in memory
ResourceRegion stereoSrcBox = new ResourceRegion { Front = 0, Back = 1, Top = 0, Bottom = 1080, Left = 0, Right = 1920 };
context.CopySubresourceRegion(texture_stereo, 0, stereoSrcBox, renderTarget.Resource, 0, 0, 0, 0);
texture_stereo.Dispose();
swapChain.Present(0, PresentFlags.None);
});
// Dispose resources
swapChain.IsFullScreen = false; // Required before swapchain dispose
device.Dispose();
swapChain.Dispose();
renderTarget.Dispose();
}
static Texture2D Make3D(Bitmap leftBmp, Bitmap rightBmp)
{
var context = device.ImmediateContext;
Bitmap left2 = leftBmp.Clone(new RectangleF(0, 0, leftBmp.Width, leftBmp.Height), PixelFormat.Format32bppArgb); // Change bmp to 32bit ARGB
Bitmap right2 = rightBmp.Clone(new RectangleF(0, 0, rightBmp.Width, rightBmp.Height), PixelFormat.Format32bppArgb);
// Show FrameCount on screen: (To test)
Graphics left_graph = Graphics.FromImage(left2);
left_graph.DrawString("Frame: " + Count.ToString(), new System.Drawing.Font("Arial", 16), Brushes.Black, new PointF(100, 100));
left_graph.Dispose();
Graphics right_graph = Graphics.FromImage(right2);
right_graph.DrawString("Frame: " + Count.ToString(), new System.Drawing.Font("Arial", 16), Brushes.Black, new PointF(200, 200));
right_graph.Dispose();
Count++;
Texture2DDescription desc2d = new Texture2DDescription()
{
ArraySize = 1,
Width = 1920,
Height = 1080,
BindFlags = BindFlags.None,
CpuAccessFlags = CpuAccessFlags.Write,
Format = SlimDX.DXGI.Format.R8G8B8A8_UNorm,
OptionFlags = ResourceOptionFlags.None,
Usage = ResourceUsage.Staging,
MipLevels = 1,
SampleDescription = new SampleDescription(1, 0)
};
Texture2D leftText2 = new Texture2D(device, desc2d); // Texture2D for each bmp
Texture2D rightText2 = new Texture2D(device, desc2d);
Rectangle rect = new Rectangle(0, 0, left2.Width, left2.Height);
BitmapData leftData = left2.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
IntPtr left_ptr = leftData.Scan0;
int left_num_bytes = Math.Abs(leftData.Stride) * leftData.Height;
byte[] left_bytes = new byte[left_num_bytes];
byte[] left_bytes2 = new byte[left_num_bytes];
System.Runtime.InteropServices.Marshal.Copy(left_ptr, left_bytes, 0, left_num_bytes); // Get Byte array from bitmap
left2.UnlockBits(leftData);
DataBox box1 = context.MapSubresource(leftText2, 0, MapMode.Write, SlimDX.Direct3D11.MapFlags.None);
box1.Data.Write(left_bytes, 0, left_bytes.Length);
context.UnmapSubresource(leftText2, 0);
BitmapData rightData = right2.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
IntPtr right_ptr = rightData.Scan0;
int right_num_bytes = Math.Abs(rightData.Stride) * rightData.Height;
byte[] right_bytes = new byte[right_num_bytes];
System.Runtime.InteropServices.Marshal.Copy(right_ptr, right_bytes, 0, right_num_bytes); // Get Byte array from bitmap
right2.UnlockBits(rightData);
DataBox box2 = context.MapSubresource(rightText2, 0, MapMode.Write, SlimDX.Direct3D11.MapFlags.None);
box2.Data.Write(right_bytes, 0, right_bytes.Length);
context.UnmapSubresource(rightText2, 0);
Texture2DDescription stereoDesc = new Texture2DDescription()
{
ArraySize = 1,
Width = 3840,
Height = 1081,
BindFlags = BindFlags.None,
CpuAccessFlags = CpuAccessFlags.Write,
Format = SlimDX.DXGI.Format.R8G8B8A8_UNorm,
OptionFlags = ResourceOptionFlags.None,
Usage = ResourceUsage.Staging,
MipLevels = 1,
SampleDescription = new SampleDescription(1, 0)
};
Texture2D stereoTexture = new Texture2D(device, stereoDesc); // Texture2D to contain stereo images and Nvidia 3DVision Signature
// Identify the source texture region to copy (all of it)
ResourceRegion stereoSrcBox = new ResourceRegion { Front = 0, Back = 1, Top = 0, Bottom = 1080, Left = 0, Right = 1920 };
// Copy it to the stereo texture
context.CopySubresourceRegion(leftText2, 0, stereoSrcBox, stereoTexture, 0, 0, 0, 0);
context.CopySubresourceRegion(rightText2, 0, stereoSrcBox, stereoTexture, 0, 1920, 0, 0); // Offset by 1920 pixels
// Open the staging texture for reading and go to last row
DataBox box = context.MapSubresource(stereoTexture, 0, MapMode.Write, SlimDX.Direct3D11.MapFlags.None);
box.Data.Seek(stereoTexture.Description.Width * (stereoTexture.Description.Height - 1) * 4, System.IO.SeekOrigin.Begin);
box.Data.Write(stereo_data, 0, stereo_data.Length); // Write the NVSTEREO header
context.UnmapSubresource(stereoTexture, 0);
left2.Dispose();
leftText2.Dispose();
right2.Dispose();
rightText2.Dispose();
return stereoTexture;
}
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用System.Windows.Forms;
使用系统图;
使用系统、绘图、成像;
使用System.IO;
使用SlimDX;
使用SlimDX.Direct3D11;
使用SlimDX.Windows;
使用SlimDX.DXGI;
使用Device=SlimDX.Direct3D11.Device;//确保我们使用DX11
使用Resource=SlimDX.Direct3D11.Resource;
命名空间slimdxt2
{
静态类程序
{
专用静态设备设备;//DirectX11设备
private static int Count;//只是为了确保正在更新内容
//立体声标题。
静态字节[]立体声图像数据=新字节[]{0x4e,0x56,0x33,0x44,//NVSTEREO图像签名=0x4433564e;
0x00,0x0F,0x00,0x00,//屏幕宽度*2=1920*2=3840=0x00000F00;
0x38,0x04,0x00,0x00,//屏幕高度=1080=0x00000438;
0x20,0x00,0x00,0x00,//dwBPP=32=0x00000020;
0x02,0x00,0x00,0x00};//dwFlags=SIH\u SCALE\u TO\u FIT=0x00000002
[状态线程]
静态void Main()
{
位图left_im=新位图(“Blue.png”);//读入位图
位图右\u im=新位图(“Red.png”);
//设备创建
var form=newrenderform(“立体测试”){ClientSize=new Size(19201080)};
var desc=新SwapChainDescription()
{
BufferCount=1,
ModeDescription=新的ModeDescription(19201080,新的Rational(120,1),格式为.R8G8B8A8_UNorm),
IsWindowed=false,//true,
outputhHandle=form.Handle,
SampleDescription=新的SampleDescription(1,0),
SwapEffect=SwapEffect.丢弃,
用法=用法.RenderTargetOutput
};
SwapChain SwapChain;
Device.CreateWithSwapChain(DriverType.Hardware,DeviceCreationFlags.Debug,desc,out Device,out swapChain);
RenderTargetView renderTarget;//创建渲染目标的视图,它是我们刚刚创建的交换链的backbuffer
使用(var resource=resource.FromSwapChain(swapChain,0))
renderTarget=新的RenderTargetView(设备、资源);
var context=device.ImmediateContext;//设置视口
var viewport=新视口(0.0f,0.0f,form.ClientSize.Width,form.ClientSize.Height);
context.outputMerge.SetTargets(renderTarget);
context.Rasterizer.SetViewports(viewport);
//防止DXGI处理alt+enter,这在Winforms中无法正常工作
使用(var factory=swapChain.GetParent())
SetWindowAssociation(form.Handle,WindowAssociationFlags.IgnoreAll);
form.KeyDown+=(o,e)=>//handle alt+输入我们自己
{
if(e.Alt&&e.KeyCode==Keys.Enter)
swapChain.IsFullScreen=!swapChain.IsFullScreen;
};
form.KeyDown+=(o,e)=>//Alt+X->退出程序
{
if(e.Alt&&e.KeyCode==Keys.X)
{
form.Close();
}
};
context.ClearRenderTargetView(renderTarget,Color.Green);//用指定的颜色填充屏幕
Texture2DDescription stereoDesc=新的Texture2DDescription()
{
ArraySize=1,
宽度=3840,
高度=1081,
BindFlags=BindFlags.None,
CpuAccessFlags=CpuAccessFlags.Write,
Format=SlimDX.DXGI.Format.R8G8B8A8_UNorm,
OptionFlags=ResourceOptionFlags.None,
用法=ResourceUsage.Staging,
MIP级别=1,
SampleDescription=新的SampleDescription(1,0)
};
//主回路
MessagePump.Run(表单,()=>
{
Texture2D texture_stereo=Make3D(左\u im,右\u im);//从内存中的两个位图创建纹理
ResourceRegion立体rcbox=new ResourceRegion{Front=0,Back=1,Top=0,Bottom=1080,Left=0,Right=1920};
CopySubresourceRegion(纹理\立体,0,立体框,renderTarget.Resource,0,0,0);
纹理_立体声处理();
swapChain.Present(0,PresentFlags.None);
});
//配置资源
swapChain.IsFullScreen=false;//在处理swapChain之前需要
device.Dispose();
swapChain.Dispose();
renderTarget.Dispose();
}
静态纹理2D Make3D(位图leftBmp、位图rightBmp)
{
var context=device.ImmediateContext;
位图left2=leftBmp.Clone(新矩形f(0,0,leftBmp.Width,leftBmp.Height),PixelFormat.Format32bppArgb);//将bmp更改为32位ARGB
位图right2=righbmp.Clone(新矩形f(0,0,righbmp.Width,righbmp.Height),PixelFormat.Format32bppArgb);
//在屏幕上显示帧数:(要测试)
Graphics left_graph=Graphics.FromImage(left2);
左\u图形.抽绳(“帧:+Count.ToString(),新建
_________________________
| | |
| img1 | img2 |
| | |
--------------------------
|_______signature________| where this last row = 1 pix tall
void RenderEye(bool rightEye, ITarget target)
{
RenderTargetView currentTarget = rightEye ? target.RenderTargetViewRight : target.RenderTargetView;
context.OutputMerger.SetTargets(target.DepthStencilView, currentTarget);
[clean color/depth]
[render scene]
[repeat for each eye]
}