ดูเหมือนว่าคำตอบที่ถูกต้องคือการข้าม ContentPipeline และใช้ Texture2D.FromStream เพื่อโหลดพื้นผิวที่รันไทม์ วิธีนี้ใช้งานได้ดีในพีซีและถึงแม้จะมีประสิทธิภาพเล็กน้อยก็เป็นสิ่งที่ฉันสามารถปรับให้เหมาะสมเมื่อใกล้ถึงวันวางจำหน่าย สำหรับตอนนี้การมีความสามารถในการปรับเปลี่ยนเนื้อหาสำหรับทั้งตัวแก้ไขและเกมเป็นสิ่งที่ฉันต้องการ เมื่อเนื้อหาถูกตรึงฉันสามารถเพิ่มประสิทธิภาพโดยกลับไปที่ ContentPipeline
เนื่องจากคุณเลือกเส้นทางนี้ฉันต้องเตือนคุณว่าจริงๆแล้วมันไม่ง่ายอย่างที่ใช้เพียงTexture2D.FromStream
สองเหตุผล:
ปัญหา # 1 - ขาดการสนับสนุนอัลฟาก่อนคูณ
XNA4 ตอนนี้จัดการพื้นผิวที่มีสีในรูปแบบอัลฟาก่อนกำหนดโดยค่าเริ่มต้น เมื่อคุณโหลดพื้นผิวผ่านไปป์ไลน์เนื้อหาการประมวลผลนั้นจะทำเพื่อคุณโดยอัตโนมัติ น่าเสียดายที่Texture2D.FromStream
ไม่ได้ทำสิ่งเดียวกันดังนั้นพื้นผิวที่ต้องการความโปร่งใสระดับหนึ่งจะถูกโหลดและแสดงผลไม่ถูกต้อง ด้านล่างเป็นภาพหน้าจอเพื่ออธิบายปัญหา:
ดังนั้นเพื่อให้ได้ผลลัพธ์ที่ถูกต้องคุณต้องทำการประมวลผลด้วยตัวเอง วิธีที่ฉันจะแสดงนั้นใช้ GPU เพื่อทำการประมวลผลดังนั้นมันจึงค่อนข้างเร็ว มันก็ขึ้นอยู่กับบทความดีดีนี้ แน่นอนคุณยังสามารถสั่งSpriteBatch
ให้เรนเดอร์ในโหมด NonPremultiplyAlpha รุ่นเก่า แต่ฉันไม่แนะนำให้ทำเช่นนั้น
ปัญหา # 2 - รูปแบบที่ไม่สนับสนุน
Texture2D.FromStream
ท่อเนื้อหาสนับสนุนรูปแบบมากกว่า โดยTexture2D.FromStream
เฉพาะรองรับ png, jpg และ gif เท่านั้น ในทางตรงกันข้ามไปป์ไลน์เนื้อหารองรับ bmp, dds, dib, hdr, jpg, pfm, png, ppm และ tga หากคุณพยายามโหลดรูปแบบที่อัปโหลดผ่านTexture2D.FromStream
คุณจะได้รับInvalidOperationException
ข้อมูลเพิ่มเติมเล็กน้อย
ฉันต้องการการสนับสนุน bmp ในเครื่องยนต์ของฉันจริงๆดังนั้นสำหรับกรณีนั้นฉันพบวิธีแก้ปัญหาที่ดูเหมือนว่าจะใช้ได้ ฉันไม่รู้เกี่ยวกับรูปแบบอื่น ๆ จับด้วยวิธีการของฉันคือการที่คุณจะต้องเพิ่มการอ้างอิงถึงSystem.Drawing
การชุมนุมในโครงการของคุณเพราะมันจะทำให้การใช้งานของพระเจ้าที่สนับสนุนรูปแบบมากกว่าImage.FromStream
Texture2D.FromStream
หากคุณไม่สนใจเกี่ยวกับการสนับสนุน bmp คุณสามารถดร็อปส่วนของโซลูชันของฉันได้อย่างง่ายดายและเพียงแค่ทำการประมวลผลอัลฟาก่อนคูณ
โซลูชัน - เวอร์ชั่นง่าย (ช้ากว่า)
ก่อนอื่นนี่คือทางออกที่ง่ายที่สุดถ้าคุณไม่สนใจการสนับสนุน bmps ในตัวอย่างนี้ขั้นตอนการประมวลผลเสร็จสิ้นทั้งหมดบน 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;
}
หากคุณสนใจเกี่ยวกับ BMPs แล้วสิ่งที่คุณต้องทำคือการโหลดภาพกับ 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 ในตอนท้ายฉันไป RenderTarget2D ทั้งหมดและคัดลอกเนื้อหาไปเป็นวัตถุ Texture2D แยกต่างหากเพราะ RenderTarget2D นั้นผันผวนและจะไม่รอดชีวิตจากการเปลี่ยนแปลงขนาดของ backbuffer ดังนั้นมันจึงปลอดภัยกว่าที่จะทำสำเนา
สิ่งที่ตลกก็คือแม้จะมีทั้งหมดนี้ในการทดสอบของฉันวิธีการนี้ทำได้ดีกว่า CPU ประมาณ 3 เท่า ดังนั้นมันจึงเร็วกว่าการไปแต่ละพิกเซลและคำนวณสีด้วยตัวคุณเอง รหัสยาวไปหน่อยดังนั้นฉันวางมันลงใน pastebin:
http://pastie.org/3651642
เพียงเพิ่มคลาสนั้นในโครงการของคุณและใช้ง่ายเหมือน:
TextureLoader textureLoader = new TextureLoader(GraphicsDevice);
Texture2D texture = textureLoader.FromFile("Content/texture.png");
หมายเหตุ: คุณจะต้องสร้างหนึ่งTextureLoader
อินสแตนซ์สำหรับเกมทั้งหมด นอกจากนี้ฉันกำลังใช้การแก้ไข BMP แต่คุณสามารถนำออกมาถ้าคุณไม่ต้องการและได้รับประสิทธิภาพจำนวนมากหรือเพียงแค่ปล่อยให้needsBmp
พารามิเตอร์เป็นเท็จ