Visa halvgenomskinlig text

Sidan uppdaterad :
Datum för skapande av sida :

sammanfattning

Gör så att texten ser halvgenomskinlig ut.

半透明の文字を表示する

Operativ miljö

Förutsättningar

XNA-versioner som stöds
  • 4.0
Plattformar som stöds
  • Windows (XP SP2 eller senare, Vista, 7)
  • Xbox 360
  • Windows Phone 7 (på engelska)
Windows Nödvändig version av Vertex Shader 2.0
Windows Pixel Shader-version som krävs 2.0

Operativ miljö

plattform
  • Windows 7
  • Xbox 360
  • Windows Phone 7 Emulator

substans

Genom att tillämpa en opacitet på 0,0~1,0 på färgstrukturen som anges av metoden SpriteBatch.DrawString kan du rita texten i halvgenomskinlighet. De flesta färger som redan har definierats i egenskaperna för färgstrukturen är inte ogenomskinliga, så de kan göras halvgenomskinliga genom att använda opacitet.

// 半透明の文字(75%)
this.spriteBatch.DrawString(this.font,
    "Draw transparent text. (75%)",
    new Vector2(50.0f, 100.0f), Color.White * 0.75f);

Color konstruktor

Ställ in färgen. Det finns också en 0,0~1,0 floatkonstruktor.

r byte Ange den röda färgen från 0~255.
g byte Ange den gröna färgen som 0~255.
b byte Ange den blå färgen från 0~255.
a byte Ange opaciteten (alfakomponenten) från 0~255.

Förresten, metoden för att ange den genomskinliga färgen på sprites har ändrats sedan XNA Framework 4.0, och för att ange ett format som "new Color(255, 255, 255, 192)" som används i XNA Framewrok 3.1 och tidigare måste du ange blandningstillståndet för SpriteBatch med "BlendState.NonPremultiplied".

// スプライトの描画準備
this.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied);

// 半透明の文字(75%)
this.spriteBatch.DrawString(this.font,
    "Draw transparent text. (75%)",
    new Vector2(50.0f, 100.0f), new Color(255255255192));

Men eftersom formeln för att beräkna utdatafärgen har ändrats kommer tecknets kant att visas i ett mörkare tillstånd.

Om utdatafärgen

I de tidigare tipsen använde vi två blandningsmönster för att visa text som ett exempel. Å andra sidan visades vacker genomskinlig text som förväntat. Å andra sidan blev textens kanter mörkare. Det beror på att formeln för att visa färgen varierar beroende på vilket blandningsläge som används.

Ange parametrarna för uttrycket till

  • resultat: Slutlig utdatafärg
  • source : Färgen på texturen du försöker rita
  • destination : Bakgrundsfärgen för destinationen
  • RGBA: Komponenter av R (röd), G (grön), B (blå) respektive A (alfa (opacitet))

Och som definierat är beräkningsformeln för de två blandningslägena följande.

BlendState.AlphaBlend (null standard) (multiplicerad alfa)
result = source.rgb + destination.rgb * (1 - source.a) // Source.rgb är dock redan alfa-tillämpad
BlendState.NonPremultiplied (interpolerad alfa)
resultat = källa.rgb * källa.a + destination.rgb * (1 - källa.a)

Faktum är att om du hittar det med den här formeln kommer resultatvärdet att vara detsamma i båda fallen. Men om du använder bilinjär filtrering utförs ovanstående beräkningar efter färginterpolering med intilliggande pixlar i pixelskuggningen, så det slutliga utdataresultatet blir annorlunda.

Jag skulle vilja göra några beräkningar för sakens skull. Om färgen på texten är vit (Color.White) är varje färgkomponent i pixeln som texten visas i (r:255, g:255, b:255, a:255). Pixlar som inte visar text är (r:0, g:0, b:0, a:0). Om vi gör texten halvtransparent vid 50 % och interpolerar den med det mellanliggande värdet av dessa två pixlar (dvs. kanten på tecknet), hur förändrar ovanstående två ekvationer resultatet?

Förresten, bakgrundsfärgen är (r:0, g:0, b:255, a:255). (Beräkningarna utförs på vit text och blå bakgrund)

Interpolering med BlendState.AlphaBlend (multiplicerad alfa)

Eftersom alfa tillämpas på varje element i textfärgen i förväg, halveras textfärgen med 255 (r:128, g:128, b:128, a:128) (Color.White * 0.5f"). Pixlar som inte har text visas lämnas som de är (r:0, g:0, b:0, a:0).

Eftersom formeln för bilinjärt filter utförs innan blandningsläget beräknar bakgrundsfärgen, blir färgen på textens kant (r:64, g:64, b:64, a:64), vilket är ett mellanliggande värde mellan (r:128, g:128, b:128, a:128) och (r:0, g:0, b:0, a:0).

Här används uttrycket

  • resultat = source.rgb + destination.rgb * (1 - source.a)

Om du använder den på:

  • Resultat = (r:64, g:64, b:64) + (r:0, g:0, b:255) * (1 - 0,25)      // 0,25 indikerar att a:64 är 25 % av a:255

Och den slutliga sammansatta färgen med bakgrundsfärgen är (R:64, G:64, B:255).

Interpolering med BlendState.NonPremultiplied (interpolerad alfa)

Färgen på texten är vit (r:255, g:255, b:255), och endast alfa halveras för att göra den halvtransparent, så värdet på pixeln som tecknet visas i är (r:255, g:255, b:255, a:128) (ny färg (255, 255, 255, 128)). Pixlar som inte visar text förblir desamma (r:0, g:0, b:0, a:0).

Eftersom formeln för bilinjärt filter utförs innan blandningsläget beräknar bakgrundsfärgen, blir färgen på textens kant (r:128, g:128, b:128, b:128, a:64), vilket är ett mellanliggande värde mellan (r:0, g:0, b:0, a:0).

Här används uttrycket

  • resultat = källa.rgb * källa.a + destination.rgb * (1 - källa.a)

Om du använder den på:

  • Resultat = (R:128, G:128, B:128) * 0.25 + (R:0, G:0, B:255) * (1 - 0.25)

Och den slutliga sammansatta färgen med bakgrundsfärgen är (R:32, G:32, B:224).

hänsyn

Eftersom bakgrundsfärgen är (r:0, g:0, b:255) gör interpolering med BlendState.AlphaBlend (r:64, g:64, b:255) att textens transparenta färg kan uttryckas vackert utan att bakgrundsfärgens pigment går förlorat. Men vid interpolering med BlendState.NonPremultiplied (r:32, g:32, b:224) är den blå komponenten mörkare än bakgrundsfärgen, så textens kanter verkar vara mörkare (naturligtvis).
Rött, grönt är mörkare än BlendState.AlphaBlend.)

Denna standardmultiplicerade alfa från XNA Framework 4.0 beskrivs i detalj i bloggen "Hinikeni XNA", så om du vill veta mer, se länken nedan. Där beskrivs det som ett exempel på att rita ett rött element mot en vit bakgrund.

Alla koder

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
#if WINDOWS_PHONE
using Microsoft.Xna.Framework.Input.Touch;
#endif

namespace TransparentText
{
    /// <summary>
    /// ゲームメインクラス
    /// </summary>
    public class GameMain : Microsoft.Xna.Framework.Game
    {
        /// <summary>
        /// グラフィックデバイス管理クラス
        /// </summary>
        private GraphicsDeviceManager graphics = null;

        /// <summary>
        /// スプライトのバッチ化クラス
        /// </summary>
        private SpriteBatch spriteBatch = null;

        /// <summary>
        /// スプライトでテキストを描画するためのフォント
        /// </summary>
        private SpriteFont font = null;


        /// <summary>
        /// GameMain コンストラクタ
        /// </summary>
        public GameMain()
        {
            // グラフィックデバイス管理クラスの作成
            this.graphics = new GraphicsDeviceManager(this);

            // ゲームコンテンツのルートディレクトリを設定
            this.Content.RootDirectory = "Content";

#if WINDOWS_PHONE
            // Windows Phone のデフォルトのフレームレートは 30 FPS
            this.TargetElapsedTime = TimeSpan.FromTicks(333333);

            // バックバッファサイズの設定
            this.graphics.PreferredBackBufferWidth = 480;
            this.graphics.PreferredBackBufferHeight = 800;

            // フルスクリーン表示
            this.graphics.IsFullScreen = true;
#endif
        }

        /// <summary>
        /// ゲームが始まる前の初期化処理を行うメソッド
        /// グラフィック以外のデータの読み込み、コンポーネントの初期化を行う
        /// </summary>
        protected override void Initialize()
        {
            // TODO: ここに初期化ロジックを書いてください

            // コンポーネントの初期化などを行います
            base.Initialize();
        }

        /// <summary>
        /// ゲームが始まるときに一回だけ呼ばれ
        /// すべてのゲームコンテンツを読み込みます
        /// </summary>
        protected override void LoadContent()
        {
            // テクスチャーを描画するためのスプライトバッチクラスを作成します
            this.spriteBatch = new SpriteBatch(this.GraphicsDevice);

            // フォントをコンテンツパイプラインから読み込む
            this.font = this.Content.Load<SpriteFont>("Font");
        }

        /// <summary>
        /// ゲームが終了するときに一回だけ呼ばれ
        /// すべてのゲームコンテンツをアンロードします
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: ContentManager で管理されていないコンテンツを
            //       ここでアンロードしてください
        }

        /// <summary>
        /// 描画以外のデータ更新等の処理を行うメソッド
        /// 主に入力処理、衝突判定などの物理計算、オーディオの再生など
        /// </summary>
        /// <param name="gameTime">このメソッドが呼ばれたときのゲーム時間</param>
        protected override void Update(GameTime gameTime)
        {
            // Xbox 360 コントローラ、Windows Phone の BACK ボタンを押したときに
            // ゲームを終了させます
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
            {
                this.Exit();
            }

            // TODO: ここに更新処理を記述してください

            // 登録された GameComponent を更新する
            base.Update(gameTime);
        }

        /// <summary>
        /// 描画処理を行うメソッド
        /// </summary>
        /// <param name="gameTime">このメソッドが呼ばれたときのゲーム時間</param>
        protected override void Draw(GameTime gameTime)
        {
            // 画面を指定した色でクリアします
            this.GraphicsDevice.Clear(Color.CornflowerBlue);

            // スプライトの描画準備
            this.spriteBatch.Begin();

            // 通常の文字
            this.spriteBatch.DrawString(this.font,
                "Draw normal text.",
                new Vector2(50.0f, 50.0f), Color.White);

            // 半透明の文字(75%)
            this.spriteBatch.DrawString(this.font,
                "Draw transparent text. (75%)",
                new Vector2(50.0f, 100.0f), Color.White * 0.75f);

            // 半透明の文字(50%)
            this.spriteBatch.DrawString(this.font,
                "Draw transparent text. (50%)",
                new Vector2(50.0f, 150.0f), Color.White * 0.5f);

            // 半透明の文字(25%)
            this.spriteBatch.DrawString(this.font,
                "Draw transparent text. (25%)",
                new Vector2(50.0f, 200.0f), Color.White * 0.25f);

            // スプライトの一括描画
            this.spriteBatch.End();

            // 登録された DrawableGameComponent を描画する
            base.Draw(gameTime);
        }
    }
}