トップページ > 過去ログ > 記事閲覧
文字にグラデーション
名前:チルチル 日時: 2010/08/19 18:14

いつもありがとうございます 今回は文字についてなんですが DrawString関数やDrawFormatString関数などで 描画する文字列にグラデーションを付けることは可能でしょうか? エッジの有無は関係なく、中の文字本体の色を 上は白で下に行くほど赤とか青にしたりすると キレイに見えそうなのでやってみたいのですが 私が思い付く方法は SetDrawArea関数で描画可能領域を横一列ずつにして 縦のピクセル数だけ色を変えながら描画する ぐらいです・・ これでもできない事はないと思いますが 描画に時間がかかって処理落ちしそうだし 文字を描画する所で毎回そんな事をすると コードが異常に長くなってしまいそうです なんとか簡単に実現する方法はないでしょうか?

Page: 1 | 2 |

Re: 文字にグラデーション ( No.1 )
名前:naohiro19 日時:2010/08/19 22:59

for文内でGetColor関数を呼び出したうちそのあとにDrawString関数を呼び出すのはどうでしょう?
Re: 文字にグラデーション ( No.2 )
名前:いっち 日時:2010/08/19 23:08

「文字のグラデーション」については以下のURLのスレッドでも話題となっていますが、 そのスレッド内で提示されている方法では実現できないでしょうか? > ttp://hpcgi2.nifty.com/natupaji/bbs/patio.cgi?mode=past&no=1366
Re: 文字にグラデーション ( No.3 )
名前:チルチル 日時:2010/08/19 23:23

≫naohiro19様 すみません意味が良くわからないのですが ≫SetDrawArea関数で描画可能領域を横一列ずつにして ≫縦のピクセル数だけ色を変えながら描画する ↑これの色を変える部分をfor文で行うと短くなるという事でしょうか? だとしたら説明不足でした それは私も思ったのですが それでも長くて重くて実用的ではなさそうなんです そもそも一列ずつの描画は良い方法では無いと思うので あくまで悪い例として書かせていただきました すいません・・ ≫いっち様 ここには書きませんでしたけど ポリゴンでグラデーションする方法は私も一瞬考えたのですが 一行ずつ描画するよりも長くなるので許容できないです・・
Re: 文字にグラデーション ( No.4 )
名前:いっち 日時:2010/08/19 23:30

> 一行ずつ描画するよりも長くなるので許容できないです・・ 「長くなる」とは処理時間のことでしょうか? それとも、ソースの文字数のことを仰っているのでしょうか?
Re: 文字にグラデーション ( No.5 )
名前:チルチル 日時:2010/08/20 00:21

え〜と両方です
Re: 文字にグラデーション ( No.6 )
名前:sy(サイ) 日時:2010/08/20 06:14

ポリゴンで描くと重くなったのでしょうか? ソースが長いのが気になるのでしたら、今の方法でやるしかないかもです。 もしポリゴンが重いのでしたら、ポリゴンで描かずにソフトウェアイメージに転送した文字の画像を DrawPixelSoftImageでグラデーションに塗りつぶせば出来ると思います。 for文で出来るのでソースも長くならないですし。何より簡単です。
Re: 文字にグラデーション ( No.7 )
名前:チルチル 日時:2010/08/20 12:57

ピクセルごとにグラデーションを付けるのは 文字とそれ以外の部分を判別するのが大変なので無理だと思います と言うより1ピクセルずつ描画するのであれば 1行ずつ描画した方が速いと思いますが それでも毎ループに100個ぐらい表示すると 処理落ちしてしまうと思うので・・
Re: 文字にグラデーション ( No.8 )
名前:tare 日時:2010/08/20 13:06

判別も何もアルファ値をそのまま保持すれば問題なく塗れると思いますが。 更に上の手法は1pxごと描画するのではなく、予めグラデーションの掛かった画像を作り、その後作られた画像を表示するというものです。 過去記事の管理人さんの手法もしかり。 (ちなみに小範囲の100個程度の表示では最近のPCならばほぼ処理落ちしません) 事前に画像を作りたくないというならば恐らくSetDrawAreaでやる他ありません。 自分は管理人さんのソースをラップし、 MakeGradString(グラデーション文字を作る) DrawGradString(作ったグラデーション文字を描画する) DeleteGradString(作ったグラデーション文字を消す) というような関数を作って運用しています。
Re: 文字にグラデーション ( No.9 )
名前:チルチル 日時:2010/08/22 19:18

なるほど最近のPCなら許容できるんですね 確かに関数化すれば1行に収まりそうです 他に方法が無かったらその方法にするとして 本当に他の方法は無いんでしょうか? DXライブラリに関しても非公開関数などは 全く把握していないので良くわからないです・・
Re: 文字にグラデーション ( No.10 )
名前:いっち 日時:2010/08/22 23:08

マスクを使ってやってみました。ただし、マスクの処理は公式で遅いとされています。 また、Ver3.03では問題なく動作するのですが、最新のテストバージョンでは思ったような結果になりませんでした。 > ttp://nukkorosu.80code.com/img/nukkorosu16125.jpg > 管理人さん 最初はZBufferを利用して実現しようと思ったのですが、ZBufferに対して直接文字列を書き込む機能が見当たりませんでした。 この機能を追加することは可能でしょうか? 需要があるか分かりませんし、現状で代替可能なので、難しかったりお忙しいようであれば忘れてください。 よろしくお願いします。 //- 以下、テストコード ("tex1.bmp"、"testMask.bmp"を使用) -// #include "DxLib.h" int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { ChangeWindowMode( TRUE ); if ( DxLib_Init( ) == -1 ) return -1; SetDrawScreen( DX_SCREEN_BACK ); SetFontCacheToTextureFlag( FALSE ); int fh = CreateFontToHandle( NULL, 20, 3 ); SetFontCacheToTextureFlag( TRUE ); int gh = LoadGraph( "tex1.bmp" ); CreateMaskScreen( ); SetMaskReverseEffectFlag( TRUE ); int mh = LoadMask( "testMask.bmp" ); while ( ProcessMessage( ) == 0 && CheckHitKey( KEY_INPUT_ESCAPE ) == 0 ) { ClearDrawScreen( ); SetUseMaskScreenFlag( TRUE ); DrawMask( 0, 0, mh, DX_MASKTRANS_NONE ); DrawStringMaskToHandle( 0, 20, 1, fh, "TEST" ); DrawGraph( 0, 0, gh, TRUE ); SetUseMaskScreenFlag( FALSE ); ScreenFlip( ); } DeleteMaskScreen( ); DxLib_End( ); return 0; }
Re: 文字にグラデーション ( No.11 )
名前:チルチル 日時:2010/08/25 18:29

なるほどマスクを使う方法もあったんですね 今までは使い道がわからなかったんですが マスク処理も色々と使えそうです DrawStringMaskToHandle関数は非公開関数なので見落としていましたが 文字の形をしたマスクというのも面白そうです でもマスク処理は重いという事なので 今までの方法の描画時間を計測して速い方法を使ってみたいと思います 皆様どうもありがとうございました
Re: 文字にグラデーション ( No.12 )
名前:管理人 日時:2010/08/26 08:56

> チルチルさん DXライブラリで描画する文字列に細工する場合、汎用性の高い文字列描画でしたらZバッファを使った方法が一番高速です が、いっちさんもご指摘の通り今までZバッファに文字列を書き込む機能が無かったのでその方法は使えませんでした Zバッファに文字列を書き込むための関数を追加したバージョンをアップしましたので、よろしければダウンロードしてください m(_ _)m http://homepage2.nifty.com/natupaji/DxLib/DxLibVCTest.exe // VisualC++ 用 http://homepage2.nifty.com/natupaji/DxLib/DxLibBCCTest.exe // BorlandC++ 用 (中身を既存のライブラリのファイルに上書きして、BCCをお使いの 場合は『再構築』、VCをお使いの場合は『リビルド』をして下さい) Zバッファに文字列を書き込む機能を利用してグラデーションの掛かった文字列を描画するプログラムは こちらのような感じになります #include "DxLib.h" // グラデーション文字描画関数 void DrawGradationString( int x, int y, const char *String, int Color1, int Color2 ) { int w, h, r1, g1, b1, r2, g2, b2 ; VERTEX vert[ 6 ] ; // 描画のサイズを取得する w = GetDrawStringWidth( String, -1 ); h = GetFontSize() ; // Zバッファを有効にする SetUseZBufferFlag( TRUE ); // Zバッファに描画する文字列より少し大きいマスクを書き込む DrawBoxToZBuffer( x - 2, y - 2, x + w + 2, y + h + 2, TRUE, DX_ZWRITE_MASK ); // Zバッファに文字列の形でマスクを刳り貫く DrawStringToZBuffer( x, y, String, DX_ZWRITE_CLEAR ); // カラーコードからRGB各成分の取得 GetColor2( Color1, &r1, &g1, &b1 ) ; GetColor2( Color2, &r2, &g2, &b2 ) ; // 画像の大きさのグラデーションボックスを描画する( マスクが刳り貫かれているところしか塗りつぶされない ) vert[ 0 ].u = 0.0f ; vert[ 0 ].v = 0.0f ; vert[ 1 ].u = 0.0f ; vert[ 1 ].v = 0.0f ; vert[ 2 ].u = 0.0f ; vert[ 2 ].v = 0.0f ; vert[ 3 ].u = 0.0f ; vert[ 3 ].v = 0.0f ; vert[ 1 ].r = vert[ 0 ].r = r1 ; vert[ 1 ].g = vert[ 0 ].g = g1 ; vert[ 1 ].b = vert[ 0 ].b = b1 ; vert[ 2 ].r = vert[ 3 ].r = r2 ; vert[ 2 ].g = vert[ 3 ].g = g2 ; vert[ 2 ].b = vert[ 3 ].b = b2 ; vert[ 2 ].x = vert[ 0 ].x = x - 1 ; vert[ 3 ].x = vert[ 1 ].x = x + w + 1 ; vert[ 1 ].y = vert[ 0 ].y = y - 1 ; vert[ 3 ].y = vert[ 2 ].y = y + h + 1 ; vert[ 4 ] = vert[ 2 ] ; vert[ 5 ] = vert[ 1 ] ; DrawPolygon( vert, 2, DX_NONE_GRAPH, FALSE ) ; // Zバッファを無効にする SetUseZBufferFlag( FALSE ); } // WinMain関数 int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { // ウインドウモードで起動 ChangeWindowMode( TRUE ); // DXライブラリの初期化 if( DxLib_Init() == -1 ) return -1; // 描画先を裏画面にする SetDrawScreen( DX_SCREEN_BACK ); // 赤から緑のグラデーションが掛かった文字列を描画する DrawGradationString( 100, 200, "グラデーション文字列", GetColor( 255, 0, 0 ), GetColor( 0, 255, 0 ) ) ; // 裏画面の内容を表画面に反映 ScreenFlip(); // キー入力待ち WaitKey() ; // DXライブラリの後始末 DxLib_End() ; // ソフトの終了 return 0 ; } ただ、こちらのZバッファを使用した方法も、いっちさんが紹介して下さったマスクを使った方法も アンチエイリアス付きの文字列描画では使うことができません アンチエイリアス付きの文字列描画でグラデーションを掛けたい場合はいっちさんが No.2 で 書き込んで下さったスレッド http://hpcgi2.nifty.com/natupaji/bbs/patio.cgi?mode=past&no=1366 に書かれている方法がDXライブラリでは最も高速です > いっちさん ご指摘ありがとうございます、危うくマスク機能が全く使えない状態で次のバージョンを リリースしてしまう所でした orz Zバッファに対する文字列の書き込みは、需要があるかどうかは微妙ですが、マスクに対しても 文字列の描画機能があるのと、殆どプログラムコードの追加無しで実現できそうだったので Zバッファに文字列を書き込むための関数を追加しました もしよろしければお試しになってみて下さい m(_ _)m ( 追加した関数の名前は DrawString 系の関数の最後に ToZBuffer が足されたものとなっています ) http://homepage2.nifty.com/natupaji/DxLib/DxLibVCTest.exe // VisualC++ 用 http://homepage2.nifty.com/natupaji/DxLib/DxLibBCCTest.exe // BorlandC++ 用 (中身を既存のライブラリのファイルに上書きして、BCCをお使いの 場合は『再構築』、VCをお使いの場合は『リビルド』をして下さい)
Re: 文字にグラデーション ( No.13 )
名前:いっち 日時:2010/08/26 19:16

修正確認しました。 文字列のZバッファ出力についても、早速の対応ありがとうございました。
Re: 文字にグラデーション ( No.14 )
名前:チルチル 日時:2010/08/27 10:18

≫管理人様 サンプルありがとうございます これはキレイなグラデーションですね 最初は「平面なのに何でZバッフア?」って思ったんですけど 良く考えたらDXライブラリは2D描画も3D機能の応用で実現しているのでこういう使い方もできるんですね アンチエイリアスが使えないのは残念ですけど あちらの方も最速との事なので これらを使わせてもらおうと思ったのですが できれば書式付文字列にも対応させたいので DxLib.hの中から使われている関数の 書式付バージョンと思われるものを探して サンプルを改造してみたのですが sprintf関数は使わない方がスッキリすると思って 可変長引数の橋渡しを試みたところ GetDrawFormatStringWidth関数では成功しましたが DrawFormatStringToZBuffer関数で失敗しているようなのです 橋渡しは可能だと思うのですが 非公開関数の仕様は名前から予想したので 使い方が間違っているかもしれません 以下のコードなのですがどこか間違っているでしょうか? #include "DxLib.h" // グラデーション文字描画関数 void DrawGradationString( int x, int y, int Color, const char *String, ... ) { int w, h, r, g, b; VERTEX vert[ 6 ] ; // 描画のサイズを取得する w = GetDrawFormatStringWidth( String ); h = GetFontSize() ; // Zバッファを有効にする SetUseZBufferFlag( TRUE ); // Zバッファに描画する文字列より少し大きいマスクを書き込む DrawBoxToZBuffer( x - 2, y - 2, x + w + 2, y + h + 2, TRUE, DX_ZWRITE_MASK ); // Zバッファに文字列の形でマスクを刳り貫く DrawFormatStringToZBuffer( x, y, DX_ZWRITE_CLEAR, String ); // カラーコードからRGB各成分の取得 GetColor2( Color, &r, &g, &b ) ; // 画像の大きさのグラデーションボックスを描画する( マスクが刳り貫かれているところしか塗りつぶされない ) vert[ 0 ].u = 0.0f ; vert[ 0 ].v = 0.0f ; vert[ 1 ].u = 0.0f ; vert[ 1 ].v = 0.0f ; vert[ 2 ].u = 0.0f ; vert[ 2 ].v = 0.0f ; vert[ 3 ].u = 0.0f ; vert[ 3 ].v = 0.0f ; vert[ 1 ].r = vert[ 0 ].r = 255 ; vert[ 1 ].g = vert[ 0 ].g = 255 ; vert[ 1 ].b = vert[ 0 ].b = 255 ; vert[ 2 ].r = vert[ 3 ].r = r ; vert[ 2 ].g = vert[ 3 ].g = g ; vert[ 2 ].b = vert[ 3 ].b = b ; vert[ 2 ].x = vert[ 0 ].x = x - 1 ; vert[ 3 ].x = vert[ 1 ].x = x + w + 1 ; vert[ 1 ].y = vert[ 0 ].y = y - 1 ; vert[ 3 ].y = vert[ 2 ].y = y + h + 1 ; vert[ 4 ] = vert[ 2 ] ; vert[ 5 ] = vert[ 1 ] ; DrawPolygon( vert, 2, DX_NONE_GRAPH, FALSE ) ; // Zバッファを無効にする SetUseZBufferFlag( FALSE ); } // WinMain関数 int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { // ウインドウモードで起動 ChangeWindowMode( TRUE ); // DXライブラリの初期化 if( DxLib_Init() == -1 ) return -1; // 描画先を裏画面にする SetDrawScreen( DX_SCREEN_BACK ); // グラデーションが掛かった文字列を描画する DrawGradationString( 100, 200, GetColor( 255, 0, 0 ), "%s", "グラデーション文字列" ) ; // 裏画面の内容を表画面に反映 ScreenFlip(); // キー入力待ち WaitKey() ; // DXライブラリの後始末 DxLib_End() ; // ソフトの終了 return 0 ; } そしてNo.2のスレッドのサンプルも とりあえず関数化してみて 見た感じは問題無く動いている感じですが 何か間違っている所はあるでしょうか? 一応、毎回やると重そうなものはstaticにして 残ってしまいそうなものは解放したつもりなのですが・・ #include "DxLib.h" // グラデーション文字描画関数 void DrawGradationString( int x, int y, const char *String, int Color, int FontHandle ) { int ImageHandle, EdgeImageHandle, DrawWidth ; VERTEX Vertex[ 6 ] ; int r, g, b ; // カラーコードからRGB各成分の取得 GetColor2( Color, &r, &g, &b ) ; int FontSize ; GetFontStateToHandle( NULL , &FontSize , NULL , FontHandle ) ; FontSize+=2; // 文字列イメージを転送する ARGB8形式の画面サイズのメモリイメージを作成( 縁用と二つ ) static int SoftImage = MakeARGB8ColorSoftImage( 640, 480 ) ; static int EdgeSoftImage = MakeARGB8ColorSoftImage( 640, 480 ) ; // 作成したメモリイメージを0で塗りつぶす FillSoftImage( SoftImage, 0, 0, 0, 0 ) ; FillSoftImage( EdgeSoftImage, 0, 0, 0, 0 ) ; // 文字列イメージをメモリイメージに書き込む BltStringSoftImageToHandle( x, y, String, SoftImage, EdgeSoftImage, FontHandle, FALSE ) ; // 描画幅を取得する DrawWidth = GetDrawStringWidthToHandle( String, lstrlen( String ), FontHandle ) ; // 描画幅と描画高さのグラフィックハンドルを作成する ImageHandle = CreateGraphFromRectSoftImage( SoftImage, x, y, DrawWidth, FontSize ) ; EdgeImageHandle = CreateGraphFromRectSoftImage( EdgeSoftImage, x, y, DrawWidth, FontSize ) ; // 縁の部分は黒色で描画 SetDrawBright( 0, 0, 0 ) ; DrawGraph( x, y, EdgeImageHandle, TRUE ) ; SetDrawBright( 255, 255, 255 ) ; // 本体部分は DrawPolygon を使用して上下に赤から青にグラデーションさせながら描画 Vertex[ 0 ].x = x - 0.5f ; Vertex[ 0 ].y = y - 0.5f ; Vertex[ 1 ].x = x + DrawWidth - 0.5f ; Vertex[ 1 ].y = y - 0.5f ; Vertex[ 2 ].x = x - 0.5f ; Vertex[ 2 ].y = y + FontSize - 0.5f ; Vertex[ 3 ].x = x + DrawWidth - 0.5f ; Vertex[ 3 ].y = y + FontSize - 0.5f ; Vertex[ 0 ].u = 0.0f ; Vertex[ 0 ].v = 0.0f ; Vertex[ 1 ].u = 1.0f ; Vertex[ 1 ].v = 0.0f ; Vertex[ 2 ].u = 0.0f ; Vertex[ 2 ].v = 1.0f ; Vertex[ 3 ].u = 1.0f ; Vertex[ 3 ].v = 1.0f ; Vertex[ 0 ].b = 255 ; Vertex[ 0 ].g = 255 ; Vertex[ 0 ].r = 255 ; Vertex[ 0 ].a = 255 ; Vertex[ 1 ].b = 255 ; Vertex[ 1 ].g = 255 ; Vertex[ 1 ].r = 255 ; Vertex[ 1 ].a = 255 ; Vertex[ 2 ].b = b ; Vertex[ 2 ].g = g ; Vertex[ 2 ].r = r ; Vertex[ 2 ].a = 255 ; Vertex[ 3 ].b = b ; Vertex[ 3 ].g = g ; Vertex[ 3 ].r = r ; Vertex[ 3 ].a = 255 ; Vertex[ 4 ] = Vertex[ 2 ] ; Vertex[ 5 ] = Vertex[ 1 ] ; DrawPolygon( Vertex, 2, ImageHandle, TRUE, TRUE ) ; DeleteSoftImage( ImageHandle ) ; DeleteSoftImage( EdgeImageHandle ) ; } // WinMain関数 int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { // ウインドウモードで起動 ChangeWindowMode( TRUE ); // DXライブラリの初期化 if( DxLib_Init() == -1 ) return -1; // 描画先を裏画面にする SetDrawScreen( DX_SCREEN_BACK ); // 縁つきアンチエイリアスフォントの作成 int FontHandle = CreateFontToHandle( NULL, -1, -1, DX_FONTTYPE_ANTIALIASING_EDGE ) ; // グラデーションが掛かった文字列を描画する for( int x=0;x<2;x++ )for( int y=0;y<20;y++ )DrawGradationString( x*320, y*20, "グラデーション文字列", GetColor( 255, 0, 0 ), FontHandle ) ; // 裏画面の内容を表画面に反映 ScreenFlip(); // キー入力待ち WaitKey() ; // DXライブラリの後始末 DxLib_End() ; // ソフトの終了 return 0 ; } あと、こちらも書式付文字列に対応させようと思って関数を探したのですが BltStringSoftImageToHandle関数の書式付バージョンが見当たりませんでした これに関してはsprintfを使うしかないでしょうか?

Page: 1 | 2 |