Directx11教程(66) D3D11屏幕文本輸出(1)


     在D3D10中,通過ID3DX10Font接口對象,我們可以方便的在屏幕上輸出文字信息,一個DrawText函數就能解決所有問題,但在D3D11中個,這個變得超級麻煩,因為微軟移除了Font接口,要在屏幕上輸出文本,用戶需要做很多事情。

通常我們可以用以下的方法來輸出文本信息:

(1)用紋理貼圖的方法,把所有的字體存儲在一張紋理上,再做一個字體查詢表,對應紋理的相應位置,可以用2D渲染的方式,把文本染出來,但這種方法不是很靈活,英文還好說,字母字符就那么多,但對於漢字就麻煩了,另外字體大小不能任意縮放。

(2)通過和GDI/GDI+進行交互,得到字體,把它們存儲在紋理中,然后再用2D渲染的方式渲染出來,這種方法可以得到任意大小的文字,而且對英文、中文都適用。

(3)用direct write,但據說效率不高,http://www.braynzarsoft.net/index.php?p=D3D11FONT 這篇教程中有詳細的介紹。

(4)使用一些文本輸出控件,比如CEGUI。

(5)用FreeType2動態生成字體紋理,然后用2D渲染的方式顯示。

在本篇教程中,我們先看看第一種方法的具體實現,程序的代碼是在myTutorialD3D11_61的基礎上修改的。

1、准備一副圖片,該圖片中包含所有的英文字母、標點以及特殊字符(ascii碼32-126之間的所有字符),該圖片將被當作紋理。

    該圖片背景是純黑色,RGB為(0,0,0),用該圖片產生font.dds紋理資源文件。

image

2、建立一個文本索引文件fontdata.txt,該文件索引ascii碼32-126之間的所有字符,該文件的格式為:

[Ascii value of character] [The character] [Left Texture U coordinate] [Right Texture U Coordinate] [Pixel Width of Character]

     第一列為字符的ascii碼,第二列為字符,第三列為字符左邊的紋理坐標,第四列為字符右邊的紋理坐標,第五列為像素寬度。

32   0.0        0.0         0
33 ! 0.0        0.000976563 1
34 " 0.00195313 0.00488281  3
35 # 0.00585938 0.0136719   8

125 } 0.573242  0.576172    3
126 ~ 0.577148  0.583984    7

      通過這幾列值,我們就可以把一個字符和紋理中的相應位置對應起來,比如一個字符串"hello”,我們可以動態創建5個四邊形,每個四邊形有2個三角形組成,三角形的頂點位置為該字符在屏幕上的顯示位置,頂點屬性中包括紋理坐標,該四邊形將通過紋理的方式顯示該字符。

下邊大致介紹下增加的代碼:

我們的2D 文本渲染在TextClass中,可以把該類看作一個sprites class, 主要的功能就是渲染文本。

首先該類用了2個結構來描述文本,第一個是文本句子的結構類型,因為文本都是顯示在四邊形中,所以該類中包含了頂點緩沖、索引緩沖、頂點數量、頂點顏色等信息。

struct SentenceType
{
    ID3D11Buffer *vertexBuffer, *indexBuffer;
    int vertexCount, indexCount, maxLength;
    float red, green, blue;
};

struct VertexType
{
    D3DXVECTOR3 position;
    D3DXVECTOR2 texture;
};

     通過函數InitializeSentence、UpdateSentence我們生成文本句子數據,RenderSentence函數渲染執行最終的渲染,其中的texture就是包含字體的紋理,該函數調用FontShader類實現最終的渲染。

bool TextClass::RenderSentence(ID3D11DeviceContext* deviceContext, SentenceType* sentence, D3DXMATRIX worldMatrix,
                               D3DXMATRIX orthoMatrix,  ID3D11ShaderResourceView* texture)

    類FontClass建立文本句子頂點、索引數據,FontShaderClass類用執行渲染。

    另外,還有2個shader文件:font.vs和font.ps, ps文件中會根據紋理的顏色來設置alpha的值,這樣既可以很好的把字體紋理和背景混合起來。

// 根據選取字符.
color = shaderTexture.Sample(SampleType, input.tex);

//如果紋理為黑色,設置透明,這樣可以鏤空不需要的背景,只顯示字體
if(color.r == 0.0f)
{
    color.a = 0.0f;
}
else
{
    color.rgb = pixelColor.rgb;
    color.a = 1.0f;
}

    最終的渲染代碼在GraphicsClass類中,主要在開始文本渲染時,要禁用zbuffer,並開啟alpha blend功能,渲染完成后,進行相反的操作。

// 關掉z buffer,以便2d渲染
m_D3D->TurnZBufferOff();

// 打開alpha blending
m_D3D->TurnOnAlphaBlending();

//得到正交投影矩陣
m_D3D->GetOrthoMatrix(orthoMatrix);
// 渲染文本
result = m_Text->Render(m_D3D->GetDeviceContext(), worldMatrix, orthoMatrix,m_TexManager->createTex(m_D3D->GetDevice(),string("font.dds")));
if(!result)
    {
    return false;
    }

// 關閉alpha blending
m_D3D->TurnOffAlphaBlending();

// 打開z buffer
m_D3D->TurnZBufferOn();


程序執行后的界面如下,我們用白色和黃色顯示了幾個字tessellation demo by mikewolf

image

完整的代碼請參考:

工程文件myTutorialD3D11_63

代碼下載:

稍后提供

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM