OpenGLES2.0 D3D座標系

Direct3D と OpenGL は座標系が違います。
そのためデータの Exporter を作るときは、どのプラットフォームにも対応できるよう
いつも両対応で作っています。

Direct3D から見ると両対応は簡単です。
というのも、Maya や XSI など多くのツールが OpenGL の右手座標系なので、
D3D の左手系に合わせるにはもともと座標系の変換処理が必要だからです。
OpenGL に対応するには反転しなければ良いだけ。

ただ OpenGLES 2.0 の場合ジオメトリもライティングもシェーダーだけで行いますし
演算式も任意です。汎用化された GPU では実装に任されているので、座標系の
違いをあまり意識しなくても良いのかもしれません。

普段使っているライブラリやシェーダーを流用することを考えて、Direct3D の
左手座標系でそのまま使ってみました。いつもの感覚でシェーダーやマトリクスの
セットを行っていたら自然にそうなりました。

OpenGL の場合も Depth Buffer の初期値はデフォルトで 1.0 を設定するようです。
比較関数も初期値は GL_LESS なので D3D と違いはありません。
Matrix の設定もモデルデータもシェーダーも D3D と同じパラメータで良いようです。

唯一変更したのは下記の設定のみ。
デフォルトは GL_CCW なので GL から見るとカリングが逆になります。

glFrontFace( GL_CW );

あとはデータもシェーダーも matrix も D3D 互換で使えます。

シェーダーはまだ GLSL のテストをしている状態です。
アニメーションはまだ未確認。

// vsh
uniform mat4	pmatrix;

attribute vec3	vposition;
attribute vec3	vnormal;
attribute vec2	vtexcoord;

varying vec4	ocolor;
varying vec2	otexcoord;

void main()
{
    gl_Position= pmatrix * vec4( vposition.xyz, 1 );

    vec3  lightdir= vec3( 0.0, 0.0, -1.0 );
    ocolor= vec4( 1.0, 1.0, 1.0, 1.0 ) * clamp( dot( vnormal, lightdir ), 0.0, 1.0 ) + 0.2;
    otexcoord= vtexcoord;
}
// fsh
precision mediump float;
varying	vec4   ocolor;
varying	vec2   otexcoord;

uniform sampler2D   texture0;

void main()
{
    vec4   tcol= texture2D( texture0, otexcoord );
    gl_FragColor= ocolor * tcol;
}
// cpp
struct v_type3 {
    float x, y, z;
};
struct v_type2 {
    float x, y;
};

static const v_type3	vdata_p[]= {
    {	-1.0f,	 1.0f,	0.0f,	},
    {	 1.0f,	 1.0f,	0.0f,	},
    {	-1.0f,	-1.0f,	0.0f,	},
    {	 1.0f,	-1.0f,	0.0f,	},
};

static const v_type3	vdata_n[]= {
    {	0.0f,	0.0f,	-1.0f,	},
    {	0.0f,	0.0f,	-1.0f,	},
    {	0.0f,	0.0f,	-1.0f,	},
    {	0.0f,	0.0f,	-1.0f,	},
};

static const v_type2	vdata_t[]= {
    {	0.0f,	0.0f,	},
    {	1.0f,	0.0f,	},
    {	0.0f,	1.0f,	},
    {	1.0f,	1.0f,	},
};

glVertexAttribPointer( attr_vposition, 3, GL_FLOAT, GL_FALSE, sizeof(v_type3), vdata_p );
glVertexAttribPointer( attr_vnormal, 3, GL_FLOAT, GL_FALSE, sizeof(v_type3), vdata_n );
glVertexAttribPointer( attr_vtexcoord, 2, GL_FLOAT, GL_FALSE, sizeof(v_type2), vdata_t );

glEnableVertexAttribArray( attr_vposition );
glEnableVertexAttribArray( attr_vnormal );
glEnableVertexAttribArray( attr_vtexcoord );

static unsigned short	idata[]= {
    0, 1, 2,
    2, 1, 3,
};

MatrixF	projection;
MatrixF	view;
MatrixF	world;

projection.SetProjection( ScreenWidth, ScreenHeight, 1.0f, 5000.0f, DEGtoRAD( 30.0f ) );
view.SetIdentity();
view.Translation( 0.0f, 0.0f, 20.0f );
world.SetIdentity();
world.RotationY( rotang );

MatrixF	mat;
mat.Mul( projection, view );
mat.Mul( world );

glUniformMatrix4fv( attr_pmatrix, 1, GL_FALSE, &mat._11 );
glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, idata );

関連エントリ
OpenGLES2.0 シェーダー管理

OpenGLES2.0 シェーダー管理

OpenGL 系はほとんど使っていないので、余りよくわかっていないことが多いです。
とりあえずシェーダーのバリエーション管理をどうするか。

Direct3D11 では D3DCompile() 命令にプリプロセッサ用のデータを渡すことが
できます。シェーダーコンパイラは Direct3D11 より中立化しました。
D3DCompiler.h / d3dcompiler.lib と独立したモジュールになっており、
FeatureLevel や D3D のナンバーと関係なく共通で使用します。

include に対応するためには ID3DInclude を定義します。
define シンボルを渡す場合は、D3D_SHADER_MACRO 構造体の配列を作っておきます。
(Direct3D 10 Shader4.0 シェーダーのコンパイル)

Shader の機能わけのために、これまでプリプロセッサ命令を活用してきました。
同じシェーダープログラムでもシンボル定義に応じて複数の機能に対応させます。

D3D_SHADER_MACRO  deflist[]= {
{  "SF_ANIMATION",  "1", },
{  NULL, NULL },
};

例えば上記の配列を D3DCompiler() に渡すと、hlsl 上では SF_ANIMATION の定義が
“1” になります。

シェーダー (hlsl) 上では

#if SF_ANIMATION
  ~
#endif

といった感じでコンパイル時の機能指定に応じてコードを分けることができます。

OpenGLES の GLSL コンパイラの場合、特にプリプロセッサ用の定義データを
そのまま渡すわけではなさそうです。
glShaderSource() では、一度のコンパイルでも複数のソースを同時に渡すことができます。
このうち 1つをプログラム内で生成したテキストに割り当てます。
例えばシェーダーコンパイル時に

#define SF_ANIMATION  1

といったテキストを生成してソースの 1つとして与えることで、D3D_SHADER_MACRO
と同じような使い方ができました。

OpenGLES2.0 はシェーダーのみと割り切ったおかげで無駄のないすっきりした
構成になっているようです。
シェーダーの世代的には ShaderModel3.0 相当と思われます。

Direct3D9 + ShaderModel3.0 の場合も、多くの機能がシェーダーで汎用化された
ために従来固定機能だったパイプラインの機能がいくつか使えなくなっています。
それでも API 的には重複する固定機能の設定が残っていたため、どちらでも動くのか
どうか、使えるのかどうかなどわかりにくい点がありました。

この問題は Direct3D10 でいったんリセットすることで解消しています。
Direct3D 10 以降はシェーダーのみと割り切って、重複する固定機能の多くを
排除しました。

そういう意味では OpenGLES2.0 は、Direct3D9 + ShaderModel3.0 というよりも、
Direct3D10 + ShaderModel4_0_Level_9_3 の方により近いといえるかもしれません。

関連エントリ
Direct3D11/DirectX11 (4) FeatureLevel と旧 GPU の互換性、テクスチャ形式など
Direct3D 10 Shader4.0 シェーダーのコンパイル

WindowsMobile CABファイルの作成

WindowsMobile 用のフリーソフトウエアは CAB 形式で配布しています。
CAB ファイルは explorer から実行するだけでインストールできるので扱いも簡単です。

今なら別の方法があるのかもしれませんが、昔から VisualStudio に付属している
cabwiz を使用しています。というか WindowsCE / PocketPC の頃に作った設定
ファイルをほとんどテンプレートとして、ずっとそのまま使ってきました。

d3dmclock の場合 (d3dmclock.inf)

[Version]
Signature	= "$Windows NT$"
Provider	= "HYP"
CESignature	= "$Windows CE$"

[CEStrings]
AppName		= d3dmclock
InstallDir	= %CE1%\%AppName%

[CEDevice.ARMWM6]
VersionMin	= 5.0
VersionMax	= 32767.0
ProcessorType	= 2577

[DestinationDirs]
Shortcuts.All = 0,%CE11%
Files.Common = 0,%InstallDir%
DefaultDestDir = 0,%InstallDir%

[Shortcuts.All]
d3dmclock,0,d3dmclock.exe,%CE11%

[SourceDisksNames]
1 = , "Common files",,C:\usr\ce\gclock

[SourceDisksNames.ARMWM6]
2 = , "ARMfiles",,C:\usr\ce\gclock\ARMV4I\Release

[SourceDisksFiles]
d3dmclock.txt = 1
font.dds = 1
bgimage0.bmp = 1
bgimage1.bmp = 1
bgimage2.bmp = 1
textimage0.dds = 1
textimage1.dds = 1
textimage2.dds = 1
textimage3.dds = 1
textimage4.dds = 1
textimage5.dds = 1
textimage6.dds = 1
textimage7.dds = 1

[SourceDisksFiles.ARMWM6]
d3dmclock.exe = 2

[DefaultInstall]
CEShortcuts	= Shortcuts.All

[DefaultInstall.ARMWM6]
CopyFiles	= Files.Common, Files.ARMWM6

[Files.Common]
d3dmclock.txt,,,0
font.dds,,,0
bgimage0.bmp,,,0
bgimage1.bmp,,,0
bgimage2.bmp,,,0
textimage0.dds,,,0
textimage1.dds,,,0
textimage2.dds,,,0
textimage3.dds,,,0
textimage4.dds,,,0
textimage5.dds,,,0
textimage6.dds,,,0
textimage7.dds,,,0

[Files.ARMWM6]
d3dmclock.exe,,,0x80000000

CEString は他で参照する定数の定義です。%~% で参照しています。
Install 先フォルダをここに記述しています。%CE1% は \Program Files

SourceDisksNames はインストールするファイルが置かれている実在のパスを指定します。

SourceDisksFiles はアーカイブするファイルがどこにあるか指定します。
後ろの番号は SourceDisksNames の番号に対応しています。

Files が実際にインストールコピーされるファイルリスト。

“.ARMWM6” がついた定義名は、もともと WindowsCE が複数の CPU に対応しており
対象 CPU 毎に CAB を用意していた頃の名残です。CPU 毎に別ファイルを指定する
場合と、共通に含めるファイルを分けて記述できるようになっています。

(1) DestinationDirs でインストール先フォルダを指定。
  %InstallDir% の定義は CEStrings にあります。
(2) SourceDisksNames.* にアーカイブするファイルの場所を記述
(3) SourceDisksFiles.* に必要なファイルを記述
  (数値は SourceDisksNames の番号に対応している)
(4) Files.* にアーカイブするファイルを記述

詳しくはこちら
MSDN スマート デバイスの .inf ファイルの概要

touchkeysip の場合 (touchkeysip.inf)

[Version]
Signature	= "$Windows NT$"
Provider	= "HYP"
CESignature	= "$Windows CE$"

[CEStrings]
AppName		= touchkeysip
InstallDir	= %CE1%\%AppName%

[CEDevice.ARM]
VersionMin	= 5.0
VersionMax	= 1000.0
ProcessorType	= 2577

[CEDevice.ARMGS]
VersionMin	= 5.0
VersionMax	= 1000.0
ProcessorType	= 2577

[DestinationDirs]
Files.Common = 0,%InstallDir%
DefaultDestDir = 0,%CE2%

[SourceDisksNames]
1 = , "Common files",,C:\usr\ce\minisip2

[SourceDisksNames.ARM]
2 = , "ARMfiles",,C:\usr\ce\minisip2

[SourceDisksNames.ARMGS]
3 = , "ARMfiles",,C:\usr\ce\minisip2\gs

[SourceDisksFiles]
touchkeysip.txt = 1
defaultscript.txt = 1
defaultkeyboard.bmp = 1

[SourceDisksFiles.ARM]
touchkeysip.dll = 2

[SourceDisksFiles.ARMGS]
touchkeysip.dll = 3

[DefaultInstall]

[DefaultInstall.ARM]
CopyFiles	= Files.Common, Files.ARM
CESelfRegister	= touchkeysip.dll

[DefaultInstall.ARMGS]
CopyFiles	= Files.Common, Files.ARMGS
CESelfRegister	= touchkeysip.dll

[Files.Common]
touchkeysip.txt,,,0
defaultscript.txt,,,0
defaultkeyboard.bmp,,,0

[Files.ARM]
touchkeysip.dll,,,0x80000000

[Files.ARMGS]
touchkeysip.dll,,,0x80000000

コマンドの実行手順は Makefile に記述しています。(install.mak)

ZIPFILEARM	= touchkeysip***.zip
CABFILEARM	= touchkeysip.ARM.CAB
EXEARM		= touchkeysip.dll

all: \
	$(EXEARM) \
	$(CABFILEARM) \
	$(ZIPFILEARM) \


zip: $(ZIPFILEARM)


_MANUALFILE	= touchkeysip.txt	\
		CommandManual.txt	\


_CABSRCFILE	= touchkeysip.txt	\
		defaultscript.txt	\
		defaultkeyboard.bmp	\


_SRCFILEARM	= $(EXEARM) \
		$(_CABSRCFILE) \


ZIPSRCFILEARM	= $(CABFILEARM)   $(_MANUALFILE)


$(ZIPFILEARM):	$(ZIPSRCFILEARM)
	7z a -tzip $(ZIPFILEARM) $(ZIPSRCFILEARM)


CABWIZE	= C:\Program Files (x86)\Microsoft Visual Studio 9.0\SmartDevices\SDK\SDKTools\Cabwiz.exe

$(CABFILEARM): touchkeysip.inf $(_SRCFILEARM)
	"$(CABWIZE)" touchkeysip.inf  /cpu ARM

VisualStudio で作成&動作確認が終わったら、nmake の実行だけで CAB の生成と
zip の作成もいっぺんに行われます。上のファイルは install.mak という名前で
各プロジェクトのフォルダに置いてあります。実行はコマンドラインから

nmake -f install.mak

プログラムの数も非常に多いし、開発中はそれぞれが頻繁に更新されるので
公開までの手順は自動化されています。
ドキュメントを修正した場合も nmake だけでアーカイブが作られます。

普段使っているスクリプトファイルを入れて

touchkeysip.dll + スクリプト

といった自分専用の CAB を作っておけば、デバイスの再インストール時に
ちょっとだけ手間が減るかもしれません。

作業向けの高性能マウスが欲しい

キーボードに結構こだわっている人はいます。
プログラマだと少々高くても良いものを探したり、好みのものを選んで使ってる
方も多いことと思います。
全く同じように、緻密ながら素早い動作が必要になるデザイナーの作業でも
マウスの性能差は作業効率に大きく影響があるのだそうでです。

知り合いのデザイナーにきいたところ、仕事がらマウス選びにはいつも
苦労しているのだそうです。

マウスの場合、性能の良い高級タイプはゲーマー向けとして売られているものが
ほとんどです。
センサーの性能や確実性、反応速度などはやはりこれらゲーマー向けマウスが
一番だとのこと。

ただどうしてもサイズが大きいものが多くて、手になじまないのが悩みだと
訴えていました。
ゲームプレイ時と作業時では、実際にマウスを動かす稼働範囲やマウス自体の
持ち方が違っているのかもしれません。
例えば手首を固定して指先でマウスを持つような持ち方の場合、
マウスが大きすぎると手のひらが密着してあまり動かせられなくなります。

持ち方だけでなく、純粋に手の大きさが違う場合もあります。
マウスのサイズにはもっとバリエーションが多くても良いのではないでしょうか。

日本のブランドである DHARMAPOINT のゲーマーマウスは、比較的小振りで
よく使っているそうです。

なんだかんだでいろいろ試しているうちに、DHARAMAPOINT ブランドの製品は
マウス全世代、マウスパッド数タイプ、交換ソール、キーボードなど
ヘッドセット以外は全部買いそろえてしまったらしい。

DHARMAPOINT

ゲーマーマウス並の高性能で、さらに作業用で持ち方にあわせて
大きさを各種選べるような、そんなマウスは無いでしょうか。
毎日ほとんどの時間をマウスとともに費やしているわけです。
ストレスを抱えながら作業するよりは少々高くても良いマウスを選びます。

Media Go で PSP のデータ管理

PC 上で PSP のデータを管理できる Media Go というソフトウエアが少し前に
リリースされていたようです。PlayStation Store に接続することも可能で、
PSP のネット環境がなくてもソフトウエアのダウンロードや購入ができます。

SONY Media Go

以前から PC 上で PSP ソフトウエアの購入はできましたが、当初はもっとシンプルな
ダウンロード専用ツールだったように覚えています。
Media Go ではさらにゲームの入れ替えやセーブデータのバックアップも可能。
PSP に転送するメディアファイルの管理もできて、統合ツールに進化しつつ
あるようです。

Media Go は PSP をつながなくてもインストール&起動することができました。
左側の「PlayStation Store」をクリックすると PSP 版のストアにアクセスできます。
ゲームタイトルやビデオの一覧はログインしなくても閲覧可能。
実際にダウンロードする場合にはアカウント情報が必要になります。

PC と PSP の接続は USB ケーブルで行います。
PSP を「USB 接続」モードにすれば空き容量やファームのバージョンなど本体の
情報が表示され、同時にメモリースティック内のデータもブラウズできます。

アイコン付きで、現在どんなゲームが入っているのか一目瞭然です。
セーブデータもわかりやすく、タイトルごとにまとまっているので扱いも容易です。

これまでもメモリースティックを直接参照すれば同じような管理はできました。
でもフォルダ名がタイトル固有 ID なので、どのファイルがどのゲームなのか
判断するのは困難だったのです。

Media Go 上では、ゲームやセーブデータのアイコン上でマウスの右ボタンを押して
「転送→ライブラリ」を選ぶと PC のライブラリに保存できます。
PSP に書き戻せるので、容量の限られたメモリースティックでも複数のゲームを
入れ替えながら使えるようです。

ライブラリの保存先はマイドキュメントの “Media Go” でした。
中をのぞいてみると、ライセンスファイルは特に指定しなくても自動で
バックアップされていることがわかります。

操作はシンプルでそれほど多機能ではありませんが、位置づけやできることは
iTunes に近いようです。時間のかかる転送もバックグラウンドで行われるので
やはり意識しているように見えます。
Sony 製のメディア管理ソフトというと、どうしても過去の重いソフトウエアたちを
思い浮かべてしまいます。Media Go は比較的動作も軽い印象でした。

ストアへの初回接続時に、言語を選択する画面が現れます。
ここで間違ったリンクをクリックしてしまうと海外のストアにつながりますが、
言語を選択し直す方法がわからなくて焦りました。
ユーザー設定から変更できるのは、メニューなど UI の言語だけでした。

レジストリの下記エントリを消して起動し直すと、再びストアの言語選択に戻れる
ことがわかりました。または Region の値を “JP” にすれば良いようです。
(レジストリを書き換える場合は自己責任でお願いします)

HKEY_CURRENT_USER\Software\Sony Corporation\PS Store\Region

すでに PS3 上で PSP のゲームのダウンロード&管理を行っているため特に移行
する必要はないのですが、データをまとめて転送できる Media Go は便利そうです。

関連エントリ
新型 PSP (PSP-2000) とゲームアーカイブス