mieki256's diary



2024/04/01(月) [n年前の日記]

#1 [prog] 疑似3D道路を描画するスクリーンセーバをC++とOpenGLで書いた

ここ最近ずっと作っていた、C++ と OpenGL を使って疑似3D道路を描画するWindows用のスクリーンセーバを、github にアップロードしておいた。

_mieki256/ssp3droadgl: Screensaver for Windows that draws pseudo 3D roads, implemented in C++ and OpenGL.




実行バイナリファイルは以下の2つ。

残っている問題点 :

このプログラム、メインPC上では何度試してもすんなりヌルヌルと動くのだけど、サブPCでは動く時と動かない時があって、どうもまだちょっとどこかしら怪しい部分が…。ちなみにPCのスペックは以下。

  • メインPC : AMD Ryzen 5 5600X + NVIDIA GeForce GTX 1060 6GB + RAM 16GB。Windows10 x64 22H2。画面解像度 1920x1080。
  • サブPC : AMD Athlon 5350 + 内蔵GPU Radeon R3 + RAM 4GB。Windows10 x64 22H2。画面解像度 1920x1200。

どうしてサブPC上ではすんなり動かないのだろう…。

リモートデスクトップソフトが絡んでないか :

サブPC上では、メインPCからLAN経由で操作できるように、リモートデスクトップソフト Brynhildr をサーバモードで常駐させていた。もしかしたらそのせいでOpenGLを使ったプログラムが、ちと動かしづらい状態になっていたのかもしれない。

管理者権限で brynhildr.exe を実行して、Service で「Delete」を選ぶことでサーバモードのサービスを無効にしてから Windows10 を再起動したら、今回作成したスクリーンセーバが起動できる確率がグンと上がったような気がする。

ただ、完全に問題が解消されたわけでもなく。スクリーンセーバが呼び出された際、最初の1〜2回の呼び出し時は何故か起動に失敗する…。3回目ぐらいでスクリーンセーバが起動するようになって、一度起動してしまえば、そこから先は何度も起動が成功するし、ずっと動き続けてくれるのだけど…。

また、スクリーンセーバ版ではなく、GLFWを使った版は、Brynhildr がサーバモードで動いていても問題無く起動するし、描画もしてくれる…。

やはりスクリーンセーバとして動かそうとした時だけ、何か妙なことが起きてるとしか思えない。でも、メインPC上なら毎回必ず起動してくれるのだよな…。何故サブPC上ではダメなのか…。

テクスチャが大き過ぎるのだろうか :

今回、ビルボード用テクスチャが 4096 x 4096 x 1枚、BG用テクスチャが 2048 x 1024 x 4枚と、結構巨大なサイズのテクスチャになってるあたりも不安要素。png や jpg をベタデータに展開する際に時間がかかってしまっているだろうし…。何より、そんなサイズでVRAMを占有してしまって大丈夫なのかどうか…。そのせいで動作が怪しくなっている可能性は…。

いや、それは違う気もする。もしテクスチャのサイズが巨大過ぎて問題が起きてるなら、GLFW版の動作も同様に怪しくならないとおかしい。しかしGLFW版はすんなり何度も確実に動いてしまっているわけだから…。テクスチャサイズはこれでも問題無いということなんだろう…。

余談。ビルボードについての課題 :

今回、各ビルボードを、四角ポリゴン(GL_QUADS)でドーンと表示してるけど。コレをちゃんと作るなら、複数のポリゴンを組み合わせて一つのビルボードにしたほうがいいのかもしれない。大昔の2Dゲームだって、スプライトを複数枚組み合わせて1つのキャラを作る場面があったわけだし…。

例えば…。
  • 横方向にずらりと並ぶ花畑的なビルボードを描画したいなら、横方向に異様に長いテクスチャを用意するより、小さい正方形のスプライトを横にいくつも並べたほうがテクスチャ領域が節約できる。
  • 木のビルボードも、葉っぱと幹を分けて組み合わせて作れば、幹の脇の透過部分を描画しなくて済む。
  • 道路の上をまたぐ橋っぽいビルボードも、柱部分と横に長い部分で分けて作れば、真ん中の透過部分を描画しなくて済む。

しかし、そのあたりを考えていくと、いっそ3Dモデルを作って描画したほうがいいのでは…。どうせ今回OpenGLを使って描画しちゃってるわけだし。地面と道路は疑似3Dだけど、その上に載せる各オブジェクトが3Dモデルになっていても何ら問題は無いよな…。もしかすると、いかにもな3Dモデルじゃなく、Z軸方向に差がある状態で複数枚のスプライト相当を重ねてあるだけでも、視差効果/パララックスが得られるかもしれない。

もっとも、3Dモデルにしてしまうのはやり過ぎかも。元々、レトロな見た目が欲しくてわざわざ疑似3Dにしているのに、3Dに寄せ過ぎるのもどうなんだろう。だったら道路も含めて全部3Dにしてしまえばいいじゃん、という話にもなりそう。

まあ、OpenGLでモデルデータを描画するのも結構一苦労しそうなので、今回はこのままでいいかなと…。

2024/04/02(火) [n年前の日記]

#1 [prog] 自作スクリーンセーバが起動しにくい問題について試行錯誤中

_昨日githubにアップロード した、C++ (MinGW g++ 6.3.0) と OpenGL で自作したWindows用スクリーンセーバが、サブPC上で起動しにくい問題について、解決策がないか試しているところ。

状況は以下。
つまり、スクリーンセーバとして作ると、サブPC上で利用しようとした時だけ、動いたり動かなかったりする状態になってしまう。

初期化処理は最低限の処理だけにしておくと良さそう :

スクリーンセーバを作る際の前提として、以下があるわけだけど…。
  • C/C++ (MinGW gcc/g++ 6.3.0) でスクリーンセーバを作る際、scrnsaveライブラリを使うと作りやすくなる。scrnsave.h を include して、libscrnsave.a をリンクする。
  • scrnsaveライブラリを使えば、たった3つの関数 ―― ScreenSaverProc()、ScreenSaverConfigureDialog(), RegisterDialogClasses() を自分で書くだけでスクリーンセーバが作れる。
  • ScreenSaverProc() 内で、WM_CREATEメッセージが送られてきたら初期化処理を行い、SetTimer() で一定時間毎に処理が呼ばれるように ―― 指定時間毎に WM_TIMER が送られてくるように指定する。
  • ScreenSaverProc() 内で、WM_TIMERメッセージが送られてきたら、毎フレームの処理を行う。

ふと、WM_CREATE が飛んできた際、そこで時間がかかる初期化処理をしてしまうとよろしくないのではないか…? と思えてきた。昨日の段階では、WM_CREATE が来た時に画像の展開処理もしていて、そこで数秒待たされる状態になっていた。

試しに、WM_CREATE が来た時は最低限の初期化処理だけをして、画像の展開は各フレーム処理内で行うように変更してみた。更に、展開すべき画像5枚分を一気に展開せず、1フレームにつき画像を1枚ずつ展開して、5フレームかけて全画像を展開するようにした。

このように変更したところ、サブPC上でも、スクリーンセーバが起動してくれる確率がグンと上がった。
  • リモートデスクトップソフト Brynhildr をサーバモードで常駐させていても、起動する確率は高い。
  • 1920x1200の画面でも、全てが問題無く描画できるようになった。
今までは、Brynhildrを落としておくとか、デスクトップ解像度を下げるとか、BG画像の4枚分は展開しない/BG描画はしないようにしないと動いてくれなかったりしたので、状況はかなり改善された。

残っている問題 :

ただ、これでもまだ問題が残ってる。
  • 最初の呼び出し時は、一瞬画面がチラついて、すぐにスクリーンセーバが終了してしまう。
  • そのまま放置して2度目の呼び出しが来ると、今度はちゃんとスクリーンセーバが起動してくれる。
何度試しても、こういう状態になる…。何が原因なのか。解決策/回避策は無いのだろうか。

メインPC上ではこんな問題は起きてない。サブPC上でだけ起きてるのだよな…。AMD製GPU(Radeon R3)のせい…?

2024/04/03追記 :

原因が分かった。デスクトップ解像度が1920x1200になっているとこの不具合が発生する。1920x1080にすれば一発でスクリーンセーバが起動する。そんなオチかよ…。トホホ。

2024/04/03(水) [n年前の日記]

#1 [prog][windows] Windows用の自作スクリーンセーバが動かない問題の回避策が分かった

_昨日、 C++ (MinGW g++ 6.3.0)とOpenGLで自作したWindows用スクリーンセーバが、サブPC上で起動したりしなかったりする問題で悩んでいた。症状は以下。
サブPCのスペックは以下。
原因が分かった。デスクトップ解像度だった。

サブPC上で選択できる最大解像度、1920x1200にしていると、この問題が起きてしまう。しかし、Windowsのデスクトップ解像度設定画面で「(推奨)」と表示されている1920x1080にすると、何の問題もなく一発でスクリーンセーバが起動するようになった。

そこかよ…。スクリーンセーバの作り方がまずかったわけではないのだな…。

このあたり、サブPCの内蔵GPU (Radeon R3, GCN世代)のスペックに絡む問題なのか、それとも、HDMI接続している液晶ディスプレイ MITSUBISHI MDT243WG-SB の問題なのか、一体どのへんが絡んでるのか分からないけれど、どうもこのサブPCは、デスクトップ解像度を1920x1200にして利用しようとすると、こういったところで妙な問題が発生するようだなと…。それともまさか、使っているHDMIケーブルのスペックの問題なのだろうか…?

何にせよ、なんだか動作が変だなと思ったら、「(推奨)」と表示されてるデスクトップ解像度に変えてみるのもアリ。なのかもしれない。

なんだかこの件はそのうち忘れそう。覚えていられる自信がない…。

OpenGLを使わなければ問題無い :

試行錯誤した際に一応分かった点をメモしておく。

まず、OpenGLを使ってないスクリーンセーバなら、解像度が1920x1200でも、こういった問題は起きない。

例えば、以下で、OpenGLを使っていないスクリーンセーバのサンプルコードが紹介されているけれど、これをビルドして、スクリーンセーバ(*.scr)にして試した際は、解像度が1920x1200でも、何の問題もなく一発ですんなりと起動することが分かった。

_Screen Saver 入門 (WebArchive)


また、以下で紹介されてるサンプルコード、もしくは自分が書いたコードは、OpenGLを使っているスクリーンセーバだけど。1920x1200では、例の不具合が ―― 1回目の呼び出しですぐ終了して、2回目の呼び出しで起動成功する不具合が発生した。そして1920x1080なら、そういった問題は発生しない。どのスクリーンセーバも一発でちゃんと起動した。

_Windows - OpenGLスクリーンセーバーサンプル: インディーズゲームデベロッパー「OMEGA POINT」
_How to Scr: Writing an OpenGL Screensaver for Windows
_mieki256/glboundballscr: Bound ball animation screensaver win32 by using OpenGL.


更に、以下はソースコードは公開されてなくて実行バイナリしかないスクリーンセーバだけど、これもOpenGLを使っているので、1920x1200では件の不具合が発生して、1920x1080なら一発で起動した。

_TeapotGLスクリーンセーバーの詳細情報 : Vector ソフトを探す!


そんなわけで、「OpenGLを使っていて」、かつ、「(推奨)」と表示されていないデスクトップ解像度にしている場合、件の不具合が発生する可能性が出てくるらしい。

スクリーンセーバじゃなければ問題無い :

念のために一応書いておくけれど、スクリーンセーバではなく、GLFWで新規にウインドウを作成してOpenGLで描画する分には、デスクトップ解像度が1920x1200でも問題無く動作した。

つまり、OpenGLの勉強をするだけなら、この問題には遭遇しない予感。フツーは GLUT や GLFW を使って実験するだろうから。

「せっかくここまで作ったんだから、試しにスクリーンセーバにでもしてみようかな」
「選択できる最大解像度で動作確認しておかないとマズイだろう」

などと欲を出して(?)作業をし始めると、こうしてハマる。でもまあ、Windows上で「(推奨)」と表示されてるデスクトップ解像度で動かしてる分には、この問題には遭遇しないだろうけど…。たぶん。

#2 [pc] サブPCを操作するのが面倒臭い

サブPCを操作して各種実験をする際、なんだかちょっと面倒臭い。サブPCには無線接続のキーボードを繋いであるので、目の前にはメインPC用のキーボード(USB有線接続)とサブPC用のキーボード(無線接続、タッチパッド付)の2つがある状態で…。サブPC用のキーボードを膝の上に置きながら作業してるけど、フラフラして打ちづらい。タッチパッドの操作もしづらい。

このへんどうにかならんかなあ…。とりあえず思いついた案をメモして考えをまとめてみよう…。。

キーボードを宙に浮かせられないか :

膝の上にあるキーボードが鬱陶しい。このキーボードを宙に浮かせられないか。ディスプレイアーム/モニターアームにノートPCを乗せられるようにする製品があった気がする。ソレをPCデスクに固定して使えば、キーボードを宙に浮かせられるよな…。

でも、ディスプレイと違って、キーボードは常に打鍵して力を加えるものだから、その手のアームで浮かせたらフラフラして使えたもんじゃないかもしれない。うっかり力を入れ過ぎてアームが外れたら危険だよな…。

サイドテーブルはどうか :

キーボードが置ける程度の小さいサイズのサイドテーブルのようなものはないか。と思ってググってみたけど…。そこまで小さいサイズのサイドテーブルは見当たらなかった。

そこそこ大きいサイズなら、いくらでも見かけるけれど、それは自分も持ってるのだよな…。ずっと畳んだ状態で部屋の隅で埃を被っているけれど。引っ張り出すのが面倒臭い。ここまで大きくなくてもいいんだよな…。

キーボードとマウスを1つずつにできないか :

そもそもキーボードとマウスが2つあるのがおかしい。人間の手の本数は限られているのだから、瞬間的には1つのキーボード、1つのマウスしか操作できない。だったら、2つは要らない。本来は1つで十分なはず。

となると、CPU切替器かな…。1つのキーボード、1つのマウスの先にCPU切替器があって、そのCPU切替器から2台のPCにUSBケーブルが伸びていて…。どう考えてもケーブルが邪魔になりそう。サブPCはメインPCから結構離れたところに置いてあるし。

Bluetoothはどうか :

キーボードとマウスを1つずつにするなら別の方法もあるなと。Bluetooth接続のキーボードとマウスを使えば、接続先を切り替えて複数のPCに対応できるのではないか。その手のキーボードは、3台ぐらいまで登録できそうでもあるし。Bluetoothだからケーブルも無いし。

各PC用にBluetooth受信機を用意しないといけない…。そもそも新規にBluetoothキーボードとマウスを購入しないと…。自分が気に入りそうなキーボードって無さそうな気もする…。

Bluetooth接続キーボードは、BIOS設定の操作ができないのもアレだな…。もっとも、BIOS設定ってそう頻繁に変更するものでもないから、そういう作業をする時だけ有線接続のキーボードを繋いでやれば済む話だろうか。

LAN接続してリモート操作でいいのでは :

どのサブPCもLAN接続しているのだから、LAN経由でリモート操作すればいいのではないか。実際、Linux機に対してはメインPCから ssh でアクセスして操作することが多いのだし。VNCを使ってデスクトップ画面を操作することもあるし。LAN経由で操作する分にはキーボードもマウスも1つで済む。新規に何か買わなくてもいい。

ただ、リモート操作は反応が遅くて…。CUIで操作する分には問題無いけど、VNCで操作すると画面がベロンベロンと書き換えられる様子が見えてしまって…。各サブPCは無線LANでLANに接続しているから速度が出なくてベロンベロン状態になるんだろうけど。いっそ有線で接続してしまおうか…。

日常的に使うわけでもないからいいか :

「BIOS設定は頻繁に変更するものではない」と書いたところで気が付いた。そもそも、サブPCで各種実験をする機会自体がそんなにないのだよな…。サブPCは常に電源を入れてるわけでもない。日常的に、頻繁に使ってるわけではなく、たまにしか使わない…。

だったら別に、このままでもいいんじゃないのか…。年に何回あるのか分からない場面のために、何かしらを新規購入するのもコスパが悪過ぎるだろう…。今の状態で我慢しよう…。

2024/04/04(木) [n年前の日記]

#1 [prog] 自作スクリーンセーバをLinuxに対応させたい

C++とOpenGLを使ってWindows用のスクリーンセーバを自作したけれど。せっかく作ったのだから Linux上でもビルドできるようにしたい。もっとも、Linux用のスクリーンセーバを作るわけではなくて、せめてGLFWを使ったデモプログラムとして動かせるようにするつもり。

Ubuntu Linux 20.04 LTS上でビルドしようとしているけれど、いくつか問題に遭遇。

Linux には tchar.h は無いのだな…。とりあえず今回は、#include <tchar.h> をコメントアウトするだけでビルドできそう。

MessageBox() も無いな…。コレもとりあえずコメントアウトしておく方向で。

実行バイナリに埋め込むバイナリファイル(*.png, *.jpg)のシンボルも、ちょっと変わる。MinGW g++ 6.3.0 用は先頭に「_」がつかないけれど、MSYS2 g++ 13.2.0 や Ubuntu Linux 22.04 LTS の g++ 11.4.0 なら先頭に「_」がつく。

ソースの切り替えについて :

Windows用とLinux用の両方でビルドが通るように、定義済みマクロでソースの中身が変わるようにした。
  • Windows上でビルドする際は _WIN32 が定義される。
  • MSYS2上でビルドする際は __MINGW64__ が定義される。
  • Linux上でビルドする際は __linux__ が定義される。

#if defined(__MINGW64__) || defined(__linux__)

// MSYS2 (Windows, g++ 13.2.0) or Linux

#else

// MinGW (Windows, g++ 6.3.0)

#endif


#ifdef _WIN32

// Windows only

#include <tchar.h>
#include <windows.h>
#include <scrnsave.h>
#include <mmsystem.h>

#endif

Ubuntuのバージョンによって結果が違ってしまう :

VMware Player + Ubuntu Linux 20.04 LTS x64 ならビルドが通るのだけど。実機 + Ubuntu Linux 22.04 LTS x64 ではビルドが通らない…。

Ubuntu Linux 20.04 LTS x64 の場合。ビルドは通る。
$ g++ --version
 g++ (Ubuntu 9.4.0-1ubuntu1~20.04.2) 9.4.0
 ...

$ ld --version
 GNU ld (GNU Binutils for Ubuntu) 2.34
 ...

$ make -f Makefile.glfw
g++ -o ssp3droadglfw.o -c ssp3droadglfw.cpp
g++ -o render.o -c render.cpp
ld -r -b binary -o sprites.o sprites.png
ld -r -b binary -o bg_summer.o bg_summer.jpg
ld -r -b binary -o bg_autumn.o bg_autumn.jpg
ld -r -b binary -o bg_winter.o bg_winter.jpg
ld -r -b binary -o bg_night.o bg_night.jpg
g++ -o ssp3droadglfw ssp3droadglfw.o render.o sprites.o bg_summer.o bg_autumn.o bg_winter.o bg_night.o -lGL -lGLU -lglfw -lm


Ubuntu Linux 22.04 LTS x64 の場合。エラーが出てしまう…。
$ g++ --version
 g++ (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0
 ...

$ ld --version
 GNU ld (GNU Binutils for Ubuntu) 2.38
 ...

$ make -f Makefile.glfw
g++ -o ssp3droadglfw.o -c ssp3droadglfw.cpp
g++ -o render.o -c render.cpp
ld -r -b binary -o sprites.o sprites.png
ld -r -b binary -o bg_summer.o bg_summer.jpg
ld -r -b binary -o bg_autumn.o bg_autumn.jpg
ld -r -b binary -o bg_winter.o bg_winter.jpg
ld -r -b binary -o bg_night.o bg_night.jpg
g++ -o ssp3droadglfw ssp3droadglfw.o render.o sprites.o bg_summer.o bg_autumn.o bg_winter.o bg_night.o -lGL -lGLU -lglfw -lm
/usr/bin/ld: render.o: relocation R_X86_64_PC32 against absolute symbol `_binary_sprites_png_size' in section `.text' is disallowed
collect2: error: ld returned 1 exit status
make: *** [Makefile.glfw:26: ssp3droadglfw] エラー 1

このエラーはどういう意味なんだろう…。

テクスチャを展開できない :

ビルドが通る、VMware Player + Ubuntu Linux 20.04 LTS x64上でも、動作に問題がある。出来上がった実行バイナリを動かしてみると、テクスチャ画像を展開できる時と、展開できない時がある…。必ず展開できるわけでもなく、必ず展開できないわけでもない。こういうバグが一番困る…。

実機上なら動作が変わるのだろうか。しかし、そちらは Ubuntu Linux 22.04 LTS だから、ビルド自体が通らない…。

#2 [prog] MSYS2パッケージをダウングレードしておいた

ここ最近、xzパッケージにバックドアが仕掛けられていたという事件が気になってる。MSYS2 のxzパッケージを調べてみたら、事件を起こしたバージョン、5.6.1 が入ってた…。

pacman -Ss xz

念のために、一つ前の 5.4.6-2 にダウングレードしてみたい。MSYS2上でそんなことをして意味があるのかないのか分からんけど…。まあ、pacman でダウングレードする方法を知っておいてもいいだろう…。

_パッケージのダウングレード - ArchWiki
_MSYS2でパッケージをダウングレードする - Qiita

/var/cache/pacman/pkg/ に、pacmanのキャッシュが残ってるらしい。調べてみたら、古いバージョンも残っていた。

$ ls /var/cache/pacman/pkg/ | grep xz
mingw-w64-i686-xz-5.4.5-1-any.pkg.tar.zst
mingw-w64-i686-xz-5.4.5-1-any.pkg.tar.zst.sig
mingw-w64-i686-xz-5.4.6-1-any.pkg.tar.zst
mingw-w64-i686-xz-5.4.6-1-any.pkg.tar.zst.sig
mingw-w64-i686-xz-5.4.6-2-any.pkg.tar.zst
mingw-w64-i686-xz-5.4.6-2-any.pkg.tar.zst.sig
mingw-w64-i686-xz-5.6.1-2-any.pkg.tar.zst
mingw-w64-i686-xz-5.6.1-2-any.pkg.tar.zst.sig
mingw-w64-x86_64-xz-5.4.5-1-any.pkg.tar.zst
mingw-w64-x86_64-xz-5.4.5-1-any.pkg.tar.zst.sig
mingw-w64-x86_64-xz-5.4.6-1-any.pkg.tar.zst
mingw-w64-x86_64-xz-5.4.6-1-any.pkg.tar.zst.sig
mingw-w64-x86_64-xz-5.4.6-2-any.pkg.tar.zst
mingw-w64-x86_64-xz-5.4.6-2-any.pkg.tar.zst.sig
mingw-w64-x86_64-xz-5.6.1-2-any.pkg.tar.zst
mingw-w64-x86_64-xz-5.6.1-2-any.pkg.tar.zst.sig
xz-5.4.5-1-x86_64.pkg.tar.zst
xz-5.4.5-1-x86_64.pkg.tar.zst.sig
xz-5.4.6-1-x86_64.pkg.tar.zst
xz-5.4.6-1-x86_64.pkg.tar.zst.sig
xz-5.4.6-2-x86_64.pkg.tar.zst
xz-5.4.6-2-x86_64.pkg.tar.zst.sig
xz-5.6.1-2-x86_64.pkg.tar.zst
xz-5.6.1-2-x86_64.pkg.tar.zst.sig

$ ls /var/cache/pacman/pkg/ | grep lzma
liblzma-5.4.5-1-x86_64.pkg.tar.zst
liblzma-5.4.5-1-x86_64.pkg.tar.zst.sig
liblzma-5.4.6-1-x86_64.pkg.tar.zst
liblzma-5.4.6-1-x86_64.pkg.tar.zst.sig
liblzma-5.4.6-2-x86_64.pkg.tar.zst
liblzma-5.4.6-2-x86_64.pkg.tar.zst.sig
liblzma-5.6.1-2-x86_64.pkg.tar.zst
liblzma-5.6.1-2-x86_64.pkg.tar.zst.sig

pacman -U でダウングレードできる。

pacman -U file:///var/cache/pacman/pkg/mingw-w64-i686-xz-5.4.6-2-any.pkg.tar.zst
pacman -U file:///var/cache/pacman/pkg/mingw-w64-x86_64-xz-5.4.6-2-any.pkg.tar.zst
pacman -U file:///var/cache/pacman/pkg/xz-5.4.6-2-x86_64.pkg.tar.zst
pacman -U file:///var/cache/pacman/pkg/liblzma-5.4.6-2-x86_64.pkg.tar.zst

$ pacman -Ss xz
clangarm64/mingw-w64-clang-aarch64-xz 5.6.1-2
    Library and command line tools for XZ and LZMA compressed files (mingw-w64)
mingw32/mingw-w64-i686-xz 5.6.1-2 [インストール済み: 5.4.6-2]
    Library and command line tools for XZ and LZMA compressed files (mingw-w64)
mingw64/mingw-w64-x86_64-xz 5.6.1-2 [インストール済み: 5.4.6-2]
    Library and command line tools for XZ and LZMA compressed files (mingw-w64)
ucrt64/mingw-w64-ucrt-x86_64-xz 5.6.1-2
    Library and command line tools for XZ and LZMA compressed files (mingw-w64)
clang32/mingw-w64-clang-i686-xz 5.6.1-2
    Library and command line tools for XZ and LZMA compressed files (mingw-w64)
clang64/mingw-w64-clang-x86_64-xz 5.6.1-2
    Library and command line tools for XZ and LZMA compressed files (mingw-w64)
msys/liblzma 5.6.1-2 (libraries) [インストール済み: 5.4.6-2]
    Library for XZ and LZMA compressed files
msys/xz 5.6.1-2 (compression) [インストール済み: 5.4.6-2]
    Library and command line tools for XZ and LZMA compressed files

インストール済み、が 5.4.6-2 になった。

ダウングレードできたら、/etc/pacman.conf の IgnorePkg= にパッケージ名を追加する必要があるらしい。これをしておかないとアップグレードされてしまうのだとか。

vi /etc/pacman.conf
IgnorePkg   = xz liblzma mingw-w64-i686-xz mingw-w64-x86_64-xz

これで合ってるのかな…。分からん…。

#3 [anime] 「勇気爆発バーンブレイバーン」最終回を視聴

録画してたソレをようやく視聴。ロボットアニメ…だろうか? だよな。たぶん。

いやはやコレは…。なんというか…。途中まで「自分は一体何を見せられているんだろう…?」と…。素晴らしい。

なんとなく、「真面目に不真面目」とか「ふざける時は全力で」とかそういう言葉が脳裏に浮かんだ。どうせやるなら徹底的に、だよな…。何にせよ、とんでもないアニメを見せてもらった気がする…。

2024/04/05(金) [n年前の日記]

#1 [prog] 自作スクリーンセーバをLinuxに対応させたい。その2

C++とOpenGLを使った自作スクリーンセーバをLinuxにも対応させようとしているところ。GLFWを使ったデモプログラムとして動かすつもり。

_mieki256/ssp3droadgl

Ubuntu Linux 22.04 LTS (g++ 11.4.0, ld 2.38)上でビルドしようとしたらリンクエラーが出てしまって悩んでしまったけれど。ソースコードに手を入れたら改善した。実行バイナリに埋め込んだpngやjpgを展開させる際、サイズの求め方を変えてみたらエラーが出ない状態になった。

ざっくり説明。

画像バイナリ(.png .jpg)を実行バイナリに含める方法は色々あるけど、今回は ld を使ってバイナリファイルをオブジェクトファイルに変換する方法を選んだ。
$ ld -r -b binary -o sprites.o sprites.png

こうしてできたオブジェクトファイルをリンクしてやることで、実行バイナリの中に画像バイナリを含めることができる。

バイナリファイルを ld でオブジェクトファイルに変換すると、*_start, *_end, *_size の3つのシンボルを、C/C++側から参照できる状態になる。

以下は objdump -x を使って、オブジェクトファイルに含まれている情報をダンプしてみた例。「SYMBOL TABLE:」で、3つのシンボルが ―― *_end、*_size、*_start が並んでることが分かる。
$ ld -r -b binary -o sprites.o sprites.png

$ objdump -x sprites.o
 
 sprites.o:     ファイル形式 elf64-x86-64
 sprites.o
 アーキテクチャ: i386:x86-64, フラグ 0x00000010:
 HAS_SYMS
 開始アドレス 0x0000000000000000
 
 セクション:
 Idx Name          Size      VMA               LMA               File off  Algn
   0 .data         00875cae  0000000000000000  0000000000000000  00000040  2**0
                   CONTENTS, ALLOC, LOAD, DATA
 SYMBOL TABLE:
 0000000000000000 l    d  .data  0000000000000000 .data
 0000000000875cae g       .data  0000000000000000 _binary_sprites_png_end
 0000000000875cae g       *ABS*  0000000000000000 _binary_sprites_png_size
 0000000000000000 g       .data  0000000000000000 _binary_sprites_png_start


C/C++側からこれらのシンボルを利用したい時は、以下のように書いておく。これで各シンボルが参照できるようになる。
extern unsigned char _binary_sprites_png_start; // binary start address
extern unsigned char _binary_sprites_png_end;   // binary end address
extern unsigned char _binary_sprites_png_size;  // binary size


このシンボルを利用して、実行バイナリ内の画像バイナリの展開処理を行うわけだけど…。今までは *_size を使って処理してた(つもりだった)。
        img_ptr = &_binary_sprites_png_start; // start address
        img_size = (size_t)&_binary_sprites_png_size; // size
        gw.spr_tex = createTextureFromMemory(img_ptr, img_size);

これを、end - start でサイズを求めるように修正してみた。
        img_ptr = &_binary_sprites_png_start; // start address
        img_size = (size_t)((&_binary_sprites_png_end) - (&_binary_sprites_png_start)); // size
        gw.spr_tex = createTextureFromMemory(img_ptr, img_size);

このように書き換えてみたところ、エラーが出なくなってビルドが通るようになった。実行バイナリも期待した通りに動作してくれた。

また、この書き換えをしたことで、Ubuntu Linux 20.04 LTS上で発生していた不具合も ―― テクスチャの展開が時々失敗する問題も何故か解決してしまった。何度試しても、必ず展開できる…。もしかして今までは、サイズが不定値になっていたのだろうか…?

#2 [prog] 自作スクリーンセーバを高DPIに対応させる

今時のWindowsは、デスクトップ設定で、文字表示その他を、125%とか150%とかに変更できる。おそらく高DPIと呼ばれる状態なのだろうけど…。

この状態にすると、スクリーンセーバ設定ダイアログ上で、スクリーンセーバのプレビュー表示がおかしな位置に表示されてしまう。この問題を解決したい。

結論を先に書いておく。マニフェストファイルを作成して、スクリーンセーバのリソースファイル内でマニフェストファイルを指定して埋め込んでおけば、一応は正常な表示になる。

環境は、MinGW g++ 6.3.0、ld 2.28、windres 2.28。Windows10 x64 22H2上で作業。

不具合を発見した経緯 :

自作したWindows用スクリーンセーバを ―― 疑似3D道路を描画するスクリーンセーバを、親父さんのPC上で動かして動作確認してみたところ、スクリーンセーバ設定ダイアログ上のプレビュー表示がおかしくなってることに気づいた。本来表示されるべき位置からかなり左上のほうに表示されてしまって、描画内容の右下だけが、プレビュー画面の左上のほうにちょっとだけ表示されてしまっている。何故だ。どうしてこうなった。

そこでふと気が付いた。親父さんは視力が衰えてしまっているので、Windowsのディスプレイ設定で、「テキスト、アプリ、その他の項目のサイズを変更する」を150%にしていた…。たぶんそのせいじゃないだろうか。

自分のメインPC上でも、そのあたりを変更してみたところ、親父さん用PCと全く同じ不具合が再現できた。

今までビルドしてきた各スクリーンセーバについても一通り試してみたところ、OpenGLを使っている/使ってないに係わらず、どのスクリーンセーバも、プレビュー表示は表示位置がおかしくなった。

この結果は、当然な気もする。自分がググって今まで参考にしてきた、スクリーンセーバの作成方法を解説しているページは、「高DPI? ナニソレ?」「WindowsのDPIと言えば96DPIに固定されてるもんだろJK」という時代に書かれているので、こういった不具合が起きることも、もちろん解決策についても、一切言及していない。故に、どのサンプルを動かしてもこういう不具合が発生するのは必然、ということなのだろう…。

マニフェストファイルがあれば動作が変わる :

ただ、試しているうちに、FreeBASICで作成したスクリーンセーバだけが、高DPIにしても正常なプレビュー表示になっていることに気づいた。

_freeBASIC Screensaver Kit Updated - freebasic.net
_FreeBASIC Screensaver Kit - freebasic.net

一体何が違うのか調べてみたところ、FreeBASICのスクリーンセーバ作成用kitには、マニフェストファイル(manifest)が添付されていることに気づいた。

そのマニフェストファイルに書かれていた内容は以下。
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" >
  <asmv3:application>
    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
      <dpiAware>true</dpiAware>
    </asmv3:windowsSettings>
  </asmv3:application>
</assembly>

内容についてググった感じでは…。この記述は、Windows Vistaの時点で追加されたDPI変更機能に対応させるための記述、ということらしい。

ちなみに今現在は、Windows10 Version 1607で追加された機能もあるらしくて、完全に対応させるならそのあたりもアプリ側で行わないといかんらしい…。

更に、このマニフェストファイルは、リソースファイルの中で取り込むように指定されていた。リソースファイルの内容は以下。
 FB_SCRNSAVER_ABOUT DIALOGEX 6, 18, 160, 62
 STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | DS_NOFAILCREATE
 FONT 10,"Arial"
 CAPTION "Mambazo Doodle"
 BEGIN
     CTEXT "Mambazo Doodle" -1, 0, 5, 160, 8
     CTEXT "Version 1.0" -1, 0, 15, 160, 8
     CTEXT "http://langfordtavern.com/" -1, 0, 25, 160, 8
     DEFPUSHBUTTON "OK" IDOK, 55, 40, 50, 14
 END 
 
 1 24 "MambazoDoodle.xml"

一番最後に、「1 24 "MambazoDoodle.xml"」 という記述がある。
  • ここで指定されているxmlファイルがマニフェストファイル。
  • 最初のほうにある「1 24」は、マニフェストファイルをリソースファイル内で指定する際のお約束らしい。

自作スクリーンセーバにも導入してみた :

試しに、自作のスクリーンセーバでも同じことをやってみた。
  • マニフェストファイル名を、「スクリーンセーバファイル名.manifest」にする。
  • リソースファイル(resource.rc)の最後に、該当行を追加。

1 24 "ssp3droadgl.scr.manifest"

この状態でビルドし直したところ、WindowsのデスクトップのDPIを変更しても、スクリーンセーバ設定ダイアログ上で正常な位置にプレビューが表示される状態になった。

_mieki256/ssp3droadgl

とりあえず今回は、この対応だけでいいんじゃないかな…。

他のスクリーンセーバも対応させておいた :

今まで作った、OpenGLを使った他のスクリーンセーバも対応させておいたとメモ。

_mieki256/ssstars_opengl
_mieki256/glboundballscr

#3 [linux] CUIファイラーRangerでファイルのアクセス権を変更したい

Linux上で動作するCUIファイラー Ranger を使って、複数のファイルのアクセス権を変更したい。今までは bash上で chmod 666 hoge.txt とか打ってたけど、何度もやってると面倒臭い。

以下の手順で変更できた。
あるいは、変更したいファイルにカーソルを合わせて、いきなり「666=」と打ってもいいらしい。見た目で「変更したよ」とは言ってこないけど、実はちゃんと変更されてる。数値を打った後、一番最後に「=」を打つことで、そのアクセス権に変更せよ、という指示を出しているらしい。

参考ページ :


2024/04/06() [n年前の日記]

#1 [linux] rangerで画像表示できるか試してた

自分は普段、Windows10 から Ubuntu Linux 22.04 LTS (Intel Core i3-6100T機) を操作したい際、MobaXterm + ssh でログインして作業している。その際、ファイルの在処などを調べたりする時は、CUIファイラー ranger を使ってる。

_CLI で Linux ファイルマネージャ ranger を使うことのメモ | Jenemal Notes
_CLIファイルマネージャrangerの基本設定 #Python - Qiita
_Ranger: CUI ファイラー - 苦労する遊び人の玩具箱 1 ドキュメント
_ターミナルで利用するCLIファイルマネージャ(ファイラー)の比較・おすすめ [インフラエンジニアのPC環境]

sudo apt install ranger

この ranger は画像のプレビュー表示もできるのだけど、MobaXterm上では画像が表示できなくてエラーになってしまう。どうにかして表示する方法はないかと試してた。

ターミナルエミュレータを起動して解決する :

MobaXterm にはXサーバも同梱されているので、アクセス先の Ubuntu Linux にインストールされているGUIアプリも起動することができる。ターミナルエミュレータ(ターミナルソフト)も起動できるので、それらを起動して、その上で ranger を使えば画像のプレビュー表示もできるのではないかと思いついた。

ただ、それぞれを起動して試してみたところ、urxvt 以外は全滅だった。

sudo apt install rxvt-unicode
urxvt &

ranger_rxvt_ss.jpg

sakura terminal も、roxtem も、rangerの画像表示はできなかった。自分の環境の場合、rangerで画像を表示したい時は urxvt を起動するしかないようだなと…。

一応、 _~/.Xdefaults で urxvt 用の設定はしておいた。設定内容については以下が参考になった。ありがたや。

_urxvt こと rxvt-unicode を使うことのメモ | Jenemal Notes
_Ubuntuにurxvt(軽量ターミナル)を導入 - mfumiの日記

ちなみに、昔の Ubuntu Linux では、この rxvt-unicode は256色に非対応だったらしいけど。説明文を見る限り、Ubuntu Linux 22.04 LTS でインストールできる rxvt-unicode は、256色をサポートしてる、と表示されている。本当に対応してるのかどうかは分からんけど…。
$ sudo aptitude search rxvt
i   rxvt-unicode   - RXVT-like terminal emulator with Unicode and 256-color support

_Ubuntu - jammy の rxvt-unicode パッケージに関する詳細

別の方法で画像をプレビュー表示する :

画像のプレビュー表示をしたいだけなら、GUIのファイラーを起動すればサムネイル表示ができるので、そちらを使ってしまうのもアリかもしれないと思いついた。

自分は普段、Ubuntu Linuxのデスクトップ環境として Xfce を利用しているので、Xfce の標準ファイラー thunar 以外なら ―― pcmanfm, nautilus, nemo, rox-filer, doublecmd 等なら、MobaXterm経由で起動してWindows10のデスクトップ上に表示できる。
pcmanfm &
nautilus &
nemo &
rox-filer &
doublecmd &

gui_filer_ss.jpg

ちなみに、thunar だけは、MobaXterm から起動すると、Windows10 のデスクトップではなく、アクセス先の実機側のデスクトップ画面に表示されてしまって利用できなかった。これはデスクトップ環境として Xfce を使っているからで…。他のデスクトップ環境を使った場合は、そのデスクトップ環境の標準ファイラーが同じ状態になる。
  • Xfce : 標準ファイラー Thunar
  • Gnome : 標準ファイラー Nautilus
  • LXDE : 標準ファイラー PCManFM

画像ビューアで画像を表示 :

そもそも画像ビューアを使ってしまえばいいのでは、と気が付いた。MobaXterm上で ranger を起動して、画像ファイルの上で Enter を叩いて、例えば画像ビューア sxiv あたりを起動してやれば画像表示ができなくもない。

ranger_sxiv_ss.jpg

ranger から sxiv を起動した場合、sxiv のウインドウ内で右クリックすると、そのフォルダ内に入っている他の画像もサムネイルで一覧表示してくれるので、これでも問題無さそうな気がする…。

#2 [anime] 「すずめの戸締り」を視聴

金曜ロードショーで放送されていたものを録画していたので視聴。新海誠監督作品の劇場アニメ。

面白かった。いや、東日本大震災がキッカケになって作られたこの作品を面白かったと言ってしまっていいのかどうかちょっと悩むけど。こういう形で昇華(?)すること自体はとても良いことだと思えるし…。

映像面では相変わらず見応えがあるなと感心。カメラマップ等を活用しているあたりが興味深い。敵(?)を表現する際のエフェクトも一体どうやって作ってるんだろうなと…。かつて宮崎アニメの「もののけ姫」でもああいった存在をCGで映像化していたわけだけど、随分と進歩が感じられる映像になっていたなと…。スケールも全然違うし…。

ハードウェアで残すか。ソフトウェアで残すか :

そもそも、東日本大震災の記憶を、こういった作品にして後世に残せないかとチャレンジしてみたこと自体が評価に値するのではないかと感じた。たしか以前、監督さんへのインタビュー記事で、「映像作家の自分はあの震災に対してこういう形でしかアプローチできない」といった感じの発言を目にした記憶があるのだけど、映像を見ていて、なるほどたしかにと納得できたというか。

自分達は、過去の大災害の記録を後世に残したいと思った際、一般的にはついついハードウェアで残すことをまず考えてしまう。例えば石碑を残すとか…。しかし、石碑の類は、あっという間に人々の記憶から忘れ去られてしまう。

何せ、大阪の街のど真ん中に、「江戸時代にここまで津波が来たよ…」と記してある碑が残ってるわけで…。どうして街のど真ん中にあるのかと考えたら、まあ、そういうことだよなと…。

あるいは、以下のような話もある…。

_寺田寅彦 津浪と人間
三陸災害地を視察して帰った人の話を聞いた。ある地方では明治二十九年の災害記念碑を建てたが、それが今では二つに折れて倒れたままになってころがっており、碑文などは全く読めないそうである。またある地方では同様な碑を、山腹道路の傍で通行人の最もよく眼につく処に建てておいたが、その後新道が別に出来たために記念碑のある旧道は淋れてしまっているそうである。

寺田寅彦 津浪と人間 より


しかし、それらの記録はハードウェアでしか残せないというわけではない。ソフトウェアで残すという方法もある。

例えば、自分が住んでいる福島県須賀川市には、松明あかしという祭りがある。めっちゃデカイ松明を作ってガンガン燃やすという祭りなのだけど、伊達政宗に滅ぼされた二階堂勢を弔うため、というのが由来。

_松明あかしの由来 / 須賀川市公式ホームページ

災害の記録というわけではないけれど、こういった事例は、ソフトウェアで記録を残そうとした事例と言える。この場合、少なくとも四百年は残せてる。

そして、新海監督が「すずめの戸締り」で試そうとしたのも、こういうことだろうなと…。娯楽性/エンターテイメント性を持った映像作品として提示しつつも、その中で過去に大災害があったことをしっかり示しておくことで、見た人の脳内に情報をインストールする…。「お話」にしてみせることで「覚えておいてね」と語りかける。ソフトウェアで記憶を伝えていこうという、立派な試みの一つと言える。「映像作家には所詮こんなことしかできない」と捉えることもできるだろうけど、「映像作家だからこそ、こんなことだってできる」と捉えることもできる。

何にせよ、後の時代に少しでも伝えていきたいと考えて、実際に作品の形にしてみせただけでも、それは賞賛されてしかるべき行為なのではないかと思えた。こんなこと、作家さんじゃなきゃできない。でも、大半の作家さんはここまでやらない。だけど新海監督は、こうしてやってみせた。それだけでも、自分は監督に拍手を送りたいなと思えたわけで。

ただ、ソフトウェアで残すのは、結構難しい…。それが面白かったら残っていくけど、つまらなかったら残らないから…。このアニメは一体どちらの扱いを受けるのか…。でもまあ、そこは時間が判断してくれることだから…。

2024/04/07() [n年前の日記]

#1 [linux] Linuxのファイラーのアイコンテーマを変更したい

Ubuntu Linux 22.04 LTS (i3-6100T機)に、Windows10 x64 22H2 + MobaXterm からアクセスして、nemo や caja のようなGUIファイラーを起動する時があるのだけど。表示されているアイコンの見た目がどうも気に入らない。おそらくは Yaruテーマが選ばれているのだろうけど、個人的に好みの見た目ではない…。

アイコンテーマを変更したいのだけど、どうやって変更したらいいのだろう。

Ubuntu のデスクトップ画面(Xfce)上なら、設定で「外観」を選んでアイコンテーマを変更すればいいのだけど。MobaXterm から起動した際は別の設定が使われるようで、Xfce側で行った変更が反映されなくて…。

何か方法はあるはずとググっているけど、解決策を紹介してるページには遭遇せず。うーん。

2024/04/08追記 :

~/config/gtk-3.0/settings.ini を修正すれば対応できそう。

#2 [anime] 「ブラック・ジャック 劇場版」を視聴

BS12で放送されていたので視聴。出崎統監督作品。OVA版の流れで作られたアニメらしい。

今はもう見られない映像スタイルなので、その点は興味深く見ることができた。こういうスタイルを今のアニメも部分的に取り込めないものかなあ…。いや、作品によってはデジタル撮影処理で結構再現してる感もあるけれど。今時は、どんなアニメもうっすらとグラデかけてたりするもんな…。

おそらくだけど、漫画から劇画に変わっていく時期を意識させられた世代の作り手達だろうから、このアニメも、漫画的なアニメから劇画的なアニメへの移行を意識しつつ作っていたのではと想像したりもする。そういえば、そもそも原作のBJも、劇画がブームになって、もう漫画は古い、手塚は古いと言われていた時期の作品だったか…。原作が目指してたはずの劇画的な印象を、OVA版も含めてこのシリーズで醸し出せないか挑戦していたのではないかなあ、と。

そのように想像すると、もしかすると今の世代にも応用できるところがありそうな…。なんでもかんでも「漫画原作アニメ」と呼んでしまって大雑把過ぎる分類をしたりせずに、あえて意識して「劇画原作アニメ」と口にしながら作業してみたら最終的な映像の印象も変わってきて他作品との差別化ができたりしないだろうか…。漫画ではなく劇画のように感じるアニメの映像スタイルとは一体どういうものなのか、ちょっと想像してみるのもアリだったりして…? 「呼び方を変えたぐらいでイメージが変わるわけないだろ」と笑われるかもしれないけれど、例えば「少年漫画原作アニメ」と「少女漫画原作アニメ」では思い浮かぶイメージも違ってくるものだし。

それはともかく。BJで90分前後の話を見せるのはなんだかちょっと違うなとも思えた。原作が基本的に1話完結モノだったし、アイデアをポンと出してさっと終わるのがBJっぽいかもなあ、と…。もしかすると、30分で1話、それを3本並べて、みたいな感じでまとめたほうがBJシリーズらしくなったのでは…。でも、劇場版となったら、それなりの尺で作りたいと皆思ってしまうものなのかな…。見る側もそういうフォーマットを期待してそうだし…。

2024/04/08(月) [n年前の日記]

#1 [linux] Linuxのファイラーのアイコンテーマを変更したい。その2

Ubuntu Linux 22.04 LTS (i3-6100T機)に、Windows10 x64 22H2 + MobaXterm からアクセスして、nemo や caja のようなGUIファイラーを起動した際に表示されているアイコンの見た目がどうも気になる。変更したい。

以下のページで紹介されている内容が関係してそうな気がする。

_GTK - ArchWiki
_XDG Base Directory - ArchWiki

以下を変更したら反映されそう。たぶん。
$XDG_CONFIG_HOME/gtk-3.0/settings.ini

ただ、自分の環境では、$XDG_CONFIG_HOME が定義されてなかった。一般的には、$XDG_CONFIG_HOME は ~/.config/ になっているらしいので、~/.config/ を眺めたところ、gtk-3.0 というフォルダがあった。

該当ファイルを修正。
vi ~/config/gtk-3.0/settings.ini
[Settings]?
gtk-application-prefer-dark-theme=0?
gtk-icon-theme-name = Numix?
gtk-theme-name = GreyBird?
gtk-font-name = DejaVu Sans 11?

nemo や caja を起動してみたところ、反映されたように見える。このファイルを弄っていけばどうにかなりそうだな…。

余談。PCManFM-qtなら面倒臭くない。 :

ちなみに、PCManFM-qt なら、PCManFM-qt 自身の設定ウインドウ内にアイコンテーマの選択項目があるので面倒臭くない。

#2 [linux] xfeファイラーについて

xfeというファイラーがあるらしい。X11アプリ。

_32bitパソコンにオススメ(?)ファイルマネージャーXfeが軽快で快適 : 森下巻々ブログ・おきてがみ

Ubuntu Linux 22.04 LTS (i3-6100T機)にインストールして、少しだけ試用してみた。
sudo apt install xfe

xfe と打って実行できる。

試用した感じでは、悪くない気がする。動作もなんとなくだけど軽いような気もするし…。

xfimageについて :

xfe と一緒に、xfimage という画像ビューアもインストールされた。

xfe上で画像ファイルを右クリックして「開く」を選べば、xfimage が起動する。もしくは端末から xfimage と打っても起動する。

右側にファイル一覧が表示されて、左側に画像が表示される。ファイルをダブルクリックしないと表示されないのがちょっとアレな気もするけど…。画像表示するだけならこれでもいいかも。ちなみに画像に含まれているアルファチャンネルは表示に反映されない。透明部分は真っ黒になった。

#3 [cg_tools] アイソメトリックについて実験中

ふと、なんとなく、アイソメトリック(Isometric Projection)の画面で車が走っていくデモプログラムってどうかなと思いついてしまったので、blenderを使って見栄えについて確認中。

大昔のゲーム機は、BG画面がタイルを敷き詰めたような仕組みだったので、アイソメトリックっぽい画面を作るには、パズルのような試行錯誤が必要だったらしいのだけど。今はフツーに3Dで描画できちゃう時代なので…。OpenGL を使えば、平行投影、かつ、カメラの角度を変えるだけでもそれらしく見えるんじゃないのかなと…。

ひとまず、blenderのカメラを透視変換から平行投影に切り替えて、見た目がどうなるか確認。

isometric_test_ss1.jpg

isometric_test_ss2.jpg

isometric_test_ss3.jpg

イケそうな気がする。カメラの角度を30度にしたほうがいいのか、45度にしたほうがいいのか、ちょっと悩むけど…。ググったところ、本来は30度になるっぽい…?

地面に模様を入れたほうがいいのかどうかも悩む。何も入れずに、フラットな見た目にしたほうがいいのかなあ…? でも、コレはチェッカー模様だからアレだけど、例えばキャンバス地だったら印象も変わるのだろうか?

#4 [anime] 「ゆるキャン△ SEASON3」1話を視聴

BS11で放送されていたソレを録画していたので視聴。秋冬キャンプをテーマにした漫画原作をTVアニメ化した作品。

3期から制作スタジオ、メインスタッフが変わって、キャラデザも原作寄りに変更されたそうで。番宣CMを目にして、作画面でちょっと不安になっていたりもしたのだけど…。実際に見てみたらちゃんとゆるキャンシリーズになっているように思えた。何より、時間の進み方が相変わらずおかしい。「アレ? もう終わっちゃうの?」みたいな。キャンプをテーマにしているせいか、見ているこちらの体感時間が通常のアニメのソレとは違ってきてしまうのではないかと思っているけど…。何にせよ、こんな時間感覚になってしまうのだから、これは間違いなくゆるキャンシリーズであろう。みたいな。

キャラデザ変更の是非について :

ネット上の感想を眺めると、キャラデザが変更されたことに不満を持ってる方がチラホラ居るようなのだけど…。メインスタッフがごっそり変わって、1期2期のキャラデザ総作監さんが抜けてしまった/続編にはノータッチになった以上、原作寄りのキャラデザに修正したことは正解だろうと個人的には思えた。

今後、仮に、4期や5期が作られることになったとして。そしてその時も、制作スタジオやメインスタッフがごっそり変わるとしたら、どこかの時点で1期2期のキャラデザとは決別しておかないとマズイ。そして、その時原典として頼るべき絵柄はどれなのかと考えたら、それはどう考えてもアニメ版1期2期ではなく、原作の絵柄が基準になるべきで…。迷ったら原作漫画を開け。そこに答えがあるはずだ。企画を引き継いだスタッフがそう考えるのは、そんなにおかしいことだろうか?

ルパン三世パート1のキャラデザやカリ城の作画監督を担当した大塚康生さんだって、「最近のルパンはカリ城のキャラデザを参考にしたものばかりですよね?」という問いかけに、「そんなことはないですよ。今のルパンのキャラデザをしてる人達も必ず原作を参考にしてキャラデザしてるはずですよ」と答えていたし。まず参考にするのは原作。その上で、過去作の絵柄も参考にして、という形にならないと…。

まあ、ルパン三世アニメ版のキャラデザの違いと比べたら、ゆるキャンのソレなんて「全部同じじゃないですか!?」レベルじゃないかなあ、とも…。「ちがいますよーっ」「これだからしろうとはダメだ! もっとよく見ろ!」と言われそうだけど、両さん達は全バージョンを肯定した上でソレを言ってる点を忘れちゃいけないよなと…。 *1

*1: と言っても全肯定した上で、やれココがどうのアソコがどうのと文句も言ってるはずなんだけど。そういう人種だよな…。

2024/04/09(火) [n年前の日記]

#1 [prog] OpenGLでモデルデータを読み込めそうか調べてる

C/C++ とOpenGLでモデルデータを読み込みたい。そのあたり何か良さそうなライブラリがあったりしないかとググっているけれど…。

Assimpというライブラリがあると知って関連情報を調べてる。

_LearnOpenGL - Assimp

Debian Linux や Ubuntu Linux なら、パッケージがあるっぽい。

_Debian -- bookworm の libassimp-dev パッケージに関する詳細
_Ubuntu - jammy の libassimp-dev パッケージに関する詳細

ただ、MinGW の gcc/g++ で利用する方法が分からない…。

MSYS2 ならパッケージが用意されているように見える。

_Package: mingw-w64-x86_64-assimp - MSYS2 Packages

2024/04/10(水) [n年前の日記]

#1 [prog][cg_tools] OpenGLでモデルデータを読み込めそうか調べてる。その2

C/C++ とOpenGLでモデルデータを読み込みたい。そのあたり何か良さそうなライブラリがあったりしないかとググっているところ。

モデルデータのフォーマットにも色々あるけれど、どのへんがいいだろう。とりあえず、gltf、もしくは、wavefront(obj)形式だろうか。

_glTF - Wikipedia
_Wavefront .objファイル - Wikipedia

gltf用ライブラリ :

gltfの読み込み用ライブラリを探したら、以下に遭遇。

_syoyo/tinygltf: Header only C++11 tiny glTF 2.0 library

まだ試用してないけど、なんだか良さそう。色々なプロジェクトで使われているようでもあるし、Windows + MinGW でも利用できると書いてあるのもありがたい。

obj用ライブラリ :

wavefront(obj)形式の読み込みライブラリを探したら、結構な数が見つかった。テキストファイルだし、フォーマットとしてシンプルなので、対応しやすいのだろう…。

_syoyo/tinyobjloader-c: Header only tiny wavefront .obj loader in pure C99
_tinyobjloader/tinyobjloader: Tiny but powerful single file wavefront obj loader
_Bly7/OBJ-Loader: A C++ OBJ Model Loader that will parse .obj & .mtl Files into Indices, Vertices, Materials, and Mesh Structures.
_tek-nishi/OBJ-loader: Wavefront OBJ loader with OpenGL 1.1, C++
_mojobojo/OBJLoader: stb-style obj loader for obj files output by blender

C/C++で書いたプログラムから、.objを直接読み込んで、解析して利用するようだなと…。

blenderからC言語の形式でエクスポート :

ググっているうちに、blenderから、C言語用の記述でモデルデータを直接エクスポートできるアドオンが存在しているという記事を見かけた。

_Blender OpenGL / C header exporter - ゲームが作れるようになるまでがんばる日記
_でらうま倶楽部 : Blenderのアドオン C header exporter がありがたい
_export - Get indices of vertices of triangulated faces in python - Blender Stack Exchange

しかし配布サイトは404。WebArchiveにページだけは残っていたけど…。

_Blender OpenGL / C header exporter... (WebArchive)

肝心のアドオンファイルは残ってなかった。ファイル名は、io_mesh_ogl-2.63.tar.gz、もしくは io_mesh_ogl_2.58.tar.gz だったようだけど…。

まあ、blender 2.63 時代のアドオンらしいので、今現在の blender では利用できない可能性が高いけど、どういう作りだったのかちょっと気になる。入手できないのは残念。

objをcに変換 :

wavefront(obj)形式を読み込んで、C/C++ の形に変換できるツールがあれば済むのではないかと思いついた。ググってみたら、やはりそういうツールを作った事例がある模様。

_glampert/obj2c: Simple command line tool to convert Wavefront OBJ models to C/C++ data arrays.
_Moon64/obj2c.py at main ・ UnderVolt/Moon64

C++で書かれた前者を試用してみることにした。環境は Windows10 x64 22H2 + MSYS2 (h++ 13.2.0)。

任意のフォルダを作成して、中に入って、githubからクローン。
mkdir obj2c
cd obj2c
git clone https://github.com/glampert/obj2c.git
cd obj2c

MSYS2 の g++ 13.2.0 を使ってビルドする。以下で、obj2c.cpp から obj2c.exe が作れる。
g++ -o obj2c.exe obj2c.cpp -static

注意点。MinGW g++ 6.3.0 でビルドしようとしたらエラーが出た。MSYS2 の g++ 13.2.0 ならエラーが出なかったし、exe も生成された。

使い方は以下。最後につけてる -c は、配列の個数も出力させるオプション。
obj2c.exe INPUT.obj OUTPUT.c -c

ちなみに、-h か --help をつければヘルプが表示される。
> obj2c.exe --help
Convert Wavefront OBJ mesh file to C/C++ data arrays.

Usage:
  $ obj2c.exe <source-file> <target-file> [options]
Options:
  -h, --help            Shows this help text.
  -v, --verbose         Be verbose; output a lot of info and timings.
  -s, --static_arrays   If present, add the 'static' qualifier to array declarations.
  -c, --write_counts    Write lengths of data arrays as constants.
      --inc_file[=name] If flag present, generate an include file externing the array variables.
                        Incompatible with 'static_arrays'. If no filename provided, uses the target file name.
  -n, --smooth_normals  If set, gen smooth per-vertex normals. Default are shared per-face 'flat' normals.
  -f, --vb_friendly     Make the output 'Vertex Buffer friendly'. That is, single index per-vertex.
      --ib_type=<type>  Index buffer data type for when using 'vb_friendly'.
                        Possible values are 16, 16std, 32 and 32std.
                        The 'std' suffix causes the use of the standard C data types found in <stdint.h>
      --no_uvs          Don't output mesh UVs, even if they are present in the OBJ file.

Created by Guilherme R. Lampert, Apr 10 2024.

それはさておき。blender 3.6.9 x64 LTS からエクスポートした .obj を変換してみたところ、たしかに頂点座標の配列等は得られたのだけど…。面毎に異なるマテリアルを指定しているのに無視されて、面情報は全部一つにまとめられてしまうようだなと…。

blenderからobjをエクスポート :

blender 3.6.9 から wavefront (obj)形式でエクスポートしたものの、マテリアルファイル (.mtl) の中にカラー情報が出てこなくて結構悩んでしまった。しかし、これは単に自分の勘違いだった。RGB を 1.0 or 0.0 にして実験していたから一見分かりづらかっただけで、.mtl の Kd (diffuse, ディフューズ色)に、blender のマテリアルのベースカラーが反映されていることが確認できた。

Ks (Specular, スペキュラ色)は、blender のスペキュラーが対応してるようだなと…。ただ、blender上ではRGB別で指定できないように見える。また、Ns (スペキュラー指数)もどこで指定すればいいのやら…。

Ka (Ambient, アンビエント色)は、blender のどこで指定すればいいのか分からない…。

#2 [nitijyou] 床下の水を組み上げようとした

昨日かなりの雨が降ったのだけど。「床下に水が溜まっているのではないか。汲み出せ」と親父さんが言い出したので、朝から床下の水の汲み出し作業をしてみた。

水を溜めておく堀(?)が満杯になって溢れていた…。横に置いてあった電動ポンプの電源供給部まで水に浸かっていた。ここまで水はこないだろうと安易に思って置いてたのだけど、失敗した…。何か台でも設置して、その上に置いておけばよかった。

汲み出しを始めてみたけれど、全く水位が変化しない。08:00-17:00まで動かしてみたけど、1cm下がったか下がってないかというレベル。

親父さんが、普段風呂の水を畑に持っていくために使っている電動ポンプ、TERADA SL-52 の存在を思い出してくれて、庭の水撒き用ホース6mを繋いで汲み出し状況を改善してくれた。

しかし、堀が空になっても、物凄い勢いで周りから水が流れ込んでくる…。10秒ぐらいでまた堀が満杯に。この勢いでは小さい電動ポンプで汲み出せるわけがない。これじゃまるで川だか沼だかの中に家が建ってるような状況…。

電動ポンプを物色 :

今回のような状況になった場合、それなりのスペックの電動ポンプが必要だなと…。今まで使ってた小さい電動ポンプでは全く歯が立たない。しかし、どのくらいの値段の製品を購入すればいいのだろうか…。

今回最終的に使った TERADA SL-52 の価格を調べてみたけど、既に生産終了品になっていて値段は分からなかった。ただ、現行品の SL-40 が12,000 - 18,000円ぐらいで販売されているようなので、SL-52 も同じくらいか、もしくはもっと高い値段だったのではないかと…。

中国メーカの製品なら 1,980円ぐらいから売られているけれど、価格差からして罠があるとしか思えない…。表記スペックを満たしてないとか、すぐに壊れるとかありそうだよな…。

2024/04/11(木) [n年前の日記]

#1 [prog][cg_tools] OpenGLでモデルデータを読み込めそうか調べてる。その3

C/C++ とOpenGLでモデルデータを読み込みたい。

wavefront形式(.obj)を読み込んでC言語の配列の形で出力する Pythonスクリプトを書き始めた。頂点情報、UV情報、法線情報を配列の形にして出力するところまではできたけど、複数のマテリアルを割り当てた .obj を読み込んだ際に面情報をどう並べたらいいのかで悩んでしまった。 何にせよ、glDrawElements() の使用例を眺めてみないと…。

Wings3Dでobjをエクスポート :

Wings3D 2.3 x64 で wavefront (.obj) をエクスポートしてみたら、中に「s 1」という行があって悩んだ。blender でエクスポートした .obj には、そんな行は無いのに…。

_Wavefront .objファイル - Wikipedia

「s 1」はスムージングを有効にする指定らしい。たしかに、Wings3D でエクスポートした .obj を blender 3.6.9 x64 LTS にインポートすると、なんだかスムージングがかかっているような見た目になる。「s 1」が入っていたから ―― スムージングを有効にする行が入っていたから、そんな状態になっていたのか…。

Wings3D上でスムージングを無効にする方法はないのだろうか…。TABキーを叩くとウインドウ上でスムージングの有効無効が切り替わるけれど、これはあくまで作業ウインドウ上の見た目を変えるためだけの機能のようで、エクスポートした .obj には反映されなかった。

線を全選択して、右クリック → エッジ属性の切替 → ハードエッジにする、を選んだら、スムージングがかかってない見た目になった。しかし、コレを .obj としてエクスポートすると、「s 2」「s 3」という行が盛り込まれてしまう…。「s off」になるわけではないのか…。

2024/04/12(金) [n年前の日記]

#1 [cg_tools] XISMO2 や Metasequoia 3.x を試用中

3Dモデルデータを作成して、wavefront (.obj) でエクスポートして、どんな内容になるのか確認したい。

Windows10 x64 22H2上で、blender 3.6.9 x64 LTS と Wings3D 2.3 を使って試していたけど、他の3DCGソフトならまた違う結果が出力されるのではないかと気になってきたので、XISMO2 225a と Metasequoia 3.1.6 をインストールして、どんな .obj がエクスポートされるのか確認することにした。

XISMO2 は無料で使える3DCGモデリングソフト。.obj でエクスポートすることができる。XISMO_225a.zip を入手して解凍して、今回は D:\Prog\XISMO2\ に置いた。

_XISMO


Metasequoia は有償のモデリングソフト。自分は 3.x 時代に購入。4.x になったら価格がグンと上がってしまったので、そちらは購入していない。無料で試用できる版もあるけれど、その版は mqo形式でしか保存できない。

_metaseq.net | 3Dモデリングソフトウェア「Metasequoia(メタセコイア)」公式サイト

metaseq316.zip を入手して解凍。D:\Prog\Metasequoia3\ に置いた、とメモ。

Metasequoia 3.1.6 からエクスポートした .obj を blender 3.6.9 x64 LTS にインポートしたら左右がおかしくなってしまった。Metasequoia から .obj でエクスポートする際は、x軸を反転したほうが良さそう。ついでに、拡大縮小率を 0.01 ぐらいにしておいたほうがいいのかもしれない。

#2 [cg_tools] Shade12で各面に異なる材質を割り当てたい

Windows10 x64 22H2 + Shade 12.1.0 Standard で、wavefront (.obj) のエクスポートの実験をしていたのだけど、ポリゴンメッシュで作られたオブジェクトの、それぞれの面に異なる材質(色)を割り当てられないものかと悩んでた。

以前の自分は、違う材質を割り当てたい部分を、オブジェクトから分離して ―― オブジェクトを複製して、不要な部分を削除して、必要なところだけ残して、そこに別の材質を割り当ててから全オブジェクトを結合していたらしいのだけど…。

_mieki256's diary - Shade12を試用中その4

今回ググってみたら、もっと簡単なやり方があった。フェイスグループなるものを利用すれば、ポリゴンメッシュの各面に任意のマスターサーフェイスを割り当てられるらしい。

_フェイスグループとは ? - Shade3D Knowledge Base
_フェイスグループを追加する - Shade3D Knowledge Base

一応手順をメモ。
  1. 事前に、必要な分のマスターサーフェイスを作成しておく。
  2. ポリゴンメッシュを選択。かつ、Mキーを押して「形状編集」モードにする。これで任意のポリゴンを選択できるようになる。
  3. 色を変えたいポリゴンをクリックして選択。
  4. 統合パレットの形状情報タブに切り替える。「情報」と書いてあるアイコンをクリックすれば選べる。
  5. 形状情報タブの下のほうにある「フェイスグループ情報」の、下のほうにある「追加」ボタンをクリック。これで、選択中のポリゴンがグループ化される。
  6. 「追加」ボタンのすぐ右にあるところでマスターサーフェイスが選べる。

shade12_facegrp_ss01.png

shade12_facegrp_ss02.png

shade12_facegrp_ss03.png

余談。マスターサーフェイスを複製したい :

マスターサーフェイスを用意する際にオブジェクトを選択して材質を削除して、とかやるのが面倒臭かった。マスターサーフェイスって複製できないのかな…。

できるらしい。

_マスターサーフェスを複製したい - Shade3D Knowledge Base

マスターサーフェイスを選択した状態で、表面材質パネルの「複製」をクリックすれば複製できた…。それだけで良かったのか…。

shade12_facegrp_ss04.png

shade12_facegrp_ss05.png

shade12_facegrp_ss06.png

2024/04/13() [n年前の日記]

#1 [nitijyou] 電動ポンプについて物色中

床下の水を汲み取るための電動ポンプを、もうちょっと強力なモノにしたほうがいいのかなと思えてきて、どんな製品がありそうかググって物色中。

今まで使っていたのは、バスポンプ 湯ポポン、なる製品だと思う。ACアダプタ部分に貼ってあるシールには「BATH PUMP 湯ポポン」としか書いてないけれど、ググった感じでは、おそらく、ミツギロン 湯ポポン10 BP-40 なる製品ではないかなと。形もよく似ているし。吐水量は 8L/min らしい。1時間なら、480L/h だろうか。

家庭用の電動ポンプと言うと、10,000円ぐらいする「水中ポンプ」と呼ばれるジャンルと、風呂場の浴槽から水を汲み出して別の何かに使うための「バスポンプ」というジャンルがある模様。吐水量は「水中ポンプ」が圧倒的に多く、「バスポンプ」は一般的に8〜10L/min がフツーっぽい。ただ、バスポンプの中にも、吐水量が2倍/3倍になったと謳う製品もあって、14 - 23L/min のモノも見かけた。

ポンプの排水コネクタも数種類あるようで。コネクタ部分の外径が、13mm, 16mm, 19mm, 22mm, 25mm 等々。16mm のものには、内径が15mmのホースを使うのだろうか。内径16mmのホースはちょっと見つからないし、あちこちの製品ページに、「内径15mmの散水ホースを利用できる」と書いてあったりもするので、おそらく内径15mmのホースがメジャーな扱いになっているのだろう。たぶん。

2024/04/14() [n年前の日記]

#1 [prog][cg_tools] OpenGLでモデルデータを読み込めそうか調べてる。その4

C/C++ とOpenGLで、何かしらのモデルデータを読み込んで描画したい。

wavefront形式(.obj)を読み込んで、C言語の配列の形で出力する Pythonスクリプトを書いてるところ。複数のマテリアルを割り当ててある場合は、頂点カラーにマテリアルの Kd 値を割り振るようにしてみた。

glDrawElements()はビミョーに使えない印象 :

OpenGL 1.1 の glDrawElements() について調べてる。

OpenGL 1.1 で頂点配列を使ってポリゴンを描画する場合、glDrawArrays() か glDrawElements() を使えるらしいのだけど。
  • glDrawArrays() ... 頂点配列を渡して描画する。
  • glDrawElements() ... 頂点配列のインデックス値の配列を渡して描画する。

頂点配列のインデックス値を渡して描画するほうが、頂点配列内の座標値が重複したりしないので、データ量は少なくて済む。実際、wavefront形式も、頂点座標群とは別に、面を構成する情報としてインデックス値群を持っているので、このメリットを意識したフォーマットになっている。

しかし各頂点には、頂点座標の他にも、法線情報(Normal情報)、テクスチャのUV座標、頂点カラー情報も持たせないといけないはずで…。

wavefront形式の場合、頂点配列、法線情報、テクスチャのUV座標のインデックス値が、別々の値になってる場面がほとんど。しかし、OpenGL の glDrawElements() のサンプルコードを見る限り、どうやら頂点、法線、UVで、別々のインデックス値を指定することはできないようで…。となると、wavefront形式が持っている面情報 = インデックス値列をそのまま OpenGL に流用することはできないようだなと…。

仕方ないので、Pythonスクリプト側で、頂点座標、法線情報、UV座標、頂点カラーを、全部配列にずらずらと展開してから出力してしまうことにした。それらの配列を使って、glDrawElements() ではなく、glDrawArrays() で描画する。

こういうデータの持ち方では、座標値が重複するのでデータ量はかなり増えてしまうけど、これはもうどうしようもないかなと…。いやまあ、glBegin() と glEnd() を使って、ポリゴンを1枚1枚ループを回して描画するようにすれば、wavefront形式が持ってる面情報をそのまま使うこともできるだろうけど、その代わり処理が遅くなってしまうはず。データは増えるけど処理が速いか、データは減るけど処理が遅いか、どっちを取るか、という話になるのだろうか。

本当に頂点配列を使うと処理は速くなるのかな。ベンチマークを取ったわけじゃないから確実なことは言えない気もする…。

2024/04/15(月) [n年前の日記]

#1 [prog][cg_tools] OpenGLでモデルデータを読み込めそうか調べてる。その5

C/C++ とOpenGLで、何かしらのモデルデータを読み込んで描画したい。

wavefront形式(.obj)を読み込んで、C言語の配列の形で出力する Pythonスクリプトは書けたので、C言語でOpenGLを使って描画するソースを書いて動作確認中。一応描画はできたような気がする。明日の日記でまとめよう…。

2024/04/16(火) [n年前の日記]

#1 [prog][cg_tools] OpenGLでモデルデータを読み込めそうか調べてる。その6

C/C++ とOpenGLで、何かしらのモデルデータを読み込んで描画したい。

今回は、wavefront形式(.obj)を Pythonスクリプトで読み込んで、C言語の配列の形で出力して、それを使って OpenGLで描画するC言語のソースを書いてみた。C/C++ でモデルデータファイルを読み込んでいるわけではないけれど、.exeの中にモデルデータを含めてしまいたい場合は、こういうやり方でもいいんじゃないかなあ、と…。

動作確認環境は以下。
先に実行結果を。今回作成した 01_drawobj.exe を実行すると以下のような見た目になる。モデルデータを描画することができている。

使用するモデルデータ :

blender 3.6.9 x64 LTS で簡単なモデルデータを作成して、wavefront形式(.obj)でエクスポートした。ファイル → エクスポート → Wavefront (.obj) を選択。
  • .objファイルは、頂点座標、テクスチャのUV座標、法線情報、面情報が保存されているファイル。
  • .mtlファイルは、マテリアル情報が保存されているファイル。

blender から .obj をエクスポートする際、四角形を三角形にするオプション(メッシュの三角面化)にチェックを入れる。後で出てくる Pythonスクリプトも、C言語のソースも、三角形ポリゴンにのみ対応させてある状態なので…。

作成したモデルデータは以下。一つは、只の四角い箱。各面が別の色になっている。

_cube01.obj
_cube01.mtl

cube01_ss01.gif


以下のモデルデータは、blenderでお馴染みのスザンヌ。目や口のあたりを別の色にしている。

_suzanne01.obj
_suzanne01.mtl

suzanne01_ss01.gif

PythonスクリプトでC言語の配列に変換 :

この wavefront形式(.obj) と .mtl を、Pythonスクリプトを使って、C言語の配列の形に変換して出力する。今回書いたPythonスクリプトは以下。ライセンスは CC0 / Public Domain ということで…。

_pyobj2c.py

使用方法は以下。
python pyobj2c.py INPUT.obj > OUTPUT.h

例えば hoge.obj というファイルを読み込ませた場合は、以下の名前の配列を作成する。
  • const float hoge_obj_vtx[] ... 頂点配列。1つにつき、{x, y, z} を持つ。
  • const float hoge_obj_nml[] ... 法線情報配列。1つにつき、{x, y, z} を持つ。
  • const float hoge_obj_uv[] ... テクスチャ座標配列。1つにつき、{x, y} を持つ。
  • const float hoge_obj_col[] ... 頂点カラー配列。1つにつき、{r, g, b, a} を持つ。
  • const unsigned int hoge_obj_vtx_size ... 頂点配列の個数
  • const unsigned int hoge_obj_nml_size ... 法線情報配列の個数
  • const unsigned int hoge_obj_uv_size ... テクスチャ座標配列の個数
  • const unsigned int hoge_obj_col_size ... 頂点カラー配列の個数
OpenGL 1.1 の glDrawArrays() を使って描画することを前提にした配列になっている。ちなみに、頂点カラーについては、マテリアル情報の Kd (Diffuse色)だけを取り出して頂点カラーにしている。


前述の2つの .obj を変換。以下の結果が得られた。

_cube01.h
_suzanne01.h

これらの配列を、C言語のソースで #include して利用する。

C言語のソース :

C言語のソースは以下。ライセンスは CC0 / Public Domain ってことで。ちなみに、ウインドウの作成等はGLFW3を利用している。

_01_drawobj.c
#include <stdlib.h>
#include <stdio.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <GLFW/glfw3.h>
// #include <SOIL/SOIL.h>

#include "cube01.h"
#include "suzanne01.h"

#define WDW_TITLE "Draw wavefront obj"

// Window size
#define SCRW 1280
#define SCRH 720

#define FOV 50.0

#define ENABLE_LIGHT 1

#if ENABLE_LIGHT
const float light_pos[4] = {1.0, 1.0, 1.0, 0.0};
const float light_ambient[4] = {0.2, 0.2, 0.2, 1.0};
const float light_diffuse[4] = {0.8, 0.8, 0.8, 1.0};
const float light_specular[4] = {0.7, 0.7, 0.7, 1.0};
#endif

typedef struct
{
  int scrw;
  int scrh;
  float fovy;
  float znear;
  float zfar;

  double angle;
} GWK;

static GWK gw;

// ----------------------------------------
// Render
void render(void)
{
  gw.angle += (45.0 / 60.0);

  // init OpenGL
  glViewport(0, 0, gw.scrw, gw.scrh);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(gw.fovy, (double)gw.scrw / (double)gw.scrh, gw.znear, gw.zfar);
  glMatrixMode(GL_MODELVIEW);

  // clear screen
  glClearColor(0, 0, 0, 1);
  glClearDepth(1.0);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  glDepthFunc(GL_LESS);
  glEnable(GL_DEPTH_TEST);
  glEnable(GL_BLEND);
  glEnable(GL_NORMALIZE);

  glLoadIdentity();

#if ENABLE_LIGHT
  glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
  glEnable(GL_COLOR_MATERIAL);

  glLightfv(GL_LIGHT0, GL_POSITION, light_pos);
  glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
  glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
  glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
  glEnable(GL_LIGHTING);
  glEnable(GL_LIGHT0);
#endif

  // obj move and rotate
  glTranslatef(0.0, 0.0, -10.0);
  float scale = 3.0;
  glScalef(scale, scale, scale);
  glRotatef(-20.0, 1, 0, 0);
  // glRotatef(gw.angle * 0.5, 1, 0, 0);
  glRotatef(gw.angle, 0, 1, 0);

  glEnable(GL_CULL_FACE);
  glCullFace(GL_BACK);

  // draw vertex array

  glEnableClientState(GL_VERTEX_ARRAY);
  // glEnableClientState(GL_TEXTURE_COORD_ARRAY);
  glEnableClientState(GL_NORMAL_ARRAY);
  glEnableClientState(GL_COLOR_ARRAY);

#if 1
  glVertexPointer(3, GL_FLOAT, 0, suzanne01_obj_vtx);
  // glTexCoordPointer(2, GL_FLOAT, 0, suzanne01_obj_uv);
  glNormalPointer(GL_FLOAT, 0, suzanne01_obj_nml);
  glColorPointer(4, GL_FLOAT, 0, suzanne01_obj_col);
  glDrawArrays(GL_TRIANGLES, 0, suzanne01_obj_vtx_size);
#else
  glVertexPointer(3, GL_FLOAT, 0, cube01_obj_vtx);
  glNormalPointer(GL_FLOAT, 0, cube01_obj_nml);
  glColorPointer(4, GL_FLOAT, 0, cube01_obj_col);
  glDrawArrays(GL_TRIANGLES, 0, cube01_obj_vtx_size);
#endif

  glDisableClientState(GL_COLOR_ARRAY);
  glDisableClientState(GL_NORMAL_ARRAY);
  // glDisableClientState(GL_TEXTURE_COORD_ARRAY);
  glDisableClientState(GL_VERTEX_ARRAY);
}

// ----------------------------------------
// init animation
void init_animation(int w, int h)
{
  gw.scrw = w;
  gw.scrh = h;
  gw.angle = 0.0;

  gw.fovy = FOV;
  gw.znear = 1.0;
  gw.zfar = 1000.0;

  glViewport(0, 0, (int)gw.scrw, (int)gw.scrh);
}

// ----------------------------------------
// Error callback
void error_callback(int error, const char *description)
{
  fprintf(stderr, "Error: %s\n", description);
}

// ----------------------------------------
// Key callback
static void key_callback(GLFWwindow *window, int key, int scancode, int action, int mods)
{
  if (action == GLFW_PRESS)
  {
    if (key == GLFW_KEY_ESCAPE || key == GLFW_KEY_Q)
    {
      glfwSetWindowShouldClose(window, GLFW_TRUE);
    }
  }
}

// ----------------------------------------
// window resize callback
static void resize(GLFWwindow *window, int w, int h)
{
  if (h == 0)
    return;

  gw.scrw = w;
  gw.scrh = h;
  glfwSetWindowSize(window, w, h);
  glViewport(0, 0, w, h);
}

// ----------------------------------------
// Main
int main(void)
{
  GLFWwindow *window;

  glfwSetErrorCallback(error_callback);

  if (!glfwInit())
  {
    // Initialization failed
    exit(EXIT_FAILURE);
  }

  glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 1); // set OpenGL 1.1
  glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);

  // create window
  window = glfwCreateWindow(SCRW, SCRH, WDW_TITLE, NULL, NULL);
  if (!window)
  {
    // Window or OpenGL context creation failed
    glfwTerminate();
    exit(EXIT_FAILURE);
  }

  glfwSetKeyCallback(window, key_callback);
  glfwSetWindowSizeCallback(window, resize);

  glfwMakeContextCurrent(window);
  glfwSwapInterval(1);

  // Init OpenGL
  int scrw, scrh;
  glfwGetFramebufferSize(window, &scrw, &scrh);
  init_animation(scrw, scrh);

  // main loop
  while (!glfwWindowShouldClose(window))
  {
    render();
    glfwSwapBuffers(window);
    glfwPollEvents();
  }

  glfwDestroyWindow(window);
  glfwTerminate();
  exit(EXIT_SUCCESS);
}

render() の中で OpenGL の描画をしている。glDrawArrays() の前後を見れば、今回のモデルデータの利用の仕方が分かるだろうか…。

  glEnable(GL_CULL_FACE);
  glCullFace(GL_BACK);

  glEnableClientState(GL_VERTEX_ARRAY);
  // glEnableClientState(GL_TEXTURE_COORD_ARRAY);
  glEnableClientState(GL_NORMAL_ARRAY);
  glEnableClientState(GL_COLOR_ARRAY);

  glVertexPointer(3, GL_FLOAT, 0, suzanne01_obj_vtx);
  // glTexCoordPointer(2, GL_FLOAT, 0, suzanne01_obj_uv);
  glNormalPointer(GL_FLOAT, 0, suzanne01_obj_nml);
  glColorPointer(4, GL_FLOAT, 0, suzanne01_obj_col);

  glDrawArrays(GL_TRIANGLES, 0, suzanne01_obj_vtx_size);

  glDisableClientState(GL_COLOR_ARRAY);
  glDisableClientState(GL_NORMAL_ARRAY);
  // glDisableClientState(GL_TEXTURE_COORD_ARRAY);
  glDisableClientState(GL_VERTEX_ARRAY);
  • glEnableClientState() で、利用したい情報を有効にする。
  • GL_VERTEX_ARRAY, GL_TEXTURE_COORD_ARRAY, GL_NORMAL_ARRAY, GL_COLOR_ARRAY 等を指定することで、頂点座標配列、テクスチャ座標配列、法線情報配列、頂点カラー配列を有効にできる。
  • glVertexPointer()、glTexCoordPointer()、glNormalPointer()、glColorPointer() で、利用したい頂点配列等を指定できる。
  • glDrawArrays() で、頂点配列を使って描画。
  • glDisableClientState() で、利用したい情報を無効化。


Makefileは以下。MinGW gcc 6.3.0、MSYS2 gcc 13.2.0、Ubuntu Linux 22.04 LTS + gcc 11.4.0 でビルドできることを確認した。

_Makefile
MODELS = cube01.h suzanne01.h
SRCS = 01_drawobj.c $(MODELS)

ifeq ($(OS),Windows_NT)
# Windows
TARGET = 01_drawobj.exe
GCC_VERSION=$(shell gcc -dumpversion)

ifeq ($(GCC_VERSION),6.3.0)
# MinGW gcc 6.3.0
LIBS = -static -lopengl32 -lglu32 -lwinmm -lgdi32 -lglfw3dll -mwindows
else
# MinGW gcc 9.2.0, MSYS2
LIBS = -static -lopengl32 -lglu32 -lwinmm -lgdi32 -lglfw3 -mwindows
endif

else
# Linux (Ubuntu Linux 22.04 LTS, gcc 11.4.0)
TARGET = 01_drawobj
LIBS = -lGL -lGLU -lglfw -lm
endif

$(TARGET): $(SRCS) Makefile
    gcc -o $@ $(SRCS) $(LIBS)

%.h: %.obj
    python pyobj2c.py $< > $@

.PHONY: clean
clean:
    rm -f *.o $(TARGET) $(MODELS)

ちなみに、MinGW gcc 6.3.0 でビルドすると、別途 glfw3.dll が必要になるけれど、MSYS2 gcc 13.2.0 でビルドすれば GLFW3 をスタティックリンクできるので、MSYS2 を使って実験したほうがいいと思う。

以下を打ってビルド。
make clean
make
01_drawobj.exe が生成される。

以上、16 日分です。

過去ログ表示

Prev - 2024/04 -
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30

カテゴリで表示

検索機能は Namazu for hns で提供されています。(詳細指定/ヘルプ


注意: 現在使用の日記自動生成システムは Version 2.19.6 です。
公開されている日記自動生成システムは Version 2.19.5 です。

Powered by hns-2.19.6, HyperNikkiSystem Project