2010-12-13

Unity 3D + freeimage library 執行時期載入圖檔

unity 本身提供方便的檔案載入功能 WWW(參考連結),它能讓程式在執行當中從網路或者硬碟載入資料,底下是一個 WWW 簡單的圖檔載入方法:

using UnityEngine;
using System.Collections;
 
public class example : MonoBehaviour {
    public string url = "http://images.earthcam.com/ec_metros/ourcams/fridays.jpg";
    IEnumerator Start() {
        WWW www = new WWW(url);
        yield return www;
        renderer.material.mainTexture = www.texture;
    }
}

但是使用WWW目前只能載入PNG和JPG兩種格式的圖檔,若要在程式執行時載入其它格式的圖檔,就要自己把檔案轉成 Unity Color 格式再寫入 Texture2D 物件,底下是使用 Unity 3D + freeimage library 來讀取圖檔的範例:

1) 到 這裡 下載 FreeImageDLL,其中包含 FreeImageNET.dll, FreeImage.dll 兩個檔案,將這兩個檔案在專案的 Plugins 目錄下。

2) 到 Project Settings --> Player --> Optimization 將 Api Compatibility Level 改為 .Net 2.0(預設通常為 .Net 2.0 Subset)

3) 建立一個 C Sharp Script 之後直接就可以使用 freeimage API,這邊列舉載入圖片的方法:

bool load24BITBMPImage(string strPath, out Texture2D pOutTex)
{
    if (!FreeImageAPI.FreeImage.IsAvailable())
    {
        pOutTex = null;
        return false;
    }
 
    FreeImageAPI.FIBITMAP dib = FreeImageAPI.FreeImage.Load(FreeImageAPI.FREE_IMAGE_FORMAT.FIF_BMP, strPath, FreeImageAPI.FREE_IMAGE_LOAD_FLAGS.DEFAULT);
    if (dib.IsNull)
    {
        FreeImageAPI.FreeImage.Unload(dib);
 
        pOutTex = null;
        return false;
    }
 
    uint nWidth = FreeImageAPI.FreeImage.GetWidth(dib);
    uint nHeight = FreeImageAPI.FreeImage.GetHeight(dib);
    uint nPitch = FreeImageAPI.FreeImage.GetPitch(dib);
 
    pOutTex = new Texture2D((int)nWidth, (int)nHeight, TextureFormat.ARGB32, false);
    Color[] pColor = new Color[nWidth * nHeight];
 
    // 參考 FreeImage Sample5 - Working with pixels
    // Iterate over all scanlines
    for (int i = 0; i < FreeImageAPI.FreeImage.GetHeight(dib); i++)
    {
        // Get scanline
        FreeImageAPI.Scanline<FreeImageAPI.RGBTRIPLE> scanline = new FreeImageAPI.Scanline<FreeImageAPI.RGBTRIPLE>(dib, i);
 
        // Get pixeldata from scanline
        FreeImageAPI.RGBTRIPLE[] rgbt = scanline.Data;
 
        // Iterate over each pixel reducing the colors intensity to 3/4 which
        // will darken the bitmap.
        for (int j = 0; j < rgbt.Length; j++)
        {
            pColor[i * nWidth + j].b = rgbt[j].rgbtBlue;
            pColor[i * nWidth + j].g = rgbt[j].rgbtGreen;
            pColor[i * nWidth + j].r = rgbt[j].rgbtRed;
        }
 
    }
 
    pOutTex.SetPixels(pColor, 0);
    pOutTex.Apply();
 
    pColor = null;
    FreeImageAPI.FreeImage.Unload(dib);
 
    return true;
}

但此方法在寫入 pColor 矩陣時的速度有點慢,關於這部分有另一種作法是使用指標操作來寫入,大概的方式是使用 FreeImage 的 GetBits 指令來取得記憶體位置, pColor 方面則是使用 GCHandle.alloc 及 AddrOfPinnedObject 來取得 pColor 的記憶體位置,最後利用呼叫外部 dll 方式由 C 語言指標來完成工作。

0 意見 :

張貼留言