DirectX 11:文本输出,使用您自己的字体纹理



我正在学习DirectX,使用的是《Sherrod A.,Jones W.-开始DirectX 11游戏编程-2011》一书。现在我正在探索关于绘制文本的第四章。

请帮我们修复我的函数,我正在用它在屏幕上画一个字符串。我已经加载了字体纹理,在函数中,我用字母创建了一些精灵,并为它们定义了纹理坐标。这编译正确,但没有绘制任何内容。怎么了?

bool DirectXSpriteGame :: DrawString(char* StringToDraw, float StartX, float StartY)
{
//VAR
HRESULT D3DResult;                                                                              //The result of D3D functions
int i;                                                                                          //Counters
const int IndexA = static_cast<char>('A');                                                      //ASCII index of letter A
const int IndexZ = static_cast<char>('Z');                                                      //ASCII index of letter Z
int StringLenth = strlen(StringToDraw);                                                         //Lenth of drawing string
float ScreenCharWidth = static_cast<float>(LETTER_WIDTH) / static_cast<float>(SCREEN_WIDTH);    //Width of the single char on the screen(in %)
float ScreenCharHeight = static_cast<float>(LETTER_HEIGHT) / static_cast<float>(SCREEN_HEIGHT); //Height of the single char on the screen(in %)
float TexelCharWidth = 1.0f / static_cast<float>(LETTERS_NUM);                                  //Width of the char texel(in the texture %)
float ThisStartX;                                                                               //The start x of the current letter, drawingh
float ThisStartY;                                                                               //The start y of the current letter, drawingh
float ThisEndX;                                                                                 //The end x of the current letter, drawing
float ThisEndY;                                                                                 //The end y of the current letter, drawing
int LetterNum;                                                                                  //Letter number in the loaded font
int ThisLetter;                                                                                 //The current letter
D3D11_MAPPED_SUBRESOURCE MapResource;                                                           //Map resource
VertexPos* ThisSprite;                                                                          //Vertecies of the current sprite, drawing
//VAR
//Clamping string, if too long
if(StringLenth > LETTERS_NUM)
{
StringLenth = LETTERS_NUM;
}
//Mapping resource
D3DResult = _DeviceContext -> Map(_vertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &MapResource);
if(FAILED(D3DResult))
{
throw("Failed to map resource");
}
ThisSprite = (VertexPos*)MapResource.pData;
for(i = 0; i < StringLenth; i++)
{
//Creating geometry for the letter sprite
ThisStartX = StartX + ScreenCharWidth * static_cast<float>(i);
ThisStartY = StartY;
ThisEndX = ThisStartX + ScreenCharWidth;
ThisEndY = StartY + ScreenCharHeight;
ThisSprite[0].Position = XMFLOAT3(ThisEndX, ThisEndY, 1.0f);
ThisSprite[1].Position = XMFLOAT3(ThisEndX, ThisStartY, 1.0f);
ThisSprite[2].Position = XMFLOAT3(ThisStartX, ThisStartY, 1.0f);
ThisSprite[3].Position = XMFLOAT3(ThisStartX, ThisStartY, 1.0f);
ThisSprite[4].Position = XMFLOAT3(ThisStartX, ThisEndY, 1.0f);
ThisSprite[5].Position = XMFLOAT3(ThisEndX, ThisEndY, 1.0f);
ThisLetter = static_cast<char>(StringToDraw[i]);
//Defining the letter place(number) in the font
if(ThisLetter < IndexA || ThisLetter > IndexZ)
{
//Invalid character, the last character in the font, loaded
LetterNum = IndexZ - IndexA + 1;
}
else
{
LetterNum = ThisLetter - IndexA;
}
//Unwraping texture on the geometry
ThisStartX = TexelCharWidth * static_cast<float>(LetterNum);
ThisStartY = 0.0f;
ThisEndY = 1.0f;
ThisEndX = ThisStartX + TexelCharWidth;
ThisSprite[0].TextureCoords = XMFLOAT2(ThisEndX, ThisEndY);
ThisSprite[1].TextureCoords = XMFLOAT2(ThisEndX, ThisStartY);
ThisSprite[2].TextureCoords = XMFLOAT2(ThisStartX, ThisStartY);
ThisSprite[3].TextureCoords = XMFLOAT2(ThisStartX, ThisStartY); 
ThisSprite[4].TextureCoords = XMFLOAT2(ThisStartX, ThisEndY);   
ThisSprite[5].TextureCoords = XMFLOAT2(ThisEndX, ThisEndY);
ThisSprite += VERTEX_IN_RECT_NUM;
}
for(i = 0; i < StringLenth; i++, ThisSprite -= VERTEX_IN_RECT_NUM);
_DeviceContext -> Unmap(_vertexBuffer, 0);
_DeviceContext -> Draw(VERTEX_IN_RECT_NUM * StringLenth, 0);
return true;
}

虽然构建顶点数组的代码乍一看是正确的,但似乎您正在尝试使用尚未设置的着色器绘制顶点!如果不看整个代码,很难准确地回答你,但我可以猜测你需要做这样的事情:

1) 通过首先从各自的缓冲区编译顶点和像素着色器来创建它们

2) 创建Input Layout描述,该描述描述将由Input Assembler阶段读取的输入缓冲区。它必须与VertexPos结构和着色器结构相匹配。

3) 设置着色器参数。

4) 只有现在,您才能设置着色器渲染参数:设置InputLayout,以及将用于通过以下方式渲染三角形的顶点和像素着色器:

_DeviceContext -> Unmap(_vertexBuffer, 0);
_DeviceContext->IASetInputLayout(myInputLayout);
_DeviceContext->VSSetShader(myVertexShader, NULL, 0); // Set Vertex shader
_DeviceContext->PSSetShader(myPixelShader, NULL, 0); // Set Pixel shader
_DeviceContext -> Draw(VERTEX_IN_RECT_NUM * StringLenth, 0);

此链接将帮助您实现您想要做的事情:http://www.rastertek.com/dx11tut12.html

此外,出于性能原因,我建议您设置IndexBuffer并使用DrawIndexed方法渲染三角形:它将允许图形适配器将顶点存储在顶点缓存中,允许从缓存中提取最近使用的顶点,而不是从顶点缓冲区中读取。有关此问题的更多信息,请访问MSDN:http://msdn.microsoft.com/en-us/library/windows/desktop/bb147325(v=vs.85).aspx

希望这能有所帮助!

p.S:另外,不要忘记在使用资源后通过调用Release()来释放资源。

最新更新