DirectX: рендеринг в экранный буфер без использования цели рендеринга - PullRequest
0 голосов
/ 22 марта 2010

Я пишу движок 2D игры с открытым исходным кодом и хочу поддерживать как можно больше устройств и платформ. Я в настоящее время только Windows Mobile, хотя. Я рендеринг с использованием DirectX Mobile, с DirectDraw в качестве запасного пути. Тем не менее, я столкнулся с небольшой проблемой.

Кажется, что хотя эталонный драйвер поддерживает createRenderTarget, многие многие многие физические устройства не поддерживают. Мне нужен какой-то способ рендеринга на экран без использования цели рендеринга, потому что я рендерирую спрайты, используя текстурированные квадраты, но мне также нужно уметь рисовать отдельные пиксели.

Вот как я это делаю прямо сейчас:

// save old values

if (Error::Failed(m_D3DDevice->GetRenderTarget(&m_D3DOldTarget)))
{
    ERROR_EXPLAIN("Could not retrieve backbuffer.");
    return false;
}

// clear render surface

if (Error::Failed(m_D3DDevice->SetRenderTarget(m_D3DRenderSurface, NULL)))
{
    ERROR_EXPLAIN("Could not set render target to render texture.");
    return false;
}

if  (Error::Failed (m_D3DDevice->Clear( 
            0,
            NULL,                        // target rectangle
            D3DMCLEAR_TARGET,
            D3DMCOLOR_XRGB(0, 0, 0),     // clear color
            1.0f, 
            0
        )
    )
)
{
    ERROR_EXPLAIN("Failed to clear render texture.");
    return false;
}

D3DMLOCKED_RECT render_rect;
if (Error::Failed(m_D3DRenderSurface->LockRect(&render_rect, NULL, NULL)))
{
    ERROR_EXPLAIN("Failed to lock render surface pixels.");
}
else
{
    m_D3DBackSurf->SetBuffer((Pixel*)render_rect.pBits);
    m_D3DRenderSurface->UnlockRect();
}

// begin scene

if (Error::Failed(m_D3DDevice->BeginScene()))
{
    ERROR_EXPLAIN("Failed to start rendering.");
    return false;
}

// =====================
// example rendering
// =====================

// some other stuff, but the most important part of rendering a sprite:
device->SetTexture(0, m_Texture));
device->SetStreamSource(0, m_VertexBuffer, sizeof(Vertex));
device->DrawPrimitive(D3DMPT_TRIANGLELIST, 0, 2);

// plotting a pixel
Surface* target = (Surface*)Device::GetRenderMethod()->GetRenderTarget();
buffer = target->GetBuffer();
buffer[somepixel] = MAKECOLOR(255, 0, 0);

// end scene

if (Error::Failed(device->EndScene()))
{
    ERROR_EXPLAIN("Failed to end scene.");
    return false;
}

// clear screen

if (Error::Failed(device->SetRenderTarget(m_D3DOldTarget, NULL)))
{
    ERROR_EXPLAIN("Couldn't set render target to backbuffer.");
    return false;
}

if (Error::Failed(device->GetBackBuffer (   
        0,
        D3DMBACKBUFFER_TYPE_MONO, 
        &m_D3DBack 
        ) 
    ) 
)
{
    ERROR_EXPLAIN("Couldn't retrieve backbuffer.");
    return false;
}

RECT dest = { 
    0, 
    0, 
    Device::GetWidth(), 
    Device::GetHeight()
};

if (Error::Failed( device->StretchRect (        
            m_D3DRenderSurface, 
            NULL,
            m_D3DBack, 
            &dest, 
            D3DMTEXF_NONE 
        )
    )
)
{
    ERROR_EXPLAIN("Failed to stretch render texture to backbuffer.");
    return false;
}

if (Error::Failed(device->Present(NULL, NULL, NULL, NULL)))
{
    ERROR_EXPLAIN("Failed to present device.");
    return false;
}

Я ищу способ сделать то же самое (рендерить спрайты с использованием аппаратного ускорения и наносить пиксели на буфер) без использования цели рендеринга.

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

Ответы [ 2 ]

2 голосов
/ 25 марта 2010

Вы не особо указали , как вы хотели построить пиксели, поэтому я начну с предположения, что это действительно порядок сложности: "buffer [somepixel] = MAKECOLOR (255, 0 , 0); ".

Мое предложение будет заключаться в том, чтобы вместо чтения обратно (что может быть очень дорого или довольно дешево в зависимости от архитектуры памяти) изменять и писать / загружать буфер; Вместо этого разместите ваши пиксели в текстуре и позвольте графическому процессору обрабатывать состав спрайтов, ускоренных графическим процессором, и отображаемых пикселей процессора.

В базовом случае это будет что-то вроде:

  1. Создайте 4-канальную текстуру размером с ваш буфер. Если ваша целевая система поддерживает это, укажите флаги использования LOCKABLE и DYNAMIC. (Если это не так, или если драйвер предпочитает неблокируемые текстуры, вам придется пройти через дополнительную системную текстуру для шага 2 ниже. И загрузить ее, используя вместо этого UpdateTexture / CopyRects)

  2. Каждый кадр, блокировка текстуры, нанесение пикселей, разблокировка текстуры. Обязательно запишите информацию о покрытии в альфа-канал пикселя, чтобы у графического процессора были некоторые данные, которые могут управлять композицией. Например. если вы хотите построить сплошной красный цвет, напишите (255, 0, 0, 255) для этого пикселя. Убедитесь, что вы очистили пиксели, которые на самом деле не хотите отображать.

  3. Настройте графический процессор для составления графиков на основе ваших спрайтов. путем рендеринга полноэкранного четырехугольника, текстурированного с помощью нанесенной вами текстуры (и с использованием точечной выборки). Для простейшего непрозрачного композиционного случая включите AlphaTestEnable, установите AlphaRef на 128, а AlphaFunc на GREATER и отключите ZEnable. Это отобразит построенные пиксели поверх спрайтов, оставив остальные пиксели спрайтов нетронутыми.

Если вы используете буфер глубины и хотите получить дополнительную производительность, вы можете визуализировать нанесенную текстуру перед спрайтами, включив ZEnable и ZWriteEnabled. (Убедитесь, что вы рендерили полноэкранный четырехугольник в ближней плоскости). Это заполнит маску буфера глубины, в которой находятся непрозрачные пиксели, которые будут перекрывать эти пиксели при последующей визуализации спрайтов.

Очевидно, что вы не ограничены просто перезаписью сплошных пикселей. Вы можете использовать альфа-смешивание с комбинацией режимов творческого смешивания и альфа-значений для создания других видов композиций и наложений.

0 голосов
/ 23 марта 2010

Если вам нужна широкая совместимость с карманными устройствами, которые не имеют аппаратного ускорения 3d (каждый настольный компьютер в течение многих лет поддерживает цели рендеринга), то вам может быть проще использовать GDI вместо DirectX.

Я не совсем слежу за тем, что вы пытаетесь сделать в опубликованном вами коде, но добавлю, что цели рендеринга не поддерживают LockRect (и текстуры, созданные с помощью флага цели рендеринга). DirectX для Windows Mobile немного отличается от обычного DirectX, так что, возможно, я неправильно понимаю это. Если вы действительно хотите использовать DirectX в Windows Mobile, найдите CreateOffscreenPlainSurface или какой-либо его аналог, управляемый DirectX. Поверхность такого типа будет блокируемой и будет поддерживать использование StretchRect непосредственно в задний буфер.

...