Part of the Khronos Group
Page 1 of 4 123 ... LastLast
Results 1 to 10 of 40

Thread: COLLADA for XNA - Take 2

  1. #1
    Senior Member
    Join Date
    Jul 2004
    Location
    Santa Clara
    Posts
    358

    COLLADA for XNA - Take 2

    *****
    Update -- please download take 2 - patch 1
    - hack to load non compliant exports from Blender
    - fixed bug reported below in this thread
    ******

    You can download here a new release of the COLLADA for XNA package, replacing the first version posted in this thread.

    Although there has been many changes since the first post, those changes are mostly structural, in order to finally be able to create a set of model/mesh/material that can be extended to all what COLLADA has to offer.

    As the previous thread discussion mentioned, Model, the 3D model primitive provided by XNA is 'just a sample' and should be replaced with something that fits better the application. In our case, we need a COLLADAModel.

    The problem is that there is a lot of hidden and non extensible code associated with Model, which makes it really difficult to replace. Once I started adding a COLLADAModel, I realized that ModelMesh cannot be used, and need to be replaces as well. The reason is that in order to create a Mesh, one has to provide a MeshContent, and attach it to a ModelContent, and then use the <Model> load/processor, which will do the conversion to the necessary vertexBuffer, indexBuffer and so forth.

    So the task to replace the sample Model to something else is large, since a lot of code needs to be provided to replaceModel Mesh, ModelMeshPart.

    Since COLLADA is very flexible, the main effort to create the IndexBuffers and VertexBuffers can be done directly in a COLLADA conditionner. So I created and added an re-indexor condionner that pack all the float arrays in a single array, and create the indexes into this array.

    (For the curious)
    The resulting COLLADA primitive have <source> without any <float_array> data, their <accessor> is referencing the one <source> that has the single float_array. This was designed like this since 1.0, but I am curious if COLLADA importers can cope with this construct. Would be interesting to add a 'save document' feature to find out.

    Then I create COLLADAModel, and associated COLLADAModel.ModelMesh, COLLADAModel.ModelMeshParts

    I also added COLLADAModel.ModelBone, and COLLADAModel.BasicMaterial since it was easy enough. Converting from COLLADAModel.BasicMaterial to BasicEffect is actually possible, since BasicEffect has been designed to be created at run-time, and not only in the content pipeline.

    Those new objects are mimic of the original XNA corresponding ones, except for the following:

    - The Indices are not packed per mesh, but are an index vector per MeshPart. There is no reason for this expect that I did not do the packing. I also did not try to optimize the index to short, or to test if the number of indexes is larger than what the graphics hardware is supporting.. so some more work is needed there.

    - I discovered that XNA Model does not support instancing. Since the Mesh reference back to the bone (position) and ModelMeshPart to their Effect, it is not possible to reuse the same Model at different position, with a different Effect. It was weird, since this is a very basic feature that I did not expect would be missing. So I added InstanceMesh, which reference a Mesh, a Bone, and has a list of Effect to be used for all the MeshParts


    In addition to having extensible objects as a basis for additional developement, I also wanted to add the capability to load content either through the content pipeline, or directly in the application, even on the 360. In game development, it is very important to allow for two data path: the complete path that goes through the full content pipeline, and the fast-path, that enable last minute art to be injected in the game for artist to do in-game tuning, it is also necessary if you want to create a level editor to be able to load the data in the application directly.

    So this version enables:

    - loading COLLADAModel using the content pipeline
    - loading COLLADAModel without using the content pipeline (direct file load)
    - loading the COLLADA Document with the content pipeline, and then creating the COLLADAModel in the application
    - loading the content as a XNA Model through the content pipeline. This is the 'old' code that I kept in there for comparison

    One interesting note, is that you'll notice that content.load<Model> does create index and vertex buffers. To do this, you need to have access to the graphicsDevice, since the graphics driver is necessary to create those objects. But the only 'plug-in' for content.load is the ContentTypeReader<>, which does not have graphicsDevice as a parameter. So you have to finalize the creation of your own 'Model' after calling content.load<MyModel>... This is weird, since this is really a design where hidden code happens on load<Model>, and this is contradicting the claim that Model is really just a sample designed to be replaced... at least not easily.

    Anyway, now that this is done, it is now possible to add COLLADA features to XNA.

    - animation.
    Unlike XNA COLLADA animations are not limited to tranforms. One can anything that has an id, including textures, colors and so forth.. should it be the next feature ?

    - Drawing order.
    XNA drawing loop first select a Mesh, and then loop through all the MeshParts in this mesh. Each MeshPart has its own Effect. Switching Effects is in general the most expensive thing to do in graphics. So the rendering loop is wrong. It should be for each Effect, render all the MeshParts that are using this Effect.
    In addition, drawing it is important to draw transparent objects last, and in a back to front order, which is not possible with the current structure. So more changes are necessary to Mesh and MeshParts.

    - Skining.
    It is not clear to me how skinning needs to be implement. Does BasicEffect has support for skinning, or should the skinning be done in the CPU, or should a full FX, with shader code, be provided to do skinning ?

    So, what do you think ?
    Should the code be re factored differently ?
    What feature should be done next ?
    How many bugs did I introduced


    Thanks for reading.

  2. #2
    Junior Member
    Join Date
    Jan 2007
    Posts
    2
    Hey remi,

    I have taken a look at your code and it works nicely with the collada models you provided. I have not read through all the threads here about collada and XNA, maybe I will do that and answer some questions you guys have here at the weekend, when I got a little bit of free time.

    Just to test out your code I tested a little bit more complex collada file, which uses a .fx shader and was exported from 3D Studio Max 8 using a mesh using that shader as its material. The collada file works fine with my collada importer in XNA, another one I wrote for MDX and I'm currently testing it on a OpenGL implementation as well. The model also works fine as a .x file and .3ds file. I can maybe provide some complex collada test files later.

    The importer crashes with the following error message:
    Building Content\Models\bones1.DAE -> bin\x86\Debug\Content\Models\bones1.xnb
    Content\Models\bones1.DAE : error : Building content threw Exception: effect id=file____Models_Shaders_SpecularNormalMapping_fx has no profile_COMMON :C:\code\Xna\colladaforxna-take2\COLLADA for XNA - take 2\COLLADAViewer\COLLADAViewer\Content\Models\bones 1.DAE
    Content\Models\bones1.DAE : error : at COLLADA.Document.Effect..ctor(Document doc, XmlNode node) in C:\code\Xna\colladaforxna-take2\COLLADA for XNA - take 2\COLLADADocument\COLLADADocument\COLLADADocument. cs:line 1113
    Content\Models\bones1.DAE : error : at COLLADA.Document..ctor(String name) in C:\code\Xna\colladaforxna-take2\COLLADA for XNA - take 2\COLLADADocument\COLLADADocument\COLLADADocument. cs:line 2190
    Content\Models\bones1.DAE : error : at COLLADA.COLLADAImporter.Import(String filename, ContentImporterContext context) in C:\code\Xna\colladaforxna-take2\COLLADA for XNA - take 2\COLLADAPipeline\COLLADAPipeline\COLLADAPipeliner .cs:line 745
    Content\Models\bones1.DAE : error : at Microsoft.Xna.Framework.Content.Pipeline.ContentIm porter`1.Microsoft.Xna.Framework.Content.Pipeline. IContentImporter.Import(String filename, ContentImporterContext context)
    Content\Models\bones1.DAE : error : at Microsoft.Xna.Framework.Content.Pipeline.BuildCoor dinator.ImportAssetDirectly(BuildItem item, String importerName)
    Content\Models\bones1.DAE : error : at Microsoft.Xna.Framework.Content.Pipeline.BuildCoor dinator.ImportAsset(BuildItem item)
    Content\Models\bones1.DAE : error : at Microsoft.Xna.Framework.Content.Pipeline.BuildCoor dinator.BuildAssetWorker(BuildItem item)
    Content\Models\bones1.DAE : error : at Microsoft.Xna.Framework.Content.Pipeline.BuildCoor dinator.BuildAsset(BuildItem item)
    Content\Models\bones1.DAE : error : at Microsoft.Xna.Framework.Content.Pipeline.BuildCoor dinator.RunTheBuild()
    Content\Models\bones1.DAE : error : at Microsoft.Xna.Framework.Content.Pipeline.Tasks.Bui ldContent.RemoteProxy.RunTheBuild(BuildCoordinator Settings settings, ITaskItem[] sourceAssets, TaskLoggingHelper msbuildLog, String[]& outputContent, String[]& rebuiltContent, String[]& intermediates)
    Done building project "COLLADAViewer.csproj" -- FAILED.

    The shader file and the used textures from the shader exist, but they are not really loaded. I guess this can be fixed with a couple of changes in the code. I noticed however that your viewer project is rather complex, try to compare that with my model viewer:

    #region Unit Testing
    public static void TestRenderModel()
    {
    Model testModel = null;
    TestGame.Start("TestRenderModel",
    delegate
    {
    testModel = new Model("Apple");
    },
    delegate
    {
    testModel.Render(Matrix.CreateScale(10));
    });
    } // TestRenderModel()
    #endregion

    Anyway, great work you are doing there. I used a completly different approach loading the collada files directly (or using an internal binary format, which is automatically generated through serializing the class that renders the collada model), which I think was much easier to implement than fighting with the limitations of the content pipeline.

    Again, not much time right now, I will take a closer look at your project this weekend.

  3. #3
    Junior Member
    Join Date
    Dec 2006
    Posts
    4

    Re: COLLADA for XNA - Take 2

    Quote Originally Posted by remi
    One interesting note, is that you'll notice that content.load<Model> does create index and vertex buffers. To do this, you need to have access to the graphicsDevice, since the graphics driver is necessary to create those objects. But the only 'plug-in' for content.load is the ContentTypeReader<>, which does not have graphicsDevice as a parameter. So you have to finalize the creation of your own 'Model' after calling content.load<MyModel>... This is weird, since this is really a design where hidden code happens on load<Model>, and this is contradicting the claim that Model is really just a sample designed to be replaced... at least not easily.
    Remi,

    I'm sorry I still have no time to make a considered reply to all your great work but I just wanted to point out that you can get at the graphics device from inside a content reader (it really would have been an oversight on Microsoft's part to not enable that). You can use code like this in your content reader's Read() method:

    Code:
    IGraphicsDeviceService graphicsDeviceService = (IGraphicsDeviceService)input.ContentManager.ServiceProvider.GetService(typeof(IGraphicsDeviceService));
    Not terribly obvious I agree. The XNA docs have a section on adding new types to the content pipeline that mentions this:

    http://msdn2.microsoft.com/en-us/lib....aspx#ID2EMBAC

    Cheers,
    Leaf.

  4. #4
    Senior Member
    Join Date
    Jul 2004
    Location
    Santa Clara
    Posts
    358

    Re: COLLADA for XNA - Take 2

    Quote Originally Posted by leafg
    I'm sorry I still have no time to make a considered reply to all your great work but I just wanted to point out that you can get at the graphics device from inside a content reader.
    Many thanks for your help. It works great and make the code cleaner.

    This actually prompt me for additional questions:
    In the current code doing the postProcessing on the Model (called inside content.load<COLLADAModel>), there is the creation of the BasicEffect from the BasicMaterial.
    - new BasicMaterial() is asking for graphicsDevice, as well as effectPool. I currently use 'null', since I am not sure what I am supposed to use
    - effect.Texture is created using Texture2D.FromFile(). This works fine, and is the only way to load the texture in you load the COLLADAModel directly. But when the post load processing is called from within the content pipeline, there must be better way to get the texture from the content pipeline ?

  5. #5
    Senior Member
    Join Date
    Jul 2004
    Location
    Santa Clara
    Posts
    358
    Hi Abi,
    many thanks for your feedback.

    Quote Originally Posted by abi
    Just to test out your code I tested a little bit more complex collada file, which uses a .fx shader and was exported from 3D Studio Max 8 using a mesh using that shader as its material. The collada file works fine with my collada importer in XNA, another one I wrote for MDX and I'm currently testing it on a OpenGL implementation as well. The model also works fine as a .x file and .3ds file. I can maybe provide some complex collada test files later.
    As of 1.4.1 COLLADA does not have default support for HLSL/FX. Built in are CG , GLSL and GLSL-ES, since we first focussed on PS3 content (CG) and content for all the Khronos graphics API (GLSL, GLSL-ES).

    But since COLLADA is extensible, the Max exporter/importer can save HLSL/.fx, in a Max specific technique. It can also import/export the standard CG technique, but wont be able to display it. This works because COLLADA externalize the parameters and everything that makes an effect from the source code of the shader programs, so you can use the same COLLADA FX and provided different shader programs code depending on your target platform. In practice this means you can save a COLLADA FX from Maya with CG shaders, and you can load it in Max, and if you save it back from Max all the CG profile will be kept, which is important as far as COLLADA is concerned to enable data interchange. If you provide the HLSL profile(code) as well as the CG profile, then you can see the effect within Max as well. Tools like FXComposer 2.0 have dual viewports where you can see the DirectX/HLSL and the OpenGL/CG side by side in the same tool, so you can create and test cross platform FX content.

    [note: this has changed recently with the new release Max8 has now support for CG, it will take some time for COLLADA Max to leverage this new capability]

    Quote Originally Posted by abi
    The importer crashes with the following error message:
    "effect id=file____Models_Shaders_SpecularNormalMapping_fx has no profile_COMMON"
    That actually is a bug in the exporter !
    The COLLADA specification says that all <effects> must have a profile_COMMON (no programmable shader), and can have as many additional profiles for specific platforms.



    Quote Originally Posted by abi
    The shader file and the used textures from the shader exist, but they are not really loaded. I guess this can be fixed with a couple of changes in the code.
    This version does not implement anything else than common profile, but that would be very interesting to add this next. I will probably only work for Max exports, until the .fx/HLSL profiles are added to the COLLADA specification, but that's a good start for sure.

    Would you mind sending me your .dae file, effects and textures ? If you have the original max file as well this would enable me to check why the exporter does not have a common_profile as well ? (remi (at) collada.org)

    Quote Originally Posted by abi
    I noticed however that your viewer project is rather complex, try to compare that with my model viewer:
    I just copy/paste a sample from the XNA doc (and fixed it). There is nothing of importance in the Viewer file, it is just convenient to load a bunch of models, rotate them with the mouse or the XBOX joystick, and switch model to models.

    Although I forgot to gather the draw code back in the COLLADAModel, so I'll do that to simplify this code.


    Quote Originally Posted by abi
    Anyway, great work you are doing there. I used a completely different approach loading the collada files directly (or using an internal binary format, which is automatically generated through serializing the class that renders the collada model), which I think was much easier to implement than fighting with the limitations of the content pipeline.
    I am trying for the COLLADA importer to be a good XNA citizen and take advantage of the content pipeline. I think that a good content pipeline is really important, so hopefully the work I am doing will be an improvement over what is provided.

    BTW, I had no idea you were taking advantage of COLLADA already. Interested to hear your feedback on this too !

    Thanks again for your time.

  6. #6
    Junior Member
    Join Date
    Aug 2004
    Posts
    7
    Quote Originally Posted by remi
    [note: this has changed recently with the new release Max8 has now support for CG, it will take some time for COLLADA Max to leverage this new capability]
    Actually I think it's Max 9 with the Cg and Cgfx support.

  7. #7
    Junior Member
    Join Date
    Dec 2006
    Posts
    4

    Re: COLLADA for XNA - Take 2

    Quote Originally Posted by remi
    This actually prompt me for additional questions:
    In the current code doing the postProcessing on the Model (called inside content.load<COLLADAModel>), there is the creation of the BasicEffect from the BasicMaterial.
    - new BasicMaterial() is asking for graphicsDevice, as well as effectPool. I currently use 'null', since I am not sure what I am supposed to use
    - effect.Texture is created using Texture2D.FromFile(). This works fine, and is the only way to load the texture in you load the COLLADAModel directly. But when the post load processing is called from within the content pipeline, there must be better way to get the texture from the content pipeline ?
    Null is fine for the EffectPool param, that basically means that all Effect instances created by BasicMaterial will have no EffectPool (used for sharing EffectParameters between different Effect instances). Another option (as used by the default Effect content reader) is to create a static EffectPool and use that for all Effects loaded. That way all Effect instances will be able to share EffectParameters. Neither is quite correct since the application may want control over the EffectPools.

    In the content pipeline you can use ExternalReference<Texture2D> to reference the textures. ContentProcessorContext.BuildAsset()/BuildAndLoadAsset() to build textures. ContentWriter.WriteExternalReference() and ContentReader.ReadExternalReference() to serialize references to the textures in a .xnb file. Not sure how that fits in with your latest code but hopefully it points you in a useful direction.

    Cheers,
    Leaf.

  8. #8
    Junior Member
    Join Date
    Jan 2007
    Posts
    3

    Re: COLLADA for XNA - Take 2

    Thanks for providing this code! I did not have a chance of using it myself (I am currently working with FBX models in XNA) but I think COLLADA can be a huge help to many people using XNA. From what I see at XNA forums, many people are using XNA with Blender and Blender's X exporter is very unreliable (and Blender has no support for FBX). Blender's COLLADA exporter is already in good shape and I feel it has potential for quikc improvement. That will send a stream of users for COLLADA with XNA.

    I think situation with Blender and .X format is typical and the same will start happening with other tools. COLLADA plugins for Maya and 3DMAX are very well supporter and updated often, in contrast with Microsoft's .X plugins. The .X is a dying format and the only alternative Microsoft offered with XNA is FBX which is not a great choice.

    I am using XNA and am thinking of moving from FBX to COLLADA in the future because of general advantages of COLLADA as a format for games contents. But there are definetely many people around who already have troubles with .X and COLLADA seems to be a natural sulution.

    Pardon my going into these minor details but I just wanted to give some feedback. As one of principal contributors to www.codeplex.com/animationcomponents , I have a seen lots of posts from people having troubles with .X.

    Michael Nikonov

  9. #9
    Junior Member
    Join Date
    Jan 2007
    Posts
    3

    Re: COLLADA for XNA - Take 2

    Quote Originally Posted by remi
    - animation.
    Unlike XNA COLLADA animations are not limited to tranforms. One can anything that has an id, including textures, colors and so forth.. should it be the next feature ?
    ...
    - Skining.
    It is not clear to me how skinning needs to be implement. Does BasicEffect has support for skinning, or should the skinning be done in the CPU, or should a full FX, with shader code, be provided to do skinning ?
    As I already mentioned, I am one of the guys behind www.codeplex.com/animationcomponents. The animationcomponents is not a big deal in it's current form but we definetely collected some knowledge of animations with XNA. So I will provide a few comments in hope they will be useful.

    XNA does not have any build-in support for animations other then bone transforms. This would be a new feature if someone would add it with COLLADA. Currently, people struggle to get skinned models animated in simpliest form, so I guess nobody's thinking of advanced features yet.

    BasicEffect does not have support for skinning. Let me suggest that you use www.codeplex.com/animationcomponents as a starting point for that - it is a working example of skinned animation in XNA, with skinning done in shader (BasicPeletteEffect). I don't think it's worth doing CPU skinning - CPU skinning is yeterday of animation. Shader skinning is a natural choice for XNA (especially taking into account that XNA is more about XBox development then PC, and XBox has very powerfull GPU).

    Animationcomponents has also a good example of custom importer with support for skinning. I think looking at that code can be useful when doing COLLADA importer for skinned models.

    Some quick tips:
    Microsoft's default implementation of ModelProcessor.ProcessVertexChannel() converts VertexElementUsage.Color channels to Color format, and replaces VertexChannelNames.Weights () channels with a pair of VertexElementUsage.BlendIndices and VertexElementUsage.BlendWeight channels (using Byte4 format for the VertexElementUsage.BlendIndices, Color for the VertexElementUsage.BlendWeight, and discarding excess weights if there are more than four per vertex).

    MeshHelper.FlattenSkeleton(MeshHelper.FindSkeleton (root)) gets a flattened list of all bones contained by the specified skeleton. The tree is calculated using a depth–first traversal. The bones are returned in the same order used by ModelProcessor to convert BoneWeight vertex channels into the BlendIndices format.

    Beware: Microsoft's model processor assigns BlendIndices in a very obscure way. What MeshHelper.FlattenSkeleton(MeshHelper.FindSkeleton (root)) returns has nothing to do with Model.Bones[i].BoneIndex at runtime. Perharps the best practice would be to override ModelProcessor.ProcessVertexChannel() and assign BlendIndices in a mode predictable way.

    I agree that Microsoft's Content DOM is not ideal and COLLADA DOM is much better. But for the beginning I would recommend to stick with Microsoft's Content DOM. Alternative approach would require too much coding and would create too much confusion. At this point in time, people have trouble figuring out fairly basic XNA Content Pipeline stuff.

    Is there a way to contribute to COLLADA for XNA? I think I could help with animation support but I don't know how to start. I mean, is it possible to host COLLADA for XNA at Sourceforge.net or Codeplex.com, so that people could contribute in an organized way?

    Michael Nikonov

  10. #10
    Junior Member
    Join Date
    Jan 2007
    Posts
    3

    Re: COLLADA for XNA - Take 2

    Quote Originally Posted by remi
    What feature should be done next ?
    I apologies if I am being off-topic, but let me suggest a feature:

    We want C# at PS3!
    (and an equivalent of XNA Framework, that is some good C# API from Sony).

Similar Threads

  1. COLLADA for XNA
    By remi in forum Contributions
    Replies: 10
    Last Post: 10-08-2013, 07:09 AM
  2. Collada x XNA
    By manuvlad in forum Design Discussions
    Replies: 3
    Last Post: 09-28-2006, 05:38 PM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •