Как управлять стереокадрами отдельно с помощью С#? (3D-очки с затвором NVIDIA)

Я пытаюсь сделать очень простое приложение, которое будет отображать разные изображения для каждого глаза. У меня есть монитор Asus VG236H и комплект NVIDIA 3D Vision, стереоочки с затвором 3D. Я использую C#, .NET Framework 2.0, DirectX 9 (управляемый Direct X) и Visual Studio 2008. Я долго искал примеры и учебные пособия, на самом деле нашел пару и взял за основу те, которые создал программу, но по какой-то причине я не могу заставить его работать.

В поисках примеров того, как отображать разные изображения для каждого глаза, многие продолжают ссылаться на презентацию NVIDIA на GDC 09 (известный документ GDC09-3DVision-The_In_and_Out.pdf) и страницы 37-40. Мой код в основном построен на основе этого примера:

  1. Я загружаю две текстуры (Red.png и Blue.png) на поверхность (_imageLeft и _imageRight) в функции LoadSurfaces()
  2. Функция Set3D() помещает эти два изображения рядом в одно большее изображение, размер которого равен 2x ширине экрана и высоте экрана + 1 (_imageBuf).
  3. Функция Set3D() продолжает работу, добавляя стереофоническую сигнатуру в последнюю строку.
  4. Функция OnPaint() берет задний буфер (_backBuf) и копирует в него содержимое объединенного изображения (_imageBuf).

Когда я запускаю программу, очки с затвором начинают работать, но я вижу только два изображения на экране рядом друг с другом. Может ли кто-нибудь помочь и сказать мне, что я делаю неправильно? Я считаю, что решение этой проблемы может также помочь другим, поскольку пока нет простого примера того, как это сделать с помощью C#.

Ниже приведены тактические части моего кода. Полный проект можно скачать здесь: http://koti.mbnet.fi/jjantti2/NVStereoTest.rar

    public void InitializeDevice()
    {
        PresentParameters presentParams = new PresentParameters();

        presentParams.Windowed = false;
        presentParams.BackBufferFormat = Format.A8R8G8B8;
        presentParams.BackBufferWidth = _size.Width;
        presentParams.BackBufferHeight = _size.Height;
        presentParams.BackBufferCount = 1;
        presentParams.SwapEffect = SwapEffect.Discard;
        presentParams.PresentationInterval = PresentInterval.One;
        _device = new Device(0, DeviceType.Hardware, this, CreateFlags.SoftwareVertexProcessing, presentParams);
    }

    public void LoadSurfaces()
    {
        _imageBuf = _device.CreateOffscreenPlainSurface(_size.Width * 2, _size.Height + 1, Format.A8R8G8B8, Pool.Default);

        _imageLeft = Surface.FromBitmap(_device, (Bitmap)Bitmap.FromFile("Blue.png"), Pool.Default);
        _imageRight = Surface.FromBitmap(_device, (Bitmap)Bitmap.FromFile("Red.png"), Pool.Default);
    }

    private void Set3D()
    {
        Rectangle destRect = new Rectangle(0, 0, _size.Width, _size.Height);
        _device.StretchRectangle(_imageLeft, _size, _imageBuf, destRect, TextureFilter.None);
        destRect.X = _size.Width;
        _device.StretchRectangle(_imageRight, _size, _imageBuf, destRect, TextureFilter.None);

        GraphicsStream gStream = _imageBuf.LockRectangle(LockFlags.None);

        byte[] data = new byte[] {0x44, 0x33, 0x56, 0x4e,   //NVSTEREO_IMAGE_SIGNATURE         = 0x4433564e
                                  0x00, 0x00, 0x0F, 0x00,   //Screen width * 2 = 1920*2 = 3840 = 0x00000F00;
                                  0x00, 0x00, 0x04, 0x38,   //Screen height = 1080             = 0x00000438;
                                  0x00, 0x00, 0x00, 0x20,   //dwBPP = 32                       = 0x00000020;
                                  0x00, 0x00, 0x00, 0x02};  //dwFlags = SIH_SCALE_TO_FIT       = 0x00000002;

        gStream.Seek(_size.Width * 2 * _size.Height * 4, System.IO.SeekOrigin.Begin);   //last row
        gStream.Write(data, 0, data.Length);

        gStream.Close();

        _imageBuf.UnlockRectangle();
    }

    protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
    {
        _device.BeginScene();

        // Get the Backbuffer then Stretch the Surface on it.
        _backBuf = _device.GetBackBuffer(0, 0, BackBufferType.Mono);
        _device.StretchRectangle(_imageBuf, new Rectangle(0, 0, _size.Width * 2, _size.Height + 1), _backBuf, new Rectangle(0, 0, _size.Width, _size.Height), TextureFilter.None);
        _backBuf.ReleaseGraphics();

        _device.EndScene();

        _device.Present();

        this.Invalidate();
    }

person Andows    schedule 09.05.2011    source источник


Ответы (1)


Мой друг нашел проблему. Байты в стереосигнатуре были в обратном порядке. Вот правильный порядок:

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;

Код отлично работает после этого изменения. Этот код может даже послужить хорошим руководством для тех, кто пытается сделать то же самое. :)

person Andows    schedule 09.05.2011