Перетворення тривимірних координат на екран
зведення
Він перетворює координати в 3D просторі в координати на екрані і відображає назву в місці розташування моделі. У зразку камера повернута, щоб було простіше побачити, що назва слідує за моделлю.
Робоче середовище
Передумови
Підтримувані версії XNA |
|
Підтримувані платформи |
|
Потрібна версія Vertex Shader для Windows | 2.0 |
Потрібна версія піксельного шейдера Windows | 2.0 |
Робоче середовище
платформа |
|
речовина
Перетворення 3D координат в координати екрана
Якщо ви хочете відобразити ім'я над головою персонажа, наприклад, у 3D-грі, необхідно розрахувати координати екрана, на яких повинен відображатися персонаж з тривимірного просторового положення персонажа.
Це може здатися складним розрахунком, але насправді дані вершин багатокутника отримуються так само, як і формула, яка використовується для перетворення даних вершин полігону з 3D-координат у координати екрану, тому нові знання не потрібні.
Існують також методи, які легко розрахувати, тому вам не доведеться писати додатковий код.
поле
У вибірці відображаються три моделі, тому ми визначаємо модель і вектор[3], які є інформацією про три положення. Він також визначає кут автоматичного повороту камери, щоб рух було легко зрозуміти.
<summary>
モデル
</summary>
private Model model = null;
<summary>
位置の配列
</summary>
private Vector3[] positions = new Vector3[3];
<summary>
カメラの水平回転角度
</summary>
private float theta = 0.0f;
Процес оновлення
Кут повороту для автоматичного повороту камери виходить з витраченого часу гри.
// カメラの水平角度を自動更新
this.theta = (float)gameTime.TotalGameTime.TotalSeconds / 2.0f;
Попереднє малювання
Після малювання спрайту буфер глибини може бути вимкнений, тому встановіть "DepthStencilState.Default", щоб увімкнути судження про малювання за значенням глибини.
Помноживши матрицю обертання осі Y на вже створену вами матрицю перегляду, ви можете обертати положення камери навколо точки інтересу. Зверніть увагу на порядок множення матриці.
// Zバッファを有効にする
this.GraphicsDevice.DepthStencilState = DepthStencilState.Default;
// ビューマトリックスに回転を合成算出
Matrix rotatedView = Matrix.CreateRotationY(this.theta) * this.view;
Отримати Viewport
Viewport надає метод перетворення з 3D просторових координат на координати екрана, тому отримайте його з GraphicsDevice.
// ビューポート取得
Viewport viewport = this.GraphicsDevice.Viewport;
Розрахунок координат екрану за 3D координатами
Знайти координати екрана за координатами 3D простору так само просто, як і за допомогою методу Viewport.Project.
Укажіть 3D-просторове положення джерела як перший аргумент, проекційну матрицю як другий аргумент і матрицю представлення як третій аргумент. Потім ви можете отримати координати на екрані як значення, що повертається.
Після цього, якщо ви витягнете значення X і Y з Vector3, ви зможете використовувати позицію відображення тексту. (Z - положення глибини)
// 3次元座標からスクリーンの座標算出
Vector3 v3 = viewport.Project(this.positions[i],
this.projection,
rotatedView,
Matrix.Identity);
Vector2 screenPosition = new Vector2(v3.X, v3.Y);
// テキスト描画
this.spriteBatch.DrawString(this.font, "Model " + (i + 1).ToString(),
screenPosition, Color.White);
Viewport.Project
метод
Проектує 3D-вектор з простору об'єктів у простір екрана.
джерело | Вектор3 | 3D просторовий координатний вектор для проекції на екранні координати |
Проекції | Матриця | Проективна матриця |
вид | Матриця | Матриця перегляду |
світ | Матриця | Визначає перше перетворення, яке має бути виконано |
Значення, що повертаються | Вектор3 | Отримує вектор на екранному просторі |
Всі коди
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 TransformToScreen
{
<summary>
ゲームメインクラス
</summary>
public class GameMain : Microsoft.Xna.Framework.Game
{
<summary>
グラフィックデバイス管理クラス
</summary>
private GraphicsDeviceManager graphics = null;
<summary>
スプライトのバッチ化クラス
</summary>
private SpriteBatch spriteBatch = null;
<summary>
スプライトでテキストを描画するためのフォント
</summary>
private SpriteFont font = null;
<summary>
モデル
</summary>
private Model model = null;
<summary>
位置の配列
</summary>
private Vector3[] positions = new Vector3[3];
<summary>
カメラの水平回転角度
</summary>
private float theta = 0.0f;
<summary>
ビューマトリックス
</summary>
private Matrix view = Matrix.Identity;
<summary>
プロジェクションマトリックス
</summary>
private Matrix projection = Matrix.Identity;
<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()
{
// 位置をランダムに設定
Random rand = new Random();
for (int i = 0; i < this.positions.Length; i++)
{
this.positions[i] =
new Vector3((float)(rand.NextDouble() - 0.5) * 10.0f,
0.0f,
(float)(rand.NextDouble() - 0.5) * 10.0f);
}
// ビューマトリックス
this.view = Matrix.CreateLookAt(new Vector3(0.0f, 10.0f, 20.0f),
Vector3.Zero,
Vector3.Up);
// プロジェクションマトリックス
this.projection = Matrix.CreatePerspectiveFieldOfView(
MathHelper.ToRadians(45.0f),
(float)this.GraphicsDevice.Viewport.Width /
(float)this.GraphicsDevice.Viewport.Height,
1.0f,
100.0f
);
// コンポーネントの初期化などを行います
base.Initialize();
}
<summary>
ゲームが始まるときに一回だけ呼ばれ
すべてのゲームコンテンツを読み込みます
</summary>
protected override void LoadContent()
{
// テクスチャーを描画するためのスプライトバッチクラスを作成します
this.spriteBatch = new SpriteBatch(this.GraphicsDevice);
// フォントをコンテンツパイプラインから読み込む
this.font = this.Content.Load<SpriteFont>("Font");
// モデルを作成
this.model = this.Content.Load<Model>("Model");
// ライトとプロジェクションはあらかじめ設定しておく
foreach (ModelMesh mesh in this.model.Meshes)
{
foreach (BasicEffect effect in mesh.Effects)
{
// デフォルトのライト適用
effect.EnableDefaultLighting();
// プロジェクションマトリックスをあらかじめ設定
effect.Projection = this.projection;
}
}
}
<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();
}
// カメラの水平角度を自動更新
this.theta = (float)gameTime.TotalGameTime.TotalSeconds / 2.0f;
// 登録された GameComponent を更新する
base.Update(gameTime);
}
<summary>
描画処理を行うメソッド
</summary>
<param name="gameTime">このメソッドが呼ばれたときのゲーム時間</param>
protected override void Draw(GameTime gameTime)
{
// 画面を指定した色でクリアします
this.GraphicsDevice.Clear(Color.CornflowerBlue);
// Zバッファを有効にする
this.GraphicsDevice.DepthStencilState = DepthStencilState.Default;
// ビューマトリックスに回転を合成算出
Matrix rotatedView = Matrix.CreateRotationY(this.theta) * this.view;
for (int i = 0; i < this.positions.Length; i++)
{
foreach (ModelMesh mesh in this.model.Meshes)
{
foreach (BasicEffect effect in mesh.Effects)
{
// ビューマトリックス
effect.View = rotatedView;
// モデルの位置設定
effect.World = Matrix.CreateTranslation(this.positions[i]);
}
// モデルを描画
mesh.Draw();
}
}
// ビューポート取得
Viewport viewport = this.GraphicsDevice.Viewport;
// スプライトの描画準備
this.spriteBatch.Begin();
// 各モデルの位置にテキストを描画
for (int i = 0; i < this.positions.Length; i++)
{
// 3次元座標からスクリーンの座標算出
Vector3 v3 = viewport.Project(this.positions[i],
this.projection,
rotatedView,
Matrix.Identity);
Vector2 screenPosition = new Vector2(v3.X, v3.Y);
// テキスト描画
this.spriteBatch.DrawString(this.font, "Model " + (i + 1).ToString(),
screenPosition, Color.White);
}
// スプライトの一括描画
this.spriteBatch.End();
// 登録された DrawableGameComponent を描画する
base.Draw(gameTime);
}
}
}