استفاده از نورها برای ترسیم چند ضلعی ها
خلاصه
از نورها (منابع نور) برای سایه زدن چند ضلعی ها استفاده می شود.
محیط عملیاتی
پیش نیازها
نسخه های XNA پشتیبانی شده |
|
پلتفرم های پشتیبانی شده |
|
نسخه Vertex Shader مورد نیاز ویندوز | 2.0 |
ویندوز نسخه Pixel Shader مورد نیاز است | 2.01 |
محیط عملیاتی
بستر |
|
ماده
درباره چراغ ها
در اینجا چند کار وجود دارد که می توانید در مورد استفاده از چراغ ها انجام دهید.
مواد
به عبارت ساده، یک ماده رنگ یک ماده است. مواد اغلب همراه با Lights استفاده می شوند و BasicEffects همچنین به شما امکان می دهد پارامترهای مواد و نور را تنظیم کنید. با این حال، اگر برنامه سایه زن خود را می نویسید، این امر صدق نمی کند و می توانید آن را آزادانه تنظیم کنید. همچنین توجه داشته باشید که رنگ ماده با رنگ رئوس متفاوت است.
مواد به طور کلی موارد زیر را دارند.
منتشر | رنگ های اصلی مواد |
محیط | رنگ رنگ هنگام قرار گرفتن در معرض نور محیط (حتی اگر نور مستقیما روی آن نتابد قابل مشاهده است) |
خاص | نور بازتاب چشمی (به شدت مانند براقیت ماشین می درخشد، و غیره) |
قدرت SpecularPower | قدرت بازتابنده (قدرت چشمی) |
فرستاده کننده | نور واگرا (خود به خود می درخشد) |
چراغ ها و نرمال ها
اگر می خواهید از چراغ استفاده کنید، به چیزی به نام "عادی" نیاز دارید. موقعیت نور نسبت به نرمال روشنایی جسم را تعیین می کند. نرمال به عنوان داده های راس تنظیم می شود.
اگر صورت رو به جهت نور باشد روشن تر است و اگر برعکس باشد تیره تر است. این امر در صورتی نیز صادق است که جهت صورت را با یک راس جایگزین کنید. جهت گیری این وجوه و رئوس را "عادی" می نامند.
اکنون، جهت نرمال ها به صراحت تعریف نشده است و دو نرمال اصلی برای تنظیم در کادر وجود دارد: در زیر.
هنگام اعمال نور بین چپ و راست تفاوت وجود دارد.
در مورد روش سمت چپ ، فضای بین چهره ها زاویه دار به نظر می رسد. دلیل این امر این است که کاملا در همان جهت حالت طبیعی صورت قرار دارد. با این حال، این روش این عیب را دارد که رئوس را نمی توان به اشتراک گذاشت.
با روش سمت راست، بسته به نحوه اعمال نور، فضای بین سطوح کمی گرد به نظر می رسد. از آنجایی که رئوس به اشتراک گذاشته می شوند، این مزیت وجود دارد که میزان داده ها کاهش می یابد. عیب آن این است که نرمال راس با جهت صورت یکسان نیست ، بنابراین حتی اگر نور مستقیما از بالا تابیده شود ، به عنوان مثال ، سطح فوقانی 100٪ تحت تأثیر نور قرار نمی گیرد.
درک آن سخت است حتی اگر آن را در یک جمله توضیح دهید، بنابراین نمودار زیر را بررسی کنید تا تفاوت را ببینید.
با نرم افزار مدل سازی به نام Metasequoia نمایش داده می شود
می بینید که از نظر ظاهری کاملا متفاوت است. در نمونه، کادر را به روش صحیح ایجاد می کنیم تا کد زائد نباشد.
زمینه
<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 };
این جعبه با استفاده از یک بافر راس و یک بافر شاخص ایجاد می شود.
ایجاد
// エフェクトを作成
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;
چندین مورد در BasicEffect وجود دارد که نور را تنظیم می کند.
ابتدا ویژگی LightingEnabled را روی true تنظیم کنید تا نور محاسبه شود.
هنگامی که متد EnableDefaultLighting را فراخوانی می کنید، رنگ نور یا ماده به طور خودکار تنظیم می شود. با این حال، استفاده از چراغ پیش فرض در این جعبه بسیار روشن است، بنابراین رنگ خاص را غیرفعال کردم و چراغ های دوم و سوم را غیرفعال کردم.
// 頂点の数
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);
این یک قطعه کد کمی طولانی است، اما داده های راس را ایجاد می کند. ساختار داده راس که این بار استفاده می شود، "VertexPositionNormalTexture" با داده های "position"، "normal" و "مختصات بافت" است. از آنجایی که XNA Framework ساختاری را فقط با "position" و "normal" ارائه نمی دهد، "Vector2.Zero" برای همه رئوس مختصات بافت مشخص شده است. (البته، اگر درک کنید، می توانید ساختار خود را بسازید.)
در مورد حالت عادی ، همانطور که در شکل قبلی نشان داده شده است ، طوری تنظیم شده است که در جهت مورب قرار گیرد. از آنجایی که نرمال ها تعاریف داده ای هستند که فقط با جهت نشان داده می شوند، جهت مشخص می شود و سپس با روش Vector3.Normalize نرمال می شود.
VertexPositionNormalTexture
سازنده
یک نمونه از ساختار "VertexPositionNormalTexture" با داده های راس برای موقعیت و مختصات نرمال و بافت ایجاد کنید.
موقعیت | بردار3 | موقعیت راس |
طبیعی | بردار3 | نرمال های راس |
بافت مختصات | بردار2 | مختصات بافت رئوس |
Vector3.Normalize
روش
یک بردار واحد از بردار مشخص شده ایجاد می کند.
ارزش | بردار3 | بردار منبع برای عادی سازی |
مقادیر برگشتی | بردار3 | بردار واحد |
// インデックスバッファを作成
this.indexBuffer = new IndexBuffer(this.GraphicsDevice,
IndexElementSize.SixteenBits, 3 * 12, BufferUsage.None);
// 頂点インデックスを書き込む
this.indexBuffer.SetData(vertexIndices);
ایجاد یک بافر ایندکس تفاوتی ندارد.
نقاشی
// 描画に使用する頂点バッファをセット
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
);
}
از آنجایی که اطلاعات راس از قبل تنظیم شده است، هیچ چیز خاصی در مورد کد ترسیم وجود ندارد.
همه کدها
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);
}
}
}