Çokgenler çizmek için ışıkları kullanın
özet
Çokgenleri gölgelendirmek için ışıklar (ışık kaynakları) kullanılır.
Çalışma ortamı
Önkoşullar
Desteklenen XNA Sürümleri |
|
Desteklenen Platformlar |
|
Windows Gerekli Köşe Gölgelendiricisi Sürümü | 2.0 |
Windows Gerekli Pixel Shader Sürümü | 2.01 |
Çalışma ortamı
peron |
|
madde
Işıklar Hakkında
İşte ışıkları kullanma konusunda yapabileceğiniz birkaç şey.
malzeme
Basit bir ifadeyle, bir malzeme bir maddenin rengidir. Malzemeler genellikle Işıklar ile birlikte kullanılır ve BasicEffects ayrıca malzeme ve ışık parametrelerini ayarlamanıza olanak tanır. Ancak, kendi gölgelendirici programınızı yazıyorsanız bu geçerli değildir ve onu serbestçe ayarlayabilirsiniz. Ayrıca, malzemenin renginin köşelerin renginden farklı olduğuna dikkat edin.
Malzemeler genellikle aşağıdaki öğelere sahiptir.
Diffüz | Maddelerin temel renkleri |
Ortam | Ortam ışığına maruz kaldığında rengin rengi (ışık doğrudan üzerine gelmese bile görülebilir) |
Aynasal | Aynasal yansıma ışığı (bir arabanın parlaklığı gibi güçlü bir şekilde parlar, vb.) |
Speküler Güç | Yansıtıcı Kuvvet (Speküler Kuvvet) |
Yayıcı | Iraksak ışık (kendi kendine parlar) |
Işıklar ve Normaller
Bir ışık kullanmak istiyorsanız, "normal" adı verilen bir şeye ihtiyacınız olacak. Işığın normale göre konumu, nesnenin parlaklığını belirler. Normal, köşe verileri olarak ayarlanacaktır.
Yüz ışığın yönüne bakıyorsa daha parlak, tam tersi ise daha koyudur. Bu, yüzün yönünü bir tepe noktası ile değiştirirseniz de geçerlidir. Bu yüzlerin ve köşelerin oryantasyonuna "normal" denir.
Şimdi, normallerin yönü açıkça tanımlanmamıştır ve kutuda ayarlanması gereken iki ana normal vardır: aşağıda.
Işık uygulandığında sol ve sağ arasında bir fark vardır.
Soldaki yöntem söz konusu olduğunda, yüzler arasındaki boşluk köşeli görünecektir. Bunun nedeni, tamamen yüzün normali ile aynı yöne yönlendirilmiş olmasıdır. Ancak bu yöntemin köşelerin paylaşılamaması gibi bir dezavantajı vardır.
Sağdaki yöntemle, ışığın nasıl uygulandığına bağlı olarak yüzeyler arasındaki boşluk hafifçe yuvarlatılmış görünecektir. Köşeler paylaşıldığından, veri miktarının azalması gibi bir avantaj vardır. Dezavantajı, tepe noktasının normalinin yüzün yönü ile aynı olmamasıdır, bu nedenle ışık doğrudan yukarıdan parlasa bile, örneğin üst yüzey ışıktan %100 etkilenmeyecektir.
Bir cümleyle açıklasanız bile anlaması zordur, bu yüzden farkı görmek için aşağıdaki şemayı kontrol edin.
Metasequoia adı verilen modelleme yazılımı ile görüntülenir
Görünüş olarak oldukça farklı olduğunu görebilirsiniz. Örnekte, kodun gereksiz olmaması için kutuyu doğru şekilde oluşturacağız.
alan
<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 };
Kutu, bir köşe tamponu ve bir indeks tamponu kullanılarak oluşturulur.
yaratım
// エフェクトを作成
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'te ışığı ayarlayan birkaç öğe vardır.
İlk olarak, ışığın hesaplanmasını bildirmek için LightingEnabled özelliğini true olarak ayarlayın.
EnableDefaultLighting yöntemini çağırdığınızda, ışığın veya malzemenin rengi otomatik olarak ayarlanır. Ancak, bu kutudaki varsayılan ışığı kullanmak çok parlak, bu yüzden aynasal rengi devre dışı bıraktım ve ikinci ve üçüncü ışıkları devre dışı bıraktım.
// 頂点の数
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);
Biraz uzun bir kod parçası, ancak köşe verileri oluşturuyor. Bu kez kullanılan köşe veri yapısı, "position", "normal" ve "texture coordinates" verileriyle "VertexPositionNormalTexture" dır. XNA Framework'ü sadece "position" ve "normal" olan bir yapı sağlamadığından, doku koordinatları için tüm köşeler için "Vector2.Zero" belirtilir. (Tabii ki, eğer anlarsanız, kendi yapınızı yapabilirsiniz.)
Normale gelince, önceki şekilde gösterildiği gibi, eğik bir yönü gösterecek şekilde ayarlanmıştır. Normaller yalnızca yönlendirme ile temsil edilen veri tanımları olduğundan, yön belirtilir ve ardından Vector3.Normalize yöntemiyle normalleştirilir.
VertexPositionNormalTexture
Oluşturucu
Konum, normal ve doku koordinatları için köşe verileriyle "VertexPositionNormalTexture" yapısının bir örneğini oluşturun.
konum | Vektör3 | Köşe Konumu |
normal | Vektör3 | Köşe normalleri |
textureKoordinat | Vektör2 | Köşelerin doku koordinatları |
Vector3.Normalize
yöntem
Belirtilen vektörden bir birim vektör oluşturur.
değer | Vektör3 | Normalleştirmek için kaynak vektör |
Dönüş Değerleri | Vektör3 | Birim vektör |
// インデックスバッファを作成
this.indexBuffer = new IndexBuffer(this.GraphicsDevice,
IndexElementSize.SixteenBits, 3 * 12, BufferUsage.None);
// 頂点インデックスを書き込む
this.indexBuffer.SetData(vertexIndices);
Bir dizin arabelleği oluşturmak da farklı değildir.
çizim
// 描画に使用する頂点バッファをセット
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
);
}
Köşe bilgisi önceden ayarlandığından, çizim koduyla ilgili özel bir şey yoktur.
Tüm Kodlar
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);
}
}
}