Я пишу приложение SlimDX для проверки пороговых значений цветовой контрастной чувствительности зрительной системы человека. Испытуемому показывают большую букву, которая слабо контрастирует с фоном, и просят идентифицировать букву. Однако мне нужна возможность отображать больше цветов, чем это доступно с простой глубиной цвета 8 бит на канал. (т.е. значения RGB 0-255). Я планирую сделать это с помощью простого алгоритма «дизеринга», реализованного в виде пиксельного шейдера HLSL. В основном, если запросить slimDX для рендеринга текста на поверхность с цветом Color4 (0,55f, 0,55f, 0,55f), который соответствует значению rgb (140,25, 140,25, 140,25), я хочу, чтобы каждый цветовой канал каждого пикселя имел с вероятностью 25% будет установлено значение 141 и с вероятностью 75% будет установлено значение 140. Это должно (в пределах нескольких пикселей) привести к тому, что буква будет отображаться как оттенок серого на 1/4 длины. между 140 и 141.
Однако я получаю ошибки в коде моего прототипа шейдера при попытке компиляции с помощью fxc. При компиляции я получаю недопустимый код символа и не знаю почему. Также, если вы гуру HLSL, просмотрите мой код и сделайте любые комментарии, которые вас поразят. Обратите внимание, что я получил случайную функцию HLSL из ответа на этот вопрос. Могу ли я сгенерировать случайное число внутри пиксельного шейдера? < / а>
Ниже мой код шейдера. Пожалуйста, простите меня, если в моем первом HLSL-коде было много ошибок:
float4 DitherByChance(float2 coords : TEXCOORD0) : COLOR0
{
float4 newColor; // The pixel color to return
float4 oldColor = tex2D(s0, coords);
// Note I know that as the code stands now rCutOff = gCutOff = bCutOff I will sort a fix for this out later
float rCutOff = random(coords); // A random float that determines if the red channel will be rounded up or down
float gCutOff = random(coords); // A random float that determines if the green channel will be rounded up or down
float bCutOff = random(coords); // A random float that determines if the blue channel will be rounded up or down
float rPercentChance = frac(oldColor.r * 255); //Chance to round red channel up
float gPercentChance = frac(oldColor.g * 255); //Chance to round green channel up
float bPercentChance = frac(oldColor.b * 255); //Chance to round blue channel up
//In the code below (1/255) is the floating point represntaion of an incress of one on the 0-255 RGB scale
if (rCutOff <= rPercentChance) newColor.r = oldColor.r + ((1 - rPercentChance) / 255); //Bump up one r value
else newColor.r = oldColor.r - rPercentChance * (1 / 255); //Bump down to ensure r is not rounded up
if (gCutOff <= gPercentChance) newColor.g = oldColor.g + ((1 - gPercentChance) / 255); //Bump up one g value
else newColor.b = oldColor.b - bPercentChance * (1 / 255); //Bump down to ensure g is not rounded up
if (bCutOff <= bPercentChance) newColor.b = oldColor.b + ((1 - bPercentChance) / 255); //Bump up one b value
else newColor.b = oldColor.b - bPercentChance * (1 / 255); //Bump down to ensure b is not rounded up
return newColor;
}
// Input: It uses texture coords as the random number seed.
// Output: Random number: [0,1), that is between 0.0 and 0.999999... inclusive.
// Author: Michael Pohoreski
// Copyright: Copyleft 2012 :-)
float random( vec2 p )
{
// We need irrationals for pseudo randomness.
// Most (all?) known transcendental numbers will (generally) work.
const vec2 r = vec2(
23.1406926327792690, // e^pi (Gelfond's constant)
2.6651441426902251); // 2^sqrt(2) (Gelfond–Schneider constant)
return fract( cos( mod( 123456789., 1e-7 + 256. * dot(p,r) ) ) );
}
РЕДАКТИРОВАТЬ: С помощью приведенного ниже ответа я немного приблизился к решению, но у меня все еще есть некоторые проблемы. Я взял комментарии catflier о том, что случайная функция, которую я позаимствовал, написана на GLSL, а не на HLSL. Мне пришлось изменить vec2 на float2 и поместить функцию random вверху. В дополнение к этому мне также пришлось написать функцию мода, потому что GLSL mod ()! = HLSL fmod. А фрактал GLSL () был заменен на HLSL frac (). У меня также была проблема, когда мой текстовый файл был закодирован с помощью UTF-8, что, как я полагаю, вызывает некоторые проблемы с fxc. После перекодирования в ANSI я смог получить более качественные сообщения об ошибках. Однако у меня все еще есть проблемы.
Я пробовал компилировать с использованием fxc /Zi /E DitherByChance DitherByChance.fx
, а также fxc /Zi /E DitherByChance /LD DitherByChance.fx
, потому что я нацелен на DX9, но оба раза у меня возникала следующая ошибка:
undeclared indentifier 's0' error
из этой строки float4 oldColor = tex2D(s0, coords);
Я не уверен, что это за аргумент s0, я только что видел его в другом примере шейдера. Я видел другой пример, когда у кого-то была объявлена глобальная переменная sampler2D и она использовалась вместо s0, поэтому я попробовал это:
sampler2D Tex0;
...
....
.....
float4 oldColor = tex2D(Tex0, coords);
Однако теперь, когда я запускаю fxc /Zi /E DitherByChance /LD DitherByChance.fx
, я получаю следующую ошибку:
vs_2_0 target does not support texture lookup
Любые идеи?