การแสดงรูปหลายเหลี่ยมสามเหลี่ยม
สรุป
แสดงรูปหลายเหลี่ยมสามเหลี่ยมในพื้นที่ 3 มิติ
สภาพแวดล้อมในการทํางาน
ข้อกําหนดเบื้องต้น
รุ่น XNA ที่รองรับ |
|
แพลตฟอร์มที่รองรับ |
|
Windows ต้องใช้เวอร์ชัน Vertex Shader | 2.0 |
เวอร์ชัน Pixel Shader ที่จําเป็นของ Windows | 2.0 |
สภาพแวดล้อมในการทํางาน
แท่น |
|
สาร
รูปหลายเหลี่ยมคืออะไร?
รูปหลายเหลี่ยมคือใบหน้าที่สร้างขึ้นโดยคําจํากัดความจุดยอดหลายจุด โดยทั่วไปรูปหลายเหลี่ยมเป็นใบหน้าสามเหลี่ยมที่ประกอบด้วยจุดยอดสามจุด และตรีกอนเป็นหน่วยที่เล็กที่สุดของรูปหลายเหลี่ยม ซอฟต์แวร์การสร้างแบบจําลองบางตัวอาจแสดงรูปหลายเหลี่ยมเป็นรูปสี่เหลี่ยมหรือรูปหลายเหลี่ยม แต่ในที่สุดสิ่งเหล่านี้จะถูกย่อยสลายเป็นรูปหลายเหลี่ยมสามเหลี่ยม
โมเดลที่แสดงในเกมเกิดจากการรวมรูปหลายเหลี่ยมสามเหลี่ยมเหล่านี้เข้าด้วยกัน
รูปหลายเหลี่ยมเกิดจากจุดยอด จุดยอดสามารถมีข้อมูล เช่น ตําแหน่งและสี ตัวอย่างนี้ยังทําจากข้อมูล "ตําแหน่ง" และ "สี"
สีของใบหน้าในตัวอย่างนี้ถูกแทรกอย่างเรียบร้อยตามสีและระยะทางที่ตั้งไว้สําหรับแต่ละจุดยอด แต่คุณสามารถเปลี่ยนได้อย่างอิสระด้วยโปรแกรม shader ของคุณเอง (เพิ่มเติมเกี่ยวกับโปรแกรม shader ในครั้งต่อไป)
คําจํากัดความของข้อมูล Vertex
ในการแสดงรูปหลายเหลี่ยม จําเป็นต้องมี "ข้อมูลจุดยอด" และโปรแกรมเมอร์ต้องตัดสินใจว่าจะรวมองค์ประกอบใดไว้ในจุดยอดนั้น เมื่อวาดรูปหลายเหลี่ยม คุณต้องบอกอุปกรณ์ ซึ่งเป็นเอ็นจิ้นการวาดภาพ ข้อมูลจุดยอดใดที่จะวาดรูปหลายเหลี่ยมด้วย เมื่อต้องการทําเช่นนี้ ให้สร้างคลาส "VertexDeclaration" และตั้งค่า "คําจํากัดความข้อมูลจุดยอด"
อย่างไรก็ตาม ตั้งแต่ XNA Game Studio 4.0 การตั้งค่านี้ง่ายขึ้น และคุณไม่จําเป็นต้องเตรียมคลาส VertexDeclaration สําหรับเคล็ดลับนี้ (เนื่องจากข้อมูลคําจํากัดความถูกฝังอยู่ในข้อมูลจุดยอดที่เฟรมเวิร์กให้ไว้แล้ว)
ข้อมูลจุดสูงสุด
ฉันเขียนว่าข้อมูลจุดยอดเป็นสิ่งจําเป็นในการวาดรูปหลายเหลี่ยม แต่ก่อนอื่นเราต้องตัดสินใจว่าเราต้องการมีข้อมูลประเภทใด ในกรณีนี้ เราจะใช้ข้อมูล "ตําแหน่ง" และ "สี" เมื่อคุณตัดสินใจได้แล้วว่าต้องการมีข้อมูลใดคุณต้องสร้างโครงสร้างเพื่อเก็บข้อมูลนั้น คุณมีอิสระในการตัดสินใจว่าข้อมูลจุดยอดคืออะไร แต่ข้อมูลจุดยอดที่ใช้กันทั่วไปถูกกําหนดไว้ในเฟรมเวิร์ก XNA แล้ว ดังนั้นตัวอย่างจึงใช้ข้อมูลจุดยอด
ข้อมูลจุดยอดที่มี "ตําแหน่ง" และ "สี" ถูกกําหนดให้เป็นโครงสร้าง "VertexPositionColor" เนื่องจากจําเป็นต้องมีจุดยอดหลายจุดเพื่อสร้างรูปหลายเหลี่ยม เราจึงประกาศว่าเป็นอาร์เรย์
<summary>
頂点データリスト
</summary>
private VertexPositionColor[] vertices = null;
ผล
ใน XNA เมื่อคุณวาดรูปหลายเหลี่ยม คุณต้องเขียนโปรแกรม shader แยกต่างหากเพื่อตัดสินใจว่าจะวาดอย่างไร ในการดําเนินการนี้ ให้สร้างไฟล์เอฟเฟกต์แยกต่างหาก เขียนโปรแกรม โหลดเป็นคลาสเอฟเฟกต์ และเรียกใช้โปรแกรม shader
อย่างไรก็ตาม หากคุณไม่จําเป็นต้องวาดรูปหลายเหลี่ยมสามเหลี่ยมธรรมดาๆ เช่นนี้ หรือเอฟเฟกต์การวาดที่ซับซ้อน อาจเป็นงานที่ยุ่งยากมาก
ด้วยเหตุนี้ XNA จึงกําหนดเอฟเฟ็กต์แบบขยายที่ช่วยให้คุณสามารถตั้งค่ารายการที่จําเป็นเป็นคุณสมบัติ เพื่อให้คุณไม่ต้องเขียนโปรแกรม shader สําหรับการวาดแบบพื้นฐาน นั่นคือคลาส "BasicEffect" เนื่องจากจุดประสงค์ของบทความนี้คือการวาดรูปหลายเหลี่ยม เราจะใช้ "BasicEffect" ที่ไม่ต้องใช้ความพยายามมากนักในการวาด
<summary>
基本エフェクト
</summary>
private BasicEffect basicEffect = null;
ฉันจะพูดถึงเอฟเฟกต์และ BasicEffects เพิ่มเติมในครั้งต่อไป
อย่างไรก็ตาม Windows Phone 7 ไม่อนุญาตให้คุณใช้เอฟเฟกต์ของคุณเอง แต่เฉพาะเอฟเฟกต์ที่สร้างขึ้นในเฟรมเวิร์กเช่น BasicEffect เท่านั้น
สร้างข้อกําหนดข้อมูลจุดยอด
จนถึง XNA Framework 3.1 คุณต้องสร้างโดยทางโปรแกรมอย่างชัดเจน แต่ตั้งแต่ 4.0 ข้อมูล จุดยอดในตัวของเฟรมเวิร์กจะรวมอยู่ในข้อมูลจุดยอดเป็น "IVertexType.VertexDeclaration" แล้ว ดังนั้นเราจะใช้ข้อมูลนี้
การสร้างเอฟเฟกต์
สร้างคลาส BasicEffect ตั้งค่าคุณสมบัติ BasicEffect.VertexColorEnabled เป็น true เพื่อรักษาสีจุดยอด
// エフェクトを作成
this.basicEffect = new BasicEffect(this.GraphicsDevice);
// エフェクトで頂点カラーを有効にする
this.basicEffect.VertexColorEnabled = true;
BasicEffect
ผู้สร้าง
สร้างอินสแตนซ์ของคลาสเอฟเฟกต์ "BasicEffect" ที่แสดงสีจุดยอด พื้นผิว และแสงโดยใช้ Shader Model 2.0
อุปกรณ์ | กราฟิกอุปกรณ์ | ระบุ GraphicsDevice สําหรับการสร้างเอฟเฟ็กต์ |
ดูเมทริกซ์และเมทริกซ์การฉายภาพ
ตั้งค่า BasicEffect เป็นเมทริกซ์มุมมองและเมทริกซ์การฉายภาพ สําหรับคําอธิบายเชิงแนวคิดของแต่ละรายการ โปรดดูลิงก์ด้านล่าง
// ビューマトリックスをあらかじめ設定 ((0, 0, 15) から原点を見る)
this.basicEffect.View = Matrix.CreateLookAt(
new Vector3(0.0f, 0.0f, 15.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
);
หากต้องการสร้างเมทริกซ์มุมมอง ให้ใช้เมธอด "Matrix.CreateLookAt"
อาร์กิวเมนต์แรกระบุตําแหน่งของกล้องอาร์กิวเมนต์ที่สองระบุจุดสนใจของกล้องและอาร์กิวเมนต์ที่สามระบุทิศทางขึ้นของกล้อง
ในกรณีนี้ จะตั้งค่าให้ดูที่จุดเริ่มต้นจากตําแหน่ง (0, 0, 15)
Matrix.CreateLookAt
วิธี
สร้างเมทริกซ์มุมมอง
ตําแหน่งกล้อง | เวกเตอร์ 3 | ตําแหน่งกล้อง |
กล้องเป้าหมาย | เวกเตอร์ 3 | จุดสนใจของกล้อง |
กล้องอัพเวกเตอร์ | เวกเตอร์ 3 | ทิศทางขึ้นของกล้อง |
เมื่อต้องการสร้างเมทริกซ์การฉายภาพ ให้ใช้เมธอด "Matrix.CreatePerspectiveFieldOfView"
ข้อโต้แย้งแรกคือมุมมองเป็นเรเดียน ในตัวอย่าง หน่วยองศาจะถูกแปลงเป็นเรเดียนโดยใช้วิธี "MathHelper.ToRadians" สําหรับข้อมูลเพิ่มเติมเกี่ยวกับเรเดียนและองศา โปรดดู เรเดียนและองศา
อาร์กิวเมนต์ที่สองระบุอัตราส่วนภาพ (อัตราส่วนภาพ) โดยปกติ คุณจะระบุค่าสําหรับ ความกว้างของมุมมอง ÷ ความสูง ในตัวอย่างจะคํานวณจากความกว้างและความสูงที่ตั้งไว้สําหรับวิวพอร์ตของอุปกรณ์
อาร์กิวเมนต์ที่สามระบุตําแหน่งการตัดไปข้างหน้า และอาร์กิวเมนต์ที่สี่ระบุตําแหน่งการตัดย้อนกลับ
Matrix.CreatePerspectiveFieldOfView
วิธี
สร้างเมทริกซ์การฉายภาพเปอร์สเปคทีฟตามการตั้งค่าของฟิลด์มุมมอง
ฟิลด์ของมุมมอง | ลอย | มุมมอง. ระบุเป็นหน่วยเรเดียน |
อัตราส่วนด้าน | ลอย | อัตราส่วนภาพ (อัตราส่วนภาพ) โดยปกติคุณจะระบุค่าสําหรับ "ความกว้าง÷ความสูงของมุมมอง" |
nearPlaneDistance | ลอย | ตําแหน่งคลิปไปข้างหน้า วัตถุที่อยู่ด้านหน้าตําแหน่งนี้จะไม่ถูกวาด |
ระยะทางเครื่องบินไกล | ลอย | ตําแหน่งคลิปด้านหลัง วัตถุที่อยู่นอกตําแหน่งนี้จะไม่ถูกวาด |
การสร้างข้อมูล Vertex
สร้างข้อมูลจุดยอดสามรายการ ขั้นแรกเราจะสร้างอาร์เรย์และสร้างจุดยอดแต่ละจุด
// 頂点データを作成する
this.vertices = new VertexPositionColor[3];
this.vertices[0] = new VertexPositionColor(new Vector3(0.0f, 3.0f, 0.0f),
Color.Red);
this.vertices[1] = new VertexPositionColor(new Vector3(3.0f, -2.0f, 0.0f),
Color.Blue);
this.vertices[2] = new VertexPositionColor(new Vector3(-3.0f, -2.0f, 0.0f),
Color.Green);
ในการสร้างข้อมูลจุดยอด ให้ระบุ "ตําแหน่งจุดยอด" และ "สีจุดยอด" ในตัวสร้างของ "VertexPositionColor"
VertexPositionColor
ผู้สร้าง
สร้างอินสแตนซ์ของโครงสร้าง "VertexPositionColor" ด้วยข้อมูลตําแหน่งและจุดยอดสี
ฐานะ | เวกเตอร์ 3 | ตําแหน่งจุดยอด |
สี | สี | สียอด |
ตั้งค่าตําแหน่งของจุดยอดเป็นช่วงที่สามารถมองเห็นได้จากกล้อง นอกจากนี้ ให้ตั้งค่าการจัดเรียงจุดยอดเป็น "ตามเข็มนาฬิกา (ตามเข็มนาฬิกา)" หากคุณตั้งค่าเป็น "ทวนเข็มนาฬิกา" รูปหลายเหลี่ยมจะมองไม่เห็น สําหรับคําอธิบายนี้ โปรดดู การระบุใบหน้าของรูปหลายเหลี่ยมที่จะวาด
การวาดรูปหลายเหลี่ยม
// パスの数だけ繰り替えし描画 (といっても直接作成した BasicEffect は通常1回)
foreach (EffectPass pass in this.basicEffect.CurrentTechnique.Passes)
{
// パスの開始
pass.Apply();
// ポリゴンを描画する
this.GraphicsDevice.DrawUserPrimitives(
PrimitiveType.TriangleList,
this.vertices,
0,
1
);
}
// 登録された DrawableGameComponent を描画する
base.Draw(gameTime);
เอฟเฟกต์มีสองประเภทที่เรียกว่า "เทคนิค" และ "เส้นทาง" ซึ่งคุณเรียกใช้โปรแกรมวาดภาพจริง เนื่องจากอาจมีหลายเส้นทางในเอฟเฟกต์เดียว ฉันจึงพยายามเรียกซ้ําๆ ใน foreach อย่างไรก็ตาม ใน BasicEffect มีเทคนิคเดียวและเส้นทางเดียว คุณจึงสามารถระบุดัชนีของเส้นทางได้โดยตรง แต่คําอธิบายข้างต้นจะสะอาดกว่าเพราะคุณสามารถแทนที่เอฟเฟกต์อื่นๆ ได้
ก่อนเริ่มการวาดภาพจริง ให้เรียกใช้เมธอด "EffectPass.Apply" เพื่อเริ่มการส่งผ่าน เมื่อเรียกวิธีนี้พารามิเตอร์ของเอฟเฟกต์ที่จะใช้ในครั้งนี้จะถูกนําไปใช้กับอุปกรณ์กราฟิก
เมื่อคุณเริ่มเส้นทางแล้ว ให้วาดรูปหลายเหลี่ยมด้วยเมธอด "GraphicsDevice.DrawUserPrimitives"
อาร์กิวเมนต์แรกระบุประเภทของ primitive ที่จะวาด ในกรณีนี้เราจะวาดรูปหลายเหลี่ยมสามเหลี่ยมดังนั้นให้ระบุ "PrimitiveType.TriangleList"
อาร์กิวเมนต์ที่สองระบุข้อมูลจุดยอดที่สร้างขึ้น
อาร์กิวเมนต์ที่สามระบุจุดยอดที่จะวาด โดยปกตินี่คือ 0
อาร์กิวเมนต์ที่สี่ระบุจํานวนดั้งเดิมที่จะวาด ในกรณีนี้มีรูปหลายเหลี่ยมสามเหลี่ยมเพียงรูปเดียวดังนั้นให้ระบุ 1 โปรดทราบว่าไม่ใช่จํานวนจุดยอด
GraphicsDevice.DrawUserPrimitives
วิธี
วาดภาพดั้งเดิมตามข้อมูลจุดยอดที่ผู้ใช้ให้มา
T | ไม่จํากัด | โครงสร้างข้อมูล Vertex |
primitiveType | ประเภทดั้งเดิม | ประเภทของดึกดําบรรพ์ที่จะวาด |
ข้อมูลจุดยอด | T[] | อาร์เรย์ของข้อมูลจุดยอดที่จะวาด |
จุดยอดออฟเซ็ต | int | ระบุจํานวนข้อมูลจุดยอดที่จะใช้ในการวาดภาพ |
primitiveCount | int | จํานวนดึกดําบรรพ์ที่จะวาด |
นั่นคือโปรแกรมวาดภาพ หากคุณเรียกใช้จริงและสามเหลี่ยมปรากฏขึ้นแสดงว่าคุณทําเสร็จแล้ว
รหัสทั้งหมด
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 DrawTriangle
{
<summary>
ゲームメインクラス
</summary>
public class GameMain : Microsoft.Xna.Framework.Game
{
<summary>
グラフィックデバイス管理クラス
</summary>
private GraphicsDeviceManager graphics = null;
<summary>
スプライトのバッチ化クラス
</summary>
private SpriteBatch spriteBatch = null;
<summary>
頂点データリスト
</summary>
private VertexPositionColor[] vertices = null;
<summary>
基本エフェクト
</summary>
private BasicEffect basicEffect = null;
<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.VertexColorEnabled = true;
// ビューマトリックスをあらかじめ設定 ((0, 0, 15) から原点を見る)
this.basicEffect.View = Matrix.CreateLookAt(
new Vector3(0.0f, 0.0f, 15.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
);
// 頂点データを作成する
this.vertices = new VertexPositionColor[3];
this.vertices[0] = new VertexPositionColor(new Vector3(0.0f, 3.0f, 0.0f),
Color.Red);
this.vertices[1] = new VertexPositionColor(new Vector3(3.0f, -2.0f, 0.0f),
Color.Blue);
this.vertices[2] = new VertexPositionColor(new Vector3(-3.0f, -2.0f, 0.0f),
Color.Green);
}
<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);
// パスの数だけ繰り替えし描画 (といっても直接作成した BasicEffect は通常1回)
foreach (EffectPass pass in this.basicEffect.CurrentTechnique.Passes)
{
// パスの開始
pass.Apply();
// ポリゴンを描画する
this.GraphicsDevice.DrawUserPrimitives(
PrimitiveType.TriangleList,
this.vertices,
0,
1
);
}
// 登録された DrawableGameComponent を描画する
base.Draw(gameTime);
}
}
}