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

Я пытаюсь использовать SlimDX и DirectX10 или 11 для управления процессом стереоизации на nVidia 3D Vision Kit. Благодаря этому вопросу Мне удалось заставить его работать в DirectX 9. Однако из-за отсутствия некоторых методов мне не удалось заставить его работать под DirectX 10 или 11.

Алгоритм выглядит так:

  1. Визуализировать изображение для левого глаза
  2. Визуализировать изображение для правого глаза
  3. Создайте текстуру, способную содержать их ПЛЮС дополнительную строку (так, чтобы размер текстуры был 2 * ширина, высота + 1)
  4. Запишите это значение NV_STEREO_IMAGE_SIGNATURE
  5. Отрисовываем эту текстуру на экране

Мой тестовый код пропускает первые два шага, так как у меня уже есть стерео текстура. Это был бывший файл .JPS, в частности один из тех, что включены в образцы изображений, поставляемые с комплектом NVIDIA 3D. Шаг номер 5 использует полноэкранный четырехугольник и шейдер для рендеринга на него стереоизображенной текстуры через матрицу орто-проекции. В образце кода, который я видел для DX9, это не нужно, и он просто вызывает метод StretchRect (...), чтобы скопировать текстуру обратно в задний буфер. Так может это по этой причине не работает? Есть ли аналогичный метод для этого в DX10? Я думал, что рендеринг в задний буфер теоретически будет таким же, как копирование (или StretchRecting) текстуры на него, но, может быть, это не так?

Вот мой код (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]

Заранее спасибо!


person TheWanderer    schedule 11.09.2011    source источник
comment
Я пытаюсь сделать что-то подобное. Я получил хорошее представление о том, как это работает, из вашего первого сообщения, но я думаю, что я не понимаю это правильно. Не могли бы вы поделиться последним. Спасибо   -  person    schedule 09.10.2011


Ответы (1)


В конце концов мне удалось это исправить. Ключ заключался в использовании метода CopySubResourceRegion для стереоизображения текстуры обратно в задний буфер с указанием ее размера (например, 1920 x 1080 вместо 3840 x 1081).

person TheWanderer    schedule 19.09.2011
comment
Для потомков вот ссылка на работающую автономную программу SlimDX, использующую этот метод. - person TheWanderer; 23.07.2013