Пиксельный рендеринг для цели рендера с полноэкранным квадратором

9

У меня есть некоторые проблемы при рендеринге набора значений для rendertarget. Значения никогда не заканчиваются в том диапазоне, в котором я их хочу. В основном я использую полноэкранный четырехугольник и пиксельный шейдер для рендеринга в текстуру rendertarget, а затем собираюсь использовать координаты текстуры в качестве основы для некоторых вычислений в шейдере. Координаты текстуры четырехугольной области от (0,0) в верхнем левом углу до (1,1) в нижнем правом углу ... проблема в том, что после интерполяции эти значения не достигают пиксельного шейдера как такового ,

Пример: я отрисовываю текстуру 4x4, и шейдер в этом случае просто выводит координаты текстуры (u, v) в красном и зеленом каналах:

return float4(texCoord.rg, 0, 1);

То, что я хочу получить, это текстура, где пиксель в верхнем левом углу - RGB (0,0,0) и, таким образом, черный, пиксель в верхнем правом углу - RGB (255,0,0) и, следовательно, яркий красный и пиксель внизу слева - RGB (0,255,0) - ярко-зеленый.

Однако вместо этого я получаю это здесь справа:

(прямое рендеринг без коррекции)
прямая визуализация квадрата, коррекция не применяется

Верхний левый пиксель черный, но я получаю относительно темно-красный и темно-зеленый только в других углах. Их значения RGB (191,0,0) и (0,191,0). Я сильно подозреваю, что это связано с местами выборки квадратора: верхний левый пиксель правильно выбирает левый верхний угол квадрата и получает (0,0) как координаты UV, но остальные угловые пиксели не выбирают из другие углы четырехугольника. Я проиллюстрировал это на левом изображении с синим прямоугольником, представляющим квад, а белыми точками - верхние координаты выборки.

Теперь я знаю о смещении в половину пикселя, которое вы должны применять к своим координатам при рендеринге выровненных по экрану квадратов в Direct3D9. Давайте посмотрим, какой результат я получу от этого:

(Квадрат отображается с половинным смещением DX9)
четырехугольник отображается с половинным смещением

Красный и зеленый стали ярче, но все еще не верны: 223 - максимум, который я получаю на канале красного или зеленого цвета. Но теперь у меня даже больше нет чистого черного, а вместо этого темно-желтовато-серый с RGB (32,32,0)!

Что мне действительно нужно, так это рендеринг:

(целевой рендер, уменьшенный размер квадрата)
чистый черный, зеленый и красный с правильной интерполяцией

Похоже, мне нужно переместить правую и нижнюю границу моего четырехугольника ровно на один пиксель вверх и влево по сравнению с первой фигурой. Тогда правый столбец и нижний ряд пикселей должны корректно получить координаты UV прямо от границы квадрата:

VertexPositionTexture[] quad = new VertexPositionTexture[]
{
    new VertexPositionTexture(new Vector3(-1.0f,  1.0f, 1f), new Vector2(0,0)),
    new VertexPositionTexture(new Vector3(1.0f - pixelSize.X,  1.0f, 1f), new Vector2(1,0)),
    new VertexPositionTexture(new Vector3(-1.0f, -1.0f + pixelSize.Y, 1f), new Vector2(0,1)),
    new VertexPositionTexture(new Vector3(1.0f - pixelSize.X, -1.0f + pixelSize.Y, 1f), new Vector2(1,1)),
};

Однако это не совсем сработало и заставило нижний и правый пиксели вообще не рендериться. Я предполагаю, что центры этих пикселей больше не покрыты квадом и, следовательно, не будут обрабатываться шейдером. Если я изменю вычисление pixelSize на какое-то крошечное количество, чтобы сделать крошечное немного больше, это как бы работает ... по крайней мере, для текстуры 4х4. Это не работает на меньших текстурах, и я боюсь, что это слегка искажает равномерное распределение значений uv на больших текстурах:

Vector2 pixelSize = new Vector2((2f / textureWidth) - 0.001f, (2f / textureHeight) - 0.001f);

(Я изменил вычисление pixelSize на 0,001f - для текстур меньшего размера, например, таблиц поиска 1D, это не работает, и мне нужно увеличить его до 0,01f или чего-то большего)

Конечно, это тривиальный пример, и я мог бы гораздо проще выполнить этот расчет на процессоре, не беспокоясь о том, чтобы отобразить UV в центры пикселей ... тем не менее, должен быть способ действительно отобразить полный, полный [0, 1] диапазон пикселей на цели рендеринга !?

Марио
источник
Не то чтобы это помогло, но у меня точно такая же проблема.
IUsedToBeAPygmy
1
Не забудьте также отключить линейную выборку.
r2d2rigo
Это не похоже на то, что используемая вами система координат соответствует пикселям экрана - если бы это было так, то похоже, что вы рисуете здесь только 2 × 2 пикселя. Первая проблема, которую я решу, - это масштабирование матриц вида проекта и модели таким образом, чтобы +1 в координатном пространстве был сдвигом на 1 пиксель на экране.
Слипп Д. Томпсон

Ответы:

4

Ваша проблема в том, что UV разработаны для текстурных координат. Координата 0,0 - это верхний левый угол верхнего левого пикселя в текстуре, который не находится там, где вы обычно хотите прочитать текстуру. Для 2D вы хотите прочитать текстуру в середине этого пикселя.

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

return float4((texCoord.rg - (0.5f/textureSize)) * (textureSize/(textureSize-1)), 0, 1);

То есть вы вычитаете соответствующее смещение, чтобы получить верхний левый пиксель в 0,0, а затем применяете масштаб, чтобы получить правильное нижнее правое.

Этого же можно добиться, расширив координаты UV для геометрии за пределами диапазона 0-1.

Адам
источник
Чтобы уточнить последнее предложение: вы можете применить это преобразование к UV в буфере вершин для четырех углов четырехугольника, а затем в пиксельном шейдере return float4(texCoord.rg, 0, 1);.
Натан Рид
Я попробовал предложенную выше формулу, и она не вполне сработала: в моем примере рендеринга 4x4 сверху я получаю 0, 42, 127 и 212 в каналах R и G, слева направо или сверху вниз. Тем не менее, я бы хотел, чтобы значения от 0 до 255 были равномерно распределены (для текстуры 4х4, которая была бы 0, 85, 170 и 255). Я также пытался изменить координаты UV, но пока не нашел правильное смещение.
Марио
0

Похоже, мне нужно переместить правую и нижнюю границу моего четырехугольника ровно на один пиксель вверх и влево по сравнению с первой фигурой.

Почти, но только половина пикселя. Просто вычтите 0,5 из ваших четырех вершин. Например, вам нужен квадроцикл 256x256 с такой же текстурой, вот ваши очки:

p1 = (-0.5, -0.5)
p2 = (-0.5, 255-0.5)
p3 = (255-0.5, 255-0.5)
p4 = (255-0.5, -0.5)

Или вместо этого вы можете добавить половину текселя в пиксельный шейдер (texCoord.rg + 0.5 * (1.0 / texSize))

Полупиксельное смещение - известный факт в DX9. Эта и эта статьи могут вам помочь.

alariq
источник
0

Это, безусловно, вызвано линейной выборкой. Если вы посмотрите на тексели справа и ниже полностью черного верхнего левого пикселя, вы увидите, что они имеют 63 в каналах R и / или G, и у 2 из них есть 2 в B. Теперь посмотрите на грязно-темно-желтый вы получите; это 31 в R и G и 1 в B. Это определенно результат усреднения текселей по группе 2x2, поэтому решение состоит в том, чтобы установить ваш текстурный фильтр на точку.

Максимус Минимус
источник
-2

Это просто потому, что вы используете texCoords из вершинного вывода, который интерполируется жестким диском после обработки вершинного шейдера.

Джейсон Хуан
источник