游戏开发论坛

 找回密码
 立即注册
搜索
查看: 5795|回复: 12

关于人物头上显示名字的问题~~~~`

[复制链接]

1

主题

3

帖子

0

积分

新手上路

Rank: 1

积分
0
发表于 2007-8-4 19:32:00 | 显示全部楼层 |阅读模式
在人物头上显示字体 我是用精灵的方式广告牌技术显示的~~先绘制精灵 在绘制字体
当摄象机围绕人物旋转的时候   字体是每个字体每个字体单独旋转的  而不是整个字符串旋转的~
我想达到 字体在人物头上~~字体完全处于3D空间中 有进大远小的效果 有遮挡关系~~
当摄象机旋转的时候 是以字符串的形式进行旋转  而不是每个单独的字体旋转~~~
请问 是什么地方造成这种问题的~~要怎么解决~~~~
我没有找到类似的问题的解决方法~~~~


伪代码
/*
LPD3DXFONT m_NameFont;
LPD3DXSPRITE m_Sprite;
LPDIRECT3DTEXTURE9 m_NameTexture;
*/
//////////----------------变换矩阵
D3DXMATRIX world ;
D3DXMatrixIdentity(&world);
m_Sprite->SetTransform(&world);
D3DXMatrixTranslation(&world, g_Camera.m_vLookat.x, g_Camera.m_vLookat.y, g_Camera.m_vLookat.z);
m_Sprite->SetWorldViewLH(&world, &g_Camera.m_matView);
////////////////////////////--------显示
m_Sprite->Begin(D3DXSPRITE_ALPHABLEND|D3DXSPRITE_BILLBOARD);       
m_Sprite->Draw(m_NameTexture, NULL, NULL, NULL, 0xffffffff);
m_Sprite->Flush();
m_NameFont->DrawTextA(m_Sprite, name, -1, NULL, DT_CENTER, 0xff00ffff);       


谢谢各位了~~~~~~

1

主题

3

帖子

0

积分

新手上路

Rank: 1

积分
0
 楼主| 发表于 2007-8-4 19:52:00 | 显示全部楼层

Re: 关于人物头上显示名字的问题~~~~`

有人说过 把字体写入WINDOWS GDI的位图中~~
然后锁顶纹理区域 逐一从位图中每个字节的写入纹理中去~~`

人少还看不出什么效率~~
如果人多了 这样的效率就低了~~

0

主题

769

帖子

1052

积分

金牌会员

Rank: 6Rank: 6

积分
1052
发表于 2007-8-4 22:00:00 | 显示全部楼层

Re:关于人物头上显示名字的问题~~~~`

LZ说的使用揭示栏就可以做到

让字体的正面一直对着摄像机

1

主题

3

帖子

0

积分

新手上路

Rank: 1

积分
0
 楼主| 发表于 2007-8-4 22:07:00 | 显示全部楼层

Re: 关于人物头上显示名字的问题~~~~`

请把连接发给我~~`
谢谢~~

6

主题

307

帖子

309

积分

中级会员

Rank: 3Rank: 3

积分
309
发表于 2007-8-5 16:57:00 | 显示全部楼层

Re:关于人物头上显示名字的问题~~~~`

billboard

文字渲染到纹理后贴上去,人的名字又不是经常变的,渲一次就可以一直用,没什么效率问题

119

主题

1367

帖子

1393

积分

金牌会员

Rank: 6Rank: 6

积分
1393
发表于 2007-8-5 18:10:00 | 显示全部楼层

Re:关于人物头上显示名字的问题~~~~`

建议还是不要用这样的技术,用点投影到视锥平面的z=1的平面上,计算出xy坐标,直接写文字在上面效果就很好了,如果一定要做文字贴图可以用下面的方法,我过去做过深入的研究


#include ".\Cachedfonttexture.h"
#include "Colors.h"

CachedFontTexture::CachedFontTexture(int _fontsize,char  *fontname, DWORD _dwBold, DWORD _dwItalic)
{
        fontsize = _fontsize;
        dwBold   = _dwBold;
        dwItalic = _dwItalic;
        strcpy(m_strFontName, fontname);
        LogOutable = false;
}

CachedFontTexture::~CachedFontTexture(void)
{
        for ( p = FontTexMap.begin( ); p != FontTexMap.end( ); p++ ) {
                if(LogOutable)
        Logger:og(DEBUG_LV, "CachedFontexture:释放贴图...[%d]", p->first);
                LPDIRECT3DTEXTURE9 _tex = ((PerFontTexCache)(p->second)).tex;
                 if(_tex)
                   _tex->Release();
        }

        //清除g_Guide
        if( g_Guide != NULL )
        {
                g_Guide->Release();
                g_Guide = NULL;
        }// end if
}



//按该文字的asc码来查找文字贴图指针,如果找不到,返回0
LPPerFontTexCache CachedFontTexture::findFont(DWORD key) {
        p = FontTexMap.find(key);
        if(p == FontTexMap.end())
                return 0;
        else
                return (LPPerFontTexCache)&p->second;
}


void CachedFontTexture::GetTexFromString(
        IDirect3DDevice9* m_pd3dDevice,
        LPDIRECT3DTEXTURE9 &_tex,
        unsigned char* str,
        int colnum, int rownum,
        bool fixed, int colspan, int rowspan,
    OUT int *texWidth, OUT int *texHeight
        ) {
                //IDirect3DTexture9*      _tex;

                int _width = 0;
                int _height = fontsize;

                //////////////////////////////////////////////////////////////根据输入自动计算贴图的尺寸
                if(fixed) { //固定行列
                        _width = (fontsize + colspan) * colnum;
                        _height = (fontsize + rowspan) * rownum;
                } else { //计算一共是多少行多少列

                        int offsetx = 0;
                        size_t len = strlen((const char *)str);

                        for(size_t i = 0; i < len; i ++) {
                                unsigned char* p = &str;
                                if(str > 128) //表明当前一定是个汉字
                                {
                                        if(offsetx > colnum * (fontsize + colspan) - fontsize) { //需要换行了
                                                //g_Log.Log(DEBUG_LV, "%d...%d", offsetx, colnum * (fontsize + colspan) - fontsize);
                                                _height += (fontsize+ rowspan);
                                                offsetx = 0;
                                        }

                                        i++;   //跳过另半个汉字
                                        if(i<len-1)
                                                offsetx+=(fontsize + colspan); //偏移中文的长度

                                } else {  //不是个汉字

                                        if(offsetx > colnum * (fontsize + colspan) - (fontsize>>1)) { //需要换行了
                                                //g_Log.Log(DEBUG_LV, "%d...%d", offsetx, colnum * (fontsize + colspan) - (fontsize>>1));
                                                _height += (fontsize+ rowspan);
                                                offsetx = 0;
                                        }

                                        if(i<len-1)
                                                offsetx+=((fontsize>> 1) + colspan); //偏移英文的长度+colspan
                                }

                        }

                        if(_height) { //表明换过行
                                _width = colnum *(fontsize + colspan);
                        } else {
                                _width = offsetx + fontsize;
                        }
                }

                if(texWidth) {
           *texWidth = _width; //输出宽度
                }

                if(texHeight) {
           *texHeight = _height; //输出高
                }

               
                if(_tex) {
                        _tex->Release();//上次创建过的先释放掉,再重新创建,否则会丢失内存了
                }

                ////需要的width和height计算完毕,下面开始创建贴图了
                HRESULT hr = m_pd3dDevice->CreateTexture( _width, _height, 1,
                        0, D3DFMT_A4R4G4B4,
                        D3DPOOL_MANAGED, &_tex, 0);

                if(LogOutable)
            Logger::Log(DEBUG_LV, "width:%d...height:%d", _width, _height);


                int offsetx = 0;
                int offsety = 0;
                size_t len = strlen((const char *)str);
                for(size_t i = 0; i < len; i ++) {
                        unsigned char* p = &str;
                       
                        LPDIRECT3DTEXTURE9 tex=GetPerFontTex(m_pd3dDevice, p)->tex;

                        if(LogOutable)
                Logger::Log(DEBUG_LV, "%d...%d", offsetx, offsety);

                        if(str > 128) //表明当前一定是个汉字
                        {
                                PasteTex(m_pd3dDevice, _tex, tex, offsetx, offsety,fontsize, fontsize);
                                i++;   //跳过另半个汉字
                                offsetx+=(fontsize + colspan);
                        } else {  //不是个汉字
                                PasteTex(m_pd3dDevice, _tex, tex, offsetx, offsety,fontsize>>1,fontsize);
                                offsetx+=((fontsize>>1) + colspan);
                        }

                        //下一个字是汉字或英文
                        if((str[i+1] > 128 && offsetx > _width  - fontsize) || str[i+1] <= 128 &&  offsetx > _width - (fontsize >>1)) { //需要换行了
                                if(fixed && offsety + fontsize+ rowspan >= _height) { //固定行列要越界了,只能截断字符串了
                                        break;
                                }
                                offsety += (fontsize+ rowspan);
                                offsetx = 0;
                        }

                }

}


void CachedFontTexture:asteTex(IDirect3DDevice9* m_pd3dDevice,
                          LPDIRECT3DTEXTURE9 &destex,
                          LPDIRECT3DTEXTURE9 &srctex,
                          DWORD offsetx,
                          DWORD offsety,
                          int fwidth,
                          int fheight
                          ) {

        //static LPDIRECT3DTEXTURE9 _destex; //test
        //if(!_destex) { //test
        //        HRESULT hr = m_pd3dDevice->CreateTexture( 32, 32, 1,
        //                0, D3DFMT_A4R4G4B4,
        //                D3DPOOL_MANAGED, &_destex, 0);
        //       
        //        if(FAILED(hr)) {
        //                return;
        //        }
        //}

        D3DLOCKED_RECT destlockedRect;
        D3DLOCKED_RECT srclockedRect;

        destex->LockRect( 0, &destlockedRect, 0, 0 );
        srctex->LockRect(0,&srclockedRect, 0, 0);

        WORD* imageDataDest = (WORD*)destlockedRect.pBits; //D3DFMT_A4R4G4B4是16位色的,所以每个单位是WORD 2位
        WORD* imageDataSrc = (WORD*)srclockedRect.pBits;

        for(int i = 0;i < fheight; i ++) {
                for(int j = 0; j < fwidth; j ++) {

                 int indexdest = (i+offsety) * destlockedRect.Pitch / 2 + (j + offsetx); //2位
                 int indexsrc = i * srclockedRect.Pitch / 2  + j;
                 imageDataDest[indexdest] = imageDataSrc[indexsrc];
                }
        }
        srctex->UnlockRect(0);
        destex->UnlockRect(0);
        //destex = _destex;
}



LPPerFontTexCache CachedFontTexture::GetPerFontTex(
                IDirect3DDevice9* m_pd3dDevice,
                unsigned char* str
                ) {
               
                unsigned char c1 = str[0];
                unsigned char c2 = str[1];

        DWORD key = 0;

                if(c1 > 128) //说明是中文
                        key = MAKEWORD(c1, c2);
                else  //说明是英文
                        key = MAKEWORD(0, c1);


        
                LPPerFontTexCache fp = findFont(key);
                if(fp)
                {
                  if(LogOutable)
              Logger::Log(DEBUG_LV, "找到了贴图...[%d]", fp->texid);
                  //fp->usedtimes++; //使用次数自增
          return fp; //找到了,返回该贴图的结构
                }

               
                LPDIRECT3DTEXTURE9 m_pTexture;

                //找不到,创建一个贴图,然后添加到FontTexMap中去
                PerFontTexCache  texCache;
               
                texCache.usedtimes = 0; //使用次数为0
               
                if(c1 > 128)
                    texCache.isEN = false;  //不是英文,是汉字
                else
                        texCache.isEN = true;  //是英文

               
                DWORD m_dwTexWidth = fontsize;
               
                if(texCache.isEN)
              m_dwTexWidth = fontsize >> 1;
       
                DWORD m_dwTexHeight = fontsize;
               
                //DWORD m_dwFontFlags = dwFlags;
                // Create a new texture for the font
                HRESULT hr = m_pd3dDevice->CreateTexture( m_dwTexWidth, m_dwTexHeight, 1,
                        0, D3DFMT_A4R4G4B4,
                        D3DPOOL_MANAGED, &m_pTexture, 0);

                if( FAILED(hr) )
                        return 0;

                // Prepare to create a bitmap
                DWORD*      pBitmapBits;
                BITMAPINFO bmi;
                ZeroMemory( &bmi.bmiHeader,  sizeof(BITMAPINFOHEADER) );
                bmi.bmiHeader.biSize        = sizeof(BITMAPINFOHEADER);
                bmi.bmiHeader.biWidth       =  (int)m_dwTexWidth;
                bmi.bmiHeader.biHeight      = -(int)m_dwTexHeight;
                bmi.bmiHeader.biPlanes      = 1;
                bmi.bmiHeader.biCompression = BI_RGB;
                bmi.bmiHeader.biBitCount    = 32;

                // Create a DC and a bitmap for the font
                HDC     hDC       = CreateCompatibleDC( NULL );
                DWORD size = 0;
                HBITMAP hbmBitmap = CreateDIBSection( hDC, &bmi, DIB_RGB_COLORS,
                        (void**)&pBitmapBits, NULL, size );


                SetMapMode( hDC, MM_TEXT );

                // Create a font.  By specifying ANTIALIASED_QUALITY, we might get an
                // antialiased font, but this is not guaranteed.
                INT nHeight    = fontsize;
                //-MulDiv( m_dwFontHeight, (INT)(GetDeviceCaps(hDC, LOGPIXELSY) * m_fTextScale), 72 );
                //DWORD dwBold   = (m_dwFontFlags&D3DFONT_BOLD)   ? FW_BOLD : FW_NORMAL;
                //DWORD dwItalic = (m_dwFontFlags&D3DFONT_ITALIC) ? TRUE    : FALSE;

                HFONT hFont    = ::CreateFont( nHeight, 0, 0, 0, dwBold, dwItalic,
                        FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
                        CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY,
                        VARIABLE_PITCH, m_strFontName );

                if( NULL==hFont )
                        return 0;

                SelectObject( hDC, hbmBitmap );
                SelectObject( hDC, hFont );

                // Set text properties
                SetTextColor( hDC, RGB(255,255,255) );
                SetBkColor(   hDC, 0x00000000 );
                SetTextAlign( hDC, TA_TOP );
               
                ExtTextOut( hDC, 0, 0, ETO_OPAQUE, 0, (LPCSTR)str, 2, NULL );

                D3DLOCKED_RECT d3dlr;
                m_pTexture->LockRect( 0, &d3dlr, 0, 0 );
                BYTE* pDstRow = (BYTE*)d3dlr.pBits;
                WORD* pDst16;
                BYTE bAlpha; // 4-bit measure of pixel intensity

                for(int y=0; y < m_dwTexHeight; y++ )
                {
                        pDst16 = (WORD*)pDstRow;
                        for(int x=0; x < m_dwTexWidth; x++ )
                        {
                                bAlpha = (BYTE)((pBitmapBits[m_dwTexWidth*y + x] & 0xff) >> 4);
                                if (bAlpha > 0)
                                {
                                        *pDst16++ = (bAlpha << 12) | 0x0fff;
                                }
                                else
                                {
                                        *pDst16++ = 0x0000;
                                }
                        }
                        pDstRow += d3dlr.Pitch;
                }

                // Done updating texture, so clean up used objects
                m_pTexture->UnlockRect(0);
               
                DeleteObject(hbmBitmap);
                DeleteDC(hDC);
                DeleteObject( hFont );

                texCache.texid = key;
                texCache.tex = m_pTexture; //把贴图保存到缓冲中去,下次还可以继续使用

                FontTexMap.insert(tex_Pair(key, texCache));
                if(LogOutable)
            Logger::Log(DEBUG_LV, "创建了贴图...[%d]", key);

                return &texCache;
        }


        void  CachedFontTexture:rawSprite(IDirect3DDevice9* m_pd3dDevice,
                LPDIRECT3DTEXTURE9 &m_pTexture,int x, int y,        D3DCOLOR color)
        {
                        if(!g_Guide) {
                      D3DXCreateSprite(m_pd3dDevice, &g_Guide); //还没创建过,那么创建一个好了
                        }
                        g_Guide->Begin( D3DXSPRITE_ALPHABLEND | D3DXSPRITE_SORT_TEXTURE );
                          g_Guide->Draw(m_pTexture,   0,   0,   &D3DXVECTOR3(x,   y,   0), color);   
                        g_Guide->End();
                }



         //将指定的文本绘制到view投影平面上
        void CachedFontTexture::DrawFontToScreen(
                IDirect3DDevice9* m_pd3dDevice,
                char *str ,int x, int y, int colnum, int rownum, D3DCOLOR color)
        {
       LPDIRECT3DTEXTURE9 __tex = 0;
           GetTexFromString(m_pd3dDevice, __tex, (unsigned char *) str, colnum, rownum, false, 1, 1);
           DrawSprite(m_pd3dDevice, __tex, x, y, color);
        }




    //将文字绘制到3D空间的某个位置,并投影到屏幕上,实现文字公告牌的效果
        void CachedFontTexture::DrawFontToWorld(IDirect3DDevice9* m_pd3dDevice, char * str, float x, float y, float z,
                int colnum, int rownum, D3DCOLOR color) {
                        D3DXVECTOR3 p(0.0f, 0.0f, 0.0f);

                        D3DXMATRIX worldMat;
                        D3DXMatrixIdentity(&worldMat);
                        worldMat._41 = x;
                        worldMat._42 = y;
                        worldMat._43 = z;

                        D3DXMATRIX viewMat;
                        D3DXMATRIX projectMat;
                        D3DVIEWPORT9 viewPortMat;
                        m_pd3dDevice->GetTransform(D3DTS_VIEW, &viewMat);
                        m_pd3dDevice->GetTransform(D3DTS_PROJECTION, &projectMat);
                        m_pd3dDevice->GetViewport(&viewPortMat);


                        D3DXVECTOR3 s;
                        //获取3D空间的P点投影到屏幕上的s点
                        D3DXVec3Project(&s, &p,
                                (D3DVIEWPORT9 *)&viewPortMat,
                                (const D3DXMATRIX*)&projectMat,
                                (const D3DXMATRIX*)&viewMat,
                                (const D3DXMATRIX*)&worldMat);

                        DrawFontToScreen(m_pd3dDevice, str, s.x, s.y, colnum, rownum, color);
                }

6

主题

307

帖子

309

积分

中级会员

Rank: 3Rank: 3

积分
309
发表于 2007-8-6 09:38:00 | 显示全部楼层

Re:关于人物头上显示名字的问题~~~~`

楼上的做法没有透视效果,结果造成远处的名字比人大,结果看过去就是满屏的人名堆在那里,视觉效果很不好。

119

主题

1367

帖子

1393

积分

金牌会员

Rank: 6Rank: 6

积分
1393
发表于 2007-8-6 12:28:00 | 显示全部楼层

Re:关于人物头上显示名字的问题~~~~`

代码部分是文字缓存+公告牌牌的实现。
如果是渲染到纹理(带缓存拼接)的方式,纹理贴在公告牌上会没有透视效果?
那就是公告牌没有透视效果了,你的意思是这样吗?


119

主题

1367

帖子

1393

积分

金牌会员

Rank: 6Rank: 6

积分
1393
发表于 2007-8-6 12:36:00 | 显示全部楼层

Re:关于人物头上显示名字的问题~~~~`

你自己去实现再去对比吧,两种方式有不同的适用之处
谁好谁不好,适合用什么位置,你自己慢慢去体会吧。

微软有个例子实现了英文的文字贴图
照那个思路去实现一套中文的文字贴图不是一件容易的事情,我是亲自做过的,上面的代码是最主要的部分。

补充一句,我的公告牌用的是绕点的公告牌,如果你要的所谓的有透视效果的公告牌,可以用绕y轴的公告牌。

算了,懒得继续再解释了。。。

6

主题

307

帖子

309

积分

中级会员

Rank: 3Rank: 3

积分
309
发表于 2007-8-6 16:59:00 | 显示全部楼层

Re:关于人物头上显示名字的问题~~~~`

举个例子
魔兽的

诛仙的


两种不同的方法,自己比较吧
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2026-1-25 11:47

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表