AI モンスターの知能
同次変換・アフィモン変換 練習問題スターに視覚を与える
2D・3DisFindPlayer / DirectX11形式は誰が決めているのか?
導入:右から掛けるルールと左から掛けるルール
1. 前回までの確認
3Dグラフィック前回、モンスターの行列計算動を if文 では、資料やライブラリによって点と行列の掛け切り替える考え方が違うを学びました。
大きく分けると例えば、次の2種類があるような処理です。
if (isAttackRange)
{
Attack();
}
else if (isFindPlayer)
{
ChasePlayer();
}
else
{
Idle();
}
この処理では、モンスターは次のように行動します。
| どちらでもない |
このプリントでは、最終的にDirectX11でよく使う行ベクトル方式で練習する。
ただし、最初に2つの違いを確認しておく。
1. 列ベクトル方式
列ベクトル方式では、点を縦に書く。
2Dの点 $P(x, y)$ は、同次座標で次のように表、条件によって行動を変えることで、モンスターが考えて動いているように見えます。
$$
P =
\left(
\begin{array}{c}
x \\
y \\
1
\end{array}
\right)
$$
変換後の点は、行列を左から掛けて求める。
$$
P' = M P
$$
つまり、行列が左、点が右にある。
2. 列ベクトル方式の平行移動ここで問い
列ベクトル方式で、x方向に $t_x$、y方向に $t_y$ 平行移動する行列は次の形変数にな注目してください。
isFindPlayer
これは、
プレイヤーを見つけているか?
を表すフラグです。
$$
T =
\left(
\begin{array}{ccc}
1 & 0 & t_x \\
0 & 1 & t_y \\
0 & 0 & 1
\end{array}
\right)
$$しかし、ここで考えるべきことがあります。
isFindPlayer は誰が決めているのか?
点に掛けるプログラムの中で、
if (isFindPlayer)
と、次のようになる書くことはできます。
$$しかし、isFindPlayer P'が true になる理由を作らなければ、モンスターはプレイヤーを見つけることができません。
つまり、
isFindPlayer = Ttrue;
P
$$
$$
\left(
\begin{array}{c}
x' \\
y' \\
1
\end{array}
\right)
\left(
\begin{array}{ccc}
1 & 0 & t_x \\
0 & 1 & t_y \\
0 & 0 & 1
\end{array}
\right)
\left(
\begin{array}{c}
x \\
y \\
1
\end{array}
\right)
$$
実際に掛け算すると、
$$
x' = 1 \times x + 0 \times y + t_x \times 1
$$
$$
y' = 0 \times x + 1 \times y + t_y \times 1
$$
したがって、
$$
x' = x + t_x
$$
$$
y' = y + t_y
$$
になる条件を、こちらで作る必要があります。
3. 行ベクトル方式ゲームAIには「知覚」が必要
モンスターが行ベクトル方式で動を決めるには、点まずゲームの状況を横に書く。
2Dの点 $P(x, y)$ は、同次座標で次のように表知る必要があります。
$$
P =
\left(
\begin{array}{ccc}
x & y & 1
\end{array}
\right)
$$
変換後の点は、点を左から行列に掛けて求める。
$$
P' = P M
$$
つまり、点が左、行列が右にある。
4. 行ベクトル方式の平行移動
行ベクトル方式で、x方向に $t_x$、y方向に $t_y$ 平行移動する行列は次の形になる。
$$
T =
\left(
\begin{array}{ccc}
1 & 0 & 0 \\
0 & 1 & 0 \\
t_x & t_y & 1
\end{array}
\right)
$$
点に掛けると、次のようになる。
$$
P' = P T
$$
$$
\left(
\begin{array}{ccc}
x' & y' & 1
\end{array}
\right)
\left(
\begin{array}{ccc}
x & y & 1
\end{array}
\right)
\left(
\begin{array}{ccc}
1 & 0 & 0 \\
0 & 1 & 0 \\
t_x & t_y & 1
\end{array}
\right)
$$
実際に掛け算すると、
$$
x' = x \times 1 + y \times 0 + 1 \times t_x
$$
$$
y' = x \times 0 + y \times 1 + 1 \times t_y
$$
したがって、
$$
x' = x + t_x
$$
$$
y' = y + t_y
$$
になる。
5. 同じ変換でも行列の形が違う
同じ「x方向に $t_x$、y方向に $t_y$ 平行移動」でも、列ベクトル方式と行ベクトル方式では、行列の形が違う。
列ベクトル方式
$$
\left(
\begin{array}{ccc}
1 & 0 & t_x \\
0 & 1 & t_y \\
0 & 0 & 1
\end{array}
\right)
$$
行ベクトル方式
$$
\left(
\begin{array}{ccc}
1 & 0 & 0 \\
0 & 1 & 0 \\
t_x & t_y & 1
\end{array}
\right)
$$
列ベクトル方式では、平行移動は右端の列に入る。
行ベクトル方式では、平行移動は下の行に入る。
6. 掛け算のやり方の違い
列ベクトル方式
列ベクトル方式では、
$$
P' = M P
$$
である。
例えば、
- プレイヤーが近くにいる
- プレイヤーが前方にいる
- プレイヤーとの間に壁がない
- プレイヤーが音を立てた
- プレイヤーが攻撃してきた
$$
\left(
\begin{array}{ccc}
a & b & c \\
d & e & f \\
g & h & i
\end{array}
\right)
\left(
\begin{array}{c}
x \\
y \\
1
\end{array}
\right)
$$などです。
このように、AIがゲームの状況を計算知る仕組みを 知覚 と呼びますると、
$$
x' = ax + by + c
$$
$$
y' = dx + ey + f
$$
$$
w' = gx + hy + i
$$
になる。
行ベクトル方式
4. 人間の「見る」とAIの「見る」は違う
行ベクトル人間は目で映像を見ています。
しかし、ゲームAIは本当に画面を見ているわけではありません。
ゲームAIは、次のような数値や条件を使って「見えているか」を判定します。
距離は近いか?
前方式でにいるか?
壁に隠れていないか?
つまり、ゲームAIの視覚とは、
$$
画像を見ること
P' = P M
$$
であはなく、
条件を満たしたら「見えている」とする処理
です。
5. まず一番簡単な視覚を作る
最初は、距離だけで考えます。
例えば、
プレイヤーが10m以内にいたら発見
$$
\left(
\begin{array}{ccc}
x & y & 1
\end{array}
\right)
\left(
\begin{array}{ccc}
a & b & c \\
d & e & f \\
g & h & i
\end{array}
\right)
$$というルールにします。
この場合、モンスターはプレイヤーとの距離を計算調べます。
VECTOR toPlayer = VSub(playerPos, enemyPos);
float distance = VSize(toPlayer);
if (distance < VIEW_DISTANCE)
{
isFindPlayer = true;
}
else
{
isFindPlayer = false;
}
ここで、VIEW_DISTANCE は視界距離です。
const float VIEW_DISTANCE = 10.0f;
6. 距離だけの視覚の問題点
距離だけで判定すると、
$$
x' = xa + yd + 1g
$$
$$
y' = xb + ye + 1h
$$
$$
w' = xc + yf + 1i
$$
にかなるり単純なAIになります。
同じ行列例えば、次のような問題があります。
問題1:後ろにいても見つかる
距離だけで判定すると、プレイヤーがモンスターの後ろにいても見つかってしまいます。
プレイヤー
↓
モンスター → 前を向いている
本当なら、モンスターの後ろにいるプレイヤーは見えないはずです。
でも距離だけで判定していると、近ければ見つかります。
問題2:壁越しでも見つかる
距離だけで判定すると、どち壁の向こうにいるプレイヤーも見つかってしまいます。
モンスター |壁| プレイヤー
本当なら側、壁があるので見えないはずです。
でも距離だけで判定していると、近ければ見つから掛けるかで使われる成分が変わるります。
7. 合成変換の順番の違い視覚に必要な条件
点より自然な視覚を作るに対しては、次の順番3つを考えます。
1. 距離
2. 向き
3. 障害物
8. 条件1:距離
まずは距離で変換したす。
プレイヤーが遠すぎるなら見えないと
これは分かりやすい条件です。
if (distance > VIEW_DISTANCE)
{
isFindPlayer = false;
}
9. 条件2:向き
次に、プレイヤーがモンスターの前方にいるかを調べます。
モンスターには向きがあります。
モンスター → 前方
プレイヤーが前方にいれば見える。
拡大縮小→$S$プレイヤー
回転平行移動プレイヤー$T$←
モンスター
しかし、プレイヤーが後ろにいるなら見えません。
列10. 前方にいるかをどう調べるか
ここで使うのが 内積 です。
必要なベクトルは2つです。
モンスターの前方式向
モンスターからプレイヤーへの場合方向
11. モンスターからプレイヤーへの方向
列まず、モンスターからプレイヤーへのベクトル方式では、を求めます。
$$
VECTOR P'toPlayer = MVSub(playerPos, PenemyPos);
$$
次に、長さを1にします。
float distance = VSize(toPlayer);
VECTOR dirToPlayer = VScale(toPlayer, 1.0f / distance);
この dirToPlayer が、モンスターから見たプレイヤーの方向であるす。
12. モンスターの前方向
次に、モンスターの前方向を用意します。
実際の計算は例として、Y軸回転から前方向を作るなら、次のようになります。
VECTOR forward =
{
sinf(enemyRotY),
0.0f,
cosf(enemyRotY)
};
ただし、モデルの正面方向や座標系によって、sinf と cosf の使い方は変わることがあります。
13. 内積で角度を調べる
2つのベクトルの内積を取ります。
float dot = VDot(forward, dirToPlayer);
dot の値は、だいたい次のように考えられます。
| dotの値 | 意味 |
|---|---|
| 1.0 に近い | 正面にいる |
| 0.0 に近い | 横にいる |
| -1.0 に近い | 後ろにいる |
14. 視野角の判定
例えば、次のようにします。
const float VIEW_DOT = 0.5f;
if (dot > VIEW_DOT)
{
isFindPlayer = true;
}
else
{
isFindPlayer = false;
}
dot > 0.5f なら、前方のある範囲内にいると判断できます。
15. VIEW_DOT の目安
| 条件 | 見える範囲の目安 |
|---|---|
dot > 0.5f |
前方約120度 |
dot > 0.707f |
前方約90度 |
dot > 0.866f |
前方約60度 |
数値を大きくすると、視野が狭くなります。
$$数値を小さくすると、視野が広くなります。
16. 距離と向きを組み合わせる
距離と向きを組み合わせると、次のような判定になります。
bool CheckCanSeePlayer()
{
VECTOR toPlayer = TVSub(playerPos, RenemyPos);
Sfloat Pdistance $$= VSize(toPlayer);
if (distance > VIEW_DISTANCE)
{
return false;
}
if (distance < 0.001f)
{
return true;
}
VECTOR dirToPlayer = VScale(toPlayer, 1.0f / distance);
VECTOR forward =
{
sinf(enemyRotY),
0.0f,
cosf(enemyRotY)
};
float dot = VDot(forward, dirToPlayer);
if (dot < VIEW_DOT)
{
return false;
}
return true;
}
この関数は、
プレイヤーが見えているなら true
見えていないなら false
を返します。
17. 条件3:障害物
まだ問題があります。
距離が近くて、前方にいても、壁の向こうにいるなら本当は見えません。
モンスター ---- 壁 ---- プレイヤー
この場合は、見えないようにしたいです。
18. 壁で見えない処理
考え方は単純です。
モンスターからプレイヤーまで線を引く
↓
途中に壁があるか調べる
↓
壁があれば見えない
↓
壁がなければ見える
このような判定を、レイ判定やライン判定と呼びます。
19. 疑似コード
bool isHitWall = CheckLineHitWall(enemyPos, playerPos);
if (isHitWall)
{
return false;
}
CheckLineHitWall は、敵とプレイヤーの間に壁があるか調べる処理だと考えてください。
20. 最終的な視覚判定
距離、向き、壁を組み合わせると、次のような流れになります。
bool CheckCanSeePlayer()
{
VECTOR toPlayer = VSub(playerPos, enemyPos);
float distance = VSize(toPlayer);
// 遠すぎるなら見えない
if (distance > VIEW_DISTANCE)
{
return false;
}
// ほぼ同じ位置なら見えている扱い
if (distance < 0.001f)
{
return true;
}
// 方向を求める
VECTOR dirToPlayer = VScale(toPlayer, 1.0f / distance);
// モンスターの前方向
VECTOR forward =
{
sinf(enemyRotY),
0.0f,
cosf(enemyRotY)
};
// 前方にいるか調べる
float dot = VDot(forward, dirToPlayer);
if (dot < VIEW_DOT)
{
return false;
}
// 壁があれば見えない
if (CheckLineHitWall(enemyPos, playerPos))
{
return false;
}
return true;
}
21. 前回のAIに接続する
視覚判定ができたら、前回のAIに接続できます。
isFindPlayer = CheckCanSeePlayer();
if (isAttackRange)
{
Attack();
}
else if (isFindPlayer)
{
ChasePlayer();
}
else
{
Idle();
}
これで、
見えたら追いかける
見えなければ待機する
というモンスターになります。
22. 何がAIらしくなるのか
距離だけで判定していたときは、
近ければ必ず見つかる
という動きでした。
しかし、視野角や壁判定を入れると、次のようになります。
後ろに回ると気づかれない
壁に隠れると見つからない
正面に出ると追いかけてくる
このようなルールがあると、プレイヤーは、
敵に見つかった
敵から隠れた
敵の背後を取った
と感じやすくなります。
つまり、合成行列は、
$$
M = T R S
$$
である。
行列のAIが少し賢く見た目としては、後に実行えまする変換ほど左側に来る。
行ベクトル方式の場合
行ベクトル方式では、
$$
P' = P M
$$
である。
実際の計算は次のようになる。
$$
P' = P S R T
$$
つまり、合成行列は、
$$
M = S R T
$$
である。
行列の見た目としては、実行したい順番に左から右へ並べればよい。
8.23. このプリントで使うルール重要な考え方
こゲームAIは、本当に人間のプリントように世界を理解しているわけでは、DirectX11形式とありません。
してかし、次のルールような情報を使うことで統一、考えているように見せることができまする。
点は行ベクトルで書く
距離
方向
角度
障害物
時間
状態
$$
P =
\left(
\begin{array}{ccc}
x & y & 1
\end{array}
\right)
$$
AIは、世界をそのまたま理解しているのではなく、
$$
P =
\left(
\begin{array}{cccc}
x & y & z & 1
\end{array}
\right)
$$
点は左から行列ゲームに掛必要な情報だける
$$
P' = P M
$$
合成変換は、実行を取り出したて判断してい順番に行列を並べる
例えば、
拡大縮小回転平行移動
なら、
$$
M = S R T
$$
であるます。
2Dの同次座標まとめ
2次元今回の点 $P(x, y)$ は、同次座標でポイントは次のように表通りです。
$$
isFindPlayer Pは勝手に決まらない
=
AIには知覚が必要
\begin{array}{ccc}
2Dのアフィン変換行列
ゲームAIの視覚は、DirectX11形式画像を見ることでは次の形ない
距離・向き・壁で「見えている」を作る
見えているかどうかをフラグになる。して、行動分岐に使う
$$
M =
\left(
\begin{array}{ccc}
a & b & 0 \\
c & d & 0 \\
t_x & t_y & 1
\end{array}
\right)
$$
2Dの基本変換行列
平行移動
$$
T =
\left(
\begin{array}{ccc}
1 & 0 & 0 \\
0 & 1 & 0 \\
t_x & t_y & 1
\end{array}
\right)
$$
拡大縮小
$$
S =
\left(
\begin{array}{ccc}
s_x & 0 & 0 \\
0 & s_y & 0 \\
0 & 0 & 1
\end{array}
\right)
$$
原点中心の回転
このプリントでは、2D回転は反時計回りを正とする。
$$
R =
\left(
\begin{array}{ccc}
\cos\theta & \sin\theta & 0 \\
-\sin\theta & \cos\theta & 0 \\
0 & 0 & 1
\end{array}
\right)
$$
第1部:2D同最後の確認問題
問1
次変換のフラグは何を表しているか説明しなさい。
bool isFindPlayer;
問題1:2D平行移動
点 $P(2, 3)$ を、次のように平行移動する。
x方向に $+4$y方向に $-1$
問い
平行移動行列 $T$ を書け。次の計算を行い、変換後の座標を求めよ。
$$
P' = P T
$$
解答欄
$$
T =
\left(
\begin{array}{ccc}
\quad & \quad & \quad \\
\quad & \quad & \quad \\
\quad & \quad & \quad
\end{array}
\right)
$$
変換後の座標:
$$
(\quad,\quad)
$$
問題2:2D拡大縮小
点 $P(2, 3)$ を、次のように拡大縮小する。
x方向に $3$ 倍y方向に $2$ 倍
問い
拡大縮小行列 $S$ を書け。次の計算を行い、変換後の座標を求めよ。
$$
P' = P S
$$
解答欄
$$
S =
\left(
\begin{array}{ccc}
\quad & \quad & \quad \\
\quad & \quad & \quad \\
\quad & \quad & \quad
\end{array}
\right)
$$
変換後の座標:
$$
(\quad,\quad)
$$
問題3:2D回転
点 $P(1, 0)$ を、原点を中心に反時計回りに $90^\circ$ 回転する。
$$
\cos 90^\circ = 0
$$
$$
\sin 90^\circ = 1
$$
問い
回転行列 $R$ を書け。次の計算を行い、変換後の座標を求めよ。
$$
P' = P R
$$
解答欄
$$
R =
\left(
\begin{array}{ccc}
\quad & \quad & \quad \\
\quad & \quad & \quad \\
\quad & \quad & \quad
\end{array}
\right)
$$
変換後の座標:
$$
(\quad,\quad)
$$
問題4:2D合成変換
点 $P(1, 2)$ に対して、次の順番で変換する。
x方向に $2$ 倍、y方向に $3$ 倍するx方向に $+5$、y方向に $-1$ 平行移動する
DirectX11形式なので、合成行列は次の順番になる。
$$
M = S T
$$
問い
拡大縮小行列 $S$ を書け。平行移動行列 $T$ を書け。合成行列 $M = S T$ を求めよ。点 $P$ の変換後の座標を求めよ。
解答欄
$$
S =
\left(
\begin{array}{ccc}
\quad & \quad & \quad \\
\quad & \quad & \quad \\
\quad & \quad & \quad
\end{array}
\right)
$$
$$
T =
\left(
\begin{array}{ccc}
\quad & \quad & \quad \\
\quad & \quad & \quad \\
\quad & \quad & \quad
\end{array}
\right)
$$
$$
M = S T =
\left(
\begin{array}{ccc}
\quad & \quad & \quad \\
\quad & \quad & \quad \\
\quad & \quad & \quad
\end{array}
\right)
$$
変換後の座標:
$$
(\quad,\quad)
$$
問題5:2D合成変換と順番の違い
点 $P(1, 1)$ に対して、次の2通りの変換を行う。
A
x方向に $+3$、y方向に $0$ 平行移動する全体を $2$ 倍に拡大する
B
全体を $2$ 倍に拡大するx方向に $+3$、y方向に $0$ 平行移動する
問い
Aの合成行列 $M_A$ を求めよ。Bの合成行列 $M_B$ を求めよ。AとBそれぞれの変換後の座標を求めよ。結果が違う理由を説明せよ。
解答欄
Aの合成行列:
$$
M_A =
\left(
\begin{array}{ccc}
\quad & \quad & \quad \\
\quad & \quad & \quad \\
\quad & \quad & \quad
\end{array}
\right)
$$
Aの変換後:
$$
(\quad,\quad)
$$
Bの合成行列:
$$
M_B =
\left(
\begin{array}{ccc}
\quad & \quad & \quad \\
\quad & \quad & \quad \\
\quad & \quad & \quad
\end{array}
\right)
$$
Bの変換後:
$$
(\quad,\quad)
$$
理由:
第2部:3D同次変換
3Dの同次座標
3次元の点 $P(x, y, z)$ は、同次座標では次のように表す。
$$
P =
\left(
\begin{array}{cccc}
x & y & z & 1
\end{array}
\right)
$$
3Dのアフィン変換行列は、DirectX11形式では次の形になる。
$$
M =
\left(
\begin{array}{cccc}
a & b & c & 0 \\
d & e & f & 0 \\
g & h & i & 0 \\
t_x & t_y & t_z & 1
\end{array}
\right)
$$
3Dの基本変換行列
平行移動
$$
T =
\left(
\begin{array}{cccc}
1 & 0 & 0 & 0 \\
0 & 1 & 0 & 0 \\
0 & 0 & 1 & 0 \\
t_x & t_y & t_z & 1
\end{array}
\right)
$$
拡大縮小
$$
S =
\left(
\begin{array}{cccc}
s_x & 0 & 0 & 0 \\
0 & s_y & 0 & 0 \\
0 & 0 & s_z & 0 \\
0 & 0 & 0 & 1
\end{array}
\right)
$$
Y軸回転
このプリントでは、DirectXの左手系を前提とする。
$$
R_y =
\left(
\begin{array}{cccc}
\cos\theta & 0 & -\sin\theta & 0 \\
0 & 1 & 0 & 0 \\
\sin\theta & 0 & \cos\theta & 0 \\
0 & 0 & 0 & 1
\end{array}
\right)
$$
$90^\circ$ の場合は次のようになる。
$$
R_y =
\left(
\begin{array}{cccc}
0 & 0 & -1 & 0 \\
0 & 1 & 0 & 0 \\
1 & 0 & 0 & 0 \\
0 & 0 & 0 & 1
\end{array}
\right)
$$
問題6:3D平行移動
点 $P(1, 2, 3)$ を、次のように平行移動する。
x方向に $+4$y方向に $-2$z方向に $+1$
問い
平行移動行列 $T$ を書け。次の計算を行い、変換後の座標を求めよ。
$$
P' = P T
$$
解答欄
$$
T =
\left(
\begin{array}{cccc}
\quad & \quad & \quad & \quad \\
\quad & \quad & \quad & \quad \\
\quad & \quad & \quad & \quad \\
\quad & \quad & \quad & \quad
\end{array}
\right)
$$
変換後の座標:
$$
(\quad,\quad,\quad)
$$
問題7:3D拡大縮小
点 $P(1, 2, 3)$ を、次のように拡大縮小する。
x方向に $2$ 倍y方向に $3$ 倍z方向に $4$ 倍
問い
拡大縮小行列 $S$ を書け。次の計算を行い、変換後の座標を求めよ。
$$
P' = P S
$$
解答欄
$$
S =
\left(
\begin{array}{cccc}
\quad & \quad & \quad & \quad \\
\quad & \quad & \quad & \quad \\
\quad & \quad & \quad & \quad \\
\quad & \quad & \quad & \quad
\end{array}
\right)
$$
変換後の座標:
$$
(\quad,\quad,\quad)
$$
問題8:3D Y軸回転
点 $P(1, 0, 0)$ を、Y軸まわりに $90^\circ$ 回転する。
問い
Y軸回転行列 $R_y$ を書け。次の計算を行い、変換後の座標を求めよ。
$$
P' = P R_y
$$
解答欄
$$
R_y =
\left(
\begin{array}{cccc}
\quad & \quad & \quad & \quad \\
\quad & \quad & \quad & \quad \\
\quad & \quad & \quad & \quad \\
\quad & \quad & \quad & \quad
\end{array}
\right)
$$
変換後の座標:
$$
(\quad,\quad,\quad)
$$
問題9:3D合成変換
点 $P(1, 2, 3)$ に対して、次の順番で変換する。
全体を $2$ 倍に拡大するY軸まわりに $90^\circ$ 回転するx方向に $+3$、y方向に $+1$、z方向に $+2$ 平行移動する
DirectX11形式なので、合成行列は次の順番になる。
$$
M = S R_y T
$$
問い
拡大縮小行列 $S$ を書け。Y軸回転行列 $R_y$ を書け。平行移動行列 $T$ を書け。合成行列 $M = S R_y T$ を求めよ。点 $P$ の変換後の座標を求めよ。
解答欄
$$
S =
\left(
\begin{array}{cccc}
\quad & \quad & \quad & \quad \\
\quad & \quad & \quad & \quad \\
\quad & \quad & \quad & \quad \\
\quad & \quad & \quad & \quad
\end{array}
\right)
$$
$$
R_y =
\left(
\begin{array}{cccc}
\quad & \quad & \quad & \quad \\
\quad & \quad & \quad & \quad \\
\quad & \quad & \quad & \quad \\
\quad & \quad & \quad & \quad
\end{array}
\right)
$$
$$
T =
\left(
\begin{array}{cccc}
\quad & \quad & \quad & \quad \\
\quad & \quad & \quad & \quad \\
\quad & \quad & \quad & \quad \\
\quad & \quad & \quad & \quad
\end{array}
\right)
$$
$$
M = S R_y T =
\left(
\begin{array}{cccc}
\quad & \quad & \quad & \quad \\
\quad & \quad & \quad & \quad \\
\quad & \quad & \quad & \quad \\
\quad & \quad & \quad & \quad
\end{array}
\right)
$$
変換後の座標:
$$
(\quad,\quad,\quad)
$$
問題10:3D合成変換と順番の違い
点 $P(1, 0, 0)$ に対して、次の2通りの変換を行う。
A
x方向に $+5$ 平行移動するY軸まわりに $90^\circ$ 回転する
B
Y軸まわりに $90^\circ$ 回転するx方向に $+5$ 平行移動する
問い
Aの合成行列 $M_A$ を求めよ。Bの合成行列 $M_B$ を求めよ。AとBそれぞれの変換後の座標を求めよ。結果が違う理由を説明せよ。
解答欄
Aの合成行列:
$$
M_A =
\left(
\begin{array}{cccc}
\quad & \quad & \quad & \quad \\
\quad & \quad & \quad & \quad \\
\quad & \quad & \quad & \quad \\
\quad & \quad & \quad & \quad
\end{array}
\right)
$$
Aの変換後:
$$
(\quad,\quad,\quad)
$$
Bの合成行列:
$$
M_B =
\left(
\begin{array}{cccc}
\quad & \quad & \quad & \quad \\
\quad & \quad & \quad & \quad \\
\quad & \quad & \quad & \quad \\
\quad & \quad & \quad & \quad
\end{array}
\right)
$$
Bの変換後:
$$
(\quad,\quad,\quad)
$$
理由:
解答例
問題1
$$
T =
\left(
\begin{array}{ccc}
1 & 0 & 0 \\
0 & 1 & 0 \\
4 & -1 & 1
\end{array}
\right)
$$
答え:
$$
(6, 2)
$$
問題2
$$
S =
\left(
\begin{array}{ccc}
3 & 0 & 0 \\
0 & 2 & 0 \\
0 & 0 & 1
\end{array}
\right)
$$
答え:
$$
(6, 6)
$$
距離だけでプレイヤーを発見するAIには、どんな問題3
がありますか。$$
R =
\left(
\begin{array}{ccc}
0 & 1 & 0 \\
-1 & 0 & 0 \\
0 & 0 & 1
\end{array}
\right)
$$
答え:
$$
(0, 1)
$$
問題4
$$
S =
\left(
\begin{array}{ccc}
2 & 0 & 0 \\
0 & 3 & 0 \\
0 & 0 & 1
\end{array}
\right)
$$
$$
T =
\left(
\begin{array}{ccc}
1 & 0 & 0 \\
0 & 1 & 0 \\
5 & -1 & 1
\end{array}
\right)
$$
$$
M = S T =
\left(
\begin{array}{ccc}
2 & 0 & 0 \\
0 & 3 & 0 \\
5 & -1 & 1
\end{array}
\right)
$$
答え:
$$
(7, 5)
$$
問題5
Aは、平行移動してから拡大するので、
$$
M_A = T S
$$
$$
M_A =
\left(
\begin{array}{ccc}
2 & 0 & 0 \\
0 & 2 & 0 \\
6 & 0 & 1
\end{array}
\right)
$$
答え:
$$
(8, 2)
$$
Bは、拡大してから平行移動するので、
$$
M_B = S T
$$
$$
M_B =
\left(
\begin{array}{ccc}
2 & 0 & 0 \\
0 & 2 & 0 \\
3 & 0 & 1
\end{array}
\right)
$$
答え:
$$
(5, 2)
$$
平行移動の前に拡大するか、後に拡大するかで、移動量も拡大2つ書きなされるかどうかが変わるい。
問題63
$$
T =
\left(
\begin{array}{cccc}
1 & 0 & 0 & 0 \\
0 & 1 & 0 & 0 \\
0 & 0 & 1 & 0 \\
4 & -2 & 1 & 1
\end{array}
\right)
$$
答え:
$$
(5, 0, 4)
$$モンスターの前方にプレイヤーがいるかを調べるために使う計算は何ですか。
問題74
$$
S =
\left(
\begin{array}{cccc}
2 & 0 & 0 & 0 \\
0 & 3 & 0 & 0 \\
0 & 0 & 4 & 0 \\
0 & 0 & 0 & 1
\end{array}
\right)
$$
答壁の向こうにいるプレイヤーを見え:
$$
(2, 6, 12)
$$ないようにするには、どのような判定が必要ですか。
問題85
$$次の処理の意味を説明しなさい。
isFindPlayer = \left(CheckCanSeePlayer();
\begin{array}{cccc}
0 & 0 & -1 & 0 \\
0 & 1 & 0 & 0 \\
1 & 0 & 0 & 0 \\
0 & 0 & 0 & 1
\end{array}
\right)
$$
答え:
$$
(0, 0, -1)
$$
問題9
$$
S =
\left(
\begin{array}{cccc}
2 & 0 & 0 & 0 \\
0 & 2 & 0 & 0 \\
0 & 0 & 2 & 0 \\
0 & 0 & 0 & 1
\end{array}
\right)
$$
$$
R_y =
\left(
\begin{array}{cccc}
0 & 0 & -1 & 0 \\
0 & 1 & 0 & 0 \\
1 & 0 & 0 & 0 \\
0 & 0 & 0 & 1
\end{array}
\right)
$$
$$
T =
\left(
\begin{array}{cccc}
1 & 0 & 0 & 0 \\
0 & 1 & 0 & 0 \\
0 & 0 & 1 & 0 \\
3 & 1 & 2 & 1
\end{array}
\right)
$$
$$
M = S R_y T =
\left(
\begin{array}{cccc}
0 & 0 & -2 & 0 \\
0 & 2 & 0 & 0 \\
2 & 0 & 0 & 0 \\
3 & 1 & 2 & 1
\end{array}
\right)
$$
答え:
$$
(9, 5, 0)
$$
問題10
Aは、平行移動してから回転するので、
$$
M_A = T R_y
$$
$$
M_A =
\left(
\begin{array}{cccc}
0 & 0 & -1 & 0 \\
0 & 1 & 0 & 0 \\
1 & 0 & 0 & 0 \\
0 & 0 & -5 & 1
\end{array}
\right)
$$
答え:
$$
(0, 0, -6)
$$
Bは、回転してから平行移動するので、
$$
M_B = R_y T
$$
$$
M_B =
\left(
\begin{array}{cccc}
0 & 0 & -1 & 0 \\
0 & 1 & 0 & 0 \\
1 & 0 & 0 & 0 \\
5 & 0 & 0 & 1
\end{array}
\right)
$$
答え:
$$
(5, 0, -1)
$$
平行移動してから回転すると、移動後の位置全体が原点の周りを回転する。
回転してから平行移動すると、向きだけを変えてから指定方向に移動する。
確認ポイント発展課題
DirectX11形式
次の合成順ようなモンスターを考えなさい。
普段は巡回している。
プレイヤーが視界に入ったら追いかける。
壁の向こうに逃げられたら見失う。
見失ったら、その場で3秒間探す。
それでも見つからなければ巡回に戻る。
点このモンスターに必要なフラグを行ベクトルで扱う場合、
$$
P' = P M
$$
である考えなさい。
そのため、変換順が例:
拡大縮小isFindPlayer;
回転bool 平行移動isLostPlayer;
bool さらに、どのようなら、
$$if文 M = S R T
$$
にを書けばよいか考えなるさい。
よくある間違い
列ベクトル形式の感覚で、
$$
M = T R S
$$
と書くと、DirectX11形式では変換順が逆になってしまう。
このプリントでは、常に
$$
P' = P M
$$
として計算する。