2023/09/06(水) [n年前の日記]
#1 [hsp] 疑似3D道路その3
_昨日
の続き。HSP 3.6 を使って、疑似3D道路が作れないか試しているところ。
道路のデータをセグメントで持つあたりは実装できたので、カーブ処理を追加してみた。
道路のデータをセグメントで持つあたりは実装できたので、カーブ処理を追加してみた。
◎ 参考ページ :
_PICO-8
を使った、以下のチュートリアル記事がとても参考になった。ありがたや。
_Creating a pseudo 3D racer
_Creating a pseudo 3D racer - part 2
_Creating a pseudo 3D racer - part 3
雛形を一つ一つ作って、そこで起きる不具合を実際に目にして、その問題を少しずつ解決していくあたりが非常に分かりやすいなと…。また、PICO-8用に書かれた各サンプルの下にある「Code」をクリックすればソースコードが全部見れるので、英文が分からなくてもソースコードを眺めていけばなんとかなりそう。
余談。PICO-8 については以下が参考になるかなと…。
_PICO-8って何? - PICO-8ゲーム開発入門(1) - AUTOMATON
_PICO-8 ゲーム開発のススメ
_PICO-8で遊ぼう!【PICO-8入門】 | INWAN'S LABO
_Creating a pseudo 3D racer
_Creating a pseudo 3D racer - part 2
_Creating a pseudo 3D racer - part 3
雛形を一つ一つ作って、そこで起きる不具合を実際に目にして、その問題を少しずつ解決していくあたりが非常に分かりやすいなと…。また、PICO-8用に書かれた各サンプルの下にある「Code」をクリックすればソースコードが全部見れるので、英文が分からなくてもソースコードを眺めていけばなんとかなりそう。
余談。PICO-8 については以下が参考になるかなと…。
_PICO-8って何? - PICO-8ゲーム開発入門(1) - AUTOMATON
_PICO-8 ゲーム開発のススメ
_PICO-8で遊ぼう!【PICO-8入門】 | INWAN'S LABO
◎ 動作画面 :
書いたサンプルの動作画面は以下。それらしくカーブが表示されている、ような気がする。
- カーソルキーの上下で、速度を上げたり下げたりできる。
- カーソルキーの左右は動作確認用。遠景の横方向スクロールのテスト。
◎ ソースコード :
以下のようなソースコードになった。
_road03.hsp
使用画像は以下。road03.hsp と同じフォルダ階層に置く。
_bg_bg0.png
_bg_bg1.png
_road03.hsp
; 疑似3D道路を描画する / Drawing pseudo 3D roads
; セグメントで道路を管理してカーブを実装
#include "hspmath.as"
#define BG0_FILE "bg_bg0.png"
#define BG1_FILE "bg_bg1.png"
#define SCR_W 640
#define SCR_H 360
; セグメントの区切りを色分け. 0 or 1
#define SEG_DELIMITER 0
; 同梱ファイル / bundled files
#pack BG0_FILE
#pack BG1_FILE
#packopt name "road03" ; exe filename
#packopt type 0 ; generate ".exe"
#packopt xsize SCR_W
#packopt ysize SCR_H
; onkey goto *jobend
; get windows size
screen 0, SCR_W, SCR_H, 0
gsel 0
; width SCR_W, SCR_H
dispw = ginfo_winx
disph = ginfo_winy
cls 4
; load bg image
bgimgid0 = 4
buffer bgimgid0, 1280, 720
picload BG0_FILE
bg0w = ginfo_winx
bg0h = ginfo_winy
bgimgid1 = 5
buffer bgimgid1, 1280, 720
picload BG1_FILE
bg1w = ginfo_winx
bg1h = ginfo_winy
; セグメント作成用データ初期化用マクロ
#define set_array(%1, %2, %3, %4, %5) \
%1(%2, 0) = %3 :\
%1(%2, 1) = %4 :\
%1(%2, 2) = %5 :
; セグメント作成用データ
dim segm, 12, 3
; set_array 配列変数名, index, count, curve, pitch
; curve と pitch は100倍した値。
; HSPは int と double を配列内で混在できないらしいので…
set_array segm, 0, 20, 0, 0
set_array segm, 1, 10, 50, 0
set_array segm, 2, 60, 200, 0
set_array segm, 3, 10, 50, 0
set_array segm, 4, 50, 0, 100
set_array segm, 5, 10, -100, 0
set_array segm, 6, 30, -400, 0
set_array segm, 7, 10, -100, 0
set_array segm, 8, 20, 0, -100
set_array segm, 9, 50, -100, 0
set_array segm, 10, 25, 200, 0
set_array segm, 11, 20, 0, 0
; セグメント総数を取得
seg_max = 0
repeat length(segm)
seg_max += segm(cnt, 0)
loop
; セグメントのz幅を指定
seg_length = 20
seg_total_length = seg_length * seg_max
; 参照されるセグメントデータとして展開
dim seg, seg_max, 3
z = 0
i = 0
repeat length(segm)
lp = segm(cnt, 0)
curve = segm(cnt, 1)
pitch = segm(cnt, 2)
repeat lp
seg(i, 0) = z
seg(i, 1) = curve
seg(i, 2) = pitch
z += seg_length
i++
loop
loop
dist = 200.0 ; 画面までの距離 / distance to screen
camera_z = 0.0
spd = 0.0
spda = 0.1
spd_max = 16.0
xd = 0.0
yd = 0.0
zd = double(seg_length)
bgx = 0.0
tgt_bgx = 0.0
*mainloop
; ESC key to exit
stick k, 255
if k & 128 : goto *jobend
; check cursor key
if k & 2 {
; Up key
spd += spda
if spd >= spd_max : spd = spd_max
}
if k & 8 {
; Down key
spd -= (spda * 3)
if spd <= 0.0 : spd = 0.0
}
if k & 1 {
; Left key
bg_x -= 16
}
if k & 4 {
; Right key
bg_x += 16
}
road_y = 100 ; 道路のy位置
road_x = 300 ; 道路の幅(片側の幅)
base_y = int(double(disph) * 0.5)
h = disph - base_y
; 最初のセグメント番号を取得
if camera_z = 0 {
seg_index = 0
} else {
; "\"はHSPの剰余記号。一般的なプログラミング言語なら "%" に相当
seg_index = (int(camera_z) / seg_length) \ seg_max
}
; カメラが居るセグメントのカーブ量を求める
curve = double(seg(seg_index, 1)) * 0.01
; カメラがセグメント内のどの位置に居るか割合を求める
z0 = seg(seg_index, 0)
z1 = z0 + seg_length
ccz = camera_z \ seg_total_length
camz = double(ccz - z0) / double(z1 - z0)
; セグメント内のカメラ位置に応じて事前に横方向にある程度ずらしておく
xd = (-camz * curve)
yd = 0.0
zd = double(seg_length)
cx = -(xd * camz)
; cx = 0.0
cy = double(road_y) + (yd * camz)
cz = 0.0
bg_x += curve * (spd * 0.5)
redraw 0 ; 描画開始 / draw start
gsel 0
; 背景(遠景)を描画 / draw BG
bgw = bg1w
bgh = bg1h
bgx = int(double(bg_x) * 0.4) \ bgw
bgy = bgh / 2 - base_y
bgid = bgimgid1
gmode 0
gosub *draw_bg
bgw = bg0w
bgh = bg0h
bgx = int(double(bg_x) * 0.5) \ bgw
bgy = bgh / 2 - base_y
bgid = bgimgid0
gmode 2
gosub *draw_bg
gmode 0
; 道路を描画 / draw road
seg_z_max = 0
seg_distance = 96
repeat seg_distance
; セグメントのz値、カーブ量、ピッチ量を取得
idx = (seg_index + cnt) \ seg_max
z0 = seg(idx, 0)
curve = double(seg(idx, 1)) * 0.01
pitch = double(seg(idx, 2)) + 0.01
; 最後のセグメントを超えて最初にループする場合、z値を調整する
if z0 > seg_z_max : seg_z_max = z0
if z0 < seg_z_max : z0 += seg_total_length
cam_z = int(camera_z) \ seg_total_length
z0 -= cam_z
z1 = z0 + seg_length
if z1 < (dist / 4) : goto *seg_cancel
if z0 = 0 : z0 = 1 ; 0で除算しないように微調整
; 画面上で描画すべきy座標位置を取得
y0 = int(road_y * dist / z0)
y1 = int(road_y * dist / z1)
; 画面上で描画すべき道路の幅(片側の幅)を取得
x0 = double(road_x) * double(dist) / double(z0)
x1 = double(road_x) * double(dist) / double(z1)
; 画面上でずらすべき中心線の位置を取得
cx0 = double(cx) * double(dist) / double(z0)
cx1 = (double(cx) + double(xd)) * double(dist) / double(z1)
h = abs(y1 - y0)
dsy = sgn(y1 - y0)
if dsy = 0 : dsy = 1
repeat h
sy = y0 + (dsy * cnt)
draw_y = sy + base_y
; 画面縦幅を超えたy座標なら描画しない
if draw_y < 0 | draw_sy > disph : continue
; 2次元的な計算で割合を求める
if y0 == y1 {
p = 0.0
} else {
p = double(sy - y0) / double(y1 - y0)
}
z = (double(z1) - double(z0)) * p + double(z0)
x = (double(x1) - double(x0)) * p + double(x0)
center_x = (cx1 - cx0) * p + cx0
addv = ((int(z) + int(camera_z)) / 40) & $1
; 1ラスター分を描画 / draw 1 raster
road_w = x * 2
draw_x = -x + (dispw / 2) + center_x
kind = addv
if SEG_DELIMITER = 1 {
; セグメントの区切りを色分けしたい場合
if sy = y0 : kind = 2
}
gosub *draw_raster_road
loop
*seg_cancel
cx += xd
cy += yd
cz += zd
xd += curve
; yd += pitch
loop
; draw text
font "Arial", 18, 1
color 1, 1, 1
pos 8, 4
mes "Press cursor key"
pos 8, disph - 32
mes "seg_index : " + seg_index
redraw 1 ; 描画終了 / draw end
camera_z += spd
await (1000 / 60)
goto *mainloop
*draw_raster_road
; 道路を1ラスター分描画 / draw road 1 raster
; draw_x, draw_y : draw x, y
; road_w : road width
; kind : 0 or 1 or 2
; dispw : screen width
; draw ground
if kind = 0 {
; color R, G, B
color 114, 185, 66
} else {
color 22, 174, 63
}
; boxf x0, y0, x1, y1
boxf 0, draw_y, dispw, draw_y
; draw road base
switch kind
case 0
color 133, 149, 158
swbreak
case 1
color 149, 168, 179
swbreak
case 2
color 255, 0, 0
swbreak
swend
boxf draw_x, draw_y, draw_x + road_w, draw_y
; draw white line
lw = double(road_w) * 48.0 / 2048.0 ; white line width
switch kind
case 0
color 255, 255, 255
lx = double(draw_x)
boxf lx, draw_y, lx + lw, draw_y
lx = lx + road_w - lw
boxf lx, draw_y, lx + lw, draw_y
lx = double(draw_x) + (double(road_w) * 0.5) - (lw * 0.5)
boxf lx, draw_y, lx + lw, draw_y
lx = double(draw_x) + double(road_w) * 0.25 - (lw * 0.5)
boxf lx, draw_y, lx + lw, draw_y
lx = double(draw_x) + double(road_w) * 0.75 - (lw * 0.5)
boxf lx, draw_y, lx + lw, draw_y
swbreak
case 1
color 228, 236, 252
lx = double(draw_x) + lw
boxf lx, draw_y, lx + lw, draw_y
lx = double(draw_x) + road_w - (lw * 2)
boxf lx, draw_y, lx + lw, draw_y
swbreak
swend
return
*draw_bg
; BGを1枚描画 / draw BG. 1 layer
; bgid : bg image buffer id
; bgx, bgy : bg position
; bgw, bgh : bg image width, height
; dispw, disph : screen width, height
if bgx >= 0 & bgx < (bgw - dispw) {
pos 0,0
gcopy bgid, bgx, bgy, dispw, disph
} else {
if bgx < 0 {
w = -bgx
pos 0, 0
gcopy bgid, bgw - w, bgy, w, disph
pos w, 0
gcopy bgid, 0, bgy, dispw - w, disph
} else {
w = bgw - bgx
pos 0, 0
gcopy bgid, bgx, bgy, w, disph
pos (bgw - bgx), 0
gcopy bgid, 0, bgy, dispw - w, disph
}
}
return
*jobend
end
使用画像は以下。road03.hsp と同じフォルダ階層に置く。
_bg_bg0.png
_bg_bg1.png
◎ 考え方 :
考え方は、前述の参考ページが分かりやすいかなと…。
_Creating a pseudo 3D racer
実のところ、カーブを表現する処理について、まだ今一つ仕組みが分かってないけど…。
とりあえず、道路データは、セグメントと呼ばれるソレで管理する。以下の画像の赤い線がセグメントの区切り部分。
セグメントが横方向に少しずつずれていくことで、カーブが表現できるということらしい。
参考ページのセグメントデータは、そのセグメントが並ぶ個数(ct)、カーブ量(tu)、の2つを並べていくけれど。
今回はそれに近い元データを一旦展開(?)して、ベタなセグメントの並びを作ってから処理するようにしてみた。
こうしておけば、z値とどのセグメントが対応してるか計算しやすくなるかなと…。メモリは多少食うけれど。
さて。各セグメントはz値を持っている。もしくは、セグメントのインデックス番号に、1セグメント当たりのz幅をかけてやれば、そのセグメントのz値を求めることができる。そして、道路の幅は今回一定としているので…。各セグメントのz値と道路幅を透視変換してやれば、各セグメントの区切りに相当する線が画面上のどのあたりに位置するかを求めることができる。
セグメント[n] と、セグメント[n+1]、二本の水平線の、画面上での位置を得ることができれば…。その二本の線で作られる台形を塗り潰すように描画してやることで、1セグメント分の道路を描画できる。
台形の塗り潰しは、HSP の場合、line で線を引いても、boxf で矩形塗り潰しをしても、どちらでもOK。横一直線 ―― 1ラスター分の塗り潰しが可能なら、それを台形の縦幅分繰り返すことで、台形の塗り潰しはできる。
これを、画面に出ているセグメント個数分繰り返せば、道路が描画できる。
また、セグメント[n」に対して、セグメント[n+1]が、横方向にある程度ずれていれば、そこの部分だけ道路が傾いているように見える。昔のレースゲームの道路は横方向のラスタースクロールをすることでそれらしく見せることができていた、というのはそういう話だろうなと。
_Creating a pseudo 3D racer
実のところ、カーブを表現する処理について、まだ今一つ仕組みが分かってないけど…。
とりあえず、道路データは、セグメントと呼ばれるソレで管理する。以下の画像の赤い線がセグメントの区切り部分。
セグメントが横方向に少しずつずれていくことで、カーブが表現できるということらしい。
参考ページのセグメントデータは、そのセグメントが並ぶ個数(ct)、カーブ量(tu)、の2つを並べていくけれど。
road={
{ct=10,tu=0},
{ct=6,tu=-1},
{ct=8,tu=0},
{ct=4,tu=1.5},
{ct=10,tu=0.2},
{ct=4,tu=0},
{ct=5,tu=-1},
}
今回はそれに近い元データを一旦展開(?)して、ベタなセグメントの並びを作ってから処理するようにしてみた。
こうしておけば、z値とどのセグメントが対応してるか計算しやすくなるかなと…。メモリは多少食うけれど。
さて。各セグメントはz値を持っている。もしくは、セグメントのインデックス番号に、1セグメント当たりのz幅をかけてやれば、そのセグメントのz値を求めることができる。そして、道路の幅は今回一定としているので…。各セグメントのz値と道路幅を透視変換してやれば、各セグメントの区切りに相当する線が画面上のどのあたりに位置するかを求めることができる。
セグメント[n] と、セグメント[n+1]、二本の水平線の、画面上での位置を得ることができれば…。その二本の線で作られる台形を塗り潰すように描画してやることで、1セグメント分の道路を描画できる。
台形の塗り潰しは、HSP の場合、line で線を引いても、boxf で矩形塗り潰しをしても、どちらでもOK。横一直線 ―― 1ラスター分の塗り潰しが可能なら、それを台形の縦幅分繰り返すことで、台形の塗り潰しはできる。
これを、画面に出ているセグメント個数分繰り返せば、道路が描画できる。
また、セグメント[n」に対して、セグメント[n+1]が、横方向にある程度ずれていれば、そこの部分だけ道路が傾いているように見える。昔のレースゲームの道路は横方向のラスタースクロールをすることでそれらしく見せることができていた、というのはそういう話だろうなと。
◎ 疑問点その1 :
ここでちょっと気になった。本当にセグメント単位で台形の形を求めて、そこを塗り潰すだけでいいのだろうか…? そんな処理をしたら、カーブにさしかかった時、道路がカクカクした形に見えたりしないだろうか。細かい直線で道路が作られているように見えてしまって、なんだかイマイチだったりしないか…。
しかし実際に試してみたら、パッと見た感じ、それほど気にならなかったので、まあいいか、と。
考えてみたら、現実世界の道路だって、道路の端にある縁石の一つ一つ、側溝の蓋の一つ一つなどは、カーブに沿って曲線を描く形になっていない。縁石も、側溝も、直線で構成されているなと…。だけど道路を走っていて、カーブではちゃんと道路が曲がっているように見えているわけだから、道路のカーブが細かい直線の並びで作られていたとしても案外気にならないのかもしれない。
しかし実際に試してみたら、パッと見た感じ、それほど気にならなかったので、まあいいか、と。
考えてみたら、現実世界の道路だって、道路の端にある縁石の一つ一つ、側溝の蓋の一つ一つなどは、カーブに沿って曲線を描く形になっていない。縁石も、側溝も、直線で構成されているなと…。だけど道路を走っていて、カーブではちゃんと道路が曲がっているように見えているわけだから、道路のカーブが細かい直線の並びで作られていたとしても案外気にならないのかもしれない。
◎ 疑問点その2 :
もう一点気になった。台形の形を求めた後、台形内のラスター単位でz値を求めて、そのz値に応じて道路の白線を描いたり描かなかったりするようにしてみたのだけど。その処理は、3Dで計算してるわけじゃなくて、2Dで計算してるわけで…。そのことで見た目がおかしくなったりしないのだろうか?
これも、実際に試してみたら全然気にならなかったので、まあいいか、と。
考えてみたら、プレステ1やセガサターンの頃だって、各ポリゴン内に描かれるテクスチャは単に2D的な変形で塗り潰していたけれど、それほど気にならなかったよなと…。いやまあ、そのポリゴンが画面に大きく表示された時は「ギャーッ」って感じではあったけど、面積が小さければほとんど気にならなかったし。
先ほどの直線云々の話もそうだけど、面積だの幅だのがそれなりに小さければ、このあたりは案外気にならないのだろう。たぶん。
これも、実際に試してみたら全然気にならなかったので、まあいいか、と。
考えてみたら、プレステ1やセガサターンの頃だって、各ポリゴン内に描かれるテクスチャは単に2D的な変形で塗り潰していたけれど、それほど気にならなかったよなと…。いやまあ、そのポリゴンが画面に大きく表示された時は「ギャーッ」って感じではあったけど、面積が小さければほとんど気にならなかったし。
先ほどの直線云々の話もそうだけど、面積だの幅だのがそれなりに小さければ、このあたりは案外気にならないのだろう。たぶん。
◎ カーブに入った時のガクガク感 :
カーブに入ると道路が急に曲がったような感じがする。本来なら、少しずつ曲がっていって、本来の曲がり具合になってから、また徐々に曲がりが少なくなっていくように感じられるほうがいいだろうなと…。
そのあたりは、セグメントデータを展開するあたりで手を加えれば多少は改善できるかもしれない。カーブ量を持っているセグメントにさしかかったら、イージングを使って少しずつ本来の角度(ずれ具合)に近づくようにセグメントを並べていけば滑らかさを付加できるのではないかと…。
たしか、現実世界の道路も、カーブに入ったら急に曲がるようにはなってないはず。カーブに入るところ、出るところで、少しずつ曲がり具合が増減するようになっていた記憶がある。そういう設計になってないダメダメな道路は、車が曲がり切れずに事故が起きる確率が高いのだとか。
そのあたりは、セグメントデータを展開するあたりで手を加えれば多少は改善できるかもしれない。カーブ量を持っているセグメントにさしかかったら、イージングを使って少しずつ本来の角度(ずれ具合)に近づくようにセグメントを並べていけば滑らかさを付加できるのではないかと…。
たしか、現実世界の道路も、カーブに入ったら急に曲がるようにはなってないはず。カーブに入るところ、出るところで、少しずつ曲がり具合が増減するようになっていた記憶がある。そういう設計になってないダメダメな道路は、車が曲がり切れずに事故が起きる確率が高いのだとか。
◎ 遠景もスクロールさせてみた :
試しに、カーブに差し掛かったら遠景も横スクロールするようにしてみた。セグメントのカーブ量を遠景BGの横スクロール量に加算してみたけど、これでいいのだろうか…。もっと違う処理のほうがらしく見えないか…。
せっかく疑似3Dでやっていることだし、遠景を2つにわけて、雲の部分と山の部分のスクロール量を変えて、多重スクロールを ―― パララックス(parallax、視差)スクロールを試みたのだけど。なんだかあまり効果が感じられないというか、不自然さが増してしまった気もするなと…。
既存のレースゲームの動画を眺めて遠景スクロールはどうしているのか確認してみたけれど、一枚絵をスクロールさせてる事例、パララックススクロールにしてる事例、どちらもあるのだよな…。
せっかく疑似3Dでやっていることだし、遠景を2つにわけて、雲の部分と山の部分のスクロール量を変えて、多重スクロールを ―― パララックス(parallax、視差)スクロールを試みたのだけど。なんだかあまり効果が感じられないというか、不自然さが増してしまった気もするなと…。
既存のレースゲームの動画を眺めて遠景スクロールはどうしているのか確認してみたけれど、一枚絵をスクロールさせてる事例、パララックススクロールにしてる事例、どちらもあるのだよな…。
◎ 余談。デフォルメ派とリアル派 :
ここからは余談だけど。本来、リアルに考えたら、遠景なんだから別々にスクロールするはずはないのだよな…。めちゃくちゃ遠くにある風景なのだから視差を感じられる動きになるわけがない。ただ、遠景がスクロールしてますよ感を誇張、というかデフォルメするために、ここはあえて嘘をついて別々にスクロールさせるのもアリと言えばアリ、とも思っていて…。このあたり、大昔に関わった某ゲームの一シーンを思い出したりもする。担当プログラマーさんは、リアルに考えたら遠景は一枚絵でスクロールするはず、と主張してた気がするのだけど、カーブのスピード感を増すために、別々に、かつ、リアルではない速度で動かしたほうが、と自分が主張してしまって…。当時の自分の主張は正しかったのかどうか、間違っていたのではないかと、実は未だに、ふとした拍子に悩み始めてしまったりする。
せっかくの疑似3Dだし、しかもゲームなんだから、いっそ思い切って誇張したほうが、という考えもアリじゃないのかと思うのだけど、たとえ疑似であってもできる範囲でリアルに見えるように、というのもアリだよなとも思えるし。
ゲームに限らず、漫画やアニメ等もそうだろうけど。娯楽商品関係には、色々な答えがあるけれどどれも正解と言えば正解、という場面があって…。そんなとき何を判断基準にしてアリナシを決めていくか、というのがちょっと悩ましいよなと。まあ、最終的には「お客さんが一番楽しめそうなのはどれか」で考えるのが理想だろうけど。それもまた、「デフォルメしたほうが楽しめるよ」派と「リアルにしたほうが楽しめるよ」派が…。
もっとも、ゲームに限って言えば、今の時代は疑似3Dなんてやらなくても3Dでゲーム画面が作れるわけで、なのにあえて疑似3Dを選ぶということは、それはもう最初からデフォルメして見せる気満々だから、ということだよなと。リアルにしたいなら、まずは疑似3Dを選ばないのが妥当だろう…。
せっかくの疑似3Dだし、しかもゲームなんだから、いっそ思い切って誇張したほうが、という考えもアリじゃないのかと思うのだけど、たとえ疑似であってもできる範囲でリアルに見えるように、というのもアリだよなとも思えるし。
ゲームに限らず、漫画やアニメ等もそうだろうけど。娯楽商品関係には、色々な答えがあるけれどどれも正解と言えば正解、という場面があって…。そんなとき何を判断基準にしてアリナシを決めていくか、というのがちょっと悩ましいよなと。まあ、最終的には「お客さんが一番楽しめそうなのはどれか」で考えるのが理想だろうけど。それもまた、「デフォルメしたほうが楽しめるよ」派と「リアルにしたほうが楽しめるよ」派が…。
もっとも、ゲームに限って言えば、今の時代は疑似3Dなんてやらなくても3Dでゲーム画面が作れるわけで、なのにあえて疑似3Dを選ぶということは、それはもう最初からデフォルメして見せる気満々だから、ということだよなと。リアルにしたいなら、まずは疑似3Dを選ばないのが妥当だろう…。
[ ツッコむ ]
以上、1 日分です。





