Menggunakan XNA ContentPipeline untuk mengekspor file di mesin tanpa XNA GS lengkap

9

Game saya menggunakan Pipeline Konten untuk memuat spriteSheet saat runtime. Artis untuk gim ini mengirimi saya spritesheet yang dimodifikasi dan saya membuat build di mesin saya dan mengirimnya proyek yang diperbarui. Jadi saya mencari cara untuk menghasilkan file xnb di mesinnya (ini adalah output dari pipa konten) tanpa dia harus menginstal studio XNA Game lengkap.

1) Saya tidak ingin artis saya memasang VS + Xna (saya tahu ada versi gratis VS tetapi ini tidak akan menskala setelah kami menambahkan lebih banyak orang ke tim). 2) Saya tidak tertarik menjalankan editor / alat ini di Xbox sehingga solusi Windows only berfungsi. 3) Saya mengetahui opsi MSBuild tetapi membutuhkan XNA lengkap

Saya meneliti blog Shawn dan menemukan opsi untuk menggunakan Sampel Msbuild atau opsi baru di XNA 4.0 yang tampak menjanjikan di sini, tetapi sepertinya memiliki batasan yang sama: Perlu menginstal XNA GS penuh karena ContentPipeline bukan bagian dari redist XNA.

Jadi, adakah yang menemukan solusi untuk ini?

Krolth
sumber

Jawaban:

11

Sepertinya jawaban yang tepat untuk ini adalah dengan melewatkan ContentPipeline dan menggunakan Texture2D.FromStream untuk memuat tekstur saat runtime. Metode ini berfungsi dengan baik di PC dan meskipun akan ada kinerja kecil hit ini adalah sesuatu yang bisa saya optimalkan begitu saya lebih dekat dengan tanggal rilis. Untuk saat ini, memiliki kemampuan memodifikasi konten untuk editor dan game secara dinamis adalah hal yang saya butuhkan. Setelah konten dibekukan, saya dapat mengoptimalkan ini dengan kembali ke ContentPipeline.

Karena Anda telah memilih rute ini, saya harus memperingatkan Anda bahwa itu sebenarnya tidak sesederhana hanya menggunakan Texture2D.FromStreamkarena dua alasan:

Masalah # 1 - Kurangnya dukungan alpha pra-dikalikan

XNA4 sekarang menangani tekstur dengan warna dalam format alfa pra-ditanamkan secara default. Ketika Anda memuat tekstur melalui pipa konten, pemrosesan itu dilakukan untuk Anda secara otomatis. Sayangnya Texture2D.FromStreamtidak melakukan hal yang sama, sehingga tekstur apa pun yang memerlukan tingkat transparansi tertentu akan dimuat dan ditampilkan secara tidak benar. Di bawah ini adalah tangkapan layar untuk menggambarkan masalah:

masukkan deskripsi gambar di sini

Jadi untuk mendapatkan hasil yang benar, Anda perlu melakukan pemrosesan sendiri. Metode yang akan saya tunjukkan menggunakan GPU untuk melakukan pemrosesan sehingga cukup cepat. Itu didasarkan pada artikel bagus ini . Tentu saja Anda juga bisa menginstruksikan SpriteBatchuntuk merender dalam mode NonPremultiplyAlpha lama tapi saya tidak benar-benar merekomendasikan melakukan itu.

Masalah # 2 - Format yang tidak didukung

Pipa konten mendukung lebih banyak format daripada Texture2D.FromStream. Secara khusus, Texture2D.FromStreamhanya mendukung png, jpg, dan gif. Di sisi lain, pipa konten mendukung bmp, dds, dib, hdr, jpg, pfm, png, ppm, dan tga. Jika Anda mencoba memuat format yang kami gunakan, Texture2D.FromStreamAnda akan mendapat InvalidOperationExceptionsedikit informasi tambahan.

Saya benar-benar membutuhkan dukungan bmp di mesin saya jadi untuk kasus khusus itu saya menemukan solusi yang tampaknya berfungsi dengan baik. Saya tidak tahu tentang format lainnya. Tangkapan dengan metode saya adalah bahwa Anda perlu menambahkan referensi ke System.Drawingperakitan ke proyek Anda, karena menggunakan GDI Image.FromStreamyang mendukung lebih banyak format daripada Texture2D.FromStream.

Jika Anda tidak peduli tentang dukungan bmp, Anda dapat dengan mudah menjatuhkan bagian dari solusi saya dan cukup melakukan pemrosesan alfa yang telah dikalikan.

Solusi - Versi Sederhana (Lebih Lambat)

Pertama-tama, inilah solusi paling sederhana jika Anda tidak peduli tentang dukungan bmps. Dalam contoh ini, tahap pemrosesan dilakukan sepenuhnya pada CPU. Ini sedikit lebih lambat daripada alternatif yang akan saya tunjukkan di bawah ini (saya melakukan benchmark kedua solusi) tetapi lebih mudah untuk dipahami:

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;
}

Jika Anda peduli tentang bmps maka hal yang perlu Anda lakukan adalah memuat gambar dengan GDI terlebih dahulu dan kemudian dikonversi menjadi PNG secara internal sebelum meneruskannya Texture2D.FromStream. Berikut kode yang melakukan itu:

// 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);
    }
}

Solusi - Versi Kompleks (Lebih Cepat)

Akhirnya, pendekatan yang saya gunakan pada proyek saya adalah menggunakan GPU untuk melakukan pemrosesan. Dalam metode ini Anda perlu membuat target render, mengatur beberapa negara campuran dengan benar, dan menggambar dua kali gambar dengan SpriteBatch. Pada akhirnya saya membahas seluruh RenderTarget2D dan mengkloning konten menjadi objek Texture2D yang terpisah karena RenderTarget2D mudah berubah dan tidak akan bertahan seperti mengubah ukuran backbuffer sehingga lebih aman untuk membuat salinan.

Yang lucu adalah bahwa bahkan dengan semua ini, pada tes saya pendekatan ini dilakukan sekitar 3 kali lebih cepat daripada pendekatan CPU. Jadi secara definitif lebih cepat daripada melewati setiap piksel dan menghitung warnanya sendiri. Kode ini agak panjang jadi saya menempatkannya di pastebin:

http://pastie.org/3651642

Cukup tambahkan kelas itu ke proyek Anda, dan gunakan sesederhana itu:

TextureLoader textureLoader = new TextureLoader(GraphicsDevice);
Texture2D texture = textureLoader.FromFile("Content/texture.png");

Catatan: Anda hanya perlu membuat satu TextureLoaderinstance untuk seluruh game. Saya juga menggunakan perbaikan BMP tetapi Anda bisa mengeluarkannya jika Anda tidak perlu dan mendapatkan banyak kinerja, atau biarkan saja needsBmpparameternya salah.

David Gouveia
sumber
wow, ini luar biasa! Ini akan banyak membantu saya :) Terima kasih banyak David, saya menghargainya.
krolth
+1 Sebenarnya, saya menggunakan FromStreamdengan aliran memori yang mengandung bitmap 32bit (disimpan ke png), seperti contoh Anda yang lain, tetapi metode ini tidak membuat tekstur yang di-pre-multiplikasi. Secara eksplisit melakukan pra-evolusi setiap warna berhasil, terima kasih.
Groo
3

Saya pikir sebagian besar tim akan melakukan perubahan xnb (well, semua perubahan benar-benar, termasuk xnb termasuk) ke server svn mereka (yang dapat diatur secara gratis) dan memungkinkan orang lain (artis, dll.) Untuk memperbarui salinan kerja mereka sendiri.

Bahkan, itu akan menjadi mekanisme yang baik bagi artis untuk mengontrol versi seni asli (pra-xnb). Dia akan melakukan perubahan itu, Anda akan memperbarui copy pekerjaan Anda itu, membangunnya (menjadikannya xnb dalam proses), mengkomit perubahan Anda, ia memperbarui copy pekerjaannya dari pekerjaan Anda dan dan semua orang memiliki semua perubahan. (Anda memiliki karya seni mentah terbaru, ia memiliki xnb (s).

Timbangan ini juga sangat baik.

Steve H.
sumber
Jadi Anda mengatakan Anda tidak berpikir itu bisa dilakukan? Saran Anda adalah menambahkan kontrol versi ke XNB dan sprite, kami sudah melakukan itu. Tapi saya tidak suka karena saya menjadi penghambat bagi mereka. Saya sudah menulis alat bagi mereka untuk mengedit animasi dan mereka dapat mencobanya di permainan. Tetapi jika mereka membuat perubahan pada spritesheet mereka harus menunggu sampai saya membangunnya sebelum mereka bisa melihatnya. Seperti yang dapat Anda bayangkan jika mereka melakukan kesalahan, mereka perlu melakukannya lagi.
krolth
@ krolth Apakah masalah besar untuk membuat artis Anda mendapatkan VS Express dan XNA sebagai bagian dari pengaturan mereka untuk bekerja pada suatu proyek? Saya pikir pada titik ini pengorbanan harus menulis panduan dan membantu orang-orang melaluinya akan jauh lebih besar daripada produktivitas yang Anda kehilangan sekarang karena seniman tidak dapat melihat pekerjaan mereka di dalam mesin. Untuk merampingkan proses, beri mereka file .BAT yang dapat mereka klik dua kali untuk mengkompilasi ulang semuanya tanpa harus membuka IDE. Dan jika mereka hanya menjalankan OS X, well, sial. Selamat datang di game dev. Mereka dapat melakukan sprite mereka dan menunggu XNB berkomitmen berikutnya.
michael.bartnett
itu bukan masalah besar, hanya rasa sakit. Tapi saya rasa itu harus dilakukan. Terima kasih semuanya atas jawaban / komentar Anda!
krolth
1

Saya terus menyelidiki ini dan akan memposting ini untuk kepentingan seseorang yang memiliki pertanyaan yang sama.

Sepertinya jawaban yang tepat untuk ini adalah dengan melewatkan ContentPipeline dan menggunakan Texture2D.FromStream untuk memuat tekstur saat runtime. Metode ini berfungsi dengan baik di PC dan meskipun akan ada kinerja kecil hit ini adalah sesuatu yang bisa saya optimalkan begitu saya lebih dekat dengan tanggal rilis.

Untuk saat ini, memiliki kemampuan memodifikasi konten untuk editor dan game secara dinamis adalah hal yang saya butuhkan. Setelah konten dibekukan, saya dapat mengoptimalkan ini dengan kembali ke ContentPipeline.

Krolth
sumber
Sudahkah Anda menguji ini dengan benar? Dari pengalaman saya Texture2D.FromStreamdengan sendirinya tidak cukup. Alasan untuk itu adalah karena versi 4 XNA bekerja dengan tekstur alfa yang telah di-preultiplied, dan sementara pipa konten menangani proses ini secara otomatis untuk Anda, Texture2D.FromStreamtidak jadi Anda mungkin akan mengalami masalah ketika menggambar sprite dengan transparansi. Saya dapat memposting solusi yang berfungsi jika Anda mau.
David Gouveia
Juga, Texture2D.FromStreamtidak mendukung memuat .BMPfile sementara pipa konten tidak. Ini adalah sesuatu yang mungkin akan membuang Anda jika Anda menggunakan .BMPaset sebelumnya dan kemudian beralih ke Texture2D.FromStream. Saya juga punya solusi untuk batasan itu. Saya hanya akan pergi ke depan dan mempostingnya.
David Gouveia
0

Lihat proyek ini .

Ini akan memungkinkan artis Anda membuat XNB dari apa saja yang didukung oleh pipa konten XNA standar. Kerangka kerja XNA yang dapat didistribusikan masih diperlukan meskipun artis Anda tidak memerlukan Visual Studio.

Klasik
sumber
Terima kasih untuk penunjuknya. Melihat kode itu sepertinya modifikasi pada sampel Microsoft yang saya rujuk. Itu tergantung pada apakah XNA Game Studio terinstal penuh (lihat ContentBuilder.cs). Menurut Anda mengapa tidak?
krolth
Saya pikir tidak. Jika Anda ingin menggunakan pipa konten maka Anda harus memiliki studio permainan lengkap. Namun proyek ini tidak mencegah artis Anda harus menggunakan Visual Studio. Satu-satunya alternatif lain adalah menulis ulang pipa konten.
ClassicThunder