忍者ブログ

Memeplexes

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

かんたんXNA4.0 その19 マテリアル

物の色はライトの色だけで決まるわけではありません。
真っ黒いものは赤い光が当たろうと緑の光が当たろうと
青い光が当たろうと白い光が当たろうと
黒です。

緑の葉っぱに白い光を当てると、
反射する光は白ではなく緑です。

どういうことかというと、
物の見かけの色はライトの色だけでなく、物そのものの色にも影響される
といういことです。
物体にどんな光が当たるかということだけではなく、
それがどれだけ物体によって跳ね返されるかにも影響されるのです。

この「物そのものの色」をマテリアルといい、
BasicEffectのプロパティで設定します。

public Vector3 DiffuseColor { get; set; }

DirectionalLightのDiffuseColorをどれだけ跳ね返すかを表します。

public Vector3 SpecularColor {get; set; }

DirectionalLightのSpecularColorをどれだけ跳ね返すかを表します。

public float SpecularPower { get; set; }

SpecularColorの色の収束っぷりを表します。
大きいほどよりよく収束します。
specularPower1.JPGSpecularPower = 1
specularPower10.JPGSpecularPower = 10
specularPower100.JPGSpecularPower = 100

public Vector3 AmbientLightColor { get; set; }

環境光による色を表します。
周りで複雑な反射を繰り返し、最終的に物体に当たる光による色です。
これは物体やカメラがどんな位置や角度にあろうと必ず物体の色に反映されます。

public Vector3 EmissiveColor { get; set; }

自分自身が放つ色です。
他のプロパティが光の反射による、惑星の光だとすれば、
このプロパティは自分から光を発する恒星の光といったところでしょうか。

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

class MyGame : Game
{
    GraphicsDeviceManager graphics;
    BasicEffect effect;
    VertexPositionNormalTexture[] vertices;

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

        int planeCount = 30;
        vertices = new VertexPositionNormalTexture[planeCount * 6];

        for (int i = 0; i < planeCount; i++)
        {
            VertexPositionNormalTexture[] plane
                = new VertexPositionNormalTexture[4];

            plane[0] = new VertexPositionNormalTexture(
                    getPosition(i, planeCount) + new Vector3(0, 1, 0),
                    getPosition(i, planeCount),
                    new Vector2((float)i / planeCount, 0)
                );
            plane[1] = new VertexPositionNormalTexture(
                    getPosition(i + 1, planeCount) + new Vector3(0, 1, 0),
                    getPosition(i + 1, planeCount),
                    new Vector2((float)(i + 1) / planeCount, 0)
                );
            plane[2] = new VertexPositionNormalTexture(
                    getPosition(i, planeCount) + new Vector3(0, -1, 0),
                    getPosition(i, planeCount),
                    new Vector2((float)i / planeCount, 1)
                );
            plane[3] = new VertexPositionNormalTexture(
                    getPosition(i + 1, planeCount) + new Vector3(0, -1, 0),
                    getPosition(i + 1, planeCount),
                    new Vector2((float)(i + 1) / planeCount, 1)
                );

            vertices[i * 6] = plane[0];
            vertices[i * 6 + 1] = plane[1];
            vertices[i * 6 + 2] = plane[2];

            vertices[i * 6 + 3] = plane[1];
            vertices[i * 6 + 4] = plane[3];
            vertices[i * 6 + 5] = plane[2];
        }
    }

    Vector3 getPosition(int index, int count)
    {
        return new Vector3(
            (float)Math.Sin(2 * Math.PI * index / count),
            0,
            (float)Math.Cos(2 * Math.PI * index / count)
            );
    }

    protected override void LoadContent()
    {
        effect = new BasicEffect(GraphicsDevice)
        {
            LightingEnabled = true,
            View = Matrix.CreateLookAt
            (
                new Vector3(0, 0, 8),  //カメラの位置
                new Vector3(0, 0, 0),   //カメラの見る点
                new Vector3(0, 1, 0)    //カメラの上向きベクトル
            ),
            Projection = Matrix.CreatePerspectiveFieldOfView
            (
                MathHelper.ToRadians(45),   //視野の角度。ここでは45°
                GraphicsDevice.Viewport.AspectRatio,//画面のアスペクト比(=横/縦)
                1,      //カメラからこれより近い物体は画面に映らない
                100     //カメラからこれより遠い物体は画面に映らない
            )
        };
    }

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

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

        effect.DirectionalLight0.Direction = new Vector3(1, 0, -1);
        effect.DirectionalLight0.DiffuseColor = Color.Gray.ToVector3();
        effect.DirectionalLight0.SpecularColor = Color.White.ToVector3();

        effect.DiffuseColor = Color.Green.ToVector3();
        effect.SpecularColor = Color.Blue.ToVector3();
        effect.SpecularPower = 100;

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

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

material.JPG

このプログラムは、円筒形を表示して、そのマテリアルを設定しています。
マテリアルのDiffuseColorは緑なので、ライトの緑成分しか跳ね返しません。
(つまりライトに緑成分がなければ真っ黒に見えます。
lightDiffuseNoGreen.JPGライトのDiffuseColor = (0.5f, 0, 0.5f)


一方マテリアルのSpecularColorは青なので、
円筒のハイライト部分は青くなっています(不自然なことに!)

自然な感じにしたいのならマテリアルの
SpecularColorは白にしたほうがいいでしょうね。
specularWhite.JPG

拍手[0回]

PR