FC2ブログ
ヽ|∵|ゝ(Fantom) の 開発blog? ホーム » Unity »【Unity】【C#】TGAをランタイムでロードする

【Unity】【C#】TGAをランタイムでロードする  


 BMPLoader に続き、これも試験的(Experimental)に VRM Live Viewer に導入しているのだが、オリジナルソースに少し手を加えた方が使い易いと思うので、ほんのちょっと改造版を載せておこう。

 今回紹介する方法は、オープンソースの TGALoader を使う方法だ。ただ、少し注意点は、「フルカラー・無圧縮」のみ対応という点だ。

 それを踏まえた改造版になる。簡単に説明すれば、「ヘッダ部分から画像データ形式を拾って、フルカラーでなければエラーを出す」というものを付け加えたものだ。あと、github にあったコメントなどの修正もついでに入れてある。


TGALoader.cs (mikezila)
TGA Loader for Unity3D (aaro4130)

(※) Unity 2019.2.21f1 / Windows10(x64) で確認



●TGALoader.cs(フルカラー・無圧縮のみ) [github のほんのちょっと改造版]
// https://gist.github.com/mikezila/10557162
// This was made by aaro4130 on the Unity forums. Thanks boss!
// https://forum.unity.com/threads/tga-loader-for-unity3d.172291/
// It's been optimized and slimmed down for the purpose of loading Quake 3 TGA textures from memory streams.

using System;
using System.IO;
using UnityEngine;

public static class TGALoader
{
public static Texture2D LoadTGA(string fileName)
{
using (var imageFile = File.OpenRead(fileName))
{
return LoadTGA(imageFile);
}
}

public static Texture2D LoadTGA(Stream TGAStream)
{

using (BinaryReader r = new BinaryReader(TGAStream))
{
r.BaseStream.Seek(2, SeekOrigin.Begin);
int type = r.ReadByte(); //(offset 2) 画像形式 (1バイト)

//フルカラー以外は非対応とする(=RLE圧縮は展開コードが必要のため)
if (type != 2)
{
throw new Exception("Only Full-color Uncompressed is supported.");
}

// Skip some header info we don't care about.
// Even if we did care, we have to move the stream seek point to the beginning,
// as the previous method in the workflow left it at the end.
r.BaseStream.Seek(9, SeekOrigin.Current); //offset 3 から +9 → 12

short width = r.ReadInt16(); //(offset 12) 画像の横幅 (2バイト)
short height = r.ReadInt16(); //(offset 14) 画像の縦幅 (2バイト)
int bitDepth = r.ReadByte(); //(offset 16) 色深度 (1バイト)

// Skip a byte of header information we don't care about.
r.BaseStream.Seek(1, SeekOrigin.Current);

Texture2D tex = new Texture2D(width, height);
Color32[] pulledColors = new Color32[width * height];

if (bitDepth == 32) //アルファあり
{
for (int i = 0; i < width * height; i++)
{
byte red = r.ReadByte();
byte green = r.ReadByte();
byte blue = r.ReadByte();
byte alpha = r.ReadByte();

pulledColors [i] = new Color32(blue, green, red, alpha);
}
} else if (bitDepth == 24) //アルファなし
{
for (int i = 0; i < width * height; i++)
{
byte red = r.ReadByte();
byte green = r.ReadByte();
byte blue = r.ReadByte();

/* (github のコメントから)
https://gist.github.com/mikezila/10557162#gistcomment-2995969
pulledColors [i] = new Color32(blue, green, red, 1); //float で 1.0 と間違えた?
1 need to be replaced by 255, in another case, texture become transparent
*/
pulledColors [i] = new Color32(blue, green, red, 255);
}
} else
{
throw new Exception("TGA texture had non 32/24 bit depth.");
}

tex.SetPixels32(pulledColors);
tex.Apply();
return tex;
}
}
}

 ファイルフォーマットに関しては以下を参考にさせて貰った。 このコードではRLE圧縮には対応してない。RLE圧縮に関しては以下の記事にも載っているので、参考にするのも良いだろう。

(参考)
TGA ファイルフォーマット (GAME PROGRAMMING UNIT)
TGA ファイルフォーマット (PROJECT ASURA)

 今回利用するヘッダ部分と画像のデータ形式だけ抜粋させて頂くと以下のような表になる。

ヘッダー (18 byte)
offsetbyte内容
01ヘッダーの後に続く、IDの長さ (ID field length)
11カラーマップの有無 (Color map type)
21データ形式 (Image type)
32カラーマップの位置 (Color map index)
52カラーマップの長さ (Color map length)
71カラーマップエントリーのビット数 (Color map size)
82X (Image origin X)
102Y (Image origin Y)
122幅 (Image width)
142高さ (Image height)
161ピクセルのビット数 (Bit per pixel)
171属性 (Discripter)

(offset 2) データ形式 (1 byte)
値(整数)内容
0イメージなし
1インデックスカラー(256色)
2フルカラー
3白黒
9インデックスカラー。RLE圧縮
10フルカラー。RLE圧縮
11白黒。RLE圧縮

 まぁ、ここでは「フルカラー・無圧縮」に限定してしまっているが、データ形式にあるように「フルカラー/インデックスカラー/白黒」と「圧縮/無圧縮」と「格納方向:縦/横」(offset 17 の属性)を組み合わせるとコードが長くなるのは容易に想像できるだろう。以下に複数の形式で TGA → BMP に変換するサンプルコードはあったので、興味があったら覗いてみるのも良いかも知れない(そしてRLE展開も作ったら公開して欲しい(笑))。

TGALoader.cs (openmetaversefoundation/libopenmetaverse)


 簡単なテストをするには以下ようなのコードで十分だろう。UI に RawImage を適当に置いて、インスペクタにセットし、読み込む画像のパスを設定してプレイすれば良い。画像が表示できたら成功だ。

●簡単な確認コード
using System;
using System.IO;
using UnityEngine;
using UnityEngine.UI;

public class TGALoaderTest : MonoBehaviour
{
public RawImage image; //画像表示用
public string path; //画像パス

// Use this for initialization
private void Start()
{
LoadTGA(path);
}

void LoadTGA(string path)
{
try
{
var tex = TGALoader.LoadTGA(path);
image.texture = tex;
}
catch (Exception e)
{
Debug.LogError(e.Message);
}
}
}

 ちなみにフルカラーのチェックをしないでRLE圧縮形式のTGAを読み込んだ場合は「Unable to read beyond the end of the stream.」というエラーが出る(たぶん圧縮してある場合は、データ長が短くなるので足りなくなり、エラーとなる)。このサンプルコードの場合はフルカラー以外では「Only Full-color Uncompressed is supported.」と出る。必要なら何か処理を入れた方が良いだろう。

 また、私が提供しているプラグインを使えば、Android でも TGA を読み込めた。実際にスマホで全天球ビューワを作ることも可能だ(これが VRM Live Viewer で実装されている)。フリーなので、自由に使って欲しい。

>>AssetStore版






(関連記事)
【Unity】【C#】BMP をランタイムで読み込む
【Unity】【C#】ランタイム時にファイルをドラッグ&ドロップして取得する(Windows のみ)
【Unity】スマホで簡易360度(パノラマ, 全天球)ビューワを作る
【Unity】Androidのトーストやダイアログ、通知、音声認識、ハード音量操作など基本的な機能を使えるプラグインを作ってみた
【Unity】AssetStore版 FantomPlugin のセットアップ


関連記事
スポンサーサイト



category: Unity

thread: ゲーム開発

janre: コンピュータ

tag: Unityオープンソースライブラリ    画像ファイル読み込み 
tb: 0   cm: --


トラックバック

トラックバックURL
→http://fantom1x.blog130.fc2.com/tb.php/354-57550cbe
この記事にトラックバックする(FC2ブログユーザー)

プロフィール

Social

検索フォーム

全記事一覧

カテゴリ

ユーザータグ

最新記事

リンク

PR