Sử dụng đèn để vẽ đa giác

Trang Cập Nhật :
Ngày tạo trang :

tóm tắt

Đèn (nguồn sáng) được sử dụng để che bóng các đa giác.

ライトを使用してポリゴンを描画する

Môi trường hoạt động

Điều kiện tiên quyết

Các phiên bản XNA được hỗ trợ
  • 4.0
Nền tảng được hỗ trợ
  • Windows (XP SP2 trở lên, Vista, 7)
  • Xbox 360
  • Windows Phone 7
Phiên bản Vertex Shader bắt buộc của Windows 2.0
Phiên bản Pixel Shader bắt buộc của Windows 2.01

Môi trường hoạt động

nền tảng
  • cửa sổ 7
  • Xbox 360
  • Trình giả lập Windows Phone 7

chất

Về đèn

Dưới đây là một vài điều bạn có thể làm về việc sử dụng đèn.

vật liệu

Nói một cách đơn giản, một vật liệu là màu của một chất. Vật liệu thường được sử dụng kết hợp với Đèn và BasicEffects cũng cho phép bạn đặt các thông số vật liệu và ánh sáng. Tuy nhiên, điều này không áp dụng nếu bạn đang viết chương trình đổ bóng của riêng mình và bạn có thể điều chỉnh nó một cách tự do. Ngoài ra, lưu ý rằng màu sắc của vật liệu khác với màu của các đỉnh.

Vật liệu thường có các mục sau.

Khuếch tán Màu sắc cơ bản của các chất
Ambient Màu sắc của màu khi tiếp xúc với ánh sáng xung quanh (có thể nhìn thấy ngay cả khi ánh sáng không chiếu trực tiếp vào nó)
Specular Ánh sáng phản chiếu đặc trưng (phát sáng mạnh mẽ như độ bóng của xe hơi, v.v.)
SpecularPower Cường độ phản xạ (Specular Strength)
Phát xạ Ánh sáng phân kỳ (tự phát sáng)

Đèn và bình thường

Nếu bạn muốn sử dụng đèn, bạn sẽ cần một thứ gọi là "bình thường". Vị trí của ánh sáng so với bình thường xác định độ sáng của vật thể. Bình thường sẽ được đặt làm dữ liệu đỉnh.

面の方向と明るさ

Nó sáng hơn nếu khuôn mặt hướng về hướng của ánh sáng, và tối hơn nếu ngược lại. Điều này cũng đúng nếu bạn thay thế hướng của khuôn mặt bằng đỉnh. Định hướng của các mặt và đỉnh này được gọi là "bình thường".

Bây giờ, hướng của các chuẩn không được xác định rõ ràng và có hai chuẩn chính để đặt trong hộp: bên dưới.

面の方向と明るさ

Có một sự khác biệt giữa bên trái và bên phải khi ánh sáng được áp dụng.

Trong trường hợp phương pháp bên trái, khoảng cách giữa các mặt sẽ xuất hiện góc cạnh. Điều này là do nó hoàn toàn được định hướng theo cùng hướng với bình thường của khuôn mặt. Tuy nhiên, phương pháp này có nhược điểm là các đỉnh không thể chia sẻ.

Với phương pháp bên phải, không gian giữa các bề mặt sẽ xuất hiện hơi tròn tùy thuộc vào cách áp dụng ánh sáng. Vì các đỉnh được chia sẻ, có một lợi thế là lượng dữ liệu giảm. Nhược điểm là bình thường của đỉnh không giống với hướng của khuôn mặt, vì vậy ngay cả khi ánh sáng được chiếu trực tiếp từ trên cao, ví dụ, bề mặt trên sẽ không bị ảnh hưởng 100% bởi ánh sáng.

Thật khó hiểu ngay cả khi bạn giải thích nó trong một câu, vì vậy hãy kiểm tra sơ đồ bên dưới để thấy sự khác biệt.

面の方向と明るさ面の方向と明るさ
Nó được hiển thị với phần mềm mô hình hóa được gọi là Metasequoia

Bạn có thể thấy rằng nó khá khác nhau về ngoại hình. Trong mẫu, chúng ta sẽ tạo hộp đúng cách để mã không bị thừa.

trường

/// <summary>
/// 基本エフェクト
/// </summary>
private BasicEffect basicEffect = null;

/// <summary>
/// 頂点バッファ
/// </summary>
private VertexBuffer vertexBuffer = null;

/// <summary>
/// インデックスバッファ
/// </summary>
private IndexBuffer indexBuffer = null;

/// <summary>
/// インデックスバッファの各頂点番号配列
/// </summary>
private static readonly Int16[] vertexIndices = new Int16[] {
    2, 0, 1, 1, 3, 2, 4, 0, 2, 2, 6, 4, 5, 1, 0, 0, 4, 5,
    7, 3, 1, 1, 5, 7, 6, 2, 3, 3, 7, 6, 4, 6, 7, 7, 5, 4 };

Hộp được tạo bằng cách sử dụng bộ đệm đỉnh và bộ đệm chỉ mục.

Sáng tạo

// エフェクトを作成
this.basicEffect = new BasicEffect(this.GraphicsDevice);

// エフェクトでライトを有効にする
this.basicEffect.LightingEnabled = true;

// デフォルトのライトの設定を使用する
this.basicEffect.EnableDefaultLighting();

// スペキュラーを無効
this.basicEffect.SpecularColor = Vector3.Zero;

// 2番目と3番目のライトを無効
this.basicEffect.DirectionalLight1.Enabled = false;
this.basicEffect.DirectionalLight2.Enabled = false;

Có một số mục trong BasicEffect đặt đèn.

Đầu tiên, đặt thuộc tính LightingEnabled thành true để hướng dẫn tính toán ánh sáng.

Khi bạn gọi phương pháp EnableDefaultLighting, màu của ánh sáng hoặc vật liệu sẽ tự động được đặt. Tuy nhiên, sử dụng đèn mặc định trên hộp này quá sáng, vì vậy tôi đã tắt màu thông số kỹ thuật và tắt đèn thứ hai và thứ ba.

// 頂点の数
int vertexCount = 8;

// 頂点バッファ作成
this.vertexBuffer = new VertexBuffer(this.GraphicsDevice,
    typeof(VertexPositionNormalTexture), vertexCount, BufferUsage.None);

// 頂点データを作成する
VertexPositionNormalTexture[] vertives = new VertexPositionNormalTexture[vertexCount];

vertives[0] = new VertexPositionNormalTexture(
    new Vector3(-2.0f, 2.0f, -2.0f),
    Vector3.Normalize(new Vector3(-1.0f, 1.0f, -1.0f)),
    Vector2.Zero);
vertives[1] = new VertexPositionNormalTexture(
    new Vector3(2.0f, 2.0f, -2.0f),
    Vector3.Normalize(new Vector3(1.0f, 1.0f, -1.0f)),
    Vector2.Zero);
vertives[2] = new VertexPositionNormalTexture(
    new Vector3(-2.0f, 2.0f, 2.0f),
    Vector3.Normalize(new Vector3(-1.0f, 1.0f, 1.0f)),
    Vector2.Zero);
vertives[3] = new VertexPositionNormalTexture(
    new Vector3(2.0f, 2.0f, 2.0f),
    Vector3.Normalize(new Vector3(1.0f, 1.0f, 1.0f)),
    Vector2.Zero);
vertives[4] = new VertexPositionNormalTexture(
    new Vector3(-2.0f, -2.0f, -2.0f),
    Vector3.Normalize(new Vector3(-1.0f, -1.0f, -1.0f)),
    Vector2.Zero);
vertives[5] = new VertexPositionNormalTexture(
    new Vector3(2.0f, -2.0f, -2.0f),
    Vector3.Normalize(new Vector3(1.0f, -1.0f, -1.0f)),
    Vector2.Zero);
vertives[6] = new VertexPositionNormalTexture(
    new Vector3(-2.0f, -2.0f, 2.0f),
    Vector3.Normalize(new Vector3(-1.0f, -1.0f, 1.0f)),
    Vector2.Zero);
vertives[7] = new VertexPositionNormalTexture(
    new Vector3(2.0f, -2.0f, 2.0f),
    Vector3.Normalize(new Vector3(1.0f, -1.0f, 1.0f)),
    Vector2.Zero);

// 頂点データを頂点バッファに書き込む
this.vertexBuffer.SetData(vertives);

Đó là một đoạn mã dài, nhưng nó tạo ra dữ liệu đỉnh. Cấu trúc dữ liệu đỉnh được sử dụng lần này là "VertexPositionNormalTexture" với dữ liệu "position", "normal" và "texture coordinates". Vì XNA Framework không cung cấp cấu trúc chỉ có "vị trí" và "bình thường", "Vector2.Zero" được chỉ định cho tất cả các đỉnh cho tọa độ kết cấu. (Tất nhiên, nếu bạn hiểu, bạn có thể tạo cấu trúc của riêng mình.)

Đối với bình thường, như thể hiện trong hình trước, nó được đặt để chỉ theo hướng xiên. Vì chuẩn là các định nghĩa dữ liệu chỉ được biểu diễn bằng hướng, hướng được chỉ định và sau đó được chuẩn hóa bằng phương pháp Vector3.Normalize.

VertexPositionNormalTexture Constructor

Tạo một thể hiện của cấu trúc "VertexPositionNormalTexture" với dữ liệu đỉnh cho vị trí và tọa độ chuẩn và kết cấu.

vị trí Vectơ3 Vị trí đỉnh
bình thường Vectơ3 Bình thường đỉnh
kết cấuPhối hợp Vectơ2 Tọa độ kết cấu của các đỉnh

Vector3.Normalize phương pháp

Tạo một vectơ đơn vị từ vectơ được chỉ định.

giá trị Vectơ3 Vector nguồn để chuẩn hóa
Trả về giá trị Vectơ3 Vector đơn vị
// インデックスバッファを作成
this.indexBuffer = new IndexBuffer(this.GraphicsDevice,
    IndexElementSize.SixteenBits, 3 * 12, BufferUsage.None);

// 頂点インデックスを書き込む
this.indexBuffer.SetData(vertexIndices);

Tạo bộ đệm chỉ mục cũng không khác.

Vẽ

// 描画に使用する頂点バッファをセット
this.GraphicsDevice.SetVertexBuffer(this.vertexBuffer);

// インデックスバッファをセット
this.GraphicsDevice.Indices = this.indexBuffer;

// パスの数だけ繰り替えし描画
foreach (EffectPass pass in this.basicEffect.CurrentTechnique.Passes)
{
    // パスの開始
    pass.Apply();

    // ボックスを描画する
    this.GraphicsDevice.DrawIndexedPrimitives(
        PrimitiveType.TriangleList,
        0,
        0,
        8,
        0,
        12
    );
}

Vì thông tin đỉnh được đặt trước, nên không có gì đặc biệt về mã vẽ.

Tất cả các mã

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
#if WINDOWS_PHONE
using Microsoft.Xna.Framework.Input.Touch;
#endif

namespace BoxReceivedLight
{
    /// <summary>
    /// ゲームメインクラス
    /// </summary>
    public class GameMain : Microsoft.Xna.Framework.Game
    {
        /// <summary>
        /// グラフィックデバイス管理クラス
        /// </summary>
        private GraphicsDeviceManager graphics = null;

        /// <summary>
        /// スプライトのバッチ化クラス
        /// </summary>
        private SpriteBatch spriteBatch = null;

        /// <summary>
        /// 基本エフェクト
        /// </summary>
        private BasicEffect basicEffect = null;

        /// <summary>
        /// 頂点バッファ
        /// </summary>
        private VertexBuffer vertexBuffer = null;

        /// <summary>
        /// インデックスバッファ
        /// </summary>
        private IndexBuffer indexBuffer = null;

        /// <summary>
        /// インデックスバッファの各頂点番号配列
        /// </summary>
        private static readonly Int16[] vertexIndices = new Int16[] {
            2, 0, 1, 1, 3, 2, 4, 0, 2, 2, 6, 4, 5, 1, 0, 0, 4, 5,
            7, 3, 1, 1, 5, 7, 6, 2, 3, 3, 7, 6, 4, 6, 7, 7, 5, 4 };


        /// <summary>
        /// GameMain コンストラクタ
        /// </summary>
        public GameMain()
        {
            // グラフィックデバイス管理クラスの作成
            this.graphics = new GraphicsDeviceManager(this);

            // ゲームコンテンツのルートディレクトリを設定
            this.Content.RootDirectory = "Content";

#if WINDOWS_PHONE
            // Windows Phone のデフォルトのフレームレートは 30 FPS
            this.TargetElapsedTime = TimeSpan.FromTicks(333333);

            // バックバッファサイズの設定
            this.graphics.PreferredBackBufferWidth = 480;
            this.graphics.PreferredBackBufferHeight = 800;

            // フルスクリーン表示
            this.graphics.IsFullScreen = true;
#endif
        }

        /// <summary>
        /// ゲームが始まる前の初期化処理を行うメソッド
        /// グラフィック以外のデータの読み込み、コンポーネントの初期化を行う
        /// </summary>
        protected override void Initialize()
        {
            // TODO: ここに初期化ロジックを書いてください

            // コンポーネントの初期化などを行います
            base.Initialize();
        }

        /// <summary>
        /// ゲームが始まるときに一回だけ呼ばれ
        /// すべてのゲームコンテンツを読み込みます
        /// </summary>
        protected override void LoadContent()
        {
            // テクスチャーを描画するためのスプライトバッチクラスを作成します
            this.spriteBatch = new SpriteBatch(this.GraphicsDevice);

            // エフェクトを作成
            this.basicEffect = new BasicEffect(this.GraphicsDevice);

            // エフェクトでライトを有効にする
            this.basicEffect.LightingEnabled = true;

            // デフォルトのライトの設定を使用する
            this.basicEffect.EnableDefaultLighting();

            // スペキュラーを無効
            this.basicEffect.SpecularColor = Vector3.Zero;

            // 2番目と3番目のライトを無効
            this.basicEffect.DirectionalLight1.Enabled = false;
            this.basicEffect.DirectionalLight2.Enabled = false;


            // ビューマトリックスをあらかじめ設定 ((6, 6, 12) から原点を見る)
            this.basicEffect.View = Matrix.CreateLookAt(
                    new Vector3(6.0f, 6.0f, 12.0f),
                    Vector3.Zero,
                    Vector3.Up
                );

            // プロジェクションマトリックスをあらかじめ設定
            this.basicEffect.Projection = Matrix.CreatePerspectiveFieldOfView(
                    MathHelper.ToRadians(45.0f),
                    (float)this.GraphicsDevice.Viewport.Width /
                        (float)this.GraphicsDevice.Viewport.Height,
                    1.0f,
                    100.0f
                );

            // 頂点の数
            int vertexCount = 8;

            // 頂点バッファ作成
            this.vertexBuffer = new VertexBuffer(this.GraphicsDevice,
                typeof(VertexPositionNormalTexture), vertexCount, BufferUsage.None);

            // 頂点データを作成する
            VertexPositionNormalTexture[] vertives = new VertexPositionNormalTexture[vertexCount];

            vertives[0] = new VertexPositionNormalTexture(
                new Vector3(-2.0f, 2.0f, -2.0f),
                Vector3.Normalize(new Vector3(-1.0f, 1.0f, -1.0f)),
                Vector2.Zero);
            vertives[1] = new VertexPositionNormalTexture(
                new Vector3(2.0f, 2.0f, -2.0f),
                Vector3.Normalize(new Vector3(1.0f, 1.0f, -1.0f)),
                Vector2.Zero);
            vertives[2] = new VertexPositionNormalTexture(
                new Vector3(-2.0f, 2.0f, 2.0f),
                Vector3.Normalize(new Vector3(-1.0f, 1.0f, 1.0f)),
                Vector2.Zero);
            vertives[3] = new VertexPositionNormalTexture(
                new Vector3(2.0f, 2.0f, 2.0f),
                Vector3.Normalize(new Vector3(1.0f, 1.0f, 1.0f)),
                Vector2.Zero);
            vertives[4] = new VertexPositionNormalTexture(
                new Vector3(-2.0f, -2.0f, -2.0f),
                Vector3.Normalize(new Vector3(-1.0f, -1.0f, -1.0f)),
                Vector2.Zero);
            vertives[5] = new VertexPositionNormalTexture(
                new Vector3(2.0f, -2.0f, -2.0f),
                Vector3.Normalize(new Vector3(1.0f, -1.0f, -1.0f)),
                Vector2.Zero);
            vertives[6] = new VertexPositionNormalTexture(
                new Vector3(-2.0f, -2.0f, 2.0f),
                Vector3.Normalize(new Vector3(-1.0f, -1.0f, 1.0f)),
                Vector2.Zero);
            vertives[7] = new VertexPositionNormalTexture(
                new Vector3(2.0f, -2.0f, 2.0f),
                Vector3.Normalize(new Vector3(1.0f, -1.0f, 1.0f)),
                Vector2.Zero);

            // 頂点データを頂点バッファに書き込む
            this.vertexBuffer.SetData(vertives);

            // インデックスバッファを作成
            this.indexBuffer = new IndexBuffer(this.GraphicsDevice,
                IndexElementSize.SixteenBits, 3 * 12, BufferUsage.None);

            // 頂点インデックスを書き込む
            this.indexBuffer.SetData(vertexIndices);
        }

        /// <summary>
        /// ゲームが終了するときに一回だけ呼ばれ
        /// すべてのゲームコンテンツをアンロードします
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: ContentManager で管理されていないコンテンツを
            //       ここでアンロードしてください
        }

        /// <summary>
        /// 描画以外のデータ更新等の処理を行うメソッド
        /// 主に入力処理、衝突判定などの物理計算、オーディオの再生など
        /// </summary>
        /// <param name="gameTime">このメソッドが呼ばれたときのゲーム時間</param>
        protected override void Update(GameTime gameTime)
        {
            // Xbox 360 コントローラ、Windows Phone の BACK ボタンを押したときに
            // ゲームを終了させます
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
            {
                this.Exit();
            }

            // TODO: ここに更新処理を記述してください

            // 登録された GameComponent を更新する
            base.Update(gameTime);
        }

        /// <summary>
        /// 描画処理を行うメソッド
        /// </summary>
        /// <param name="gameTime">このメソッドが呼ばれたときのゲーム時間</param>
        protected override void Draw(GameTime gameTime)
        {
            // 画面を指定した色でクリアします
            this.GraphicsDevice.Clear(Color.CornflowerBlue);

            // 描画に使用する頂点バッファをセット
            this.GraphicsDevice.SetVertexBuffer(this.vertexBuffer);

            // インデックスバッファをセット
            this.GraphicsDevice.Indices = this.indexBuffer;

            // パスの数だけ繰り替えし描画
            foreach (EffectPass pass in this.basicEffect.CurrentTechnique.Passes)
            {
                // パスの開始
                pass.Apply();

                // ボックスを描画する
                this.GraphicsDevice.DrawIndexedPrimitives(
                    PrimitiveType.TriangleList,
                    0,
                    0,
                    8,
                    0,
                    12
                );
            }

            // 登録された DrawableGameComponent を描画する
            base.Draw(gameTime);
        }
    }
}