NV_STEREO_IMAGE_SIGNATURE 和 DirectX 10/11(nVidia 3D Vision)

3
我正在尝试使用SlimDX和DirectX10或11来控制nVidia 3D Vision套件上的立体化过程。由于这个问题,我已经成功地在DirectX 9中实现了它。然而,由于一些缺少的方法,我无法在DirectX 10或11下使其工作。
算法如下:
1. 渲染左眼图像 2. 渲染右眼图像 3. 创建一个纹理,能够容纳两个图像以及额外的一行(因此纹理大小为2 * 宽度,高度+1) 4. 写入NV_STEREO_IMAGE_SIGNATURE值 5. 在屏幕上渲染此纹理
我的测试代码跳过了前两个步骤,因为我已经有了一个立体纹理。它曾经是一个.JPS文件,具体来说是那些随着nvidia 3D套件提供的示例图片之一。第5步使用全屏四边形和着色器通过正交投影矩阵将立体化纹理渲染到其上。我看到的DX9示例代码不需要这样做,只需调用StretchRect(...)方法将纹理复制回后台缓冲区即可。所以也许是因为这个原因它没有起作用?在DX10中有类似的方法吗?我认为渲染到后台缓冲区理论上与将纹理复制(或StretchRect)到后台缓冲区相同,但也许并非如此?
以下是我的代码(slimdx): 立体化过程
static Texture2D Make3D(Texture2D stereoTexture)
{
// stereoTexture contains a stereo image with the left eye image on the left half 
// and the right eye image on the right half
// this staging texture will have an extra row to contain the stereo signature
Texture2DDescription stagingDesc = 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 staging = new Texture2D(device, stagingDesc);

// 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 = 3840 };
// Copy it to the staging texture
device.CopySubresourceRegion(stereoTexture, 0, stereoSrcBox, staging, 0, 0, 0, 0);

// Open the staging texture for reading
DataRectangle box = staging.Map(0, MapMode.Write, SlimDX.Direct3D10.MapFlags.None);
// Go to the last row
box.Data.Seek(stereoTexture.Description.Width * stereoTexture.Description.Height * 4, System.IO.SeekOrigin.Begin);
// Write the NVSTEREO header
box.Data.Write(data, 0, data.Length);
staging.Unmap(0);

// Create the final stereoized texture
Texture2DDescription finalDesc = new Texture2DDescription()
{
    ArraySize = 1,
    Width = 3840,
    Height = 1081,
    BindFlags = BindFlags.ShaderResource,
    CpuAccessFlags = CpuAccessFlags.Write,
    Format = SlimDX.DXGI.Format.R8G8B8A8_UNorm,
    OptionFlags = ResourceOptionFlags.None,
    Usage = ResourceUsage.Dynamic,
    MipLevels = 1,
    SampleDescription = new SampleDescription(1, 0)
};

// Copy the staging texture on a new texture to be used as a shader resource
Texture2D final = new Texture2D(device, finalDesc);
device.CopyResource(staging, final);
staging.Dispose();
return final;
}

NV_STEREO_IMAGE_SIGNATURE 数据

// The NVSTEREO header.
    static byte[] 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

主页

private static Device device;

[STAThread]
static void Main()
{
// 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 = true,
                   OutputHandle = form.Handle,
                   SampleDescription = new SampleDescription(1, 0),
                   SwapEffect = SwapEffect.Discard,
                   Usage = Usage.RenderTargetOutput
               };

SwapChain swapChain;
Device.CreateWithSwapChain(null, DriverType.Hardware, DeviceCreationFlags.Debug, desc, out device, out swapChain);
//Stops Alt+enter from causing fullscreen skrewiness.
Factory factory = swapChain.GetParent<Factory>();
factory.SetWindowAssociation(form.Handle, WindowAssociationFlags.IgnoreAll);

Texture2D backBuffer = Resource.FromSwapChain<Texture2D>(swapChain, 0);
RenderTargetView renderView = new RenderTargetView(device, backBuffer);

ImageLoadInformation info = new ImageLoadInformation()
                                {
                                    BindFlags = BindFlags.None,
                                    CpuAccessFlags = CpuAccessFlags.Read,
                                    FilterFlags = FilterFlags.None,
                                    Format = SlimDX.DXGI.Format.R8G8B8A8_UNorm,
                                    MipFilterFlags = FilterFlags.None,
                                    OptionFlags = ResourceOptionFlags.None,
                                    Usage = ResourceUsage.Staging,
                                    MipLevels = 1
                                };

// Make texture 3D
Texture2D sourceTexture = Texture2D.FromFile(device, "medusa.jpg", info);
Texture2D stereoizedTexture = Make3D(sourceTexture);
ShaderResourceView srv = new ShaderResourceView(device, stereoizedTexture);

// Create a quad that fills the whole screen
ushort[] idx;
TexturedVertex[] quad = CreateTexturedQuad(Vector3.Zero, 1920, 1080, out idx);

// fill vertex and index buffers
DataStream stream = new DataStream(4*24, true, true);
stream.WriteRange(quad);
stream.Position = 0;

Buffer vertices = new SlimDX.Direct3D10.Buffer(device, stream, new BufferDescription()
                                                                   {
                                                                       BindFlags = BindFlags.VertexBuffer,
                                                                       CpuAccessFlags = CpuAccessFlags.None,
                                                                       OptionFlags = ResourceOptionFlags.None,
                                                                       SizeInBytes = 4*24,
                                                                       Usage = ResourceUsage.Default
                                                                   });
stream.Close();

stream = new DataStream(6*sizeof (ushort), true, true);
stream.WriteRange(idx);
stream.Position = 0;
Buffer indices = new SlimDX.Direct3D10.Buffer(device, stream, new BufferDescription()
                                                                  {
                                                                      BindFlags = BindFlags.IndexBuffer,
                                                                      CpuAccessFlags = CpuAccessFlags.None,
                                                                      OptionFlags = ResourceOptionFlags.None,
                                                                      SizeInBytes = 6*sizeof (ushort),
                                                                      Usage = ResourceUsage.Default
                                                                  });

// Create world view (ortho) projection matrices
QuaternionCam qCam = new QuaternionCam();

// Load effect from file. It is a basic effect that renders a full screen quad through 
// an ortho projectio=n matrix
Effect effect = Effect.FromFile(device, "Texture.fx", "fx_4_0", ShaderFlags.Debug, EffectFlags.None);
EffectTechnique technique = effect.GetTechniqueByIndex(0);
EffectPass pass = technique.GetPassByIndex(0);
InputLayout layout = new InputLayout(device, pass.Description.Signature, new[]
                                                                             {
                                                                                 new InputElement("POSITION", 0,
                                                                                                  Format.
                                                                                                      R32G32B32A32_Float,
                                                                                                  0, 0),
                                                                                 new InputElement("TEXCOORD", 0,
                                                                                                  Format.
                                                                                                      R32G32_Float,
                                                                                                  16, 0)
                                                                             });
effect.GetVariableByName("mWorld").AsMatrix().SetMatrix(
    Matrix.Translation(Layout.OrthographicTransform(Vector2.Zero, 90, new Size(1920, 1080))));
effect.GetVariableByName("mView").AsMatrix().SetMatrix(qCam.View);
effect.GetVariableByName("mProjection").AsMatrix().SetMatrix(qCam.OrthoProjection);
effect.GetVariableByName("tDiffuse").AsResource().SetResource(srv);

// Set RT and Viewports
device.OutputMerger.SetTargets(renderView);
device.Rasterizer.SetViewports(new Viewport(0, 0, form.ClientSize.Width, form.ClientSize.Height, 0.0f, 1.0f));

// Create solid rasterizer state
RasterizerStateDescription rDesc = new RasterizerStateDescription()
                                       {
                                           CullMode = CullMode.None,
                                           IsDepthClipEnabled = true,
                                           FillMode = FillMode.Solid,
                                           IsAntialiasedLineEnabled = true,
                                           IsFrontCounterclockwise = true,
                                           IsMultisampleEnabled = true
                                       };
RasterizerState rState = RasterizerState.FromDescription(device, rDesc);
device.Rasterizer.State = rState;

// Main Loop
MessagePump.Run(form, () =>
    {
        device.ClearRenderTargetView(renderView, Color.Cyan);

        device.InputAssembler.SetInputLayout(layout);
        device.InputAssembler.SetPrimitiveTopology(PrimitiveTopology.TriangleList);
        device.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(vertices, 24, 0));
        device.InputAssembler.SetIndexBuffer(indices, Format.R16_UInt, 0);

        for (int i = 0; i < technique.Description.PassCount; ++i)
        {
            // Render the full screen quad
            pass.Apply();
            device.DrawIndexed(6, 0, 0);
        }

        swapChain.Present(0, PresentFlags.None);
    });

// Dispose resources
vertices.Dispose();
layout.Dispose();
effect.Dispose();
renderView.Dispose();
backBuffer.Dispose();
device.Dispose();
swapChain.Dispose();

rState.Dispose();
stereoizedTexture.Dispose();
sourceTexture.Dispose();
indices.Dispose();
srv.Dispose();
}[/code]

提前感谢!


我正在尝试做类似的事情。我从你的第一篇帖子中对它的工作原理有了很好的理解,但我认为我还没有弄对。 你能分享最后一点吗?谢谢。 - user986351
1个回答

4

我最终成功解决了这个问题。关键在于使用 CopySubResourceRegion 方法将立体化纹理复制回后备缓冲区,并指定其尺寸(例如:1920 x 1080 而不是 3840 x 1081)。


1
为了后人,这里是一个链接到一个使用此方法的工作自包含SlimDX程序的 链接 - TheWanderer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接