У меня есть некоторые проблемы при рендеринге набора значений для 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] диапазон пикселей на цели рендеринга !?
Ответы:
Ваша проблема в том, что UV разработаны для текстурных координат. Координата 0,0 - это верхний левый угол верхнего левого пикселя в текстуре, который не находится там, где вы обычно хотите прочитать текстуру. Для 2D вы хотите прочитать текстуру в середине этого пикселя.
Если моя математика верна, что вам нужно сделать, чтобы обойти это:
return float4((texCoord.rg - (0.5f/textureSize)) * (textureSize/(textureSize-1)), 0, 1);
То есть вы вычитаете соответствующее смещение, чтобы получить верхний левый пиксель в 0,0, а затем применяете масштаб, чтобы получить правильное нижнее правое.
Этого же можно добиться, расширив координаты UV для геометрии за пределами диапазона 0-1.
источник
return float4(texCoord.rg, 0, 1);
.Почти, но только половина пикселя. Просто вычтите 0,5 из ваших четырех вершин. Например, вам нужен квадроцикл 256x256 с такой же текстурой, вот ваши очки:
Или вместо этого вы можете добавить половину текселя в пиксельный шейдер (texCoord.rg + 0.5 * (1.0 / texSize))
Полупиксельное смещение - известный факт в DX9. Эта и эта статьи могут вам помочь.
источник
Это, безусловно, вызвано линейной выборкой. Если вы посмотрите на тексели справа и ниже полностью черного верхнего левого пикселя, вы увидите, что они имеют 63 в каналах R и / или G, и у 2 из них есть 2 в B. Теперь посмотрите на грязно-темно-желтый вы получите; это 31 в R и G и 1 в B. Это определенно результат усреднения текселей по группе 2x2, поэтому решение состоит в том, чтобы установить ваш текстурный фильтр на точку.
источник
Это просто потому, что вы используете texCoords из вершинного вывода, который интерполируется жестким диском после обработки вершинного шейдера.
источник