Menggunakan lampu untuk menggambar poligon
ringkasan
Lampu (sumber cahaya) digunakan untuk menaungi poligon.
Lingkungan operasi
Prasyarat
Versi XNA yang Didukung |
|
Platform yang Didukung |
|
Versi Vertex Shader yang Diperlukan Windows | 2.0 |
Versi Pixel Shader yang Diperlukan Windows | 2.01 |
Lingkungan operasi
balei-balei |
|
zat
Tentang Lampu
Berikut adalah beberapa hal yang dapat Anda lakukan tentang menggunakan lampu.
bahan
Secara sederhana, bahan adalah warna suatu zat. Material sering digunakan bersama dengan Lights, dan BasicEffects juga memungkinkan Anda untuk mengatur parameter material dan cahaya. Namun, ini tidak berlaku jika Anda menulis program shader Anda sendiri, dan Anda dapat menyesuaikannya dengan bebas. Juga, perhatikan bahwa warna material berbeda dari warna simpul.
Bahan umumnya memiliki item berikut.
Menyebar | Warna dasar zat |
Ambient | Warna warna saat terkena cahaya sekitar (terlihat meskipun cahaya tidak menyinari langsung di atasnya) |
Spekular | Cahaya pantulan spekular (bersinar kuat seperti kilap mobil, dll.) |
Kekuatan Spekuler | Kekuatan Reflektif (Kekuatan Spekular) |
Emisif | Cahaya yang berbeda (bersinar dengan sendirinya) |
Lampu dan Normal
Jika Anda ingin menggunakan lampu, Anda memerlukan sesuatu yang disebut "normal". Posisi cahaya dalam kaitannya dengan normal menentukan kecerahan objek. Normal akan ditetapkan sebagai data simpul.
Lebih terang jika wajah menghadap ke arah cahaya, dan lebih gelap jika sebaliknya. Ini juga berlaku jika Anda mengganti arah wajah dengan simpul. Orientasi wajah dan simpul ini disebut "normal".
Sekarang, arah normal tidak ditentukan secara eksplisit, dan ada dua normal utama yang harus diatur dalam kotak: di bawah ini.
Ada perbedaan antara kiri dan kanan saat cahaya diterapkan.
Dalam kasus metode di sebelah kiri, ruang di antara wajah akan tampak bersudut. Ini karena sepenuhnya berorientasi ke arah yang sama dengan normal wajah. Namun, metode ini memiliki kelemahan bahwa simpul tidak dapat dibagikan.
Dengan metode di sebelah kanan, ruang antar permukaan akan tampak sedikit membulat tergantung pada bagaimana cahaya diterapkan. Karena simpul dibagikan, ada keuntungan bahwa jumlah data berkurang. Kerugiannya adalah normal simpul tidak sama dengan arah wajah, jadi meskipun cahaya bersinar langsung dari atas, misalnya, permukaan atas tidak akan 100% terpengaruh oleh cahaya.
Sulit untuk dipahami bahkan jika Anda menjelaskannya dalam sebuah kalimat, jadi periksa diagram di bawah ini untuk melihat perbedaannya.
Itu ditampilkan dengan perangkat lunak pemodelan yang disebut Metasequoia
Anda dapat melihat bahwa penampilannya sangat berbeda. Dalam sampel, kita akan membuat kotak dengan cara yang benar sehingga kodenya tidak berlebihan.
kebun
<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 };
Kotak dibuat menggunakan buffer simpul dan buffer indeks.
Penciptaan
// エフェクトを作成
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;
Ada beberapa item di BasicEffect yang mengatur cahaya.
Pertama, atur properti LightingEnabled ke true untuk menginstruksikan cahaya yang akan dihitung.
Saat Anda memanggil metode EnableDefaultLighting, warna cahaya atau material diatur secara otomatis. Namun, menggunakan lampu default pada kotak ini terlalu terang, jadi saya menonaktifkan warna spekular dan menonaktifkan lampu kedua dan ketiga.
// 頂点の数
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);
Ini adalah kode yang agak panjang, tetapi membuat data simpul. Struktur data simpul yang digunakan kali ini adalah "VertexPositionNormalTexture" dengan data "position", "normal", dan "texture coordinates". Karena Kerangka Kerja XNA tidak menyediakan struktur hanya dengan "posisi" dan "normal", "Vector2.Zero" ditentukan untuk semua simpul untuk koordinat tekstur. (Tentu saja, jika Anda mengerti, Anda dapat membuat struktur Anda sendiri.)
Adapun normal, seperti yang ditunjukkan pada gambar sebelumnya, diatur untuk menunjuk ke arah miring. Karena normal adalah definisi data yang hanya diwakili oleh orientasi, arah ditentukan dan kemudian dinormalisasi dengan metode Vector3.Normalize.
VertexPositionNormalTexture
pembangun
Buat instance struktur "VertexPositionNormalTexture" dengan data simpul untuk posisi dan koordinat normal dan tekstur.
posisi | Vektor3 | Posisi Simpul |
biasa | Vektor3 | Normal simpul |
Koordinat tekstur | Vektor2 | Koordinat tekstur simpul |
Vector3.Normalize
Metode
Membuat vektor satuan dari vektor yang ditentukan.
nilai | Vektor3 | Vektor sumber untuk menormalkan |
Nilai Pengembalian | Vektor3 | Vektor satuan |
// インデックスバッファを作成
this.indexBuffer = new IndexBuffer(this.GraphicsDevice,
IndexElementSize.SixteenBits, 3 * 12, BufferUsage.None);
// 頂点インデックスを書き込む
this.indexBuffer.SetData(vertexIndices);
Membuat buffer indeks tidak berbeda.
gambar
// 描画に使用する頂点バッファをセット
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
);
}
Karena informasi simpul diatur sebelumnya, tidak ada yang istimewa tentang kode gambar.
Semua Kode
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);
}
}
}