忍者ブログ

Memeplexes

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

かんたんXNA その15 かんたんなライティング

このページは古いです
最新版はこちら

ここではBasicEffectを使って簡単なライティングを行います。
ライティングというのは光の当たり具合によって明るくしたり暗くしたりすることです。
赤道直下なら太陽の光がもろに当たるため明るくなりますが、
北極や南極はほとんど当たらないため暗くなります。

ここでは、また違った頂点、VertexPositionNormalTextureを使います。
(できればもっとシンプルな"VertexPositionNormalColor"みたいなものを使いたいのですが、
残念ながらXNAには用意されていません。)


これは新たに法線(ノーマル:面に対して垂直な線)のデータを持っています。
跳ね返る光の強さを(内部で)計算して光の効果を出すのに必要だからです。
(法線を知らない、あるいは忘れてしまったという人のために少し直感的な説明をしておきます。
まずは鏡を用意してください。手鏡でも洗面所の鏡でもかまいません。
そして鏡の中のあなたの目を見てください。
鏡の中の目から鏡の外のあなたの本物の目を結んだ直線がその鏡の法線です。
(そう、別に目でなくても、鏡の中の何かと鏡の外の本物を結べばなんでも法線になります。)
鏡でないものの法線を考えたいときには、その物体が鏡であると考えて同じ事をすると法線が求まります。)


理屈の上では法線(ノーマル)は頂点の座標データから自動的に計算することが出来るのですが、
描画の最中にそんなことをしていてはパフォーマンスが低下してしまいますし、
法線を利用した裏ワザ的なものも出来なくなってしまうので、
最初に手作業で設定してやらなければならないことになっているのでしょう。(多分)

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;


public class MyGame : Microsoft.Xna.Framework.Game
{
    GraphicsDeviceManager graphics;
    BasicEffect effect;

    VertexPositionNormalTexture[] vertices = new VertexPositionNormalTexture[3];

    ContentManager content;
    Texture2D texture;


    public MyGame()
    {
        graphics = new GraphicsDeviceManager(this);
        content = new ContentManager(Services);

        vertices[0].Position = new Vector3(0, 1, 0);
        vertices[0].TextureCoordinate = new Vector2(0.5f, 0);
        vertices[0].Normal = new Vector3(0, 0, 1);

        vertices[1].Position = new Vector3(1, 0, 0);
        vertices[1].TextureCoordinate = new Vector2(1, 1);
        vertices[1].Normal = new Vector3(0, 0, 1);

        vertices[2].Position = new Vector3(-1, 0, 0);
        vertices[2].TextureCoordinate = new Vector2(0, 1);
        vertices[2].Normal = new Vector3(0, 0, 1);
    }

    protected override void LoadGraphicsContent(bool loadAllContent)
    {
        if (loadAllContent)
        {
            effect = new BasicEffect(graphics.GraphicsDevice, null);
            effect.Projection = Matrix.CreatePerspectiveFieldOfView(
                MathHelper.ToRadians(45),
                Window.ClientBounds.Width / (float)Window.ClientBounds.Height,
                1,
                100
                );
            effect.View = Matrix.CreateLookAt(
                new Vector3(0, 0, 3),
                new Vector3(0, 0, 0),
                new Vector3(0, 1, 0)
                );
            effect.TextureEnabled = true;
            effect.EnableDefaultLighting();

            texture = content.Load<Texture2D>("FlyingSpaghettiMonster");
        }
    }

    protected override void UnloadGraphicsContent(bool unloadAllContent)
    {
        if (unloadAllContent) { content.Unload(); }
    }

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

        graphics.GraphicsDevice.VertexDeclaration = new VertexDeclaration(
            graphics.GraphicsDevice,
            VertexPositionNormalTexture.VertexElements
            );

        effect.Texture = texture;

        effect.Begin();

        foreach (EffectPass pass in effect.CurrentTechnique.Passes)
        {
            pass.Begin();

            graphics.GraphicsDevice.DrawUserPrimitives<VertexPositionNormalTexture>(
                PrimitiveType.TriangleList,
                vertices,
                0,
                1
                );

            pass.End();
        }

        effect.End();
    }
}

xnaSimplestLighting.JPG
このサンプルでは各頂点に法線を設定し、ライティングしているので左側が暗くなっています。

参考までにライティング無しだとこうなります。
xnaSimplextTriangleTextured.JPG

BasicEffect.EnableDefaultLightingを忘れないでください。
これを呼ばないと上の図のようにライティングが無しになってしまいます。
このメソッドは自動的にいい感じにライトを設定してくれます。
(いい感じの照明をするのは本当は難しい設定が必要ですが、このメソッドはそれを自動的にしてくれるのです)

拍手[0回]

PR