private COLLADAScene GetScene(Library_Visual_Scenes scenes) { var scene = new COLLADAScene(); scene.Instance_Visual_Scene = new InstanceWithExtra() { Url = $"#{scenes.Visual_Scene.First().Id}" }; return(scene); }
public void ExportToCollada(string outputPath) { var collada = new COLLADA(); var asset = new asset(); var contributor = new assetContributor(); if (ArtToolInfo != null) { contributor.authoring_tool = ArtToolInfo.FromArtToolName; } else { contributor.authoring_tool = "LSLib COLLADA Exporter v" + Common.LibraryVersion(); } asset.contributor = new assetContributor[] { contributor }; asset.created = DateTime.Now; asset.modified = DateTime.Now; asset.unit = new assetUnit(); asset.unit.name = "meter"; // TODO: Handle up vector, etc. properly? if (ArtToolInfo != null) { asset.unit.meter = ArtToolInfo.UnitsPerMeter; } else { asset.unit.meter = 1; } asset.up_axis = UpAxisType.Y_UP; collada.asset = asset; var geometries = new List <geometry>(); var controllers = new List <controller>(); var geomNodes = new List <node>(); ExportModels(geometries, controllers, geomNodes); var animations = new List <animation>(); var animationClips = new List <animation_clip>(); if (Animations != null) { foreach (var anim in Animations) { var anims = anim.ExportAnimations(); animations.AddRange(anims); var clip = new animation_clip(); clip.id = anim.Name + "_Animation"; clip.name = anim.Name; clip.start = 0.0; clip.end = anim.Duration; clip.endSpecified = true; var animInstances = new List <InstanceWithExtra>(); foreach (var animChannel in anims) { var instance = new InstanceWithExtra(); instance.url = "#" + animChannel.id; animInstances.Add(instance); } clip.instance_animation = animInstances.ToArray(); animationClips.Add(clip); } } var rootElements = new List <object>(); if (animations.Count > 0) { var animationLib = new library_animations(); animationLib.animation = animations.ToArray(); rootElements.Add(animationLib); } if (animationClips.Count > 0) { var animationClipLib = new library_animation_clips(); animationClipLib.animation_clip = animationClips.ToArray(); rootElements.Add(animationClipLib); } if (geometries.Count > 0) { var geometryLib = new library_geometries(); geometryLib.geometry = geometries.ToArray(); rootElements.Add(geometryLib); } if (controllers.Count > 0) { var controllerLib = new library_controllers(); controllerLib.controller = controllers.ToArray(); rootElements.Add(controllerLib); } var visualScenes = new library_visual_scenes(); var visualScene = new visual_scene(); visualScene.id = "DefaultVisualScene"; visualScene.name = "unnamed"; visualScene.node = geomNodes.ToArray(); visualScenes.visual_scene = new visual_scene[] { visualScene }; var visualSceneInstance = new InstanceWithExtra(); visualSceneInstance.url = "#DefaultVisualScene"; rootElements.Add(visualScenes); var scene = new COLLADAScene(); scene.instance_visual_scene = visualSceneInstance; collada.scene = scene; collada.Items = rootElements.ToArray(); collada.Save(outputPath); }
public void Export(string filePath) { PalletProperties palletProperties = _palletSolution.Analysis.PalletProperties; COLLADA model = new COLLADA(); // asset model.asset = new asset() { created = DateTime.Now, modified = DateTime.Now }; model.asset.keywords = "StackBuilder Pallet Case"; model.asset.title = _palletSolution.Title; model.asset.unit = new assetUnit() { name = "millimeters", meter = 0.001 }; model.asset.up_axis = UpAxisType.Z_UP; library_images images = new library_images(); library_materials materials = new library_materials(); library_effects effects = new library_effects(); library_geometries geometries = new library_geometries(); library_nodes nodes = new library_nodes(); library_cameras cameras = new library_cameras(); library_animations animations = new library_animations(); library_visual_scenes scenes = new library_visual_scenes(); COLLADAScene colladaScene = new COLLADAScene(); model.Items = new Object[] { images, materials, effects, geometries, nodes, cameras, animations, scenes }; model.scene = colladaScene; // colors and materials List <effect> listEffects = new List <effect>(); List <material> listMaterials = new List <material>(); List <image> listImages = new List <image>(); // effects effect effectPallet; material materialPallet; CreateMaterial(palletProperties.Color, null, null, "Pallet", out effectPallet, out materialPallet); listEffects.Add(effectPallet); listMaterials.Add(materialPallet); Box box = new Box(0, _palletSolution.Analysis.BProperties); // build list of effects / materials / images uint faceIndex = 0; foreach (Face face in box.Faces) { // build texture image if any string textureName = null; if (face.HasBitmap) { textureName = string.Format("textureFace_{0}", faceIndex); string texturePath = System.IO.Path.Combine( System.IO.Path.GetDirectoryName(filePath) , textureName + ".jpg"); double dimX = 0.0, dimY = 0.0; switch (faceIndex) { case 0: dimX = box.Width; dimY = box.Height; break; case 1: dimX = box.Width; dimY = box.Height; break; case 2: dimX = box.Length; dimY = box.Height; break; case 3: dimX = box.Length; dimY = box.Height; break; case 4: dimX = box.Length; dimY = box.Width; break; case 5: dimX = box.Length; dimY = box.Width; break; default: break; } face.ExtractFaceBitmap(dimX, dimY, _bmpWidth, texturePath); // create image listImages.Add( new image() { id = textureName + ".jpg", name = textureName + ".jpg", Item = @".\" + textureName + @".jpg" } ); } material materialCase; effect effectCase; CreateMaterial(face.ColorFill, textureName, "0", string.Format("Case{0}", faceIndex), out effectCase, out materialCase); listEffects.Add(effectCase); listMaterials.Add(materialCase); ++faceIndex; } // add to image list images.image = listImages.ToArray(); // case lines material effect effectCaseLines; material materialCaseLines; CreateMaterial(Color.Black, null, null, "CaseLines", out effectCaseLines, out materialCaseLines); listEffects.Add(effectCaseLines); listMaterials.Add(materialCaseLines); effects.effect = listEffects.ToArray(); materials.material = listMaterials.ToArray(); // geometries geometry geomPallet = new geometry() { id = "palletGeometry", name = "palletGeometry" }; geometry geomCase = new geometry() { id = "caseGeometry", name = "caseGeometry" }; geometries.geometry = new geometry[] { geomPallet, geomCase }; // pallet mesh meshPallet = CreatePalletMesh(palletProperties); geomPallet.Item = meshPallet; // case mesh meshCase = CreateCaseMesh(_palletSolution.Analysis.BProperties as BoxProperties); geomCase.Item = meshCase; // library_animations animation animationMain = new animation() { id = "animationMain_ID", name = "animationMain" }; animations.animation = new animation[] { animationMain }; List <object> listAnimationSource = new List <object>(); // library_visual_scenes visual_scene mainScene = new visual_scene() { id = "MainScene", name = "MainScene" }; scenes.visual_scene = new visual_scene[] { mainScene }; List <node> sceneNodes = new List <node>(); sceneNodes.Add(new node() { id = "PalletNode", name = "PalletNode", instance_geometry = new instance_geometry[] { new instance_geometry() { url = "#palletGeometry", bind_material = new bind_material() { technique_common = new instance_material[] { new instance_material() { symbol = "materialPallet", target = string.Format("#{0}", materialPallet.id) } } } } } }); uint caseIndex = 0; foreach (ILayer layer in _palletSolution) { BoxLayer bLayer = layer as BoxLayer; if (null == bLayer) { continue; } foreach (BoxPosition bp in bLayer) { Vector3D translation = bp.Position; Vector3D rotations = bp.Transformation.Rotations; node caseNode = new node() { id = string.Format("CaseNode_{0}_ID", caseIndex), name = string.Format("CaseNode_{0}", caseIndex), ItemsElementName = new ItemsChoiceType2[] { ItemsChoiceType2.translate, ItemsChoiceType2.rotate, ItemsChoiceType2.rotate, ItemsChoiceType2.rotate }, Items = new object[] { new TargetableFloat3() { Values = new double[] { translation.X, translation.Y, translation.Z }, sid = "t", }, new rotate() { Values = new double[] { 1.0, 0.0, 0.0, rotations.X }, sid = "rx" }, new rotate() { Values = new double[] { 0.0, 1.0, 0.0, rotations.Y }, sid = "ry" }, new rotate() { Values = new double[] { 0.0, 0.0, 1.0, rotations.Z }, sid = "rz" } }, instance_geometry = new instance_geometry[] { new instance_geometry() { url = "#caseGeometry", bind_material = new bind_material() { technique_common = new instance_material[] { new instance_material() { symbol = "materialCase0", target = "#material_Case0_ID" }, new instance_material() { symbol = "materialCase1", target = "#material_Case1_ID" }, new instance_material() { symbol = "materialCase2", target = "#material_Case2_ID" }, new instance_material() { symbol = "materialCase3", target = "#material_Case3_ID" }, new instance_material() { symbol = "materialCase4", target = "#material_Case4_ID" }, new instance_material() { symbol = "materialCase5", target = "#material_Case5_ID" }, new instance_material() { symbol = "materialCaseLines", target = "#material_CaseLines_ID" } } } } } }; sceneNodes.Add(caseNode); // animations CreateAnimation(caseIndex, (uint)_palletSolution.CaseCount, listAnimationSource, bp); // increment case index ++caseIndex; } } // add nodes mainScene.node = sceneNodes.ToArray(); animationMain.Items = listAnimationSource.ToArray(); // library_cameras camera cameraCamera = new camera() { id = "Camera-Camera", name = "Camera-Camera" }; cameraOpticsTechnique_commonPerspective cameraPerspective = new cameraOpticsTechnique_commonPerspective() { znear = new TargetableFloat() { sid = "znear", Value = 1.0 }, zfar = new TargetableFloat() { sid = "zfar", Value = 10000.0 } }; cameraCamera.optics = new cameraOptics() { technique_common = new cameraOpticsTechnique_common() { Item = cameraPerspective } }; cameras.camera = new camera[] { cameraCamera }; // colladaScene colladaScene.instance_visual_scene = new InstanceWithExtra() { url = "#MainScene" }; model.Save(filePath); model.Save(System.IO.Path.ChangeExtension(filePath, "xml")); }
public static string ExportFile(FullModelData data, string path) { path = path.Replace(".model", ".dae"); List <SectionHeader> sections = data.sections; Dictionary <UInt32, ISection> parsed_sections = data.parsed_sections; byte[] leftover_data = data.leftover_data; // Set up the XML structure library_geometries libgeoms = new library_geometries(); library_visual_scenes libscenes = new library_visual_scenes(); COLLADAScene scene = new COLLADAScene { instance_visual_scene = new InstanceWithExtra { url = "#scene" } }; COLLADA collada = new COLLADA { Items = new object[] { libgeoms, libscenes }, scene = scene, asset = new asset { created = DateTime.UtcNow, modified = DateTime.UtcNow, // Otherwise it defaults to Y-up (see asset's constructor), while we're // using Z-up. Without the asset tag Blender defaults to Z-up, so if you // remove this then the presence of the asset tag flips the model. up_axis = UpAxisType.Z_UP, }, }; // Build the mesh List <geometry> geometries = new List <geometry>(); List <node> nodes = new List <node>(); int model_i = 0; foreach (SectionHeader sectionheader in sections) { if (sectionheader.type == model_data_tag) { Model model_data = (Model)parsed_sections[sectionheader.id]; if (model_data.version == 6) { continue; } model_i++; string model_id = model_i + "-" + model_data.HashName.String; PassthroughGP passthrough_section = model_data.PassthroughGP; Geometry geometry_section = passthrough_section.Geometry; Topology topology_section = passthrough_section.Topology; geometry geom = SerializeModel(geometry_section, topology_section, model_data, model_id); geometries.Add(geom); node root_node = new node { id = "model-" + model_id, name = "Model " + model_id, type = NodeType.NODE, instance_geometry = new instance_geometry[] { new instance_geometry { url = "#model-geom-" + model_id, name = "Model Geom" + model_id } } }; nodes.Add(root_node); if (model_data.SkinBones == null) { continue; } SkinBones sb = model_data.SkinBones; //Console.WriteLine(sb.bones); //Console.WriteLine(sb); node bone_root_node = new node { id = "model-" + model_id + "-boneroot", name = "Model " + model_id + " Bones", type = NodeType.NODE, /*Items = new object[] * { * new matrix * { * sid = "transform", // Apparently Blender really wants this * Values = MathUtil.Serialize(sb.unknown_matrix) * } * }, * ItemsElementName = new ItemsChoiceType2[] * { * ItemsChoiceType2.matrix * }*/ }; root_node.node1 = new node[] { bone_root_node }; Dictionary <Object3D, node> bones = new Dictionary <Object3D, node>(); // In order to find locators, which aren't present in the SkinBones // object, we check the child of each object we process. // // To then process those, we use a queue (to_parse) which lists the // objects in our TODO list to search. We draw from this as we process them. // // We also keep the list of what we have processed in (parsed), so we don't // process anything twice. // // TODO rewrite this code to be based around children, removing the need for a seperate // loop after this that arranges the heirachy of nodes. List <Object3D> parsed = new List <Object3D>(sb.Objects); Queue <Object3D> to_parse = new Queue <Object3D>(sb.Objects); int i = 0; while (to_parse.Count != 0) { Object3D obj = to_parse.Dequeue(); string bonename = obj.HashName.String; // Find the locators and such, and add them to the TODO list foreach (Object3D child in obj.children) { if (!parsed.Contains(child)) // Don't process something twice { parsed.Add(child); to_parse.Enqueue(child); } } Vector3 translate; Quaternion rotate; Vector3 scale; Matrix4x4.Decompose(obj.Transform, out scale, out rotate, out translate); Matrix4x4 final_rot = Matrix4x4.CreateFromQuaternion(rotate); final_rot.Translation = translate; if (obj.Parent == null || !sb.Objects.Contains(obj.Parent)) { Matrix4x4 fixed_obj_transform = obj.WorldTransform; Matrix4x4.Decompose(fixed_obj_transform, out scale, out rotate, out translate); // Fixes the head, but breaks the arms // For now, leave it like this //final_rot = final_rot.MultDiesel(fixed_obj_transform); } // If the object is not contained within the SkinBones // object, it must be a locator. bool locator = !sb.Objects.Contains(obj); // Add the node bones[obj] = new node { id = "model-" + model_id + "-bone-" + bonename, name = (locator ? "locator-" : "") + bonename, type = NodeType.JOINT, Items = new object[] { new matrix { sid = "transform", // Apparently Blender really wants this Values = MathUtil.Serialize(final_rot) }, }, ItemsElementName = new ItemsChoiceType2[] { ItemsChoiceType2.matrix } }; i++; } foreach (var(obj, nod) in bones) { node parent = bone_root_node; if (bones.ContainsKey(obj)) { parent = bones[obj.Parent]; } if (parent.node1 == null) { parent.node1 = new node[1]; } else { node[] children = parent.node1; Array.Resize(ref children, children.Length + 1); parent.node1 = children; } parent.node1[parent.node1.Length - 1] = nod; } } } libgeoms.geometry = geometries.ToArray(); libscenes.visual_scene = new visual_scene[] { new visual_scene { id = "scene", name = "Scene", node = nodes.ToArray() } }; using (FileStream fs = new FileStream(path, FileMode.Create, FileAccess.Write)) { collada.Save(fs); // Do we need this? // fs.Close(); } return(path); }
public static void ExportIOModelAsDAE(string FileName, IOModel m) { COLLADA colladaFile = new COLLADA(); List <geometry> list_geometries = new List <geometry>(m.Meshes.Count); if (m.HasMeshes) { foreach (IOMesh iomesh in m.Meshes) { geometry g = new geometry(); g.name = iomesh.Name; g.id = iomesh.Name + $"_{m.Meshes.IndexOf(iomesh)}"; List <double> list_positions = new List <double>(); List <double> list_normals = new List <double>(); List <double> list_uvs = new List <double>(); List <double> list_colors = new List <double>(); foreach (IOVertex v in iomesh.Vertices) { list_positions.Add(v.Position.X); list_positions.Add(v.Position.Y); list_positions.Add(v.Position.Z); list_normals.Add(v.Normal.X); list_normals.Add(v.Normal.Y); list_normals.Add(v.Normal.Z); list_uvs.Add(v.UV0.X); list_uvs.Add(v.UV0.Y); } // Position source source_position = new source(); { float_array floats = new float_array(); floats.count = (ulong)list_positions.Count; floats.id = g.id + "_pos_arr"; floats.Values = list_positions.ToArray(); source_position = CreateSource(list_positions.Count, 3, floats.id, floats, new param[] { new param() { name = "X", type = "float" }, new param() { name = "Y", type = "float" }, new param() { name = "Z", type = "float" } }); } // Normal source source_normal = new source(); { float_array floats = new float_array(); floats.count = (ulong)list_normals.Count; floats.id = g.id + "_nrm_arr"; floats.Values = list_normals.ToArray(); source_normal = CreateSource(list_normals.Count, 3, floats.id, floats, new param[] { new param() { name = "X", type = "float" }, new param() { name = "Y", type = "float" }, new param() { name = "Z", type = "float" } }); } // UV0 source source_uv0 = new source(); { float_array floats = new float_array(); floats.count = (ulong)list_uvs.Count; floats.id = g.id + "_uv0_arr"; floats.Values = list_uvs.ToArray(); source_uv0 = CreateSource(list_uvs.Count, 2, floats.id, floats, new param[] { new param() { name = "S", type = "float" }, new param() { name = "T", type = "float" } }); } // vertices vertices vertices = new vertices(); vertices.id = g.id + "_verts"; vertices.input = new InputLocal[] { new InputLocal() { source = "#" + source_position.id, semantic = "POSITION" }, new InputLocal() { source = "#" + source_normal.id, semantic = "NORMAL" }, new InputLocal() { source = "#" + source_uv0.id, semantic = "TEXCOORD" } }; // triangles triangles triangles = new triangles(); triangles.count = (ulong)iomesh.Indices.Count; triangles.input = new InputLocalOffset[] { new InputLocalOffset() { offset = 0, semantic = "VERTEX", source = "#" + vertices.id } }; triangles.p = string.Join(" ", iomesh.Indices); // creating mesh mesh geomesh = new mesh(); geomesh.source = new source[] { source_position, source_normal, source_uv0 }; geomesh.Items = new object[] { triangles }; geomesh.vertices = vertices; g.Item = geomesh; list_geometries.Add(g); } } library_geometries lib_geometry = new library_geometries(); lib_geometry.geometry = list_geometries.ToArray(); // controllers List <controller> list_controller = new List <controller>(); if (m.HasMeshes && m.HasSkeleton) { // create lists List <source> skinSources = new List <source>(); List <string> boneNames = new List <string>(); List <double> InverseBinds = new List <double>(); foreach (RBone b in m.Skeleton.Bones) { boneNames.Add(b.Name); InverseBinds.AddRange(new double[] { b.InvWorldTransform.M11, b.InvWorldTransform.M21, b.InvWorldTransform.M31, b.InvWorldTransform.M41, b.InvWorldTransform.M12, b.InvWorldTransform.M22, b.InvWorldTransform.M32, b.InvWorldTransform.M42, b.InvWorldTransform.M13, b.InvWorldTransform.M23, b.InvWorldTransform.M33, b.InvWorldTransform.M43, b.InvWorldTransform.M14, b.InvWorldTransform.M24, b.InvWorldTransform.M34, b.InvWorldTransform.M44, }); } // setup controllers foreach (IOMesh iomesh in m.Meshes) { controller controller = new controller() { id = iomesh.Name + "_" + m.Meshes.IndexOf(iomesh) + "_controller" }; list_controller.Add(controller); // create source for weights List <double> weights = new List <double>(); List <int> bones = new List <int>(); List <int> boneCount = new List <int>(); StringBuilder build_v = new StringBuilder(); foreach (IOVertex v in iomesh.Vertices) { int bcount = 0; if (v.BoneWeights.X > 0) { if (!weights.Contains(v.BoneWeights.X)) { weights.Add(v.BoneWeights.X); } build_v.Append($"{(int)v.BoneIndices.X} {weights.IndexOf(v.BoneWeights.X)} "); bcount++; } if (v.BoneWeights.Y > 0) { if (!weights.Contains(v.BoneWeights.Y)) { weights.Add(v.BoneWeights.Y); } build_v.Append($"{(int)v.BoneIndices.Y} {weights.IndexOf(v.BoneWeights.Y)} "); bcount++; } if (v.BoneWeights.Z > 0) { if (!weights.Contains(v.BoneWeights.Z)) { weights.Add(v.BoneWeights.Z); } build_v.Append($"{(int)v.BoneIndices.Z} {weights.IndexOf(v.BoneWeights.Z)} "); bcount++; } if (v.BoneWeights.W > 0) { if (!weights.Contains(v.BoneWeights.W)) { weights.Add(v.BoneWeights.W); } build_v.Append($"{(int)v.BoneIndices.W} {weights.IndexOf(v.BoneWeights.W)} "); bcount++; } boneCount.Add(bcount); } // skin Name_array arr_name = new Name_array(); arr_name.count = (ulong)boneNames.Count; arr_name.id = controller.id + "joints"; arr_name.Values = boneNames.ToArray(); source source_skin = CreateSource(boneNames.Count, 1, arr_name.id, arr_name, new param[] { new param() { name = "JOINT", type = "name" } }); // bind float_array arr_bind = new float_array(); arr_bind.count = (ulong)InverseBinds.Count; arr_bind.id = controller.id + "binds"; arr_bind.Values = InverseBinds.ToArray(); source source_binds = CreateSource(InverseBinds.Count, 16, arr_bind.id, arr_bind, new param[] { new param() { name = "TRANSFORM", type = "float4x4" } }); // weight source source_weight = new source(); { float_array floats = new float_array(); floats.count = (ulong)weights.Count; floats.id = controller.id + "_weights"; floats.Values = weights.ToArray(); source_weight = CreateSource(weights.Count, 1, floats.id, floats, new param[] { new param() { name = "WEIGHT", type = "float" }, }); } skin skin = new skin(); skin.source1 = "#" + iomesh.Name + $"_{m.Meshes.IndexOf(iomesh)}"; skin.source = new source[] { source_skin, source_binds, source_weight }; skin.joints = new skinJoints() { input = new InputLocal[] { new InputLocal() { semantic = "JOINT", source = "#" + source_skin.id }, new InputLocal() { semantic = "INV_BIND_MATRIX", source = "#" + source_binds.id } } }; //skin weights skin.vertex_weights = new skinVertex_weights(); skin.vertex_weights.count = (ulong)iomesh.Vertices.Count; skin.vertex_weights.input = new InputLocalOffset[] { new InputLocalOffset() { semantic = "JOINT", source = "#" + source_skin.id, offset = 0 }, new InputLocalOffset() { semantic = "WEIGHT", source = "#" + source_weight.id, offset = 1 } }; skin.vertex_weights.vcount = string.Join(" ", boneCount); skin.vertex_weights.v = build_v.ToString(); controller.Item = skin; } } library_controllers lib_controllers = new library_controllers(); lib_controllers.controller = list_controller.ToArray(); // scene nodes List <node> scene_nodes = new List <node>(); int visual_index = 0; if (m.HasSkeleton) { Dictionary <RBone, node> boneToNode = new Dictionary <RBone, node>(); foreach (RBone b in m.Skeleton.Bones) { // create bone node node node = new node(); node.name = b.Name; node.id = "bone" + visual_index++; node.sid = b.Name; node.type = NodeType.JOINT; // add transform matrix mat = new matrix() { Values = new double[] { b.Transform.M11, b.Transform.M21, b.Transform.M31, b.Transform.M41, b.Transform.M12, b.Transform.M22, b.Transform.M32, b.Transform.M42, b.Transform.M13, b.Transform.M23, b.Transform.M33, b.Transform.M43, b.Transform.M14, b.Transform.M24, b.Transform.M34, b.Transform.M44, } }; node.ItemsElementName = new ItemsChoiceType2[] { ItemsChoiceType2.matrix }; node.Items = new object[] { mat }; // deal with parenting boneToNode.Add(b, node); if (b.ParentID == -1) { scene_nodes.Add(node); } else { if (boneToNode[m.Skeleton.Bones[b.ParentID]].node1 == null) { boneToNode[m.Skeleton.Bones[b.ParentID]].node1 = new node[0]; } node[] parentnode = boneToNode[m.Skeleton.Bones[b.ParentID]].node1; Array.Resize <node>(ref parentnode, parentnode.Length + 1); parentnode[parentnode.Length - 1] = node; boneToNode[m.Skeleton.Bones[b.ParentID]].node1 = parentnode; } } } if (m.HasMeshes) { foreach (IOMesh iomesh in m.Meshes) { node node = new node() { id = "mesh" + visual_index++, name = iomesh.Name, type = NodeType.NODE }; if (m.HasSkeleton) { instance_controller controller = new instance_controller() { url = iomesh.Name + "_" + m.Meshes.IndexOf(iomesh) + "_controller" }; controller.skeleton = new string[] { "#bone0" }; node.instance_controller = new instance_controller[] { controller }; } scene_nodes.Add(node); } } // visual scene root library_visual_scenes scenes = new library_visual_scenes(); scenes.visual_scene = new visual_scene[] { new visual_scene() { id = "visualscene0", name = "rdmscene" } }; scenes.visual_scene[0].node = scene_nodes.ToArray(); // scene COLLADAScene scene = new COLLADAScene(); scene.instance_visual_scene = new InstanceWithExtra() { url = "#visualscene0" }; // putting it all together colladaFile.Items = new object[] { lib_geometry, lib_controllers, scenes }; colladaFile.scene = scene; colladaFile.Save(FileName); }