ページ 1 / 1
暗い中、一部分だけ光っているように表現するには?
Posted: 2009年6月27日(土) 16:09
by 山崎
お世話になっております、山崎です。
今回は、一部分だけ光っているように表現する方法について伺いに参りました。
現在、「夜の暗いフィールド上のあるオブジェクトが光を放って、そこだけ丸く明るくなっている」
という表現をしたいと思っています。
私の今作っているゲームの1フレーム中での大きな流れは、
0.ClearDrawScreen()
1.マップデータを元にマップチップを配置し、フィールドを描画する
2.フィールド上にオブジェクトを描画する
3.フィールド上の個々のオブジェクト内の処理をする(移動、当たり判定など)
4.ゲーム内の天気を画面全体に描画
5.ゲーム内の時間によって、画面全体の暗さを変化させる(昼ならそのまま、夜なら黒く)
6.ScreenFlip()
このように、フィールド上のオブジェクトを描画した後、画面全体に対して黒をブレンドし
夜の暗さを表現しております。ブレンドの方式はアルファブレンドを使っています。
夜の暗さの表現は、フィールドとオブジェクトと天気の描画の後、下のコードのように行っています。
if(Night<=Time || Time<Morning)//夜ならば
{
SetDrawBlendMode(DX_BLENDMODE_ALPHA,150);
DrawBox(0,0,640,480,GetColor(0,0,0),TRUE);//画面を暗くする
}
光を放つあるオブジェクトをフィールドに配置して、
夜暗くなってもそのオブジェクトの周りだけ昼間のように明るいままにしたいと考えていますが、
どのようにすればいいのかと悩んでおります。
このとき、オブジェクトの中心に近いほどぼうっと明るく、中心から遠いほど暗い、といった表現にしたいです。
明るいままにしたいというのは、そのオブジェクトの周りだけ丸く、あるいは楕円形に
黒がブレンドされない、という感じです。
SetDrawArea()の使用を考えたのですが、これでは矩形にしか描画領域を設定できません。
マスク処理も考えてはいるのですが、この処理は重いため、
最後の手段にしようと考えています。
どのような手法を使えば、暗い画面の一部分だけ丸く明るく表現できるのでしょうか。
Re:暗い中、一部分だけ光っているように表現するには?
Posted: 2009年6月27日(土) 17:12
by patei
龍神録のEDみたいに一部分だけ明るくってことですか?
Re:暗い中、一部分だけ光っているように表現するには?
Posted: 2009年6月27日(土) 17:13
by ねこ
自己流ですが添付した画像を使用しています。
1.通常の描画を行う。
2.画像の左側を明るい部分の中央に描画
3.画像の右側を明るい部分の中央に描画
4.暗い部分を矩形で黒塗り描画
画像はグラデーションで円を黒で描いたものです。
中央~中間~外枠で0%~0%~100%で描いています。
本来左右に分けなくてもいい気がするんですが、なんとなく分けてます。
透明度を使えば、段々暗く。という手法も出来ます。
楕円の場合は描画関数のどれかを使ってX方向を延ばす感じで。
Re:暗い中、一部分だけ光っているように表現するには?
Posted: 2009年6月27日(土) 18:17
by Libra
ねこさんの画像の白黒を反転させた画像を用いて、
減算ブレンドを使ってみてはいかがでしょうか?
Re:暗い中、一部分だけ光っているように表現するには?
Posted: 2009年6月27日(土) 19:19
by 山崎
pateiさん、ねこさん、Libraさん、ご返信誠にありがとうございます。
>pateiさん
申し訳ないながら、龍神録は人がプレイしているのを脇から見たことはあるのですが、
自分でプレイしたことがありません。
エンディングがどんな感じなのかわからないので…申し訳ないです。
>ねこさん
ご紹介頂いた画像を用いて試してみたところ、
見事に一部分だけ明るいままにすることに成功しました。
本当にありがとうございます!!
楕円にするやり方も後ほど試していこうと思っています。
これに関してもうひとつ質問したいのですがよろしいでしょうか。
最後に、光っている部分以外の領域を黒で暗くするとき、
光っている部分だけをよけて矩形で画面全体を黒で塗っていくと、
何回かに分けて画面を塗っていかなければいけないですよね。
光っている部分が1つなら4回のDrawBox()で画面全体を塗りつぶすことになります。
もし光っている部分が複数あると、この画面を暗く塗りつぶす作業が大変になると思うのですが、
これを避ける手法はありますでしょうか?
SetDrawArea()が「描画できる領域のセット」ではなく「描画されない領域のセット」
だったら1度の塗りつぶしで光っている部分以外の画面全体を塗りつぶせるのですが…。
ところでもうひとつ、添付していただいた画像についてお伺いしたいのですが、
どのようにすれば、あのような画像を作成・編集できるのでしょうか?
先ほど、ペイントで読み込んで編集しようとしたところ、
画像が全て真っ黒になってしまいました。
また、私は訳あって赤を透過色にしているのですが、
添付していただいた画像は背景部分が白なのに
私のプログラムで読み込んでもちゃんと白い部分が透過されました。
どのようなテクニックを用いているのでしょうか…?
(記事一回編集しました。質問を追加しました。)
Re:暗い中、一部分だけ光っているように表現するには?
Posted: 2009年6月27日(土) 19:51
by yu
>>どのようにすれば、あのような画像を作成・編集できるのでしょうか?
>>先ほど、ペイントで読み込んで編集しようとしたところ、
>>画像が全て真っ黒になってしまいました。
pngにはαチャンネルというものがあって
不透明度の値を保存しています。
α値が高いほど不透明です (確か;
windowsに付属で付いているペイントではαチャンネルは確か扱えないので
フリーのペイントソフトで編集するのをお勧めします
自分は Gimp を使っています
フリーですが中々高機能だと思います
Re:暗い中、一部分だけ光っているように表現するには?
Posted: 2009年6月27日(土) 20:29
by ねこ
>山崎さん
<透過
透過はyuさんも言われてますようにαチャンネルという要素があり
上手く説明できないのですが、白い部分は「透明」なので画像を描画しても何も表示されない状態になっています。
<作成・編集
私の作成方法はAdobe FLASH CS4で作画⇒PNGで書き出しという形を取っています。
PNG画像となっているため、書き出した画像から再編集は難しいです。
またグラフィック系ツールはAdobe製品のFLASHとPhotoShopで作業しているため
作成について、フリーで出来るようなものとかがちょっと分かりません。
yuさんの仰るGimpというツールを見てみたところPhotoShopに近い感じなのでいけそうかなぁと。
すいません、確信が持てません(汗)
作業したFLASH CS4には30日無料体験版というのもありますので、
フリーで難しかったらお試しに落として見るのも良いかもしれません。
<複数の場合
すいません、僕もその問題は解決できていません。
理論的には画面全体への黒塗りに対してLibraさんのいうような減算処理を複数加えて、最終的に描画すればいいのだと思うのですが
その方法を見つけるに至っていません。
また、複数の場合は明るい部分が重なった時、添付した画像をそのまま描画すると重なって変な表示になります。複数の場合だと減算処理は最終的に必須になります。
Re:暗い中、一部分だけ光っているように表現するには?
Posted: 2009年6月27日(土) 22:41
by チルチル
横から失礼します
>>もし光っている部分が複数あると、この画面を暗く塗りつぶす作業が大変になると思うのですが
流れが良く理解できていないので全然違うことを言ってるかもしれませんが
画面全体を暗くした後にオブジェクトの周りだけ加算ブレンドすれば良いんじゃないでしょうか?
Re:暗い中、一部分だけ光っているように表現するには?
Posted: 2009年6月27日(土) 23:03
by Libra
ペイントで編集するのであれば、自分は「Logo!」
というフリーソフトを使っています。
本来の使い方ではないのですが、背景のグラデーション機能を
使って画像を作ることができます。
左:減算ブレンドすれば、黒い部分が出て見える
右:こんな画像も設定で作れます。
(Windowsペイント編集可)
Re:暗い中、一部分だけ光っているように表現するには?
Posted: 2009年6月27日(土) 23:38
by yu
>>オブジェクトの周りだけ加算ブレンドすれば良いんじゃないでしょうか?
加算ブレンドは透明度が高くなるというわけでは無いと思うので
不可能だと思います・・・(間違ったこと言ってたらすみません;)
>>複数の場合
処理負荷を犠牲にしても良いならこんな方法でも一応・・・
ですが、完全な円ではないので荒いです;
後、今即席で作ったので多分どこかでおかしなことをしているかと思います。
実際に使うのなら是非自分で書き直してください;
今思いましたがこの方法なら DrawPolygonBase関数 でやらなくても普通にできそうですね;
Re:暗い中、一部分だけ光っているように表現するには?
Posted: 2009年6月28日(日) 00:45
by 山崎
yuさん、ねこさん、チルチルさん、Libraさん、ご返信誠にありがとうございます。
PNGファイルにもαチャンネルというものがあるんですね。
DXライブラリにαチャンネルという機能が事は知っていましたが、
PNGファイルにももともとその機能があるとは知りませんでした。
かなり役に立ちそうなので、機会があれば積極的に使っていきたいと思います。
お教え頂き本当にありがとうございます。
yuさんにご紹介いただいたGINPというフリーソフト、
早速ダウンロードさせていただきました。
まだ使い方はわかりませんが、これから試しに使っていこうと思います。
グラデーションができるペイントソフトを探していたので、非常に助かりました。
それで本題の明かりの表現なのですが、
画面全体をαブレンドで黒を塗る→オブジェクトの描画→オブジェクト周辺に白で加算ブレンド
画面全体を減算ブレンドで白を塗る→オブジェクトの描画→オブジェクト周辺に白で加算ブレンド
この二つを試してみましたが、どちらも満足のいく結果ではありませんでした。
ちょっと自信がないですが、ここでyuさんやLibraさんやねこさんがおっしゃる方法は、
1.画面にマップとオブジェクトを描画
2.中心が黒で外側が白のグラデーション円を、光らせたい部分に減算ブレンド
3.グラデーション円を描画した部分以外をSetDrawArea()で描画領域に指定
4.画面全体に黒をαブレンド
ということでよろしいでしょうか?
3の処理はやはり避けられないのでしょうか。
yuさんに添付していただいたコードですが、
こちらでビルドしてみたところ
LINK : warning LNK4098: defaultlib 'MSVCRTD' は他のライブラリの使用と競合しています。/NODEFAULTLIB:library を使用してください。
LIBCMTD.lib(dbgheap.obj) : error LNK2005: __CrtSetCheckCount は既に MSVCRTD.lib(MSVCR90D.dll) で定義されています。
など、39個のエラーが出てしまいました。
せっかく考えていただいたのに申し訳ございません・・・。
Re:暗い中、一部分だけ光っているように表現するには?
Posted: 2009年6月28日(日) 01:36
by Justy
[color=#d0d0ff"># 山崎さん[/color]
>夜暗くなってもそのオブジェクトの周りだけ昼間のように明るいままにしたいと考えていますが、
>どのようにすればいいのかと悩んでおります
こういうのはどうでしょう。
一応画面全体が暗くなって、10個のライトがうろちょろします。
mod_uploader
ttp://toku.xdisc.net/u/download/1246161160.zip
pass:qwer
----- 説明
・ libディレクトリに DXライブラリ一式を入れて下さい
・ slnは VisualStudio2008 SP1で作られていますので、それ以外の場合は開けないかもしれません。
その場合はソリューション・プロジェクトを作り直してください。
・ ソースコード上の BUILD_MORE_BRIGHTNESS定義を有効にするともう少し明るくなります。
具体的な処理は UserLoop()の中で行っているので、その処理を追ってください。
全体の暗くなる度合いは SetBackgroundColor()で調整出来ます。
2009/06/28 12:26 コードを修正
[color=#d0d0ff"># チルチルさん[/color]
>画面全体を暗くした後にオブジェクトの周りだけ加算ブレンドすれば良いんじゃないでしょうか
暗くなった画面に対する加算は(薄く暗くしたのならそんなに目立たないのですが)
色の範囲が狭くなった状態に対して加算することになるので、思っていたような絵に
ならない気がします。
Re:暗い中、一部分だけ光っているように表現するには?
Posted: 2009年6月28日(日) 01:41
by ねこ
やりたい事を疑似的に再現してみてました。
// 新画像ハンドル保持用グローバル変数
int g_Handle = -1;
// ===============================================
// [ 初期化時 ]
// 添付の画像を読み込む
int iLight = LoadGraph( ".\\Img\\Temp2.png" );
// 全体を白で塗潰す
DrawBox( 0, 0, 640, 480, RGB_WHITE, TRUE );
// サンプルに2ヵ所程描画する
DrawGraph( 100, 100, iLight );
DrawGraph( 400, 200, iLight );
// 画面の画像を取得
g_Handle = MakeGraph( 640, 480 );
GetDrawScreenGraph( 0, 0, 640, 480, g_Handle );
// スクリーンクリア
ClsDrawScreen();
// ===============================================
// [ 描画時 ]
// 現在で上記で作った画像を描画する
if( g_Handle != -1 )
{
SetDrawBlendMode( DX_BLENDMODE_SUB, 255 );
DrawGraph( 0, 0, g_Handle, TRUE );
SetDrawBlendMode( DX_BLENDMODE_NOBLEND, 0 );
}
山崎さんの作られてるものはスクロールもあると思うのですが、その場合は何枚か用意するって事でここでは割愛させてもらいます。
1.マップ変更時等の初期化処理で白塗りに明かりの箇所に添付した座標を描画しておく
2.明かりの箇所を描画し終えた時点での画面ハンドルを取得する
3.オブジェクト等描画後に「描画処理」の内容を描画する。真っ暗にするなら255、うっすら暗くするなら64等調整する。
スクロールする場合は何枚か作っておいてマップチップのようにずらして表示する。
なおこの処理の場合明かりが消灯する程度なら2枚用意したり出来ますが、
主人公キャラに合わせて変更(主人公キャラ周辺を明るくする)となるとリアルタイムに再取得する必要があるため処理負荷が高くなります。
一応これ使えないかなぁって思ってるのが「DrawBlendGraph」関数なんですが、
あんまり意味分かって無くて試せてません。
Re:暗い中、一部分だけ光っているように表現するには?
Posted: 2009年6月28日(日) 01:49
by ねこ
添付してなかった(汗) 添付します。
Re:暗い中、一部分だけ光っているように表現するには?
Posted: 2009年6月28日(日) 02:03
by ねこ
>Justyさん
スレ主さんじゃないですが感動しました。SetDrawScreenはこんな使い方もできるんですね。
そしてDrawGraphの引数にもなるとは・・・
今ある処理の中でも「手間」になってた処理を簡略化できそうです。大変参考になりました。
Re:暗い中、一部分だけ光っているように表現するには?
Posted: 2009年6月28日(日) 02:44
by Justy
>SetDrawScreenはこんな使い方もできるんですね
途中で描画先を切り替えられる、というのはいろいろ使いどころがありますよね。
難を言うなら、MakeScreen()は GPUの性能が低い場合……多分新たなレンダリング先の
バッファが用意できなくて……失敗することがあることでしょうか。
(今時のなら大丈夫だとは思いますが)
低スペックでも動くように作るならねこさんが書かれたような GetDrawScreenGraph()の方が
いいのかもしれません。
Re:暗い中、一部分だけ光っているように表現するには?
Posted: 2009年6月28日(日) 10:24
by yu
>>Justy様
他の画面に暗さとライトを描画してから
その画面を乗算ブレンドで裏画面に描画・・・
ねこ様と同じく、こんな使い方ができたのかと感動しました
非常に参考になりました~
Re:暗い中、一部分だけ光っているように表現するには?
Posted: 2009年6月28日(日) 10:28
by 山崎
Justyさん、ねこさん、ご返信誠にありがとうございます。
返答が遅くなって申し訳ございません、Justyさんに紹介頂いたプログラムを読み解いておりました。
>Justyさん
紹介頂いたコードを実行させて頂きました。
まず驚いたのは、丁寧にインデントやコメント、改行が施された見やすいソースコードです。
細部まで見やすくわかりやすいように気遣われていて、う~んとうなりながら読んでおりました。
教科書にでも載りそうな洗練されたコードだと感じました。
SetBackgroundColor、GetDrawBlendMode、SetDoubleStartValidFlag、MakeScreenなど
見慣れない関数に戸惑いましたが、なんとかプログラムを読み解くことができました。
1.MakeScreenでスクリーンをサブ画面として新たに用意する
2.サブ画面全体を暗く(黒く)塗りつぶし、光の部分だけを白く塗る
3.裏画面に背景やオブジェクトを描画する
4.裏画面にサブ画面を乗算ブレンドする
この処理をすることによって、部分的に明るくして、その部分以外を一度に暗くできるのですね。
大変勉強になりました。
早速この処理を私のゲームに実装させていただきます!
おかげさまで悩んでいたことが解決いたしました、感謝の言葉もございません!
>ねこさん
ねこさんに紹介頂いたコードも、是非とも参考にさせて頂きますね。
画像も添付していただき、本当にありがとうございました。
ところで、先ほど上であげたMakeScreenやSetDoubleStartValidFlagなどの関数なのですが、
これらの関数のリファレンスや説明などはどこかにあるのでしょうか?
DXライブラリのサイトのリファレンスを検索しましたが見当たりませんでした。
記事は今回で「解決!」にさせて頂きますが、
もしご存知の方がいらっしゃいましたら教えて頂けると幸いです。
Re:暗い中、一部分だけ光っているように表現するには?
Posted: 2009年6月28日(日) 10:31
by yu
>>これらの関数のリファレンスや説明などはどこかにあるのでしょうか?
非公開関数なのでリファレンスには無いと思います
ヘッダファイルにどのような関数なのかはコメントしてありますよ
Re:暗い中、一部分だけ光っているように表現するには?
Posted: 2009年6月28日(日) 10:47
by 山崎
yuさん、ご返信ありがとうございます。
先ほどDxLib.hの中を確認して参りました。
知らない関数がたくさんありましたが、中には使えそうなものもありました。
お教えいただき、ありがとうございます。
MakeScreenなど、リファレンスには載ってなくても使いどころのありそうな関数を
まとめたサイトやテキストファイルなどがあれば便利そうですね。
…もしかして既にあるのでしょうか。
でも本家のリファレンスに載っていないという事は、やはりあまり多用しない方がいいのでしょうかな。
Re:暗い中、一部分だけ光っているように表現するには?
Posted: 2009年6月28日(日) 11:18
by ねこ
>Justyさん
なるほど、負荷はGPUのメモリにかかっちゃうのですね。気を付けて使ってみようと思います。
>山崎さん
一時DxLibWikiみたいなものがあったようですが、なんか揉めて停止しちゃってますね。
その周辺にDxLib公式にない関数のリファレンスがちょこっとありました。
公式BBSを見ていると、何か要望があって管理人さんが対応した関数を作って
リファレンスには反映していない、というものが多いみたいです。
名前を見て気になる関数があったら、公式BBSで検索してみるとサンプルコード等見つかるかもしれません。
Re:暗い中、一部分だけ光っているように表現するには?
Posted: 2009年6月28日(日) 13:18
by Justy
>おかげさまで悩んでいたことが解決いたしました
解決して何よりです。
>関数のリファレンスや説明などはどこかにあるのでしょうか
一覧を見たい場合には使えないのですが、1つの関数の挙動の詳細を知りたい場合は
DxLibMakeの方のソースを追って調べるという手もあります。
いろいろあちこち飛ぶんで、慣れないと追いづらいんですが、確実です。