通常、プリミティブの裏は描画する必要がないため、デフォルトではプリミティブの背面は描画されないように設定されています。このようなテクニックをカリングと呼び、裏向きになっているプリミティブは画面から消えてしまいます。
プリミティブの表裏は、頂点の位置と順番によって決められます。これまでも何度か、三角形のプリミティブを描画する場合は時計回りに頂点を並べなければならないことを説明してきました。これは、反時計回りに頂点を並べると、プリミティブの裏側が視点の方向に向いてしまい、カリングによって描画されないためです。
■ 図 01 時計回りの頂点

つまり、時計回りに頂点が並んでいる向きが表、反時計回りに並んでいる向きが裏となります。自由に視点移動ができるようなゲームの場合、プリミティブの裏側に回られてしまうと描画されなくなってしまいます。そのため、表裏両面を描画する場合は、カリングの設定を変更しなければなりません。
カリングの設定は GraphicsDevice クラスの RenderState プロパティが返すオブジェクトに対して行います。プリミティブの裏を描画するには
CullMode プロパティを変更してください。
■ RenderState クラス CullMode プロパティ
public CullMode CullMode { get; set; }
CullMode プロパティには、どの面をカリングするかを指定する Microsoft.Xna.Framework.Graphics.CullMode
列挙型のメンバを設定します。
■ Microsoft.Xna.Framework.Graphics.CullMode 列挙型
public enum CullMode
CullMode 列挙型には、時計回りの面をカリングする CullClockwiseFace メンバ、反時計回りの面をカリングする CullCounterClockwiseFace
メンバ、そしてカリングを行わないことを表す None メンバが定義されています。デフォルトでは、CullCounterClockwiseFace
メンバが設定されています。
プリミティブを回転させたり、カメラがプリミティブの背面に移動できる場合で、プリミティブの両面を描画したいのであれば、CullMode プロパティに
None メンバを設定してください。
■ Sample01
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
public class Test : Game
{
public static void Main(string[] args)
{
using (Game game = new Test()) game.Run();
}
private GraphicsDeviceManager graphics;
private VertexPositionColor[] vertices;
private int rot;
private Matrix view;
private Matrix projection;
private BasicEffect effect;
private VertexDeclaration dec;
public Test()
{
graphics = new GraphicsDeviceManager(this);
Vector3 cameraPos = new Vector3(0, 0, 5);
Vector3 cameraTarget = new Vector3(0, 0, 0);
Vector3 cameraUp = new Vector3(0, 1, 0);
view = Matrix.CreateLookAt(cameraPos, cameraTarget, cameraUp);
float fieldOfView = MathHelper.ToRadians(45);
int aspect = Window.ClientBounds.Width / Window.ClientBounds.Height;
projection = Matrix.CreatePerspectiveFieldOfView(fieldOfView, aspect, 1, 10);
vertices = new VertexPositionColor[] {
new VertexPositionColor(new Vector3(0F, 1, 0), Color.Red),
new VertexPositionColor(new Vector3(1, -1, 0), Color.Blue),
new VertexPositionColor(new Vector3(-1F, -1F, 0), Color.Green),
};
rot = 0;
}
protected override void Initialize()
{
effect = new BasicEffect(GraphicsDevice, null);
effect.VertexColorEnabled = true;
dec = new VertexDeclaration(GraphicsDevice, VertexPositionColor.VertexElements);
base.Initialize();
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.RenderState.CullMode = CullMode.None;
GraphicsDevice.VertexDeclaration = dec;
GraphicsDevice.Clear(Color.White);
if (rot == 360) rot = 0;
else rot++;
effect.World = Matrix.CreateRotationY(MathHelper.ToRadians(rot));
effect.View = view;
effect.Projection = projection;
effect.Begin();
foreach (EffectPass pass in effect.CurrentTechnique.Passes)
{
pass.Begin();
GraphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleList, vertices, 0, 1);
pass.End();
}
effect.End();
base.Draw(gameTime);
}
}
■ 実行結果

上記のプログラムは、CreateRotationY()
メソッドで生成した行列を使ってワールド変換を行い、三角形のプリミティブを常に回転させています。デフォルトの設定では、三角形を回転させてもカリングによって裏面が表示されることはありません。そのため、三角形が途中で画面から消えてしまいます。そこで CullMode
プロパティの設定を変更し、裏面のカリングを行わないようにしています。プログラムを実行すると、回転する三角形の両面が正しく描画されていることを確認できます。