0

有没有办法绘制具有多个彩色水平区域的文本?例如,我想绘制文本“Hello”,下半部分为红色,上半部分为绿色。要使用的文本必须是动态的。使用普通纹理,我将只使用 Draw 方法并传递一个子矩形来绘制不同颜色的纹理部分,但用于文本?

4

4 回答 4

1

最好的方法可能涉及自定义着色器。但是,你也应该能够用剪刀矩形来做到这一点。

  1. 以您的上部颜色(绿色)正常绘制文本
  2. 设置一个ScissorRectangle只允许在文本的下半部分绘图
  3. 使用底部颜色(红色)正常绘制文本。上半部分应该被剪掉,所以绿色文本应该保留在那里。

澄清一下,您的文本应该两次都绘制在同一个地方。

于 2011-09-02T20:58:22.770 回答
1

我知道这是一个老问题,但这个工具将允许您创建具有各种效果的自定义位图字体,如阴影、浮雕、发光。它将为您生成字体纹理,然后您可以编辑和添加多种颜色或其他后处理效果。在 XNA 中使用它只需添加到您的 Content 项目,并将 ContentProcessor 设置为“Sprite Font Texture”。然后,您可以像加载普通精灵字体一样在游戏中加载它。

于 2012-10-26T16:01:42.310 回答
1

我会使用“Crappy Coding Guy”建议的自定义效果来执行此操作,它需要向效果发送一些数据,下面的代码是您需要逐像素淡化颜色 1 和之间的字符串颜色的 HLSL颜色2。您可以通过从中减去 0.5 并将用于 lerp 的值乘以 10 来使其饱和。

float4x4 Projection;
float4 Color1, Color2;
float FontHeight;
float2 Location;

Texture2D FontTexture;
sampler TextureSampler = sampler_state { texture = <FontTexture> ; magfilter = LINEAR; minfilter = LINEAR; mipfilter=LINEAR; AddressU = clamp; AddressV = clamp;};

struct VertexShaderInput
{
    float4 Position : POSITION0;
    float2 Texture : TEXCOORD0;
};

struct VertexShaderOutput
{
    float4 Position : POSITION0;
    float2 Texture : TEXCOORD0;
    float2 OriginalPosition : TEXCOORD1;
};

VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
    VertexShaderOutput output;

    output.OriginalPosition = input.Position;
    output.Texture = input.Texture;
    output.Position = mul(input.Position, Projection);

    return output;
}

float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
    float4 fontColor = lerp (Color1, Color2,  (1.0 / FontHeight) * (input.OriginalPosition.y - Location.y));
    return tex2D(TextureSampler, input.Texture)*  fontColor;
}

technique Technique1
{
    pass Pass1
    {
        VertexShader = compile vs_2_0 VertexShaderFunction();
        PixelShader = compile ps_2_0 PixelShaderFunction();
    }
}

以及使用它的 C#。(显然您不必每帧设置效果的所有参数,我只是不想发布太多方法,如果您需要完整的示例,我很乐意通过电子邮件发送给您)

protected override void Draw(GameTime gameTime)
{
   GraphicsDevice.Clear(Color.CornflowerBlue);
   fontEffect.Parameters["Projection"].SetValue(Matrix.CreateOrthographicOffCenter(0, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height, 0, 0, 1));
   fontEffect.Parameters["Color1"].SetValue(Color.Red.ToVector4());
   fontEffect.Parameters["Color2"].SetValue(Color.Blue.ToVector4());
   fontEffect.Parameters["FontHeight"].SetValue(font.LineSpacing);
   FieldInfo fontTexture = typeof(SpriteFont).GetField("textureValue", BindingFlags.NonPublic | BindingFlags.Instance);
   fontEffect.Parameters["FontTexture"].SetValue((Texture2D)fontTexture.GetValue(font));            
   fontEffect.CurrentTechnique.Passes[0].Apply(); 

   spriteBatch.Begin( SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.PointClamp, DepthStencilState.Default, RasterizerState.CullNone, fontEffect);            
   spriteBatch.DrawString(font, "abcdefghijklmnopqrstuvxyz", new Vector2(10, 100), Color.White);
   spriteBatch.End();

   base.Draw(gameTime);
}

编辑:你可能会注意到我不得不从 sprite 字体中取出纹理,这是一个非常烦人的私有字段!如果有人知道更好的方法来获得这个,请告诉!

于 2011-09-16T15:52:45.993 回答
0

如果你想要更多的控制,你可以使用两种不同的 spritefont 纹理。使用位图字体生成器获取初始 spritefont:http ://create.msdn.com/en-US/education/catalog/utility/bitmap_font_maker 。如果需要,修改您的纹理以使其看起来不错(投影等)。复制字体纹理并用透明的洋红色覆盖文本的上半部分。然后你画你的文字两次,第二次用修改过的字体和不同的颜色。这种方法的优点是你的上半部分和下半部分不需要用直线描绘,即上半部分可能会粘在顶部等等。

于 2011-09-05T06:37:16.697 回答