忍者ブログ

Memeplexes

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

[PR]

×

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


XNAで物理シミュレーション(JigLibX) その3

「その1」ではJigLibXのシステムを初期化しました。
「その2」では箱を描画しました。
今回、「その3」では、箱を動かします。

箱を動かすのはちょっとやっかいです。
あらたなクラスBoxActorを作ります。


プログラム

BasicWorldGame.cs
using Microsoft.Xna.Framework;
using JigLibX.Physics;
using JigLibX.Collision;

public class BasicWorldGame : Microsoft.Xna.Framework.Game
{
    GraphicsDeviceManager graphics;

    PhysicsSystem world;
    BoxActor fallingBox;
    BoxActor immovableBox;

    BoxRenderer boxRenderer;

    public BasicWorldGame()
    {
        graphics = new GraphicsDeviceManager(this);
        InitializePhysics();
    }

    private void InitializePhysics()
    {
        world = new PhysicsSystem { };
        world.CollisionSystem = new CollisionSystemSAP();

        fallingBox = new BoxActor(new Vector3(0, 20, 0), new Vector3(1, 1, 1));
        immovableBox = new BoxActor(new Vector3(0, -5, 0), new Vector3(5, 5, 5));
        immovableBox.Body.Immovable = true;

        world.AddBody(fallingBox.Body);
        world.AddBody(immovableBox.Body);
    }


    protected override void LoadContent()
    {
        boxRenderer = new BoxRenderer(GraphicsDevice);
    }

    protected override void UnloadContent()
    {
        boxRenderer.Dispose();
    }

    protected override void Update(GameTime gameTime)
    {
        world.Integrate(1f / 60);
        base.Update(gameTime);
    }

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

        boxRenderer.SetCamera(
            Matrix.CreateLookAt(
                new Vector3(5, 5, 40),
                new Vector3(),
                Vector3.Up
                ),
            Matrix.CreatePerspectiveFieldOfView(
                MathHelper.ToRadians(45),
                GraphicsDevice.Viewport.AspectRatio,
                0.1f,
                1000f
                )
            );
        drawBox(fallingBox);
        drawBox(immovableBox);

        base.Draw(gameTime);
    }

    private void drawBox(BoxActor box)
    {
        boxRenderer.Draw(box.GetWorldTransform());
    }
}
BoxActor.cs
using Microsoft.Xna.Framework;
using JigLibX.Physics;
using JigLibX.Collision;
using JigLibX.Geometry;
using JigLibX.Math;

public class BoxActor 
{
    private Vector3 scale;

    public Body Body { get; private set; }
    private CollisionSkin skin;

    public BoxActor(Vector3 position, Vector3 scale)
    {
        this.scale = scale;

        this.Body = new Body();
        this.skin = new CollisionSkin(this.Body);

        this.Body.CollisionSkin = this.skin;

        this.skin.AddPrimitive(
            new Box(Vector3.Zero, Matrix.Identity, scale),
            new MaterialProperties(
                0.8f, // elasticity
                0.8f, // static roughness
                0.7f  // dynamic roughness
            ));

        SetMass(1.0f);
        this.Body.MoveTo(position, Matrix.Identity);
    }

    private void SetMass(float mass)
    {
        PrimitiveProperties primitiveProperties = new PrimitiveProperties(
            PrimitiveProperties.MassDistributionEnum.Solid,
            PrimitiveProperties.MassTypeEnum.Mass,
            mass
            );

        float junk;
        Vector3 centerOfMass;
        Matrix inertiaTensor, inertiaTensorCenterOfMass;

        this.skin.GetMassProperties(
            primitiveProperties,
            out junk, 
            out centerOfMass,
            out inertiaTensor,
            out inertiaTensorCenterOfMass
            );

        this.Body.BodyInertia = inertiaTensorCenterOfMass;
        this.Body.Mass = mass;
        this.skin.ApplyLocalTransform(new Transform(-centerOfMass, Matrix.Identity));
    }

    public Matrix GetWorldTransform()
    {
        return Matrix.CreateScale(scale)
            * skin.GetPrimitiveLocal(0).Transform.Orientation
            * Body.Orientation
            * Matrix.CreateTranslation(Body.Position);
    }
}


JigLibXDemo03.jpg


このシミュレーションには大きな箱と小さな箱が登場します。
大きな箱は空中に固定されていて、どんなことをしても動きません。

一方小さな箱は自由に動きます。
重力の影響を受けて下へ落下します。
落下していき最後は大きな箱に衝突しバウンスするのです。








拍手[0回]

PR

XNAで物理シミュレーション(JigLibX) その2

今回は箱を描画するだけです。
よくわかっている人は飛ばしてください。

Xna部分の変更だけでJigLibX部分には変更ありません。

プログラム

BasicWorldGame.cs
using Microsoft.Xna.Framework;
using JigLibX.Physics;
using JigLibX.Collision;

public class BasicWorldGame : Game
{
    GraphicsDeviceManager graphics;
    PhysicsSystem world;
    BoxRenderer boxRenderer;

    public BasicWorldGame()
    {
        graphics = new GraphicsDeviceManager(this);
        InitializePhysics();
    }

    private void InitializePhysics()
    {
        world = new PhysicsSystem();
        world.CollisionSystem = new CollisionSystemSAP();
    }

    protected override void LoadContent()
    {
        boxRenderer = new BoxRenderer(GraphicsDevice);
    }

    protected override void UnloadContent()
    {
        boxRenderer.Dispose();
    }

    protected override void Update(GameTime gameTime)
    {
        world.Integrate(1 / 60f);

        base.Update(gameTime);
    }

    protected override void Draw(GameTime gameTime)
    {
        graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
        boxRenderer.SetCamera(
            Matrix.CreateLookAt(
                new Vector3(2, 1, 5),
                new Vector3(),
                Vector3.Up
                ),
            Matrix.CreatePerspectiveFieldOfView(
                MathHelper.ToRadians(45),
                GraphicsDevice.Viewport.AspectRatio,
                0.1f, 1000
                )
            );
        boxRenderer.Draw(Matrix.Identity);
        base.Draw(gameTime);
    }
}

BoxRenderer.cs
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

class BoxRenderer:System.IDisposable
{
    public GraphicsDevice GraphicsDevice { get; private set; }
    VertexBuffer vertexBuffer;
    BasicEffect basicEffect;

    public BoxRenderer(GraphicsDevice graphicsDevice)
    {
        GraphicsDevice = graphicsDevice;
        basicEffect = new BasicEffect(GraphicsDevice) { VertexColorEnabled = true};

        Vector3[] positions = new []
        {
            new Vector3(1, 1, 1),
            new Vector3(1, -1, 1),
            new Vector3(-1, -1,1),
            new Vector3(-1, 1, 1),

            new Vector3(1, 1, -1),
            new Vector3(1, -1, -1),
            new Vector3(-1, -1,-1),
            new Vector3(-1, 1, -1),
        };
        VertexPositionColor[] vertices = new[]
        {
            new VertexPositionColor(positions[0], Color.Blue),
            new VertexPositionColor(positions[1], Color.Blue),
            new VertexPositionColor(positions[2], Color.Blue),

            new VertexPositionColor(positions[3], Color.Blue),
            new VertexPositionColor(positions[0], Color.Blue),
            new VertexPositionColor(positions[2], Color.Blue),

            
            new VertexPositionColor(positions[3], Color.Red),
            new VertexPositionColor(positions[2], Color.Red),
            new VertexPositionColor(positions[7], Color.Red),

            new VertexPositionColor(positions[7], Color.Red),
            new VertexPositionColor(positions[2], Color.Red),
            new VertexPositionColor(positions[6], Color.Red),
            

            new VertexPositionColor(positions[0], Color.Green),
            new VertexPositionColor(positions[3], Color.Green),
            new VertexPositionColor(positions[7], Color.Green),

            new VertexPositionColor(positions[0], Color.Green),
            new VertexPositionColor(positions[7], Color.Green),
            new VertexPositionColor(positions[4], Color.Green),


            new VertexPositionColor(positions[4], Color.Cyan),
            new VertexPositionColor(positions[6], Color.Cyan),
            new VertexPositionColor(positions[5], Color.Cyan),

            new VertexPositionColor(positions[4], Color.Cyan),
            new VertexPositionColor(positions[7], Color.Cyan),
            new VertexPositionColor(positions[6], Color.Cyan),


            new VertexPositionColor(positions[5], Color.Magenta),
            new VertexPositionColor(positions[2], Color.Magenta),
            new VertexPositionColor(positions[1], Color.Magenta),

            new VertexPositionColor(positions[5], Color.Magenta),
            new VertexPositionColor(positions[6], Color.Magenta),
            new VertexPositionColor(positions[2], Color.Magenta),


            new VertexPositionColor(positions[0], Color.Yellow),
            new VertexPositionColor(positions[5], Color.Yellow),
            new VertexPositionColor(positions[1], Color.Yellow),

            new VertexPositionColor(positions[0], Color.Yellow),
            new VertexPositionColor(positions[4], Color.Yellow),
            new VertexPositionColor(positions[5], Color.Yellow),
        };

        vertexBuffer = new VertexBuffer(
            graphicsDevice,
            typeof(VertexPositionColor),
            vertices.Length,
            BufferUsage.WriteOnly
            );
        vertexBuffer.SetData<VertexPositionColor>(vertices);
    }

    public void SetCamera(Matrix view, Matrix projection)
    {
        basicEffect.View = view;
        basicEffect.Projection = projection;
    }

    public void Draw(Matrix world)
    {
        basicEffect.World = Matrix.CreateScale(1 / 2f) * world;
        basicEffect.CurrentTechnique.Passes[0].Apply();


        GraphicsDevice.SetVertexBuffer(vertexBuffer);
        GraphicsDevice.DrawPrimitives(
            PrimitiveType.TriangleList,
            0, 
            vertexBuffer.VertexCount / 3
            );
    }

    public void Dispose()
    {
        basicEffect.Dispose();
        vertexBuffer.Dispose();
    }
}


このプログラムは斜め上から見た箱を描きます。

JigLibXDemo02.jpg


まだシミュレーターと結びつけていないので、動きません。











拍手[0回]


XNAで物理シミュレーション(JigLibX) その1

物理シミュレーターJigLibX

このブログでは今までの所描画(それも基礎的な)ばかり扱っていました。
「見た目」ばかりで「動き」はほとんど無視です。

ここでは物理シミュレーションでよりリアルな動きを目指します。

物理シミュレーションといっても難しいことをする必要はありません。
ライブラリがいくつかあるからです。
私はODE(C/C++用ライブラリ)をC++/CLIでラップしてしばらく使っていました。
が、最近JigLibXというものを知りました。

JigLibX

これはC#で書かれています。
これの良いところは、ちょこっと修正すればSilverlightからも使えるところです。
オリジナルのソースにはunsafeとかがたくさんあってSilverlightから使えないようですが。
しかしunsafeを取り除いてSilverlightから使えるようにしたバージョンがあります

SilverlightのXNAはオリジナルのXNAよりややこしいので、簡単のため、ここではオリジナルのXNAを使うことにします。
でもこれから書くことはSilverlightのXNAに転用可能です。
安心して下さい。

まず次のページを参考にします。

Basic World

このページはJIgLibXで物理シミュレーションする方法を簡単に開設してくれています。
ここではそれをやや変更しながら紹介していきたいと思います。


物理システムと衝突システムの初期化とアップデート

まず一つ一つやっていきましょう。
次のようなコードを書きます。

using Microsoft.Xna.Framework;
using JigLibX.Physics;
using JigLibX.Collision;

public class BasicWorldGame : Game
{
    GraphicsDeviceManager graphics;
    PhysicsSystem world;

    public BasicWorldGame()
    {
        graphics = new GraphicsDeviceManager(this);
        InitializePhysics();
    }

    private void InitializePhysics()
    {
        world = new PhysicsSystem();
        world.CollisionSystem = new CollisionSystemSAP();
    }

    protected override void Update(GameTime gameTime)
    {
        world.Integrate(1 / 60f);

        base.Update(gameTime);
    }

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

        base.Draw(gameTime);
    }
}



このプログラムは初期化とアップデートするだけで何もしません。
(ですから実行画面は省きます)

コンストラクタ内で物理計算に必要なオブジェクトを初期化し、Updateメソッド内で物理計算をすすめるメソッドを呼んでいます。
(本来は初期化後に箱や球体を物理システムに追加して、箱がバウンスするさまを楽しめるのですが)


PhysicsSystemクラス

public class PhysicsSystem
{
    public PhysicsSystem();

    public CollisionSystem CollisionSystem { get; set; }
...
    public void Integrate(float dt);
...
}




PhysicsSystemクラスはシミュレーターで動かす物体を管理します。
今回は物体を追加しません。
今回はPhysicsSystem.CollisionSystemプロパティで衝突システムをセットしています。

衝突システムとはシミュレートする物体間の衝突を検知するシステムだと思われます。
(物体の動きをシミュレートするには、どの物体とどうぶつかったかを検出する必要があります)
次のような種類があります。

クラス名 解説
CollisionSystemBrute すべての物体を、全ての他の物体に対して衝突をチェックします。一見遅そうですが、小さなシーンではこれは速度が出て、CollisionSystemGridより速いでしょう。
CollisionSystemGrid 世界をあるサイズのグリッドに分割したCollisionSystemです。物体が均等に散らばっていると、チェックの回数が減ります(速度が出ます)。
CollisionSystemSAP sweep-and-pruneアルゴリズムを使ったCollisionSystemです。




PhysicsSystem.Integrate()メソッドはシミュレーションを行うメソッドです。
Integrateとは積分のことでしょう。
シミュレーションを動かす作業は積分だと考えることができます。
つまり力から速度を出し、速度から位置を出すわけですね。

Integrateの引数dtは、進める速度です。
XnaではUpdateは1秒間に60回呼ばれるので、dt = 1 / 60fでいいでしょう。










拍手[1回]


Silverlight5からXnaを使う その3 マウスとキーボード

前回までは三角形を回転させました。
しかしその三角形は自分で勝手に回るだけです。
ゲームを作りたいならユーザーがマウスを動かしたりキーボードをカチャカチャしたりするのに反応すべきです。


(キーボードの矢印キー「←か→」を押してください)

非SilverlightなXnaにはMouseクラスやKeyboardクラスがあります。
それを使ってマウスやキーボードの状態を取得できたのです。
が、Silverlight版Xnaには該当するクラスが公式にはありません。

ありません、では困るのでちゃんと用意されています。

Silverlight 5 Toolkit December 11

このサイトにあるmsiファイルを実行すると、Microsoft.Xna.Framework.Toolkitがインストールされます。
そのdllから、MouseクラスやKeyboardクラスが使えるようになるのです。
ただし使い方はオリジナルのものとちょっと違います。
はじめにRootControlにコントロールのインスタンスをセットする必要があります。

詳しく見て行きましょう。


プログラム

using System;
using System.Windows.Controls;

using Microsoft.Xna.Framework;
using Xna = Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.Windows.Graphics;
using Microsoft.Xna.Framework.Input;


namespace SilverlightXna03
{
    public partial class MainPage : UserControl
    {
        private VertexBuffer vertexBuffer;
        private BasicEffect basicEffect;
        private bool loaded = false;
        private float angle;

        public MainPage()
        {
            InitializeComponent();
            showGpuError();
            Keyboard.RootControl = this;
        }

        private void showGpuError()
        {
            if (GraphicsDeviceManager.Current.RenderMode == RenderMode.Hardware)
            { return; }

            string message;
            switch (GraphicsDeviceManager.Current.RenderModeReason)
            {
                case RenderModeReason.Not3DCapable:
                    message = "あなたのグラフィックスハードウェアはこのページを表示出来ません";
                    break;
                case RenderModeReason.GPUAccelerationDisabled:
                    message = "ハードウェアグラフィックスアクセラレーションがこのwebページでは有効にされていません。\n\n" +
                        "webサイトのオーナーに通知してください";
                    break;
                case RenderModeReason.TemporarilyUnavailable:
                    message = "あなたのグラフィックスハードウェアは一時的に使用不可能になっています。\n\n" +
                        "webページをリロードするかブラウザを再起動してください。";
                    break;
                case RenderModeReason.SecurityBlocked:
                    message =
                      "webサイトが3Dグラフィックスを表示できるようにするには、システム構成を変える必要があります。\n\n" +
                      "  1. ここを右クリックします\n" +
                      "  2. 'Silverlight'を選択します\n" +
                      "     ('Microsoft Silverlight Configuration'ダイヤログが表示されます)\n" +
                      "  3. 'Permissions'タブを選択します\n" +
                      "  4. このサイトをリストの中から見つけ、その3Dグラフィックスパーミッションを'Deny'から'Allow'に変えます\n" +
                      "  5. 'OK'をクリックします\n" +
                      "  6. ページをリロードします";
                    break;
                default:
                    message = "不明なエラー";
                    break;
            }

            textBlock.Text = "3D表示がブロックされました!\n\n\n" + message;
        }

        private void DrawingSurface_Draw(object sender, DrawEventArgs e)
        {
            if (!loaded)
            {
                LoadContent();
                loaded = true;
            }

            Update();
            Draw();
            e.InvalidateSurface();
        }


        private GraphicsDevice GraphicsDevice
        {
            get
            {
                return GraphicsDeviceManager.Current.GraphicsDevice;
            }
        }

        private void LoadContent()
        {
            VertexPositionColor[] vertices = new[]
                {
                    new VertexPositionColor(
                        new Vector3(-1, -1, 0), 
                        new Color(1f, 0, 0)
                    ),
                    new VertexPositionColor(
                        new Vector3(0, 1, 0),
                        new Color(1f, 1f, 1f)
                    ),
                    new VertexPositionColor(
                        new Vector3(1, -1, 0),
                        new Color(0, 0, 1f)
                    )
                };

            vertexBuffer = new VertexBuffer(
                GraphicsDevice,
                VertexPositionColor.VertexDeclaration,
                vertices.Length,
                BufferUsage.WriteOnly
                );
            vertexBuffer.SetData(0, vertices, 0, vertices.Length, 0);

            basicEffect = new BasicEffect(GraphicsDevice)
            {
                VertexColorEnabled = true,
                Projection = Matrix.CreatePerspectiveFieldOfView(
                    MathHelper.ToRadians(45),
                    GraphicsDevice.Viewport.AspectRatio,
                    1, 100
                    )
            };
        }

        private void Update()
        {
            KeyboardState keyboardState = Keyboard.GetState();

            if (keyboardState.IsKeyDown(System.Windows.Input.Key.Left))
            {
                angle += 0.01f;
            }
            if (keyboardState.IsKeyDown(System.Windows.Input.Key.Right))
            {
                angle += -0.01f;
            }
        }

        private void Draw()
        {
            GraphicsDevice.Clear(new Xna.Color(0.39f, 0.58f, 0.93f));
            GraphicsDevice.RasterizerState = RasterizerState.CullNone;

            basicEffect.View = Matrix.CreateLookAt(
                new Vector3
                    (
                    3 * (float)Math.Sin(angle),
                    0,
                    3 * (float)Math.Cos(angle)
                    ),
                new Vector3(),
                Vector3.Up
                );

            basicEffect.CurrentTechnique.Passes[0].Apply();
            GraphicsDevice.SetVertexBuffer(vertexBuffer);
            GraphicsDevice.DrawPrimitives(
                PrimitiveType.TriangleList,
                0,
                vertexBuffer.VertexCount / 3
                );
        }
    }
}

Silverlight版のKeyboardStateクラス、Keyboardクラス、MouseStateクラス、Mouseクラスは
オリジナルのXnaバージョンのクラスとほとんどかわりません。
ただし気を付けなければいけないことが1つだけ。
GetStateメソッドで状態を得る前に、RootControlプロパティでコントロールをセットしなければいけません。
このプログラムではコントロールのコンストラクタでそれを行なっています。
あとは普通のXnaと全く同じです。


追記 2012/03/10

どうやらMouse.RootControlにセットすると、右クリックした時にSilverlightメニューが現れなくなるようです。
ですからshowGpuErrorのメッセージは次のように書き換えるべきかもしれません:

1.[スタート]-[すべてのプログラム]をクリックします。
2.[Microsoft Silverlight]-[Silverlight]を選択します
    ([Microsoft Silverlight の構成
]ダイヤログが表示されます)
3. [アクセス許可]タブを選択します
4. このサイトをリストの中から見つけ、その3Dグラフィックスアクセス許可を[拒否]から[許可]に変えます
5. [OK]をクリックします
6. ページをリロードします

拍手[1回]


Silverlight5からXnaを使う その2 テクスチャ三角形

前回はくるくる回る色つき三角形を表示しました。
今回はテクスチャ付き三角形を表示してみます。


Microsoft Visual Web Developer 2010 Expressでこれをやるには一苦労です。
(といっても最初からやり方がわかっていればそう難しくないのですが)
プログラムは次のようになります。


プログラム

MainPage.xaml.cs
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
using Microsoft.Xna.Framework;
using Xna = Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.Windows.Graphics;

namespace SilverlightXna02
{
    public partial class MainPage : UserControl
    {
        private VertexBuffer vertexBuffer;
        private BasicEffect basicEffect;
        private bool loaded = false;

        public MainPage()
        {
            InitializeComponent();
            showGpuError();
        }

        private void showGpuError()
        {
            if (GraphicsDeviceManager.Current.RenderMode == RenderMode.Hardware)
            { return; }

            string message;
            switch (GraphicsDeviceManager.Current.RenderModeReason)
            {
                case RenderModeReason.Not3DCapable:
                    message = "あなたのグラフィックスハードウェアはこのページを表示することが出来ません";
                    break;
                case RenderModeReason.GPUAccelerationDisabled:
                    message = "ハードウェアグラフィックスアクセラレーションがこのwebページでは有効にされていません。\n\n" +
                        "webサイトのオーナーに教えてあげてください";
                    break;
                case RenderModeReason.TemporarilyUnavailable:
                    message = "あなたのグラフィックスハードウェアは一時的に使用不可能になっています。\n\n" +
                        "webページをリロードするかブラウザを再起動してください。";
                    break;
                case RenderModeReason.SecurityBlocked:
                    message =
                      "webサイトが3Dグラフィックスを表示できるようにするには、システム構成を変える必要があります。\n\n" +
                      "  1. ページを右クリックします\n" +
                      "  2. 'Silverlight'を選択します\n" +
                      "     ('Microsoft Silverlight Configuration'ダイヤログが表示されます)\n" +
                      "  3. 'Permissions'タブを選択します\n" +
                      "  4. このサイトをリストの中から見つけ、その3Dグラフィックスパーミッションを'Deny'から'Allow'に変えます\n" +
                      "  5. 'OK'をクリックします\n" +
                      "  6. ページをリロードします";
                    break;
                default:
                    message = "不明なエラー";
                    break;
            }

            textBlock.Text = "3D表示がブロックされました!\n\n\n" + message;
        }

        private void DrawingSurface_Draw(object sender, DrawEventArgs e)
        {
            if (!loaded)
            {
                LoadContent();
                loaded = true;
            }

            Draw();
            e.InvalidateSurface();
        }

        private GraphicsDevice GraphicsDevice
        {
            get
            {
                return GraphicsDeviceManager.Current.GraphicsDevice;
            }
        }

        private void LoadContent()
        {
            VertexPositionTexture[] vertices = new[]
                {
                    new VertexPositionTexture(
                        new Vector3(-1, -1, 0),
                        new Vector2(0, 1)
                    ),
                    new VertexPositionTexture(
                        new Vector3(0, 1, 0),
                        new Vector2(0.5f, 0)
                    ),
                    new VertexPositionTexture(
                        new Vector3(1, -1, 0),
                        new Vector2(1, 1)
                    )
                };

            vertexBuffer = new VertexBuffer(
                GraphicsDevice,
                typeof(VertexPositionTexture), 
                vertices.Length,
                BufferUsage.WriteOnly
                );
            vertexBuffer.SetData(0, vertices, 0, vertices.Length, 0);

            basicEffect = new BasicEffect(GraphicsDevice)
            {
                TextureEnabled = true,
                Texture = LoadTexture("PenguinsSmall.jpg"),
                Projection = Matrix.CreatePerspectiveFieldOfView(
                    MathHelper.ToRadians(45),
                    GraphicsDevice.Viewport.AspectRatio,
                    1, 100
                    )
            };

            //大きさが2^nでないテクスチャはClampにする必要がある?
            GraphicsDevice.SamplerStates[0] = SamplerState.LinearClamp;
        }

        private Texture2D LoadTexture(string name)
        {
            System.IO.Stream imageStream = Application.GetResourceStream(
                new Uri(name, UriKind.Relative)
                ).Stream;

            Texture2D texture = null;
            System.Threading.ManualResetEvent eventWaiter 
                = new System.Threading.ManualResetEvent(false);

            Dispatcher.BeginInvoke(delegate
            {
                var image = new BitmapImage();
                image.SetSource(imageStream);

                texture = new Texture2D(
                    GraphicsDevice,
                    image.PixelWidth,
                    image.PixelHeight,
                    false,
                    SurfaceFormat.Color);
                image.CopyTo(texture);
                eventWaiter.Set();
            });

            eventWaiter.WaitOne();
            return texture;
        }

        private void Draw()
        {
            GraphicsDevice.Clear(new Xna.Color(0.39f, 0.58f, 0.93f));
            GraphicsDevice.RasterizerState = RasterizerState.CullNone;

            basicEffect.View = Matrix.CreateLookAt(
                new Vector3
                    (
                    3 * (float)Math.Sin(Environment.TickCount / 400d),
                    0,
                    3 * (float)Math.Cos(Environment.TickCount / 400d)
                    ),
                new Vector3(),
                Vector3.Up
                );

            basicEffect.CurrentTechnique.Passes[0].Apply();
            GraphicsDevice.SetVertexBuffer(vertexBuffer);
            GraphicsDevice.DrawPrimitives(
                PrimitiveType.TriangleList,
                0,
                vertexBuffer.VertexCount / 3
                );
        }
    }
}


いくつか注意する点があります。
まずBitmapImageですが、これはポリゴンに貼り付けるテクスチャをロードするのに使っています。
これはWPFに根ざしたクラスなので非UIスレッドからは呼び出せません。
そしてどうやら、Drawは非UIスレッドらしいのです。
もうお分かりでしょう。
Dispatcher.BeginInvokeの中でBitmapImageの操作を行う必要があるのです。

また、サンプラーステートも設定をきちんとしなくてはいけません。
大きさが2のn乗でないテクスチャを使う場合には、SamplerStates[0]をClampに明示的にしなくてはいけないようです。
普通のXnaの場合にはそうでなかったのに不思議な話ですね。

テクスチャはBuild ActionをContentにしてください。


おまけ

プロジェクトファイルです。



拍手[0回]