忍者ブログ

Memeplexes

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

[PR]

×

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


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回]

PR

Silverlight5からXnaを使う

Silverlight5からXnaを使えるようになりました。
つまり自分のホームページに3DCGをリアルタイムで表示することが出来るようになったのです。


以下のページを参考にしてプログラムを書いてみました。
[Silverlight]Silverlight5ベータで3D表示する方法(「関西ゲームプログラミング勉強会」LT内容)
3D Basics using Silverlight-5 and XNA 


プログラム

MainPage.xaml.cs
using System;
using System.Windows;
using System.Windows.Controls;

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

namespace SilverlightXna
{
    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()
        {
            VertexPositionColor[] vertices = new[]
                {
                    new VertexPositionColor(
                        new Vector3(-1, -1, 0), 
                        new Xna.Color(1f, 0, 0)
                    ),
                    new VertexPositionColor(
                        new Vector3(0, 1, 0),
                        new Xna.Color(1f, 1f, 1f)
                    ),
                    new VertexPositionColor(
                        new Vector3(1, -1, 0),
                        new Xna.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 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
                );
        }
    }
}
MainPage.xaml

<UserControl x:Class="SilverlightXna.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">

    <Grid x:Name="LayoutRoot" Background="LightGray">
        <TextBlock x:Name="textBlock"></TextBlock>
        <DrawingSurface Draw="DrawingSurface_Draw"/>
    </Grid>
</UserControl>
SilverlightXnaTestPage.aspx
<%@ Page Language="C#" AutoEventWireup="true" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>SilverlightXna</title>
    <style type="text/css">
    html, body {
	    height: 100%;
	    overflow: auto;
    }
    body {
	    padding: 0;
	    margin: 0;
    }
    #silverlightControlHost {
	    height: 100%;
	    text-align:center;
    }
    </style>
    <script type="text/javascript" src="Silverlight.js"></script>
    <script type="text/javascript">
        function onSilverlightError(sender, args) {
            var appSource = "";
            if (sender != null && sender != 0) {
              appSource = sender.getHost().Source;
            }
            
            var errorType = args.ErrorType;
            var iErrorCode = args.ErrorCode;

            if (errorType == "ImageError" || errorType == "MediaError") {
              return;
            }

            var errMsg = "Unhandled Error in Silverlight Application " +  appSource + "\n" ;

            errMsg += "Code: "+ iErrorCode + "    \n";
            errMsg += "Category: " + errorType + "       \n";
            errMsg += "Message: " + args.ErrorMessage + "     \n";

            if (errorType == "ParserError") {
                errMsg += "File: " + args.xamlFile + "     \n";
                errMsg += "Line: " + args.lineNumber + "     \n";
                errMsg += "Position: " + args.charPosition + "     \n";
            }
            else if (errorType == "RuntimeError") {           
                if (args.lineNumber != 0) {
                    errMsg += "Line: " + args.lineNumber + "     \n";
                    errMsg += "Position: " +  args.charPosition + "     \n";
                }
                errMsg += "MethodName: " + args.methodName + "     \n";
            }

            throw new Error(errMsg);
        }
    </script>
</head>
<body>
    <form id="form1" runat="server" style="height:100%">
    <div id="silverlightControlHost">
        <object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="100%" height="100%">
		  <param name="source" value="ClientBin/SilverlightXna.xap"/>
		  <param name="onError" value="onSilverlightError" />
		  <param name="background" value="white" />
		  <param name="minRuntimeVersion" value="5.0.61118.0" />
		  <param name="autoUpgrade" value="true" />
          <param name="EnableGPUAcceleration" value="true" />
		  <a href="http://go.microsoft.com/fwlink/?LinkID=149156&v=5.0.61118.0" style="text-decoration:none">
 			  <img src="http://go.microsoft.com/fwlink/?LinkId=161376" alt="Get Microsoft Silverlight" style="border-style:none"/>
		  </a>
	    </object><iframe id="_sl_historyFrame" style="visibility:hidden;height:0px;width:0px;border:0px"></iframe></div>
    </form>
</body>
</html>



MainPage.xaml.csは赤白青の三角形を表示し、それを回転させます。
何の変哲もないxnaプログラムと言いたいところですが、LoadContentやDrawは自分で書かなければいけないようです。
SilverlightXnaTestPage.aspxではEnableGPUAccelerationをtrueにするのがキモです。

そうそう、このプログラムをMicrosoft Visual Web Developer 2010 Expressで動かすには参照の追加が必要です。

Microsoft.Xna.Framework
Microsoft.Xna.Framework.Graphics
Microsoft.Xna.Framework.Graphics.Extensions
Microsoft.Xna.Framework.Math
System.Windows.Xna


beta版の時には結構不自由だったようですが、リリース番ではそこそこ使えるようになっているようですね。


おまけ

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

拍手[1回]


SilverlightでNUnitするには?

私は今まで勘違いをしていたようです。
SilverlightプロジェクトをNUnitと組み合わせられないと。
テストできないと。
しかしそうでもなかったようです。

ググっても全く情報が出てこなかったところからしてこんな勘違いをしていたのは私一人のような気もしますがメモしておきます。

まず勘違いその1
「Microsoft Visual Web Developer 2010 Expressは一つのソリューションに一つのプロジェクトだけ」
(ゆえにNUnitのテストプロジェクトも作れない!)

これは×です。
ちゃんと複数プロジェクトを持ったソリューションを作れます。
File > New > Projectときて、Solution:項目をCreate new SolutionからAdd to solutionに変更するのです。
これで既存のソリューションに新たにプロジェクトを作れます。
複数のプロジェクトを作れるのです。


勘違いその2
「Silverlightと普通の.netのランタイムは完全に違うため片方のアセンブリがもう片方を使うことはできない」
(ゆえにSilverlightのアセンブリをNUnitのアセンブリはテストできない!)

これはどうも半分正しい気がします。
経験からして上手くいかないこともあったような気がします(記憶が曖昧なのでみなさん検証してみてください)。
Silverlightが普通の.netのアセンブリを使うことは出来なかったような・・・。

で、うまくいく方法とはどういう方法かというと

NUnit(通常の.net)

↓(参照)

テスト用アセンブリ(通常の.net)

↓(参照)

テストされるアセンブリ(Silverlight)


これで出来ました。
SilverlightのコードをNUnitでテストすることができたのです。
つまりSilverlightが.netを使うのはできないけど.netがSilverlightを使うことは出来るのですね。

ただ、今これはIDEでやるとワーニングが出るのでもしかしたら正しい方法ではないのかもしれませんね。

拍手[0回]


かんたんXNA4.0 完了

かんたんXNAをXNA4.0に変換する作業がようやく終わりました。

まとめ

しかしあれですね今見ると恥ずかしいコード書いています。
new VertexDeclaration(~)をDrawメソッドの中で書いていたり。
そんなことしたらグラフィックス関係のリソースが浪費されてしまいそうです!
もしかしたらGCがあるから大丈夫と思って書いたのかもしれませんが。

全部上書きしようと思いましたが当時のXNAと今のXNAはだいぶ違うので
別バージョンということで残しておこうと思います。
オリジナルバージョンはDirectXの参考にもなるかもしれませんしね。

気づいたのはXNAがだいぶ簡略化されていること。
VertexDeclarationが(表舞台から)なくなったのはすごいです。
最初のうちはこれの存在に?な人もいたはずです。
また学習曲線がなだらかになりました。

拍手[0回]


かんたんXNA4.0 HLSL編 その7 テクスチャ


今回はテクスチャです。
ポリゴンの上に貼り付けるテクスチャを扱います。
つまりBasicEffectで言うとTextureプロパティ関連でやっていたことです。
ただしはるかに柔軟なことが出来ます。


大まかな流れを言うと、

「まずHLSL側でtexture型のグローバル変数を宣言し、
C#側からそれにインスタンスをセットし、
ピクセルシェーダでそのテクスチャから
相当するテクスチャ座標の色をサンプルして出力する」、

といったぐあいです。


これをやると「ピクセルの色は自分が完全に決めているんだなぁ」という実感が持てると思います。
ちょこっとプログラムを書き換えると水面の波のような効果を出すことも出来ます。


HLSLでテクスチャを宣言するにはこうします:

texture [変数名];

このテクスチャのテクセル(テクスチャのピクセル)の色を、
ピクセルシェーダで使います。
つまり、ピクセルシェーダの引数として与えられるテクスチャ座標に
対応する部分のテクスチャの色をtex2D関数を使って得て、戻り値として返すのです。

float4 tex2D ( sampler samplerState, float2 textureCoordinate )

textureCoordinateはテクスチャ上の座標を意味します。ここに指定した座標の色が返されます。
この関数の戻り値は色を表すfloat4です。
こいつをピクセルシェーダに使うことになるでしょう。

ただし、最初の引数samplerというのを見てわかるように、
初学者にとっては困ったことですが、このままではtex2D関数を使うことが出来ません。
テクスチャからどのように色を取り出す(サンプルする)かを
表すサンプラを宣言しなければならないのです。
このサンプラしだいで表示されるテクスチャがギザギザになったり滑らかになったりします。

しかしまあ、最初は一番シンプルな例を見るべきでしょう。
ギザギザにはなってしまいますが。

sampler [変数名] = sampler_state
{
        Texture = <テクスチャの変数名>;
};

「テクスチャの変数名」というのは、このサンプラが使うテクスチャです。
(HLSLの将来のバージョンではこれを設定する必要はなく、
サンプラとテクスチャは(正当にも)独立して扱えるようですが、
現時点では必ずテクスチャを指定してやらねばなりません。)

テクスチャの変数名は < > で囲ってやらなければなりません。(でも試したところ ( ) でもいけました。)
単に変数名を書いただけではコンパイルエラーになります。
(まあ、初期化が行われるときには変数にインスタンスは入っていないでしょうから正当です。
C#側からセットして初めてテクスチャの変数がつかえるようになるわけですからね。)

もしかしたら < > にはC/C++でいう変数のポインタみたいな意味があるのかもしれません。(わかりませんが)

この { } の中では他にも
テクスチャからサンプルする色を滑らかにするフィルターの
設定が出来るのですが、それは後で述べることにします。

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

class MyGame : Game
{
    GraphicsDeviceManager graphics;

    Effect effect;
    VertexPositionTexture[] vertices = 
    {
        new VertexPositionTexture(new Vector3(0, 1, 0), new Vector2(0.5f, 0)),
        new VertexPositionTexture(new Vector3(1, 0, 0), new Vector2(1, 1)),
        new VertexPositionTexture(new Vector3(-1, 0, 0), new Vector2(0, 1))
    };

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

    protected override void LoadContent()
    {
        effect = Content.Load<Effect>("Content/MyEffect");
        Matrix view = Matrix.CreateLookAt(
            new Vector3(1, 0, 1),
            new Vector3(),
            new Vector3(0, 1, 0)
            );
        Matrix projection = Matrix.CreatePerspectiveFieldOfView(
            MathHelper.ToRadians(90),
            GraphicsDevice.Viewport.AspectRatio,
            0.1f,
            100
            );

        effect.Parameters["View"].SetValue(view);
        effect.Parameters["Projection"].SetValue(projection);
        effect.Parameters["MyTexture"].SetValue(Content.Load<Texture2D>("Content/Xnalogo"));
    }

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

        foreach (var pass in effect.CurrentTechnique.Passes)
        {
            pass.Apply();

            GraphicsDevice.DrawUserPrimitives<VertexPositionTexture>
            (
                PrimitiveType.TriangleList,
                vertices,
                0,
                vertices.Length / 3
            );
        }
    }
}

MyEffect.fx
float4x4 View;
float4x4 Projection;

texture MyTexture;
sampler mySampler = sampler_state{
	Texture = <MyTexture>;
};

struct VertexPositionTexture
{
	float4 Position : POSITION;
	float4 TextureCoordinate : TEXCOORD;
};

VertexPositionTexture MyVertexShader(VertexPositionTexture input)
{
	VertexPositionTexture output;
	output.Position = mul(input.Position, mul(View, Projection));
	output.TextureCoordinate = input.TextureCoordinate;
	return output;
}

float4 MyPixelShader(float2 textureCoordinate : TEXCOORD) : COLOR
{
	return tex2D(mySampler, textureCoordinate);
}

technique MyTechnique
{
	pass MyPass
	{
		VertexShader = compile vs_2_0 MyVertexShader();
		PixelShader = compile ps_2_0 MyPixelShader();
	}
}

hlslTesture.jpg
(公式のXnalogo.pngを拝借してきました。クリックで拡大)

テクスチャがちゃんと張り付いていますね。

しかし、よくみると、テクスチャがギザギザしています。
一番近い"a"のところなんか荒すぎてすりガラスのようです。
手前はテクスチャが拡大されるので、そのように見えるのです。
これを治し滑らかにするには、サンプラでフィルターを指定してやります。

(ギザギザにならないこともあります。環境によってはデフォルトの値が異なるようです)

使うフィルターはMagFilter (Magnification filter)、
テクスチャが拡大されるときに使われえるフィルターです。
これをLinearにセットすると、拡大したとき滑らかに表示されます。
フィルターにセットできる値は、C#でのTextureFilter列挙型に対応しているようです。

定数名 解説
Point  滑らかになりません。一番近いテクセルの色が使われます。ギザギザです。
Linear  バイリニアフィルターです。周りの2x2の領域の中での平均値が使われます。いろんなサンプルを見たところ、これが一番使われているようですね。
Anisotropic  異方性フィルターです。

とりあえずLinearを使えば良いようです。
ほとんどのサンプルがLinearをフィルターとして使っています。

float4x4 View;
float4x4 Projection;

texture MyTexture;
sampler mySampler = sampler_state{
	Texture = <MyTexture>;
	MagFilter = Linear;
};

struct VertexPositionTexture
{
	float4 Position : POSITION;
	float4 TextureCoordinate : TEXCOORD;
};

VertexPositionTexture MyVertexShader(VertexPositionTexture input)
{
	VertexPositionTexture output;
	output.Position = mul(input.Position, mul(View, Projection));
	output.TextureCoordinate = input.TextureCoordinate;
	return output;
}

float4 MyPixelShader(float2 textureCoordinate : TEXCOORD) : COLOR
{
	return tex2D(mySampler, textureCoordinate);
}

technique MyTechnique
{
	pass MyPass
	{
		VertexShader = compile vs_2_0 MyVertexShader();
		PixelShader = compile ps_2_0 MyPixelShader();
	}
}

magLinear.jpg
近くの文字、"a"が滑らかになりました。

しかしやっぱり、よく見ると変です。
確かに近くの文字は滑らかになりましたが、遠くの文字はまだ荒れています。
"x"の下の部分がなんだかギザギザしていますね。

遠くの文字は遠近法によって縮小されるからです。
MagFilterをセットすることによってテクスチャを拡大したときには滑らかになったものの、
テクスチャを逆に縮小したときにはまだギザギザしてしまうのです。

テクスチャが縮小されるときに使われるフィルターはMinFilter (Minification Filter)です。
これにLinearをセットすると、テクスチャが縮小されたときも滑らかになります。
float4x4 View;
float4x4 Projection;

texture MyTexture;
sampler mySampler = sampler_state{
	Texture = <MyTexture>;
	MagFilter = Linear;
	MinFilter = Linear;
};

struct VertexPositionTexture
{
	float4 Position : POSITION;
	float4 TextureCoordinate : TEXCOORD;
};

VertexPositionTexture MyVertexShader(VertexPositionTexture input)
{
	VertexPositionTexture output;
	output.Position = mul(input.Position, mul(View, Projection));
	output.TextureCoordinate = input.TextureCoordinate;
	return output;
}

float4 MyPixelShader(float2 textureCoordinate : TEXCOORD) : COLOR
{
	return tex2D(mySampler, textureCoordinate);
}

technique MyTechnique
{
	pass MyPass
	{
		VertexShader = compile vs_2_0 MyVertexShader();
		PixelShader = compile ps_2_0 MyPixelShader();
	}
}

minMagFilter.jpg
xの字もなめらかになりました。

拍手[0回]