# text and rotation

## Recommended Posts

Hello, I want to write text in my window, but with variable orientation. I have made a few test with the CD3DFont class, but it is unaffected by the world transformations. I haven't tested the ID3DXFont, because I have read that it's a frame killer. Any suggestions ? Regards Oliver

##### Share on other sites
Aside from using some library like libttf, you could use ID3DXFont (The performance is absolutely fine, I don't know where you heard it's poor performance, but that's incorrect), and use a sprite with world transform applied to it when you call DrawText().

##### Share on other sites
Hi Steve,

Thanx for the quick reply. Regarding ID3DXFont, I'm quoting below a book that I use to discover DirectX : Introduction to 3D Game Programming with DirectX 9.0 by Frank Luna, Wordware Publishing.

Chapter 9, introduction :
"This interface uses GDI internally to draw the text, and so we take a performance hit using this interface"

Oliver

##### Share on other sites
Pretty much all text rendering libraries will use GDI to draw the text. ID3DXFont caches the characters it renders, so there's only a hit the first time you draw a character. After that it doesn't go anywhere near GDI.

##### Share on other sites
Hi Steve,
Your remark sounds logical, I'll try using ID3DXFont then. I've digged a bit to find an exemple, but most tutos I've found use NULL for the sprite pointer.
Could you briefly outline the usage of the custom sprite so I can use it ? I'd also like to use untransformed coordinates for my text, rather than device coordinate. I've found that I should use the D3DXSPRITE_OBJECTSPACE flag for my sprite - is that correct ?

Oliver

##### Share on other sites
Actually I dislike the way the base font class of the D3DX library works. (Many draws for each character or so depending on how the gliph are rendered/ordered in the textures)
If you are using lots of static text, or you need alpha blending, I would suggest rolling a personal class to draw text using GDI+. (draw the text to a texture with GDI+ and then draw the text on screen on a quad that you can transform with your matrix). Its a lot lighter on CPU load compared to the D3DX one (while using more video memory)

After all on all Vista+ systems, GDI is no more hardware accelerated so it doesn't make any difference.

##### Share on other sites
Quote:
 Original post by oliver_mptCould you briefly outline the usage of the custom sprite so I can use it?
When you pass NULL for the sprite pointer, ID3DXFont uses one it prepared earlier internally. It's more efficient to pass a valid sprite pointer if you're making multiple DrawText() calls per frame, since then all characters are drawn using one sprite.
ID3DXSprite is internally implemented as a dynamic vertex buffer and static index buffer, so using one ID3DXSprite instance for multiple DrawText() calls means fewer SetStreamSource() / SetIndices() calls, which means fewer batches, which means better performance.

To use a particular sprite, you create one at app startup (When you create the font for instance) with D3DXCreateSprite(), and then call ID3DXSprite::Begin() prior to rendering any text, then pass it to the DrawText() calls, optionally changing any sprite state beforehand.

Quote:
 Original post by oliver_mptI'd also like to use untransformed coordinates for my text, rather than device coordinate. I've found that I should use the D3DXSPRITE_OBJECTSPACE flag for my sprite - is that correct ?
By default ID3DXSprite will draw in screen coordinates; is that not what you want?

Quote:
 Original post by feal87Actually I dislike the way the base font class of the D3DX library works. (Many draws for each character or so depending on how the gliph are rendered/ordered in the textures)
That's true - ID3DXFont is designed as a helper class, it's not meant as any sort of ultimate text rendering class. If you use a non-NULL ID3DXSprite parameter to DrawText(), it's usually a good idea to use the D3DXSPRITE_SORT_TEXTURE flag to reduce the number of draw calls.

Quote:
 Original post by feal87If you are using lots of static text, or you need alpha blending, I would suggest rolling a personal class to draw text using GDI+. (draw the text to a texture with GDI+ and then draw the text on screen on a quad that you can transform with your matrix). Its a lot lighter on CPU load compared to the D3DX one (while using more video memory)
It's quite a lot of work to write your own text renderer (Particularly if you want to handle "exotic" characters like Arabic and suchlike), I wouldn't recommend it unless ID3DXFont is proven to be too inefficient.
You can always achieve the same effect without having to write any GDI code by drawing your text to a render target and then using it as a texture.

##### Share on other sites
First thanks Steve for the detailed answer.

let's see what I tried :

I have created a font (ID3DXFont* Font) and a sprite (ID3DXSprite* pD3DXSprite)
and here is the chunk of code I use :

D3DXMatrixTranslation(&TransfmMatrix, 1.0f, -1.0f, 0.0f)
char Text[] = "Some text 101";

pD3DXSprite->Begin(D3DXSPRITE_OBJECTSPACE);
pD3DXSprite->SetTransform(&TransfmMatrix);
Font->DrawText(pD3DXSprite,Text(int(strlen(Text)),&font_rect,DT_LEFT|DT_EXPANDTABS,D3DCOLOR_XRGB(155,30,200));
pD3DXSprite->End();

font_rect is set to my screen size 640x480

1) Nothing is drawn

2) I remove D3DXSPRITE_OBJECTSPACE and replace it by any other flag, the text is drawn at the screen origin. I have to use screen coordinates in D3DXMatrixTranslation to get an effective translation.

What I would like to achieve is to be able to give the transformation (translations) in untransformed coordinates (world coordinates).

Any hint on how to do that ?

##### Share on other sites
Hi,

I tried the code mentionned, but it does not seem to help. In the sample you mentionned they also use screen coordinates.
My point is to NOT use screen coordinates, but world coordinates to be independent of the window size, and use homogeneous coordinates with the object vertices (specified in world, untransformed coordinates).
Is there a way to specify a translation in world coordinates ? I'm only able to translate my text (and sprite) using screen coordinates ?
Of course, I can write a mathematical expression to transform from world coordinates to screen, taking the window size into account, but I'm sure directX can do it faster than that.

Oliver

##### Share on other sites
I see. In that case, using D3DXSPRITE_OBJECTSPACE should work. Where is your camera? I think that the sprites will be drawn at the origin with this flag (You could check with PIX to see what information is being written to the ID3DXSprite vertex buffer).

##### Share on other sites
My view is set by default (I didn't set it). I use an ortho projection defined as follows :

D3DXMatrixOrthoLH(
&proj,
4.0f, // width
4.0f, // height
1.0f, // near plane
1000.0f);// far plane

I have tried to play a bit with PIX, but I've never used it before. I captured calls on a given frame and have the following kind of information

<0x04FE4258> ID3DXSprite::Draw(0x04FED200, 0x0012FAAC, 0x0012FA90, 0x0012FA7C, D3DCOLOR_ARGB(0xff,0x9b,0x1e,0xc8))

That's pretty useless for me, I can only recognize the color, but not the vertex coordinates ...

I also tried to set the camera position to look along the z axis with :

D3DXVECTOR3 position(0.0f,0.0f,0.0f);
D3DXVECTOR3 target(0.0f,0.0f,100.0f);
D3DXVECTOR3 worldup(0.0f,1.0f,0.0f);
D3DXMATRIX V;
D3DXMatrixLookAtLH(&V, &position, &target, &worldup);
Device->SetTransform(D3DTS_VIEW,&V);

but no more results, the text is not visible ...

##### Share on other sites
Your camera is at (0, 0, 0) looking at +Z, with your near clip set at Z=1, but ID3DXSprite is probably drawing at Z=0, meaning it's obscured by the near clip plane.

What if you move your camera further back, or change the translation matrix to move the sprite to Z += 5 or so?

##### Share on other sites
I just tried that, no way !
Playing with the camera position or near clipping plane had no effect.

Oliver

##### Share on other sites
Running a test app I have through Pix as "A replayable Direct3D call stream", and then inspecting a frame (And clicking on the "Render" tab to allow me to view objects), I see:
6991 <0x04D75190> IDirect3DDevice9::SetVertexDeclaration(0x04D76E98)
Selecting the 0x04D76E98 part shows a vertex format of float3, D3DCOLOR, float2 for position, colour and texture coordinates.
A little further down, there's a call to:
<0x04D676F8> IDirect3DVertexBuffer9::Lock(0, 0, 0x0012F758, D3DLOCK_NOOVERWRITE)
That shows that the sprite is locking the vertex buffer at offset 0. Scrolling down to the unlock line and double clicking on the vertex buffer object pointer then shows the buffer contents.
Filling in the vertex format above as:
float3 position;int color;float2 tex0;

then going to the "buffer" tab shows that the text is being drawn as it would be in screen coordinates:
#      X        Y        Z        Colour U       V0      1.000    3.000    0.000    -1     0.043   0.0271      1.000    20.000   0.000    -1     0.043   0.0942      13.000   3.000    0.000    -1     0.090   0.0273      13.000   20.000   0.000    -1     0.090   0.0944      14.000   3.000    0.000    -1     0.164   0.027...

If you draw a quad near the origin (Not using ID3DXSprite or ID3DXFont), can you see it? You need to make sure your camera is where you think it is before you can go much further.

##### Share on other sites
Hi Steve,

First, a lot of thanks for all your efforts to help me !

I have tried to draw a triangle in the xy plane, at z=0. It is defined as :

Triangle->Lock(0, 0, (void**)&vertices, 0);
vertices[0] = Vertex(-1.0f, 0.0f, 0.0f, D3DCOLOR_XRGB(255,0,0));
vertices[1] = Vertex( 0.0f, 1.0f, 0.0f,D3DCOLOR_XRGB(255,0,0));
vertices[2] = Vertex(1.0f, 0.0f, 0.0f,D3DCOLOR_XRGB(255,0,0));
Triangle->Unlock();

Then, the projection and view are defined by :

D3DXMatrixOrthoLH(
&proj, // proj matrix
4.0f, // width
4.0f, // height
-1.0f, // near plane
1000.0f); // far plane
Device->SetTransform(D3DTS_PROJECTION, &proj);
D3DXVECTOR3 position(0.0f,0.0f,0.0f);
D3DXVECTOR3 target(0.0f,0.0f,100.0f);
D3DXVECTOR3 worldup(0.0f,1.0f,0.0f);
D3DXMATRIX V;
D3DXMatrixLookAtLH(&V, &position, &target, &worldup);
Device->SetTransform(D3DTS_VIEW,&V);

Finally, the drawing code is :

D3DXMATRIX WorldMatrix;

Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(10,0,10), 1.0f, 0);
Device->BeginScene();
Device->SetStreamSource(0, Triangle, 0, sizeof(Vertex));
Device->SetFVF(D3DFVF_XYZ | D3DFVF_DIFFUSE);
// Draw one triangle.
Device->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);

pD3DXSprite->Begin(D3DXSPRITE_OBJECTSPACE);
//pD3DXSprite->Begin(D3DXSPRITE_ALPHABLEND);
D3DXMatrixTranslation(&WorldMatrix, 1.0f, 1.0f, 0.0f);
char Text[] = "Test String";
pD3DXSprite->SetTransform(&WorldMatrix);
Font->DrawText(pD3DXSprite,Text(int(strlen(Text)),&font_rect,DT_LEFT|DT_EXPANDTABS,D3DCOLOR_XRGB(155,30,200));
pD3DXSprite->End();

Device->EndScene();
Device->Present(0, 0, 0, 0);

The triangle is correctly drawn, but not the text.
If I comment out Begin(D3DXSPRITE_OBJECTSPACE); and use Begin(D3DXSPRITE_ALPHABLEND); or whatever, then the text is drawn near the origin

Oliver

##### Share on other sites
The following works for me:
// Setup:void D3DWindow::SetupState(){	// Create the projection matrix (45 degrees FOV), and set it on the device	D3DXMATRIXA16 matProj;	float fAspect = (float)m_thePresentParams.BackBufferWidth /		(float)m_thePresentParams.BackBufferHeight;	D3DXMatrixPerspectiveFovLH(&matProj, D3DXToRadian(45.0f), fAspect, 0.1f, 1000.0f);	m_pDevice->SetTransform(D3DTS_PROJECTION, &matProj);	// Create the view matrix (Camera), and set it on the device	D3DXMATRIXA16 matView;	D3DXVECTOR3 vEye(0, 0, -500.0f);     // Camera position	D3DXVECTOR3 vAt(0, 0, 0);           // Camera look-at position	D3DXVECTOR3 vUp(0, 1.0f, 0);        // Camera "up" direction	D3DXMatrixLookAtLH(&matView, &vEye, &vAt, &vUp);	m_pDevice->SetTransform(D3DTS_VIEW, &matView);	// Invert the Y axis (ID3DXSprite draws with +Y being "down"	D3DXMATRIXA16 matWorld;	D3DXMatrixScaling(&matWorld, 1.0f, -1.0f, 1.0f);	m_pDevice->SetTransform(D3DTS_WORLD, &matWorld);}// Rendering:hResult = m_pSprite->Begin(D3DXSPRITE_ALPHABLEND | D3DXSPRITE_OBJECTSPACE);if(SUCCEEDED(hResult)){	m_pFont->DrawText(m_pSprite, TEXT("Hello world!"), -1, NULL, DT_LEFT | DT_WORDBREAK,		D3DCOLOR_XRGB(255, 255, 255));	m_pSprite->End();}
I think the problem is that your camera is still way too close - the text is pretty large. With the camera at -500 on Z, the text still takes up about a quarter of the width of the screen.

##### Share on other sites
Hi Steve,

I have tried your small code, without success. However I'm still using the ortho projection and that's the point I think.

I tried to reduce the size of the font to a minimum, and got big blocks drawn; looks like they're part of a huge font drawing.

I think the whole story is a matter of coordinates - using PIX as you previously mentionned, I examined the data corresponding to the vertex for the font elements, they have the format (float3, D3DCOLOR, float2). For the float3 representing the XYZ coordinates, I find from pix that integer values up to 12 are produced, which is far out of my window extent (defined as -2,2 both on X and Y axis). So it seems that the font elements vertices still make use of screen coordinates.

I think you observe the same thing, a very large font size but you are able to see the text because you use perspective projection and a far away point of view, making the text appear smaller.

Still not clear to me ...

##### Share on other sites
Quote:
 Original post by oliver_mptI have tried your small code, without success. However I'm still using the ortho projection and that's the point I think.
Yes, you'll need to adjust your coordinate range to see the text, or set a scaling transform before rendering it.

Quote:
 Original post by oliver_mptI tried to reduce the size of the font to a minimum, and got big blocks drawn; looks like they're part of a huge font drawing.
That sounds like you don't have the D3DXSPRITE_ALPHABLEND flag; you need both that and D3DXSPRITE_OBJECTSPACE.

Quote:
 Original post by oliver_mptI think the whole story is a matter of coordinates - using PIX as you previously mentionned, I examined the data corresponding to the vertex for the font elements, they have the format (float3, D3DCOLOR, float2). For the float3 representing the XYZ coordinates, I find from pix that integer values up to 12 are produced, which is far out of my window extent (defined as -2,2 both on X and Y axis). So it seems that the font elements vertices still make use of screen coordinates.I think you observe the same thing, a very large font size but you are able to see the text because you use perspective projection and a far away point of view, making the text appear smaller.
Well, the font vertices aren't going to change - you need to accommodate for the range of values you can expect from the text.
There's two options:
1. Change your coordinate range from -2..+2 to -200..+200 or something else large so you can see the text clearly
2. Set a scaling transform as part of the world matrix to scale the text down to a reasonable size.

##### Share on other sites
Hi Steve,

It's clearer now. I see the whole thing.

Thanks a lot for all your input - I learned a lot.

Oliver

## Create an account

Register a new account

• ### Forum Statistics

• Total Topics
628336
• Total Posts
2982158

• 9
• 24
• 9
• 9
• 13