Как нарисовать текст в сцене?
У меня есть некоторый код, который я давно скачал из интернета, и я хотел поиграть с ним.
Поэтому я извлек интересные части, создал прокси d3d9.dll и подключил к игре.
Теперь у меня есть вопрос, потому что я не могу найти различие в рисовании между этими двумя частями кода, которые определяют, должна ли быть нарисована вершина на экране или в игровой сцене.
(Я имею в виду, например, HUD на экране, и вы всегда видите его, а транспортное средство на игровой сцене, когда вы поворачиваетесь, вы не видите его).
Первая часть - это код, который я хочу редактировать, я хочу, чтобы он отображал текст в игровой сцене, а не на экране в виде статического текста.
Код, который используется в DLL это:
float m_fTexCoords[224][4];
float CD3DFont::DrawLength ( const char *szText ) const
{
float len = 0.0f;
float sub = ( m_dwCreateFlags & FCR_BORDER ) ? 2.0f : 0.0f;
for ( const char *p = szText; *p; p++ )
{
int c = *(unsigned char *)p - 32;
if ( c >= 0 && c < 224 )
len += ( (m_fTexCoords[c][2] - m_fTexCoords[c][0]) * m_texWidth - sub ) - m_chrSpacing * 2;
}
return len;
}
HRESULT CD3DFont::Print ( float x, float y, DWORD color, const char *szText)
{
if ( !m_isReady )
return E_FAIL;
float strWidth = DrawLength( szText );
x -= (float)m_chrSpacing;
if ( FAILED(this->BeginRender()) )
return E_FAIL;
DWORD fvf;
m_pD3Ddev->GetFVF( &fvf );
m_pD3Ddev->SetFVF( D3DFVF_BITMAPFONT );
m_pD3Ddev->SetTexture( 0, m_pD3Dtex );
m_pD3Ddev->SetStreamSource( 0, m_pD3Dbuf, 0, sizeof(d3dvertex_s) );
while ( *szText )
{
UINT usedTriangles = 0;
d3dvertex_s *pVertex;
if ( FAILED(m_pD3Dbuf->Lock(0, 0, (void **) &pVertex, D3DLOCK_DISCARD)) )
{
m_pD3Ddev->SetFVF( fvf );
this->EndRender();
return E_FAIL;
}
for ( ; *szText; szText++ )
{
int c = *(unsigned char *)szText - 32;
if ( !(c >= 0 && c < 224) )
continue;
float tx1 = m_fTexCoords[c][0];
float tx2 = m_fTexCoords[c][2];
float ty1 = m_fTexCoords[c][1];
float ty2 = m_fTexCoords[c][3];
float w = ( tx2 - tx1 ) * m_texWidth;
float h = ( ty2 - ty1 ) * m_texHeight;
*pVertex++ = Init2DVertex( x - 0.5f, y - 0.5f, color, tx1, ty1 ); //topleft
*pVertex++ = Init2DVertex( x + w - 0.5f, y - 0.5f, color, tx2, ty1 ); //topright
*pVertex++ = Init2DVertex( x - 0.5f, y + h - 0.5f, color, tx1, ty2 ); //bottomleft
*pVertex++ = Init2DVertex( x + w - 0.5f, y - 0.5f, color, tx2, ty1 ); //topright
*pVertex++ = Init2DVertex( x + w - 0.5f, y + h - 0.5f, color, tx2, ty2 ); //bottomright
*pVertex++ = Init2DVertex( x - 0.5f, y + h - 0.5f, color, tx1, ty2 ); //bottomleft
if ( m_dwCreateFlags & FCR_BORDER )
w -= 2.0f;
x += w - ( m_chrSpacing * 2 );
usedTriangles += 2;
if ( usedTriangles >= m_maxTriangles )
break;
}
if ( usedTriangles > 0 )
{
m_pD3Dbuf->Unlock();
m_pD3Ddev->DrawPrimitive( D3DPT_TRIANGLELIST, 0, usedTriangles );
}
}
m_pD3Ddev->SetFVF( fvf );
this->EndRender();
return S_OK;
}
Затем я увидел функцию с именем "DrawLine", поэтому я решил проверить ее и посмотреть, что она делает, и она рисует линию в игровом мире, а не статическую линию на экране, поэтому, когда я оборачиваюсь и не увидеть конкретные позиции - я не вижу линии:
bool CD3DRender::DrawLine ( const D3DXVECTOR3 &a, const D3DXVECTOR3 &b, DWORD dwColor )
{
if ( FAILED(CD3DBaseRender::BeginRender()) )
return false;
////////////////////////////////////////////////////
// Make sure we have a valid vertex buffer.
if ( m_pD3Dbuf == NULL )
{
return false;
}
m_pD3Ddev->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG2 );
m_pD3Ddev->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2 );
//m_pD3Ddev->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
//m_pD3Ddev->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
m_pD3Ddev->SetRenderState( D3DRS_CLIPPING, false );
m_pD3Ddev->SetRenderState ( D3DRS_ZENABLE, false );
//m_pD3Ddev->SetRenderState ( D3DRS_LIGHTING, false );
D3DLVERTEX lineList[2];
//////////////////////////////////////////////////
// Lock the vertex buffer and copy in the verts.
m_pD3Dbuf->Lock( 0, 0, (void **) &lineList, D3DLOCK_DISCARD | D3DLOCK_NOSYSLOCK ); // flogs: D3DLOCK_NOSYSLOCK, D3DLOCK_DISCARD
{
lineList[0].x = a.x;
lineList[0].y = a.y;
lineList[0].z = a.z;
lineList[0].color = dwColor;
lineList[0].specular = dwColor;
lineList[1].x = b.x;
lineList[1].y = b.y;
lineList[1].z = b.z;
lineList[1].color = dwColor;
lineList[1].specular = dwColor;
}
m_pD3Dbuf->Unlock();
// store FVF to restore original at the end of this function
DWORD fvf;
m_pD3Ddev->GetFVF( &fvf );
m_pD3Ddev->SetFVF( D3DFVF_LVERTEX );
//m_pD3Ddev->SetFVF( D3DFVF_PRIMITIVES );
////////////////////////////////////////////////////
// Draw!
m_pD3Ddev->DrawPrimitiveUP( D3DPT_LINESTRIP, 1, lineList, sizeof(lineList) / 2 );
// reset states
m_pD3Ddev->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
m_pD3Ddev->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
m_pD3Ddev->SetRenderState ( D3DRS_ZENABLE, true );
m_pD3Ddev->SetRenderState( D3DRS_CLIPPING, true );
// restore FVF
m_pD3Ddev->SetFVF( fvf );
CD3DBaseRender::EndRender();
return true;
}
Теперь вопрос: где разница? Где этот код говорит:
"Эй, нарисуйте текст на экране проигрывателя и оставьте его там"?
а также
"Эй, нарисуй это в игровом мире, нарисуй только ту часть, которую может увидеть игрок"?
Может кто-то указать мне верное направление? Или, может быть, как отредактировать функцию Print для отображения текста в игровом мире?
заранее спасибо.
Краткий пример того, чего я хочу добиться:
Что теперь делает Print (зеленое поле) и что я хочу от него (красное поле)
(скриншоты, взятые из другой игры, где такие "3d-тексты" существуют, но программа имеет закрытый источник):
Вы можете видеть, что положение текста в красном поле изменилось на экране, но не в игре. Я тоже хочу это сделать. (вы можете увидеть красный и синий # тоже)
Код DrawLine уже создает линию в игре, но это всего лишь строка, а не текст, так как же в итоге получается, что другой - нет, а другой - нет?
1 ответ
Я могу только догадываться, что делает остальная часть вашего кода. Кажется, что Print
Метод вызывается в среде, где матрицы преобразования были установлены для формирования ортографического представления, в то время как DrawLine
Метод использует игровые матрицы.
Однако вы не хотите рисовать текст на сцене. Это может привести к смещению и неправильному масштабированию текста. То, что вы действительно хотите сделать, это получить положение на экране, где будет положение сцены, и нарисовать там текст. Для этого вы можете использовать функцию D3DXVec3Project. Обязательно предоставьте правильные матрицы преобразования. Не обновленные для 2D-рендеринга.