Colladaからマテリアルとメッシュ取得
モデルデータに必要なものを取得してみた。
無理やり取得してる感がある。
次はDirectXが読みやすいような形式でバイナリ化
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Xml.Linq; using System.Text; using System.Windows.Forms; using Microsoft.DirectX; using Microsoft.DirectX.Direct3D; namespace WindowsFormsApplication1 { /// <summary> /// ペア /// </summary> struct Pair { public uint Count; public uint Stride; } /// <summary> /// マテリアル情報 /// </summary> struct Material { public string MaterialName; public List<string> TextureFileName; public Vector4 DiffuseColor; public Vector4 AmbientColor; public Vector4 EmissionColor; public Vector4 SpecularColor; public float Shininess; public float RefractionIndex; } /// <summary> /// メッシュ /// </summary> struct Mesh { public string MeshName; public List<Pair> VertexNum; public List<Pair> NormalNum; public List<Pair> TexCoordNum; public List<Vector3> VertexList; public List<Vector3> NormalList; public List<List<Vector2>> TexCoordList; public int MaterialIndex; } public partial class Form1 : Form { private Dictionary<string, string> m_ImageDictionary; private List<Material> m_MaterialList; private List<Mesh> m_MeshList; /// <summary> /// コンストラクタ /// </summary> public Form1() { m_ImageDictionary = new Dictionary<string, string>(); m_MaterialList = new List<Material>(); m_MeshList = new List<Mesh>(); InitializeComponent(); } /// <summary> /// ロードボタンが押された /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button1_Click(object sender, EventArgs e) { openFileDialog1.InitialDirectory = @"D:\text\dae"; if (openFileDialog1.ShowDialog() == DialogResult.OK) { string dae_filename = openFileDialog1.FileName; textBox1.Text = dae_filename; parseDAE(dae_filename); } } /// <summary> /// DAEを解釈 /// </summary> /// <param name="dae_filename"></param> private void parseDAE(string dae_filename) { var load_dae = XDocument.Load(@dae_filename); XNamespace ex = @"http://www.collada.org/2005/11/COLLADASchema"; // テクスチャ m_ImageDictionary = parseTexture(load_dae, ex); // マテリアル m_MaterialList = parseMaterial(load_dae, ex); // メッシュ m_MeshList = parseMesh(load_dae, ex); } /// <summary> /// テクスチャの連想配列作成 /// </summary> /// <param name="dae"></param> /// <param name="ex"></param> /// <returns></returns> private Dictionary<string, string> parseTexture(XDocument dae, XNamespace ex) { Dictionary<string, string> imageDictionary = new Dictionary<string, string>(); var query = from n in dae.Descendants(ex + "image") select n; foreach (var elem in query) { imageDictionary.Add(elem.Attribute("id").Value, elem.Value); } return imageDictionary; } /// <summary> /// マテリアルリスト /// </summary> /// <param name="dae"></param> /// <param name="ex"></param> /// <returns></returns> private List<Material> parseMaterial(XDocument dae, XNamespace ex) { List<Material> materialList = new List<Material>(); var query_mat = from m in dae.Descendants(ex + "material") select m; foreach (var element in query_mat) { string matName = element.Attribute("id").Value; XElement instance_effect = (XElement)element.FirstNode; string effectName = instance_effect.Attribute("url").Value.Replace("#", ""); var query = from n in dae.Descendants(ex + "effect") where (n.Attribute("id").Value.CompareTo(effectName) == 0) select n; foreach (var elem in query) { Material mat = new Material(); mat.TextureFileName = new List<string>(); // マテリアル名 mat.MaterialName = matName; // テクスチャ名(複数の場合あり) XElement el = elem; var q = from m in el.Descendants(ex + "surface") select m; foreach (var e in q) { string texname = m_ImageDictionary[e.Value]; mat.TextureFileName.Add(texname); } // diffuse mat.DiffuseColor = parseColor("diffuse", el, ex); // ambient mat.AmbientColor = parseColor("ambient", el, ex); // emission mat.EmissionColor = parseColor("emission", el, ex); // specular mat.SpecularColor = parseColor("specular", el, ex); // shininess mat.Shininess = parseParam("shiniess", el, ex); // refraction index mat.RefractionIndex = parseParam("index_of_refraction", el, ex); materialList.Add(mat); } } return materialList; } /// <summary> /// library_effects内の色を解析 /// </summary> /// <param name="colorname"></param> /// <param name="element"></param> /// <param name="ex"></param> /// <returns></returns> private Vector4 parseColor(string colorname, XElement element, XNamespace ex) { var query = from m in element.Descendants(ex + colorname) select m; Vector4 color = new Vector4(); foreach (var e in query) { string col = e.Value; string[] array = col.Split(' '); if (array.Count() > 1) { color.X = float.Parse(array[0]); color.Y = float.Parse(array[1]); color.Z = float.Parse(array[2]); color.W = float.Parse(array[3]); } else { color.X = color.Y = color.Z = color.W = 1.0f; } } return color; } /// <summary> /// float解析 /// </summary> /// <param name="colorname"></param> /// <param name="element"></param> /// <param name="ex"></param> /// <returns></returns> private float parseParam(string paramname, XElement element, XNamespace ex) { var query = from m in element.Descendants(ex + paramname) select m; float param = 0.0f; foreach (var e in query) { string p = e.Value; if (p.Length > 0) { param = float.Parse(p); } } return param; } /// <summary> /// メッシュ解析 /// </summary> /// <param name="dae"></param> /// <param name="ex"></param> /// <returns></returns> private List<Mesh> parseMesh(XDocument dae, XNamespace ex) { List<Mesh> meshList = new List<Mesh>(); var query = from n in dae.Descendants(ex + "geometry") select n; foreach (var elem in query) { Mesh mesh = new Mesh(); // メッシュ名 mesh.MeshName = elem.Attribute("id").Value; // 頂点数 mesh.VertexNum = parseElementPairArray(true, "-positions-array", elem, ex); // 法線数 mesh.NormalNum = parseElementPairArray(true, "-normals-array", elem, ex); // TexCoord数 mesh.TexCoordNum = parseElementPairArray(false, "#"+mesh.MeshName + "-map-", elem, ex); // 頂点 mesh.VertexList = parseVector3Element("-positions-array", elem, ex); // 法線 mesh.NormalList = parseVector3Element("-normals-array", elem, ex); // TexCoord mesh.TexCoordList = parseVector2ElementArray(mesh.TexCoordNum.Count(), false, mesh.MeshName + "-map-", elem, ex); // マテリアルインデックス mesh.MaterialIndex = parseMeshMaterial(ref m_MaterialList, elem, ex); meshList.Add(mesh); } return meshList; } /// <summary> /// 要素数の解析 /// </summary> /// <param name="element"></param> /// <param name="ex"></param> /// <returns></returns> private Pair parseElementPair( bool end, string endWith, XElement element, XNamespace ex) { var query = from m in element.Descendants(ex + "accessor") where end?m.Attribute("source").Value.EndsWith(endWith):m.Attribute("source").Value.StartsWith(endWith) select m; Pair pair = new Pair(); foreach (var e in query) { string countString = e.Attribute("count").Value; string strideString = e.Attribute("stride").Value; pair.Count = uint.Parse(countString); pair.Stride = uint.Parse(strideString); } return pair; } /// <summary> /// 要素数の解析 /// </summary> /// <param name="element"></param> /// <param name="ex"></param> /// <returns></returns> private List<Pair> parseElementPairArray(bool end, string endWith, XElement element, XNamespace ex) { var query = from m in element.Descendants(ex + "accessor") where end ? m.Attribute("source").Value.EndsWith(endWith) : m.Attribute("source").Value.StartsWith(endWith) select m; List<Pair> pairList = new List<Pair>(); foreach (var e in query) { Pair pair = new Pair(); string countString = e.Attribute("count").Value; string strideString = e.Attribute("stride").Value; pair.Count = uint.Parse(countString); pair.Stride = uint.Parse(strideString); pairList.Add(pair); } return pairList; } private uint parseElementNum(bool end, string endWith, XElement element, XNamespace ex) { var query = from m in element.Descendants(ex + "accessor") where end?m.Attribute("source").Value.EndsWith(endWith):m.Attribute("source").Value.StartsWith(endWith) select m; uint num = 0; foreach (var e in query) { ++num; } return num; } /// <summary> /// Vector3データ解析 /// </summary> /// <param name="element"></param> /// <param name="ex"></param> /// <returns></returns> private List<Vector3> parseVector3Element(string vec3element, XElement element, XNamespace ex) { List<Vector3> vertexList = new List<Vector3>(); var query = from m in element.Descendants(ex + "float_array") where m.Attribute("id").Value.EndsWith(vec3element) select m; Vector3 vec = new Vector3(); foreach (var e in query) { string v = e.Value; string[] array = v.Split(' '); int cnt = 0; for (int i = 0; i < array.Count(); ++i) { if (cnt == 2) { vec.X = float.Parse(array[i - 2]); vec.Y = float.Parse(array[i - 1]); vec.Z = float.Parse(array[i - 0]); vertexList.Add(vec); cnt = 0; } else { ++cnt; } } } return vertexList; } /// <summary> /// Vector2データ解析 /// </summary> /// <param name="element"></param> /// <param name="ex"></param> /// <returns></returns> private List<Vector2> parseVector2Element(bool end, string vec2element, XElement element, XNamespace ex) { List<Vector2> vecList = new List<Vector2>(); var query = from m in element.Descendants(ex + "float_array") where end ? m.Attribute("id").Value.EndsWith(vec2element) : m.Attribute("id").Value.StartsWith(vec2element) select m; Vector2 vec = new Vector2(); foreach (var e in query) { string v = e.Value; string[] array = v.Split(' '); int cnt = 0; for (int i = 0; i < array.Count(); ++i) { if (cnt == 1) { vec.X = float.Parse(array[i - 1]); vec.Y = float.Parse(array[i - 0]); vecList.Add(vec); cnt = 0; } else { ++cnt; } } } return vecList; } /// <summary> /// Vector2配列データ解析 /// </summary> /// <param name="element"></param> /// <param name="ex"></param> /// <returns></returns> private List<List<Vector2>> parseVector2ElementArray(int num, bool end, string vec2element, XElement element, XNamespace ex) { List<List<Vector2>> listList = new List<List<Vector2>>(); for (int i = 0; i < num; ++i) { List<Vector2> list = parseVector2Element(end, vec2element+i.ToString(), element, ex); listList.Add(list); } return listList; } private int parseMeshMaterial(ref List<Material> matList, XElement element, XNamespace ex) { var query = from m in element.Descendants(ex + "polylist") select m; int ret = 0; int num = matList.Count(); foreach (var e in query) { string mat = e.Attribute("material").Value; for (int i = 0; i < num; ++i) { string refMat = matList[i].MaterialName; if (refMat.CompareTo(mat) == 0) { return i; } } } return ret; } } }