Какой код вершинного шейдера следует использовать для пиксельного шейдера, используемого для простого 2D-рисования SpriteBatch в XNA? - PullRequest
2 голосов
/ 19 ноября 2011

Введение

Прежде всего, почему вершинный шейдер требуется для SilverlightEffect (файл .slfx) в Silverlight 5? Я пытаюсь перенести простую 2D игру XNA на Silverlight 5 RC, и я хотел бы использовать базовый пиксельный шейдер . Этот шейдер прекрасно работает в XNA для Windows и Xbox, но я не могу заставить его скомпилировать с Silverlight как SilverlightEffect.

В блоге MS для Silverlight Toolkit говорится, что "нет разницы между .slfx и .fx", но, по-видимому, это не совсем так - или, по крайней мере, SpriteBatch работает над магией для мы в "обычной XNA", а не в "Silverlight XNA".

Если я пытаюсь напрямую скопировать файл пиксельного шейдера в проект Silverlight (и изменить его на поддерживаемый импортер / процессор «Эффект - Silverlight»), при попытке компилирования появляется следующее сообщение об ошибке:

Invalid effect file. Unable to find vertex shader in pass "P0"

Действительно, в моем файле пиксельных шейдеров нет вершинного шейдера. Мне не нужно было этого с моими другими приложениями 2D XNA, так как я просто делаю базовое рисование SpriteBatch.

Я попытался добавить вершинный шейдер в свой файл шейдера, используя Комментарий Реми Гиллиг к этому сообщению в блоге Шона Харгривса , но он не совсем работает. Файл шейдера успешно компилируется, и я вижу на экране некоторое подобие моей игры, но оно крошечное, искаженное, повторяется и все перемешано. Ясно, что что-то не так.


Настоящий вопрос

Итак, это подводит меня к реальному вопросу: поскольку требуется вершинный шейдер, существует ли базовая функция вершинного шейдера, которая работает для простого 2D-рисования SpriteBatch?

А если вершинному шейдеру в качестве параметров требуются матрицы мира / вида / проекта, какие значения я должен использовать для 2D-игры?

Может ли помочь какой-нибудь шейдер? Спасибо!

Ответы [ 2 ]

3 голосов
/ 19 ноября 2011

В XNA SpriteBatch предоставляет собственный вершинный шейдер. Поскольку в Silverlight 5 нет SpriteBatch, вы должны предоставить свой собственный.

Возможно, вы захотите посмотреть исходный код для шейдера, который SpriteBatch использует (он находится в SpriteEffect.fx). Вот его вершинный шейдер, он довольно прост:

void SpriteVertexShader(inout float4 color    : COLOR0,
                        inout float2 texCoord : TEXCOORD0,
                        inout float4 position : SV_Position)
{
    position = mul(position, MatrixTransform);
}

Так что теперь вам просто нужны входная позиция и матрица преобразования (и координаты текстуры, но они довольно просты).

В том же сообщении в блоге, которое вы связали , в конце рассказывается, как настроить матрицу ( также здесь ). Вот оно снова:

Matrix projection = Matrix.CreateOrthographicOffCenter(0, viewport.Width, viewport.Height, 0, 0, 1);
Matrix halfPixelOffset = Matrix.CreateTranslation(-0.5f, -0.5f, 0);
Matrix transformation = halfPixelOffset * projection;

(Примечание: я не уверен, что Silverlight действительно требует полупиксельного смещения для поддержания выравнивания текселей ( ref ). Вероятно, так и есть.)

Хитрость заключается в том, что позиционирование спрайта выполняется вне шейдера, на процессоре. Вот порядок действий SpriteBatch:

  • Начните с четырех вершин в прямоугольнике, где (0,0) - верхний левый угол, а текстуры (ширина, высота) - нижний правый
  • Перевести назад по происхождению
  • Масштаб
  • Поворот
  • Перевести на должность

Это помещает вершины спрайта в «пространство клиента», а затем матрица преобразования преобразует эти вершины из пространства клиента в пространство проекции (которое используется для рисования).

У меня есть версия этого преобразования с высокой степенью точности в ExEn (SpriteBatch.InternalDraw в SpriteBatchOpenGL.cs), которую вы можете легко адаптировать для своего использования.

1 голос
/ 05 февраля 2012

Сегодня я сталкивался с этим вопросом и хочу добавить, что вы можете выполнять все вычисления в самом вершинном шейдере:

float2 Viewport; //Set to viewport size from application code

void SpriteVertexShader(inout float4 color    : COLOR0,
                       inout float2 texCoord : TEXCOORD0,
                       inout float4 position : POSITION0)
{
   // Half pixel offset for correct texel centering.
   position.xy -= 0.5;
   // Viewport adjustment.
   position.xy = position.xy / Viewport;
   position.xy *= float2(2, -2);
   position.xy -= float2(1, -1);
}

(я не писал этого, спасибо за комментариив статье , упомянутой выше)

...