点群データを用いたマインクラフトワールドの構築および再現性
タイトルww論文かよwww
マイクラで3Dの地形って再現できるのかなぁと思い、点群データを使ってみることにした。にー兄さんに相談したらG空間情報センターにいいデータが転がっているとのことだったので、とりあえずダウンロード。
なんかバーチャル静岡というらしい。この地図から特定の区域を選択すればダウンロードできる。
てっきり obj ファイルとかでダウンロードできるのかなぁと思ったら、las 形式になってる。このままだと開けないみたいなので、QGIS をインストールして開いてみることに。
プラグインも必要みたいなので記事通りにすすめてみる。
やはりかwww
これ、LAStools のフォルダをCドライブ直下に入れないとダメみたいですね。他のディレクトリに入れても上記のスレッドのようなエラーが表示されます。なんでなんすかね?(ちなみにそのディレクトリ先のパスは指定したつもりだった。)
とりあえず実行中みたいなのでしばらく放置。
約30分経過したけどまだ処理中...大丈夫なのかこれ???
やり直したら5秒くらいでできたw
すごい
まって、las から txt へ変換はできたんだけど読み方が全然わからん。自分の想像としては x, y, z, R, G, B で構成されているものだと思っていたけど
-86400.000 -136826.560 0.310
-86400.000 -136858.500 0.250
-86400.000 -137085.710 0.320
-86400.000 -137087.930 0.320
...
どうやって読むのこれ???
これ一つ一つが座標ってこと???
色々調べたら、CloudCompare のOSSを使用してPTS形式にすれば座標(x,y,z)と強度、色(R, G, B)を情報として含められそう。
やってみるかな
こっちのほうが使いやすい気がするなぁ
あと、点を大きくするとちょっとマイクラ感もある!
CloudCompare 上で File > Save > ASCII Cloud 形式で保存
このとき、ヘッダーにタイトルをつけるといい感じにしてくれる
ここからデータの補正を行っていく。例えば、x座標はとんでもない数値になっているけど、基準点をゼロにしておきたいので補正項を加えておいたほうが良いかも。ちなみに座標の取り方は画像の通り。
なんでZ軸が高さやねん!(マイクラはY軸が高さ)
ジャストアイディアなアルゴリズム
- csv形式を読み込む
- Splitでリストに格納
- 0番目に格納されている各座標の値を0になるように調整(補正項計算)
- 新たな座標としてリストに書き込み
- 色データは以前書いた記事(ユークリッド距離計算)を参考にブロック近似(本当は教師あり学習とかでブロックを判別できたらいいけどね)
-
/setblock <x> <y> <z> <blockId>
の形式で書き込み& txt ファイル書き出し
ちょっと疲れてきたので後日やろうかな...
とりあえず補正項計算したあとに座標 (x, y, z) と色データ (R, G, B) だけを抽出してテキスト形式に吐き出すプログラムを書いてみた。徹夜テンションで書いているのでもっと効率化できるところとかありそうだけど、今はとりあえず動くもので。
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine("Please enter CSV file.");
var path = Console.ReadLine();
var pointList = GetPointList(path);
Console.WriteLine("load complete.\nwriting...");
WriteFile(pointList);
Console.WriteLine("Done.");
}
static List<Point> GetPointList(string path)
{
var points = new List<Point>();
Console.WriteLine("loading...");
try
{
using (StreamReader sr = new StreamReader(path))
{
string line = "";
double def_x;
double def_y;
line = sr.ReadLine();
var first_col = line.Split(",");
def_x = double.Parse(first_col[0]);
def_y = double.Parse(first_col[1]);
while ((line = sr.ReadLine()) != null)
{
var col = line.Split(",");
points.Add(new Point(double.Parse(col[0]) - def_x, double.Parse(col[1]) - def_y, double.Parse(col[2]), int.Parse(col[13]), int.Parse(col[14]), int.Parse(col[15])));
}
}
return points;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return null;
}
}
static void WriteFile(List<Point> points)
{
try
{
using (StreamWriter sw = new StreamWriter(@"C:\Users\<user>\Desktop\output.txt"))
{
points.ForEach(point =>
{
sw.WriteLine($"{point.x},{point.y},{point.z},{point.R},{point.G},{point.B}");
});
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return;
}
}
}
public struct Point
{
public double x;
public double y;
public double z;
public int R;
public int G;
public int B;
public Point(double x, double y, double z, int R, int G, int B)
{
this.x = x;
this.y = y;
this.z = z;
this.R = R;
this.G = G;
this.B = B;
}
}
だいぶスッキリしたかも。
とりあえず、座標を書き出すところで
sw.WriteLine($"/setblock {(int)point.x} {(int)point.z} {(int)point.y} stone");
と変更し、コマンド生成するプロジェクトと、マイクラにコマンドを実行するプロジェクトを作ってやってみた。
using MinecraftConnection;
internal class Program
{
static MinecraftCommands command = new MinecraftCommands("127.0.0.1", 25575, "minecraft");
static void Main(string[] args)
{
Console.WriteLine("Please enter minecraft command list txt");
var path = Console.ReadLine();
var commandList = GetCommandList(path);
Console.WriteLine("execute commands...");
commandList.ForEach(list =>
{
command.SendCommand(list);
});
Console.WriteLine("Done.");
}
static List<string> GetCommandList(string path)
{
var commands = new List<string>();
Console.WriteLine("loading...");
try
{
using (StreamReader sr = new StreamReader(path))
{
string line = "";
while ((line = sr.ReadLine()) != null)
{
commands.Add(line);
}
}
return commands;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return null;
}
}
}
コマンドは約350万行(つまり点群も350万点ある)
全部石ブロックだけど、点群データをマイクラでも表現できた。
あとはブロックの種類を判定して組み込むだけやな!寝る!
色空間ミスってしまったので、マイクラのブロックの色空間をRGBにするか、点群データの色空間をLabに変換するかのどちらかを取らないといかん。
Lab に変換するには RGB → XYZ → Lab のフローをふまないとダメみたい
下記はJSだけど普通にC#に読み変えれば行ける