これに対する正しい答えは、ContentPipelineをスキップし、Texture2D.FromStreamを使用して実行時にテクスチャをロードすることです。この方法はPCで正常に機能し、パフォーマンスが少し低下しても、リリース日に近づいたら最適化できます。現時点では、エディターとゲームの両方のコンテンツを動的に変更する機能が必要です。コンテンツがフリーズしたら、ContentPipelineに戻ってこれを最適化できます。
このルートを選択したので、次のTexture2D.FromStream
2つの理由で実際に使用するほど簡単ではないことを警告します。
問題#1-乗算済みアルファサポートの欠如
XNA4は、デフォルトであらかじめ乗算されたアルファ形式の色を持つテクスチャーを処理するようになりました。コンテンツパイプラインを通じてテクスチャをロードすると、その処理は自動的に行われます。残念ながらTexture2D.FromStream
、同じことは行わないため、ある程度の透明度を必要とするテクスチャは、ロードされて正しくレンダリングされません。以下は、問題を説明するスクリーンショットです。
したがって、正しい結果を得るには、自分で処理を行う必要があります。これから紹介する方法では、GPUを使用して処理を行うため、かなり高速です。この素晴らしい記事に基づいています。もちろんSpriteBatch
、古いNonPremultiplyAlphaモードでレンダリングするように指示することもできますが、実際にそれを行うことはお勧めしません。
問題#2-サポートされていない形式
コンテンツパイプラインは、よりも多くの形式をサポートしていますTexture2D.FromStream
。特に、Texture2D.FromStream
png、jpg、gifのみをサポートしています。一方、コンテンツパイプラインはbmp、dds、dib、hdr、jpg、pfm、png、ppm、tgaをサポートしています。あなたはを通してusuported形式をロードしようとした場合Texture2D.FromStream
、あなたは買ってあげるInvalidOperationException
わずかな追加情報を。
エンジンでbmpサポートが本当に必要だったので、その特定のケースでは、問題なく動作するように見える回避策を見つけました。他のフォーマットについては知りません。私の方法の難点は、System.Drawing
アセンブリへの参照をプロジェクトに追加する必要があることです。Image.FromStream
これは、よりも多くの形式をサポートするGDIを使用するためですTexture2D.FromStream
。
bmpのサポートを気にしない場合は、ソリューションのその部分を簡単に削除して、乗算済みアルファ処理を実行できます。
ソリューション-シンプルバージョン(遅い)
まず、bmpのサポートを気にしない場合の最も簡単な解決策を次に示します。この例では、処理段階はすべてCPUで行われます。以下に示す代替案よりも少し遅いですが(両方のソリューションのベンチマークを行いました)、理解しやすくなっています。
public static Texture2D FromStream(GraphicsDevice graphicsDevice, Stream stream)
{
Texture2D texture = Texture2D.FromStream(graphicsDevice, stream);
Color[] data = new Color[texture.Width * texture.Height];
texture.GetData(data);
for (int i = 0; i != data.Length; ++i)
data[i] = Color.FromNonPremultiplied(data[i].ToVector4());
texture.SetData(data);
return texture;
}
bmpに関心がある場合は、最初にGDIを使用して画像を読み込み、次に内部的にPNGに変換してからに渡しTexture2D.FromStream
ます。これを行うコードは次のとおりです。
// Load image using GDI because Texture2D.FromStream doesn't support BMP
using (Image image = Image.FromStream(stream))
{
// Now create a MemoryStream which will be passed to Texture2D after converting to PNG internally
using (MemoryStream ms = new MemoryStream())
{
image.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
ms.Seek(0, SeekOrigin.Begin);
texture = Texture2D.FromStream(_graphicsDevice, ms);
}
}
ソリューション-複雑なバージョン(高速)
最後に、私のプロジェクトで使用するアプローチは、代わりにGPUを使用して処理を行うことです。このメソッドでは、レンダーターゲットを作成し、いくつかのブレンドステートを適切に設定し、SpriteBatchでイメージを2回描画する必要があります。最後に、RenderTarget2Dは揮発性であり、バックバッファーサイズの変更などの影響を受けないので、RenderTarget2D全体を調べて、コンテンツを別のTexture2Dオブジェクトに複製します。コピーを作成する方が安全です。
面白いことに、これらすべてを使用しても、私のテストでは、このアプローチはCPUアプローチよりも約3倍高速でした。そのため、各ピクセルを調べて色を自分で計算するよりも断然高速です。コードは少し長いので、私はそれをペーストビンに入れました:
http://pastie.org/3651642
そのクラスをプロジェクトに追加し、次のように簡単に使用します。
TextureLoader textureLoader = new TextureLoader(GraphicsDevice);
Texture2D texture = textureLoader.FromFile("Content/texture.png");
注:TextureLoader
ゲーム全体に対して1つのインスタンスを作成するだけで済みます。また、私はBMP修正を使用していますが、必要がなく、一連のパフォーマンスを得るか、needsBmp
パラメーターをfalseのままにしておく場合は、それを削除できます。