Я пытаюсь применить вуаль войны к областям на экране, не в настоящее время видимом плееру. Я делаю это путем рендеринга игрового содержания в одном RenderTarget
и вуаль войны в другого, и затем я объединяю их с файлом эффектов, который подражает от игры RenderTarget
и альфа от вуали войны представляет цель. FOW RenderTarget
является черным, где FOW появляется, и белый, где он не делает.
Это действительно работает, но это окрашивает вуаль войны (непоказанные местоположения) белый вместо намеченного цвета черного цвета.
Прежде, чем применить эффект я очищаю backbuffer устройства белому. То, когда я пытаюсь очиститься, это к черному цвету, не вуали войны появляется вообще, который я принимаю, является продуктом альфы, смешивающейся с черным цветом. Это работает на все другие цвета, однако - предоставление получающегося экрана оттенка того цвета.
Как делают меня archieve черная вуаль в то время как все еще способность сделать альфу, смешивающуюся между двумя целями рендеринга?
Код рендеринга для применения FOW:
private RenderTarget2D mainTarget;
private RenderTarget2D lightTarget;
private void CombineRenderTargetsAndDraw()
{
batch.GraphicsDevice.SetRenderTarget(null);
batch.GraphicsDevice.Clear(Color.White);
fogOfWar.Parameters["LightsTexture"].SetValue(lightTarget);
batch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);
fogOfWar.CurrentTechnique.Passes[0].Apply();
batch.Draw(
mainTarget,
new Rectangle(0, 0, batch.GraphicsDevice.PresentationParameters.BackBufferWidth, batch.GraphicsDevice.PresentationParameters.BackBufferHeight),
Color.White
);
batch.End();
}
Файл эффектов я использую для применения FOW:
texture LightsTexture;
sampler ColorSampler : register(s0);
sampler LightsSampler = sampler_state{
Texture = <LightsTexture>;
};
struct VertexShaderOutput
{
float4 Position : POSITION0;
float2 TexCoord : TEXCOORD0;
};
float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
float2 tex = input.TexCoord;
float4 color = tex2D(ColorSampler, tex);
float4 alpha = tex2D(LightsSampler, tex);
return float4(color.r, color.g, color.b, alpha.r);
}
technique Technique1
{
pass Pass1
{
PixelShader = compile ps_2_0 PixelShaderFunction();
}
}
Я не слишком глубоко изучал XNA и не могу установить его в данный момент, чтобы проверить с CTP версии 4.0, но из чтения документации похоже, что вы удваиваете. Насколько я понимаю, BlendState.AlphaBlend
заставляет SpriteBatch
альфа-смешивать каждый отрисованный спрайт.
Согласно документации он использует настройки по умолчанию
ColorSourceBlend = Blend.One,
AlphaSourceBlend = Blend.One,
ColorDestinationBlend = Blend.InverseSourceAlpha,
AlphaDestinationBlend = Blend.InverseSourceAlpha,
Которые должны иметь следующее влияние:
Один: Каждый компонент цвета умножается на (1, 1, 1, 1, 1).
InverseSourceAlpha: Каждый компонент цвета умножается на обратную величину альфа-значения источника. Этот можно представить как (1 - As, 1 - As, 1 - As, 1 - As), где As - альфа-значение значение назначения.
Таким образом, если вы используете Blend.AlphaBlend
, вы можете очистить задний буфер до черного цвета и затем рендерить только спрайты карты, непосредственно понижая альфу там, где она должна быть затемнена. Это просто обесцветит пиксели карты, которые "покрыты" FOW, заставляя их альфа-смешиваться с черным цветом заднего буфера.
Если вы хотите использовать шейдерный подход, вы можете альфа-смешивать шейдер между двумя целями рендеринга. Я немного не понял из вашего объяснения, как именно вы хотите смешивать. Вы говорите, что хотите сделать альфа-смешение, но ваша цель рендеринга FOW черная там, где есть туман, и белая там, где его нет. Если вы используете альфа для управления смешиванием, цвет тумана должен быть однородным (или текстурированным, в зависимости от ситуации) по всей цели рендеринга, в соответствии с тем, какой внешний вид вы хотите получить. Скажем, вы хотите черный туман, ваши цвета должны быть (0, 0, 0) по всей цели рендеринга, а значение альфа должно меняться в зависимости от того, где вы хотите его показать.
Используя этот подход, вы можете изменить ваш шейдер на что-то вроде следующего:
float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
float2 tex = input.TexCoord;
float4 color = tex2D(ColorSampler, tex);
float4 fow = tex2D(LightsSampler, tex);
// color * inverse of FOW alpha + FOW * FOW alpha
return float4(color.r * (1-fow.a) + fow.r * fow.a,
color.g * (1-fow.a) + fow.g * fow.a,
color.b * (1-fow.a) + fow.b * fow.a,
1);
}
Я давно не занимался шейдерами на HLSL, но я уверен, что это можно написать гораздо проще. В любом случае, если FOW черный (и back buffer очищен до черного, и вы не накладываете различные спрайты с альфа-смешением друг на друга - см. ответ Джоэла), этот подход не отличается от прямой установки альфа спрайта карты на основе наличия или отсутствия FOW.
Похоже, вы столкнулись с ситуацией, которую Шон Харгривз описал в этом сообщении в блоге:
Предварительно умноженная альфа и композиция изображения
Попробуйте переключиться на предварительно умноженную альфа , как он предлагает, и позвольте нам известен результат: -)