忍者ブログ

Memeplexes

プログラミング、3DCGとその他いろいろについて

[PR]

×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。


かんたんXNA4.0 その2 背景のクリア

前回では、ウィンドウが全く描画を行っていませんでした。
そのため、XP以前の環境だと他のウィンドウに隠されると跡が残ってたいへん見苦しいものでした。

これではいけません!

このような跡はすぐに消せるようにならなければなりません。
それが出来るようになったのが、以下のコードです:

using Microsoft.Xna.Framework;

class MyGame : Game
{
    GraphicsDeviceManager graphics;

    public MyGame()
    {
        graphics = new GraphicsDeviceManager(this);
    }

    protected override void Draw(GameTime gameTime)
    {
        GraphicsDevice.Clear(Color.CornflowerBlue);
    }

    static void Main()
    {
        using (MyGame game = new MyGame())
        {
            game.Run();
        }
    }
}

xna4.0SimplestClearable.jpg

このプログラムは、一秒間に60回背景を空色で塗りつぶしています。
それをやっているのがDrawメソッドですが、こいつは一秒間に大体60回呼ばれるのです。

これだけひんぱんに背景を消しているので、もう他のウィンドウに隠されても大丈夫です。
(Vista以降だと何もしなくても大丈夫ですが)

さて、注目すべきは一秒間に60回塗りつぶしているという部分です。
XP以前の普通のプログラム、WindowsFormsなどでは、他のウィンドウに隠れたときなど、描画すべきときにしか描画しませんでした。
しかし、XNAではそのようにはしません。
狂ったように、何も変化が無くても、とりあえず60回描画します
ゲームプログラミングとは、そのようなものだということです。

もう少し細かいところに注目してみましょう。
このプログラムでは、まずMicrosoft.Xna.Framework.GraphicsDeviceManagerのインスタンスを作成しています。
これは、ゲームのウィンドウのサイズやフルスクリーン、それと描画全般を行うGraphicsDeviceを管理するマネージャーです。
(管理(マネージ)するマネージャーとは変な表現ですが、まぁ大目に見てください)

重要なのはこのクラスというよりも、そのプロパティからアクセスできる、GraphicsDeviceです。
このGraphicsDeviceは役割としてはちょうどWin32でいうHDCやWindowsFormsやJavaのGraphicsクラスのようなものです。
つまり、描画はこれを通じて行うのです。
点を表示するにも、線を表示するにも、2D画像を表示するにも、3Dのモデルを表示するにもこのGraphicsDeviceが必要です。
(もっとも、2Dの場合はカプセル化されていて、描画の時には意識する必要はありませんが)

このプログラムではGraphicsDevice.Clearを使って、ウィンドウのクライアント領域を空色で塗りつぶしています。
もちろん色は別に空色でなくてもかまいません。
でもでも黒でもかまいませんが、Xnaの多くのサンプルでは、空の色に似ているからでしょうか、Color.CornflowerBlueを使っています。
多数決の原則(?)により、次回からもColor.CornflowerBlueを使うことにします。

 

拍手[2回]

PR

かんたんXNA4.0 その1 ウィンドウの表示

XNAを簡単なレベルから少しずつ整理していこうと思います。
まずは一番簡単なプログラムから。
class MyGame : Microsoft.Xna.Framework.Game
{
    static void Main()
    {
        using (MyGame game = new MyGame())
        {
            game.Run();
        }
    }
}

これはおそらくXNAの最も簡単なプログラムで、
Gameクラス(を継承したMyGameクラス)のオブジェクトを作り、Runメソッドを呼んでいます。
実行すると(ゲームの)ウィンドウが表示されるだけです。

xna4.0Simplest.jpg

Vista以降では何の面白みもないウィンドウですが、XP以前だと面白い現象が見られます。
他のウィンドウで覆い隠すとこんな風に跡が残ってしまうのです。
これは描画を全くしていないからですね。

xnaSimplestCovered.JPG

※ちなみに(どうでもいいことですが)、このウィンドウのタイトルはMyGameとなっていますが、これはクラスの名前ではなくて実行ファイルの名前に関係しているようです。
というのも、このコードをコンパイルして出来たプログラムは"MyGame.exe"だったのですが、この名前を"Game.exe"に変更するとタイトルはGameになったからです。

ただ、これはコマンドラインから普通にコンパイルした場合の話で、VisualC#を使った場合には、AssemblyInfo.csのAssemblyTitleがタイトルを表しているようです。

拍手[0回]


かんたんXNA4.0 (XNA入門)

XNA入門:かんたんXNA
をXNA4.0用に書きなおそうと思います。
  1. ウィンドウの表示
  2. 背景のクリア
  3. 2D画像の表示
  4. 画像ファイルを表示
  5. 三角形の表示
  6. 3D三角形の表示
  7. アニメーション
  8. 3Dカメラのアニメーション
  9. キーボード入力
  10. 3D四角形
  11. VertexBuffer
  12. Game.Initializeメソッド
  13. IndexBuffer
  14. テクスチャ三角形
  15. 簡単なライティング
  16. ワイヤーフレーム
  17. 透過パーティクル
  18. BasicEffectで平行光
  19. マテリアル
  20. 深度バッファ
  21. 深度バッファへの書き込み
  22. 深度バイアス
  23. 深度バッファ関数
  24. アルファ・ブレンディング
  25. ブレンド関数
  26. ステンシル・バッファ
  27. ビューポートで分割スクリーン
  28. テクスチャへの描画 RenderTarget
  29. カスタム頂点
HLSL編
  1. エフェクトファイル
  2. 構造体
  3. スカラーとベクトル型
  4. フロー制御文
  5. グローバル変数
  6. マトリックス
  7. テクスチャ

拍手[12回]


XNAで音を合成 DynamicSoundEffectInstanceクラス

突然ですが、 XNA4.0では自在に音を合成できるクラスが用意されているようです。
自在に合成とは一体何を言っているのかというと、こういうことです。

これまでXNAではたしか予め録音された音しか再生できなかったと思います。
ものが爆発した音なら爆発音を最初からファイルに保存しておいてそれを必要なときに再生するという形でした。
しかし新しいMicrosoft.Xna.Framework.Audio.DynamicSoundEffectInstanceクラスはちがいます。
波形データをリアルタイムで作って、それを再生できるのです。

もしかすると物理世界をシミュレートして、その結果として音を鳴らすというようなことが出来るかもしれませんね。
先程の例で言うと爆発時の空気の振動を計算してそれを使えるかもしれませんん。
あるいは音声の合成とかゲームとは別のベクトルで面白そうです。

ではやってみましょう。

using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;

namespace XnaDynamicAudio
{
    static class Program
    {
        static void Main(string[] args)
        {
            const int samplePerSecond = 8000;
            const int secondsToPlay = 3;

            using (DynamicSoundEffectInstance dynamicSound = new DynamicSoundEffectInstance(samplePerSecond, AudioChannels.Mono))
            {
                byte[] buffer = createAWave(samplePerSecond, secondsToPlay, 440);
                dynamicSound.SubmitBuffer(buffer);
                FrameworkDispatcher.Update();
                dynamicSound.Play();
                System.Threading.Thread.Sleep(secondsToPlay * 1000);
            }
        }

        private static byte[] createAWave(int samplePerSecond, int secondsToPlay, int heltz)
        {
            byte[] buffer = new byte[samplePerSecond * secondsToPlay];

            for (int i = 0; i < buffer.Length; i++)
            {
                buffer[i] = (byte)(
                    byte.MaxValue / 4 * (1 + Math.Sin((Math.PI * heltz) * i / samplePerSecond))
                    );
            }

            return buffer;
        }
    }
}



このサンプルプログラムを実行すると、ピーという音が鳴ります。
440Hzのサイン波。
つまり、ラの音です。


クラス

このサンプルプログラムに登場した重要なクラスは2つ有ります。
DynamicSoundEffectInstanceクラスとFrameworkDispatcherクラスです。

DynamicSoundEffectInstanceはダイナミックな再生を司るクラスだからいいとして、FrameworkDispatcherとはなんでしょう?
これはXNAで使うコンポーネントを管理するらしく、普段は内部で呼ばれているようです。

が、今回のプログラムのように、「XNAは使うけれどGameは使わないよ」というような場合にはFrameworkDispatcher.Updateメソッドを自分で呼ばなければならないのです。
これは1フレームに一回の呼び出しが推奨されています

拍手[2回]


[XNA]パラレル・スプリット・シャドウマップで影の解像度を上げる


ここにあるパラレル・スプリット・シャドウマップなるもののデモを少しリファクタリングしてみました。(この記事を書いてから何度か変更しています)

PssmDemo2.0.zip(XNA Game Studio 2.0)

マーチンファウラーさんによれば、他人の書いたコードを理解するのにリファクタリングは役に立つそうですしね。



パラレル・スプリット・シャドウマップ

パラレル・スプリット・シャドウマップというのは、シャドウマップで作った影をくっきり見せるためのテクニックの一つで、2006年から2007年にかけて、香港中文大学のFan Zhangさんとその愉快な仲間たちによって考案されたものです。日本語に訳すとしたら「平行分割シャドウマップ」といったところでしょうか…?。普通のシャドウマップは影にカメラを近付けると影がジャギジャギになってしまうので、「それならシャドウマップをいくつかに分割して、カメラに近いところは高い解像度にすればいい!」というのが基本的なアイデアです。そういう意味で、3DMark2006のカスケード・シャドウマップに似ていると言えます。

もう少し詳しく見ていきます。そもそもなぜこのパラレル・スプリット・シャドウマップというのが考え出されたのかというと、フツーのシャドウマップには影がジャギジャギになるという問題があるからです。

sm.jpg
普通のシャドウマップです。遠くの影はそうでもありませんが、手前の影はでこぼこが目立ちます。

これはシャドウマップの精度が足りないからです。もちろんシャドウマップの解像度を上げればこのジャギジャギは緩和されますが、それではビデオメモリを食いまくります。

そこでどうするのかというと、カメラに写っている空間を何分割かして、それぞれの領域のシャドウマップを別々に作ってやります。

pssmDesc1.jpg

この分割がミソで、この分割を上手くやらないと効果はありません。といっても難しいことはなく、ようするにカメラに近いところは小さく区切って、カメラから遠いところは大きく区切ればいいのです。そうすれば自動的に、近いところのシャドウマップは高解像度に、遠いところのシャドウマップは低解像度になります(もちろんこれはすべてのシャドウマップのサイズが同じ場合です。分割を同じようにやって、なおかつシャドウマップのサイズを近いところは大きく、遠いところは小さく、というふうにしても同じような結果が得られるでしょう)。そうすると…近いところの影も鮮明に描けます!めでたしめでたしというわけです。


2分割の場合
split2.jpg
すばらしいですね。影がぐっとはっきりしてきました。

3分割
split3.jpg
2分割のときほど劇的な変化はありませんが、それでもさらに影がはっきりしています。


PSSM公式(?)サイトにあるXNAのサンプルでは1つのレンダーターゲットを各シャドウマップに使いまわして描画しています。つまり、シャドウマップ1を描画、空間1の物体を影付きで描画、シャドウマップ2を描画、空間2の物体を影付きで描画……ということを繰り返しています。ということは「空間の分割数 * 2」のDrawコールが必要です。これはCPUがボトルネックになりそうです。

シャドウマップ1を描画 → 空間1の物体を描画 →
シャドウマップ2を描画 → 空間2の物体を描画 →
シャドウマップ3を描画 → 空間3の物体を描画 →
…以下略

もっとも、シャドウマップを別々のレンダーターゲットに描画して、それをテクスチャの配列としてEffectにセットして、シーンを一気に描画するという方法も使えるはずです(ということがZhangさんの文に書いてました)。この方法なら「空間の分割数 + 1」ですみますからね。


拍手[0回]