Як щодо чогось подібного?
Не малюйте освітлення, не підфарбовуючи плиточні спрайти. Намалюйте непросвітлену плитку до цілі візуалізації, а потім намалюйте індикатори плитки до другої цілі візуалізації, представляючи кожну з них як прямокутник сірого масштабу, що покриває область плитки. Для візуалізації кінцевої сцени використовуйте шейдер для об'єднання двох цілей візуалізації, затемнення кожного пікселя першого відповідно до значення другого.
Це дасть саме те, що ви маєте зараз. Це вам не допомагає, тож давайте трохи змінимо це.
Змініть розміри цілі відображення світлової карти так, щоб кожна плитка була представлена одним пікселем , а не прямокутною областю. Складаючи кінцеву сцену, використовуйте стан пробовідбору з лінійною фільтрацією. Інакше залиште все інше те саме.
Припускаючи, що ви правильно написали свій шейдер, світлова карта повинна бути ефективно «розширена» під час композиції. Це дозволить отримати хороший градієнтний ефект безкоштовно через пробник текстури графічного пристрою.
Можливо, ви також зможете вирізати шейдер і зробити це простіше, використовуючи BlendState, що потемніє, але мені доведеться експериментувати з ним, перш ніж я можу дати вам детальну інформацію.
ОНОВЛЕННЯ
Я мав певний час сьогодні насправді знущатися над цим. Відповідь вище відображає мою звичку використовувати шейдери як мою першу відповідь на все, але в цьому випадку вони насправді не потрібні, і їх використання непотрібно ускладнює речі.
Як я запропонував, ви можете досягти точно такого ж ефекту за допомогою спеціального BlendState. Зокрема, це користувацька BlendState:
BlendState Multiply = new BlendState()
{
AlphaSourceBlend = Blend.DestinationAlpha,
AlphaDestinationBlend = Blend.Zero,
AlphaBlendFunction = BlendFunction.Add,
ColorSourceBlend = Blend.DestinationColor,
ColorDestinationBlend = Blend.Zero,
ColorBlendFunction = BlendFunction.Add
};
Рівняння змішування є
result = (source * sourceBlendFactor) blendFunction (dest * destBlendFactor)
Так що з нашим користувацьким BlendState це стає
result = (lightmapColor * destinationColor) + (0)
Що означає, що вихідний колір чисто білого (1, 1, 1, 1) збереже колір призначення, а вихідний колір чистого чорного (0, 0, 0, 1) потемніє колір призначення до чистого чорного та будь-якого відтінок сірого посередині потемніє колір призначення на середню кількість.
Щоб застосувати це на практиці, спочатку зробіть все, що вам потрібно зробити, щоб створити свою світлу карту:
var lightmap = GetLightmapRenderTarget();
Тоді просто намалюйте свою неосвітлену сцену прямо до резервного буфера, як зазвичай:
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend);
/* draw the world here */
spriteBatch.End();
Потім намалюйте світлу карту за допомогою спеціального BlendState:
var offsetX = 0; // you'll need to set these values to whatever offset is necessary
var offsetY = 0; // to align the lightmap with the map tiles currently being drawn
var width = lightmapWidthInTiles * tileWidth;
var height = lightmapHeightInTiles * tileHeight;
spriteBatch.Begin(SpriteSortMode.Immediate, Multiply);
spriteBatch.Draw(lightmap, new Rectangle(offsetX, offsetY, width, height), Color.White);
spriteBatch.End();
Це помножить колір призначення (неосвітлену плитку) на вихідний колір (світлу карту), відповідним чином потемніє не освітлену плитку та створить ефект градієнта в результаті масштабування текстури світлової карти до необхідного розміру.