C# 讀取DAE模型的主代碼
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.DirectX.Direct3D;
using System.IO;
using System.Xml;
using Microsoft.DirectX;
using System.Xml.XPath;
namespace WorldWind.Renderable.Model
{
/// <summary>
/// DAE模型讀取器
/// </summary>
public class ColladaLoader
{
#region 主加載
/// <summary>
/// 從文件中加載模型
/// </summary>
/// <param name="device"></param>
/// <param name="fileName"></param>
/// <returns></returns>
/// <exception cref="FileNotFoundException">文件不存在或者文件名錯誤</exception>
/// <exception cref="FormatException">格式不正確,讀取不了</exception>
public static ColladaScene FromFile(Device device, string fileName)
{
//初始化判斷
if (string.IsNullOrEmpty(fileName))
throw new FileNotFoundException("FileName Is Null Or Empty");
if (File.Exists(fileName) == false)
throw new FileNotFoundException("DAE File Not Found");
#region 通過XMLNode的方式
//打開文件
//XmlDocument doc = new XmlDocument();
//try
//{
// doc.Load(fileName);
//}
//catch
//{
// throw new FormatException("DAE Format Is Not Sopport");
//}
//XmlNode element = doc["COLLADA"];
//if (element == null)
//{
// throw new FormatException("DAE Format Is Not Sopport");
//}
//創建模型
//ColladaScene scene = new ColladaScene(element, device);
//return scene;
#endregion
#region 通過Reader的方式
string leadingNodeName = "COLLADA";
XmlReaderSettings readerSettings = new XmlReaderSettings();
XmlReader docReader = null;
try
{
docReader = XmlReader.Create(fileName, readerSettings);
XPathDocument docNav = new XPathDocument(docReader);
XPathNavigator nav = docNav.CreateNavigator();
XPathNodeIterator colladaNode = nav.SelectChildren(XPathNodeType.Element);
if (colladaNode.Count > 0)
{
colladaNode.MoveNext();
ColladaScene scene = new ColladaScene(colladaNode, device);
return scene;
}
else
{
throw new Exception("找不到[" + leadingNodeName + "]這個節點");
}
}
catch
{
throw;
}
finally
{
if (docReader != null)
{
docReader.Close();
}
}
#endregion
}
#endregion
#region 只獲得材質的節點
/// <summary>
/// 只獲得材質的節點
/// </summary>
/// <param name="daeFileXmlDoc">輸入模型的XmlDoc</param>
/// <returns></returns>
public static List<XmlNode> GetDaeTextureNodes(XmlDocument daeFileXmlDoc)
{
XmlNode element = daeFileXmlDoc["COLLADA"];
List<XmlNode> nodes = new List<XmlNode>();
XmlNode effectLibNode = element["library_effects"];
nodes.AddRange(GetDaeTextureNodesFromEffectLibNode(effectLibNode).ToArray());
nodes.AddRange(GetDaeTextureNodesFromImageLibNode(effectLibNode).ToArray());
return nodes;
}
/// <summary>
/// 獲得來自EffectLibrary節點的材質節點
/// </summary>
/// <param name="effectLibNode"></param>
/// <returns></returns>
private static List<XmlNode> GetDaeTextureNodesFromEffectLibNode(XmlNode effectLibNode)
{
List<XmlNode> nodes = new List<XmlNode>();
if (effectLibNode == null)
return nodes;
foreach (XmlNode effectNode in effectLibNode.ChildNodes)
{
if (effectNode.Name == "effect")
{
XmlNode profile_COMMON = effectNode["profile_COMMON"];
if (profile_COMMON == null)
continue;
XmlNode image = profile_COMMON["image"];
if (image == null)
continue;
XmlNode init_from = image["init_from"];
if (init_from == null)
continue;
nodes.Add(init_from);
}
}
return nodes;
}
/// <summary>
/// 獲得來自ImageLibrary節點的材質節點
/// </summary>
/// <param name="imageLibNode"></param>
/// <returns></returns>
private static List<XmlNode> GetDaeTextureNodesFromImageLibNode(XmlNode imageLibNode)
{
List<XmlNode> nodes = new List<XmlNode>();
if (imageLibNode == null)
return nodes;
foreach (XmlNode imageNode in imageLibNode.ChildNodes)
{
if (imageNode.Name == "image")
{
XmlNode init_from = imageNode["init_from"];
if (init_from == null)
continue;
nodes.Add(init_from);
}
}
return nodes;
}
#endregion
}
#region 子集信息
/// <summary>
/// 材質
/// </summary>
public class ColladaImage
{
public string TextureFileName_Init_from;
#region 構造函數
public ColladaImage(XmlNode imageNode)
{
TextureFileName_Init_from = imageNode.InnerText;
}
public ColladaImage(XPathNodeIterator imageNode)
{
TextureFileName_Init_from = imageNode.Current.Value;
}
#endregion
}
/// <summary>
/// 其他信息
/// </summary>
public class ColladaEffectProfileInfo
{
public string Surface;
public ColladaImage ImageInfo;
#region 構造函數
public ColladaEffectProfileInfo(XmlNode colladaNode, XmlNode profileNode)
{
XmlNode surfaceNode = profileNode["newparam"]["surface"];
if (surfaceNode != null)
Surface = surfaceNode.InnerText;
LoadImage(colladaNode, profileNode, Surface);
}
public ColladaEffectProfileInfo(XPathNodeIterator colladaNode, XPathNodeIterator profileNode)
{
XPathNodeIterator surfaceNode =WorldWind.Aide.XmlGetHelper.MoveToChild(profileNode,new string[]{"newparam","surface"});
if (surfaceNode != null)
Surface = surfaceNode.Current.Value;
LoadImage(colladaNode, profileNode, Surface);
}
#endregion
#region 獲得材質的信息
private void LoadImage(XmlNode colladaNode, XmlNode profileNode, string surface)
{
if (profileNode["image"] != null)
{
ImageInfo = new ColladaImage(profileNode["image"]);
}
else
{
XmlNode imageNodes = colladaNode["library_images"];
if (imageNodes == null)
return;
foreach (XmlNode imageNode in imageNodes.ChildNodes)
{
if (imageNode.Attributes["id"].Value == surface)
{
ImageInfo = new ColladaImage(imageNode);
break;
}
}
}
}
private void LoadImage(XPathNodeIterator colladaNode, XPathNodeIterator profileNode, string surface)
{
XPathNodeIterator imageIter = WorldWind.Aide.XmlGetHelper.MoveToChild(profileNode, new string[] { "image"});
if (imageIter != null)
{
ImageInfo = new ColladaImage(imageIter);
}
else
{
XPathNodeIterator imageNodes = WorldWind.Aide.XmlGetHelper.MoveToChild(colladaNode, new string[] { "library_images" });
if (imageNodes == null)
return;
XPathNodeIterator imageNode = imageNodes.Current.SelectChildren("image", imageNodes.Current.NamespaceURI);
if (imageNode.Count == 0)
throw new Exception("無法獲得材質library_images/image");
while(imageNode.MoveNext())
{
string idStr = imageNode.Current.GetAttribute("id", "");
if (idStr == surface)
{
ImageInfo = new ColladaImage(imageNode);
break;
}
}
}
}
#endregion
}
/// <summary>
/// 效果
/// </summary>
public class ColladaEffect
{
public ColladaEffectProfileInfo Profile_COMMON;
#region 構造函數
public ColladaEffect(XmlNode colladaNode, XmlNode effectNode)
{
Profile_COMMON = new ColladaEffectProfileInfo(colladaNode, effectNode["profile_COMMON"]);
}
public ColladaEffect(XPathNodeIterator colladaNode, XPathNodeIterator effectNode)
{
XPathNodeIterator profile_COMMONNode = WorldWind.Aide.XmlGetHelper.MoveToChild(effectNode, new string[] { "profile_COMMON" });
if (profile_COMMONNode == null)
throw new Exception("不含有library_effects/effect/profile_COMMON節點");
Profile_COMMON = new ColladaEffectProfileInfo(colladaNode, profile_COMMONNode);
}
#endregion
}
/// <summary>
/// 材質
/// </summary>
public class ColladaMatrial
{
public ColladaEffect EffectInfo;
#region 構造函數
public ColladaMatrial(XmlNode colladaNode, XmlNode matrialNode)
{
string m_url = matrialNode["instance_effect"].Attributes["url"].Value;
LoadEffectInfo(colladaNode, m_url);
}
public ColladaMatrial(XPathNodeIterator colladaNode, XPathNodeIterator matrialNode)
{
XPathNodeIterator instance_effectNode = WorldWind.Aide.XmlGetHelper.MoveToChild(matrialNode, new string[] { "instance_effect" });
if (instance_effectNode == null)
throw new Exception("不能訪問library_materials/material/instance_effect節點");
string m_url = instance_effectNode.Current.GetAttribute("url", "");
LoadEffectInfo(colladaNode, m_url);
}
#endregion
#region 加載效果信息
private void LoadEffectInfo(XmlNode colladaNode, string url)
{
XmlNode effectNodes = colladaNode["library_effects"];
foreach (XmlNode effectNode in effectNodes)
{
if ("#" + effectNode.Attributes["id"].Value == url)
{
EffectInfo = new ColladaEffect(colladaNode, effectNode);
break;
}
}
}
private void LoadEffectInfo(XPathNodeIterator colladaNode, string url)
{
XPathNodeIterator effectNode = WorldWind.Aide.XmlGetHelper.MoveToChild(colladaNode, new string[] { "library_effects", "effect" });
if (effectNode == null)
throw new Exception("無法獲得Collada/library_effects節點");
while(true)
{
string idStr = effectNode.Current.GetAttribute("id", "");
if ("#" + idStr == url)
{
EffectInfo = new ColladaEffect(colladaNode, effectNode);
break;
}
if (effectNode.MoveNext() == false)
break;
}
}
#endregion
}
/// <summary>
/// 一個空間對象的信息
/// </summary>
public class ColladaGeometry
{
public string ID;
public Vector3[] Vertices;
public Vector3[] Normals;
public Vector3[] Texcoords;
public int[] Indices;
#region 構造函數
public ColladaGeometry(XmlNode geometryNode,Matrix matrix)
{
XmlNode sourceElement = geometryNode["mesh"];
ID = geometryNode.Attributes["id"].Value;
Vertices = LoadColladaGeometrySource(sourceElement, "POSITION");
Normals = LoadColladaGeometrySource(sourceElement, "NORMAL");
Texcoords = LoadColladaGeometrySource(sourceElement, "TEXCOORD");
if (sourceElement["polylist"] != null)
{
//polylist類型的
Indices = LoadColladaGeometryPolylist(sourceElement, "polylist");
}
else if (sourceElement["triangles"] != null)
{
LoadColladaTriangles(sourceElement["triangles"]);
}
if (Normals == null)
{
Normals = new Vector3[Vertices.Length];
for (int i = 0; i < Vertices.Length; i++)
{
Normals[i] = new Vector3(0, 0, 1);
}
}
TransformVertical(matrix);
}
public ColladaGeometry(XPathNodeIterator geometryNode, Matrix matrix)
{
XPathNodeIterator sourceElement = WorldWind.Aide.XmlGetHelper.MoveToChild(geometryNode, "mesh");
ID = WorldWind.Aide.XmlGetHelper.GetAttribute(geometryNode, "id");
Vertices = LoadColladaGeometrySource(sourceElement, "POSITION");
Normals = LoadColladaGeometrySource(sourceElement, "NORMAL");
Texcoords = LoadColladaGeometrySource(sourceElement, "TEXCOORD");
XPathNodeIterator polylistNode = WorldWind.Aide.XmlGetHelper.MoveToChild(sourceElement, "polylist");
XPathNodeIterator trianglesNode = WorldWind.Aide.XmlGetHelper.MoveToChild(sourceElement, "triangles");
if (polylistNode != null)
{
//polylist類型的
Indices = LoadColladaGeometryPolylist(sourceElement, "polylist");
}
else if (trianglesNode != null)
{
LoadColladaTriangles(trianglesNode);
}
if (Normals == null)
{
Normals = new Vector3[Vertices.Length];
for (int i = 0; i < Vertices.Length; i++)
{
Normals[i] = new Vector3(0, 0, 1);
}
}
TransformVertical(matrix);
}
#endregion
#region 獲得source源
private string GetSourceNodeID(XmlNode meshNode, string semantic)
{
foreach (XmlNode desNode in meshNode.ChildNodes)
{
if (desNode.Name == "source")
continue;
foreach (XmlNode inputNode in desNode.ChildNodes)
{
if (inputNode.Name == "input")
{
string inputNodeSemantic = inputNode.Attributes["semantic"].Value;
if (inputNodeSemantic == semantic)
{
return inputNode.Attributes["source"].Value;
}
}
}
}
return null;
}
private string GetSourceNodeID(XPathNodeIterator meshNode, string semantic)
{
XPathNodeIterator sourceNode = meshNode.Current.SelectChildren( XPathNodeType.Element);
if (sourceNode.Count == 0)
throw new Exception("無法獲得節點library_geometries/geometry/mesh/source節點");
while(sourceNode.MoveNext())
{
if (sourceNode.Current.Name == "source")
continue;
XPathNodeIterator inputNode = sourceNode.Current.SelectChildren("input", sourceNode.Current.NamespaceURI);
if (inputNode.Count == 0)
throw new Exception("無法獲得節點library_geometries/geometry/mesh/source/input節點");
while (inputNode.MoveNext())
{
string inputNodeSemantic = inputNode.Current.GetAttribute("semantic", "");
if (inputNodeSemantic == semantic)
{
return inputNode.Current.GetAttribute("source", "");
}
}
}
return null;
}
private void TransformVertical(Matrix matrix)
{
for (int i = 0; i < Vertices.Length; i++)
{
Vector4 v = new Vector4(Vertices[i].X, Vertices[i].Y, Vertices[i].Z, 1);
float x = matrix.M11 * v.X + matrix.M12 * v.Y + matrix.M13 * v.Z + matrix.M14 * v.W;
float y = matrix.M21 * v.X + matrix.M22 * v.Y + matrix.M23 * v.Z + matrix.M24 * v.W;
float z = matrix.M31 * v.X + matrix.M32 * v.Y + matrix.M33 * v.Z + matrix.M34 * v.W;
Vertices[i] = new Vector3(x, y, z);
}
}
#endregion
#region 加載模型頂點序列
/// <summary>
/// 加載地理源數據
/// </summary>
/// <param name="meshNode"></param>
/// <param name="sourceName"></param>
/// <returns></returns>
private Vector3[] LoadColladaGeometrySource(XmlNode meshNode, string semantic)
{
XmlNode sourceItemElement = null;
string sourceID = GetSourceNodeID(meshNode, semantic);
if (sourceID == null)
return null;
foreach (XmlNode sourceNode in meshNode.ChildNodes)
{
if (sourceNode.Name == "source"
&& "#" + sourceNode.Attributes["id"].Value == sourceID)
{
sourceItemElement = sourceNode;
break;
}
}
if (sourceItemElement == null)
return null;
int vertCount = int.Parse(sourceItemElement["float_array"].Attributes["count"].Value);
int demPerVertex = int.Parse(sourceItemElement["technique_common"]["accessor"].Attributes["stride"].Value);
//navigate to vertex
XmlNode vertexArrayElement = sourceItemElement["float_array"];
string tStr = vertexArrayElement.InnerText.Trim();
return ParseVector3(tStr, vertCount, demPerVertex);
}
/// <summary>
/// 加載地理源數據
/// </summary>
/// <param name="meshNode"></param>
/// <param name="sourceName"></param>
/// <returns></returns>
private Vector3[] LoadColladaGeometrySource(XPathNodeIterator meshNode, string semantic)
{
XPathNodeIterator sourceItemElement = meshNode.Current.SelectChildren("source", meshNode.Current.NamespaceURI);
string sourceID = GetSourceNodeID(meshNode, semantic);
if (sourceID == null)
return null;
while(sourceItemElement.MoveNext())
{
string idStr = sourceItemElement.Current.GetAttribute("id", "");
if( "#" + idStr == sourceID)
{
break;
}
}
if (sourceItemElement == null)
return null;
int vertCount = int.Parse(
WorldWind.Aide.XmlGetHelper.GetAttribute(sourceItemElement,
new string[] { "float_array" }, "count"));
int demPerVertex = int.Parse(
WorldWind.Aide.XmlGetHelper.GetAttribute(sourceItemElement,
new string[] { "technique_common","accessor" }, "stride"));
string vertStr = WorldWind.Aide.XmlGetHelper.GetInnerText(sourceItemElement, new string[] { "float_array" }).Trim();
return ParseVector3(vertStr, vertCount, demPerVertex);
}
/// <summary>
/// 解析字符串到Vector3
/// </summary>
/// <param name="vertStr"></param>
/// <param name="vertCount"></param>
/// <param name="demPerVertex"></param>
/// <returns></returns>
private Vector3[] ParseVector3(string vertStr, int vertCount, int demPerVertex)
{
//navigate to vertex
Vector3[] vert = new Vector3[vertCount / demPerVertex];
string[] texCoordPart = vertStr.Split(' ');
int count = vertCount / demPerVertex;
int numPartPerItem = demPerVertex;
for (int i = 0; i < count; i++)
{
vert[i].X = float.Parse(texCoordPart[i * numPartPerItem + 0]);
vert[i].Y = float.Parse(texCoordPart[i * numPartPerItem + 1]);
//support 3 texCoords per vertex
if (numPartPerItem > 2)
{
vert[i].Z = float.Parse(texCoordPart[i * numPartPerItem + 2]);
}
else
vert[i].Z = 0;
}
return vert;
}
/// <summary>
/// 加載索引表
/// </summary>
/// <param name="meshNode"></param>
/// <param name="nodeName">默認爲Polylist</param>
/// <returns></returns>
private int[] LoadColladaGeometryPolylist(XmlNode meshNode, string nodeName)
{
XmlNode polylistNode = meshNode[nodeName];
XmlNode dataElement = polylistNode["p"];
int verticesPerFace = 3;
int referenceCount = int.Parse(polylistNode.Attributes["count"].Value);
string rStr = dataElement.InnerText.Trim();
return ParseIntArray(rStr, referenceCount, verticesPerFace);
}
/// <summary>
/// 加載索引表
/// </summary>
/// <param name="meshNode"></param>
/// <param name="nodeName">默認爲Polylist</param>
/// <returns></returns>
private int[] LoadColladaGeometryPolylist(XPathNodeIterator meshNode, string nodeName)
{
XPathNodeIterator polylistNode = WorldWind.Aide.XmlGetHelper.MoveToChild(meshNode, new string[] { nodeName });
XPathNodeIterator dataElement = WorldWind.Aide.XmlGetHelper.MoveToChild(polylistNode, new string[] {"p" });
string rStr = dataElement.Current.Value;
int verticesPerFace = 3;
int referenceCount = int.Parse(polylistNode.Current.GetAttribute("count", ""));
return ParseIntArray(rStr, referenceCount, verticesPerFace);
}
private int[] ParseIntArray(string rStr, int referenceCount, int verticesPerFace)
{
string[] refPart = rStr.Split(' '); // Splits spaces between words in st
int[] vertexReferenceArray = new int[referenceCount * verticesPerFace];
for (int i = 0; i < vertexReferenceArray.Length; i++)
{
vertexReferenceArray[i] = int.Parse(refPart[i]); //for vertices
}
return vertexReferenceArray;
}
#endregion
#region 獲得基於triangles類型的頂點索引
private void LoadColladaTriangles(XmlNode trianglesNode)
{
int count = int.Parse(trianglesNode.Attributes["count"].Value);
int inputCount = trianglesNode.ChildNodes.Count - 1;//input的個數
string rStr = trianglesNode.InnerText.Trim();
string[] refPart = rStr.Split(' ');
int[] vertexReferenceArray = new int[refPart.Length];
if (refPart.Length != count * inputCount * 3)
throw new Exception("LoadColladaTriangles計算錯誤");
for (int i = 0; i < refPart.Length; i++)
vertexReferenceArray[i] = int.Parse(refPart[i]);
foreach (XmlNode inputNode in trianglesNode.ChildNodes)
{
if (inputNode.Name != "input")
continue;
string semantic = inputNode.Attributes["semantic"].Value;
int offset = int.Parse(inputNode.Attributes["offset"].Value);
switch (semantic)
{
case "VERTEX":
LoadColladaTriangleIndices(vertexReferenceArray, offset, inputCount);
break;
case "TEXCOORD":
AdjuestColladaTriangleTexcoordValue(vertexReferenceArray, offset, inputCount);
break;
}
}
}
private void LoadColladaTriangles(XPathNodeIterator trianglesNode)
{
int count = int.Parse(trianglesNode.Current.GetAttribute("count", ""));
XPathNodeIterator inputNode = trianglesNode.Current.SelectChildren("input", trianglesNode.Current.NamespaceURI);
int inputCount = inputNode.Count;//input的個數
string rStr = trianglesNode.Current.Value.Trim();
string[] refPart = rStr.Split(' ');
int[] vertexReferenceArray = new int[refPart.Length];
if (refPart.Length != count * inputCount * 3)
throw new Exception("LoadColladaTriangles計算錯誤");
for (int i = 0; i < refPart.Length; i++)
vertexReferenceArray[i] = int.Parse(refPart[i]);
while(inputNode.MoveNext())
{
string semantic = inputNode.Current.GetAttribute("semantic", "");
int offset = int.Parse(inputNode.Current.GetAttribute("offset", ""));
switch (semantic)
{
case "VERTEX":
LoadColladaTriangleIndices(vertexReferenceArray, offset, inputCount);
break;
case "TEXCOORD":
AdjuestColladaTriangleTexcoordValue(vertexReferenceArray, offset, inputCount);
break;
}
}
}
/// <summary>
/// 加載基於Triangle的索引
/// </summary>
/// <param name="vertexReferenceArray"></param>
/// <param name="offset"></param>
/// <param name="numPerSeg"></param>
private void LoadColladaTriangleIndices(int[] vertexReferenceArray,int offset,int numPerSeg)
{
Indices = new int[vertexReferenceArray.Length/numPerSeg];
for (int i = 0; i < Indices.Length; i++)
{
Indices[i] = vertexReferenceArray[numPerSeg * i + offset];
}
}
/// <summary>
/// 調整Textcoord的位置
/// </summary>
/// <param name="vertexReferenceArray"></param>
/// <param name="offset"></param>
/// <param name="numPerSeg"></param>
private void AdjuestColladaTriangleTexcoordValue(int[] vertexReferenceArray, int offset, int numPerSeg)
{
//不能理解
}
#endregion
}
/// <summary>
/// 場景空間信息
/// </summary>
public class ColladaVisualSceneNodeGeometry
{
#region 屬性
private string m_matrial;
private string m_url;
#endregion
#region 對外屬性
public ColladaGeometry GeometryInfo;
public ColladaMatrial MatrialInfo;
#endregion
#region 構造函數
public ColladaVisualSceneNodeGeometry(XmlNode colladaNode, XmlNode instanceGeometryNode,Matrix matrix)
{
m_url = instanceGeometryNode.Attributes["url"].Value;
m_matrial = instanceGeometryNode["bind_material"]["technique_common"]["instance_material"].Attributes["target"].Value;
LoadGeometryInfo(colladaNode["library_geometries"], matrix);
LoadMatrialInfo(colladaNode, colladaNode["library_materials"]);
}
public ColladaVisualSceneNodeGeometry(XPathNodeIterator colladaNode, XPathNodeIterator instanceGeometryNode, Matrix matrix)
{
m_url = instanceGeometryNode.Current.GetAttribute("url", "");
m_matrial=WorldWind.Aide.XmlGetHelper.GetAttribute(instanceGeometryNode,new string[]{
"bind_material","technique_common","instance_material"},"target");
//XPathNodeIterator matrialNode = WorldWind.Aide.XmlGetHelper.MoveToChild(instanceGeometryNode,
// new string[] { "bind_material", "technique_common", "instance_material" });
//if (matrialNode == null)
// throw new Exception("不能獲得instanceGeometry/bind_material/technique_common/instance_material節點的數據");
XPathNodeIterator geometryNodes = WorldWind.Aide.XmlGetHelper.MoveToChild(colladaNode, new string[] { "library_geometries" });
if (geometryNodes==null)
throw new Exception("無法獲得collada/library_geometries的節點");
LoadGeometryInfo(geometryNodes, matrix);
XPathNodeIterator materialNodes = WorldWind.Aide.XmlGetHelper.MoveToChild(colladaNode, new string[] { "library_materials" });
if(materialNodes==null)
throw new Exception("無法獲得collada/library_materials的節點");
LoadMatrialInfo(colladaNode, materialNodes);
}
#endregion
#region 加載其他信息
private void LoadGeometryInfo(XmlNode geometryNodes, Matrix matrix)
{
foreach (XmlNode geometryNode in geometryNodes)
{
if ("#" + geometryNode.Attributes["id"].Value == m_url)
{
GeometryInfo = new ColladaGeometry(geometryNode, matrix);
break;
}
}
}
private void LoadGeometryInfo(XPathNodeIterator geometryNodes, Matrix matrix)
{
XPathNodeIterator geometryNode = geometryNodes.Current.SelectChildren("geometry", geometryNodes.Current.NamespaceURI);
if (geometryNode.Count == 0)
throw new Exception("無法獲得library_geometries/geometry節點");
while (geometryNode.MoveNext())
{
string idStr = geometryNode.Current.GetAttribute("id", "");
if ("#" + idStr == m_url)
{
GeometryInfo = new ColladaGeometry(geometryNode, matrix);
break;
}
}
}
private void LoadMatrialInfo(XmlNode colladaNode, XmlNode materialNodes)
{
foreach (XmlNode materialNode in materialNodes)
{
if ("#" + materialNode.Attributes["id"].Value == m_matrial)
{
MatrialInfo = new ColladaMatrial(colladaNode, materialNode);
break;
}
}
}
private void LoadMatrialInfo(XPathNodeIterator colladaNode, XPathNodeIterator materialNodes)
{
XPathNodeIterator materialNode = materialNodes.Current.SelectChildren("material", materialNodes.Current.NamespaceURI);
if (materialNode.Count == 0)
throw new Exception("無法獲得library_materials/material節點");
while (materialNode.MoveNext())
{
string idStr = materialNode.Current.GetAttribute("id", "");
if ("#" + idStr == m_matrial)
{
MatrialInfo = new ColladaMatrial(colladaNode, materialNode);
break;
}
}
}
#endregion
}
/// <summary>
/// 場景節點
/// </summary>
public class ColladaVisualSceneNode:IDisposable
{
#region 屬性
private bool m_disposed = false;
private SupperMesh m_meshObject;
#endregion
#region 對外屬性
public string ID;
/// <summary>
/// 模型對象
/// </summary>
public SupperMesh MeshObject
{
get { return m_meshObject; }
}
///// <summary>
///// 當前節點的模型
///// </summary>
//public Mesh MeshObject
//{
// get
// {
// return m_meshObject;
// }
//}
///// <summary>
///// 當前節點的材質信息
///// </summary>
//public ExtendedMaterial[] ExtentdMatrials
//{
// get { return m_extentdMatrials; }
//}
/// <summary>
/// 是否被卸載了
/// </summary>
public bool Disposed
{
get { return m_disposed; }
}
#endregion
#region 構造函數
public ColladaVisualSceneNode(XPathNodeIterator colladaNode, XPathNodeIterator sceneNodeNode, Device device)
{
ID = sceneNodeNode.Current.GetAttribute("id", "");
List<ColladaVisualSceneNodeGeometry> nodeGeometries = new List<ColladaVisualSceneNodeGeometry>();
LoadColladaSubsitMesh(colladaNode, sceneNodeNode, device, nodeGeometries, Matrix.Identity);
UpAxisEnum upAxis = GetUpAxis(colladaNode);
//BuildMesh(nodeGeometries, device, upAxis);
GenerateMeshObject(nodeGeometries, upAxis, device);
}
public ColladaVisualSceneNode(XmlNode colladaNode, XmlNode sceneNodeNode, Device device)
{
ID = sceneNodeNode.Attributes["id"].Value;
List<ColladaVisualSceneNodeGeometry> nodeGeometries = new List<ColladaVisualSceneNodeGeometry>();
LoadColladaSubsitMesh(colladaNode, sceneNodeNode, device, nodeGeometries, Matrix.Identity);
UpAxisEnum upAxis = GetUpAxis(colladaNode);
GenerateMeshObject(nodeGeometries, upAxis, device);
}
/// <summary>
/// 生成模型
/// </summary>
/// <param name="nodeGeometries"></param>
/// <param name="upAxis"></param>
/// <param name="device"></param>
private void GenerateMeshObject(List<ColladaVisualSceneNodeGeometry> nodeGeometries, UpAxisEnum upAxis, Device device)
{
//BuildMesh(nodeGeometries, device, upAxis);
Mesh[] meshes = new Mesh[nodeGeometries.Count];
ExtendedMatrialArray[] matrials = new ExtendedMatrialArray[nodeGeometries.Count];
for (int i = 0; i < nodeGeometries.Count; i++)
{
ExtendedMaterial[] matrial;
BildMesh(nodeGeometries[i], device, upAxis, out meshes[i], out matrial);
matrials[i] = new ExtendedMatrialArray(matrial);
}
m_meshObject = new SupperMesh(meshes, matrials);
}
#endregion
#region 獲得模型子集
private void LoadColladaSubsitMesh(XmlNode colladaNode,
XmlNode sceneNodeNode,
Device device,
List<ColladaVisualSceneNodeGeometry> nodeGeometries,
Matrix matrix)
{
//這裏
if (sceneNodeNode["instance_geometry"] != null &&
sceneNodeNode["node"] != null)
{
throw new Exception("系統暫不能理解既存在instance_geometry又存在node的場景節點");
}
if (sceneNodeNode["instance_geometry"] != null)
{
//Node下面多個instance_geometry
foreach (XmlNode geometryNode in sceneNodeNode.ChildNodes)
{
if (geometryNode.Name == "instance_geometry")
{
nodeGeometries.Add(new ColladaVisualSceneNodeGeometry(colladaNode, geometryNode, matrix));
}
}
}
else if (sceneNodeNode["node"] != null)
{
//Node下面有Matrix
Matrix m = LoadColladaNodeMatrix(sceneNodeNode["node"]["matrix"]);
m = m * matrix;
//Node下面有很多個Node
foreach (XmlNode childNode in sceneNodeNode.ChildNodes)
{
if (childNode.Name == "node")
{
LoadColladaSubsitMesh(colladaNode, childNode, device, nodeGeometries, m);
}
}
}
else
{
throw new Exception("系統暫不能理解場景節點既不存在instance_geometry又不存在node的場景節點");
}
}
private void LoadColladaSubsitMesh(
XPathNodeIterator colladaNode,
XPathNodeIterator sceneNodeNode,
Device device,
List<ColladaVisualSceneNodeGeometry> nodeGeometries,
Matrix matrix)
{
//這裏
XPathNodeIterator instance_geometryNode = sceneNodeNode.Current.SelectChildren("instance_geometry", sceneNodeNode.Current.NamespaceURI);
XPathNodeIterator nodeNode = sceneNodeNode.Current.SelectChildren("node", sceneNodeNode.Current.NamespaceURI);
if (instance_geometryNode.Count==0 &&
nodeNode.Count==0)
{
//throw new Exception("系統暫不能理解既存在instance_geometry又存在node的場景節點");
}
if (instance_geometryNode.Count != 0)
{
//Node下面多個instance_geometry
while (instance_geometryNode.MoveNext())
{
nodeGeometries.Add(new ColladaVisualSceneNodeGeometry(colladaNode, instance_geometryNode, matrix));
}
}
else if (nodeNode.Count != 0)
{
//Node下面有Matrix
XPathNodeIterator matrixIter = WorldWind.Aide.XmlGetHelper.MoveToChild(sceneNodeNode, new string[] { "node", "matrix" });
Matrix m = LoadColladaNodeMatrix(matrixIter);
m = m * matrix;
//Node下面有很多個Node
XPathNodeIterator nodeIter = sceneNodeNode.Current.SelectChildren("node", sceneNodeNode.Current.NamespaceURI);
if (nodeIter.Count == 0)
throw new Exception("無法獲得visual_scene/node/node節點");
while (nodeIter.MoveNext())
{
LoadColladaSubsitMesh(colladaNode, nodeIter, device, nodeGeometries, m);
}
}
else
{
throw new Exception("系統暫不能理解場景節點既存在instance_geometry又存在node的場景節點");
}
}
#endregion
#region 矩陣
private Matrix LoadColladaNodeMatrix(XmlNode matrixNode)
{
if (matrixNode == null)
return Matrix.Identity;
string matrixStr = matrixNode.InnerText;
return LoadColladaNodeMatrix(matrixStr);
}
private Matrix LoadColladaNodeMatrix(XPathNodeIterator matrixNode)
{
if (matrixNode == null)
return Matrix.Identity;
string matrixStr = matrixNode.Current.Value;
return LoadColladaNodeMatrix(matrixStr);
}
private Matrix LoadColladaNodeMatrix(string matrixStr)
{
string[] mValues = matrixStr.Trim().Split(' ');
if (mValues.Length != 16)
throw new Exception("COLLADA 矩陣不爲16個子");
float[] mValueFs = new float[16];
for (int i = 0; i < 16; i++)
{
mValueFs[i] = float.Parse(mValues[i]);
}
Matrix m = new Matrix();
m.M11 = mValueFs[0]; m.M12 = mValueFs[1]; m.M13 = mValueFs[2]; m.M14 = mValueFs[3];
m.M21 = mValueFs[0 + 4]; m.M22 = mValueFs[1 + 4]; m.M23 = mValueFs[2 + 4]; m.M24 = mValueFs[3 + 4];
m.M31 = mValueFs[0 + 8]; m.M32 = mValueFs[1 + 8]; m.M33 = mValueFs[2 + 8]; m.M34 = mValueFs[3 + 8];
m.M41 = mValueFs[0 + 12]; m.M42 = mValueFs[1 + 12]; m.M43 = mValueFs[2 + 12]; m.M44 = mValueFs[3 + 12];
return m;
}
#endregion
#region 構建模型
/// <summary>
/// 構建模型
/// </summary>
/// <param name="nodeGeometries"></param>
/// <param name="device"></param>
/// <param name="upAixs"></param>
//private void BuildMesh(List<ColladaVisualSceneNodeGeometry> nodeGeometries, Device device,UpAxisEnum upAixs)
//{
// int numberFace = 0;
// int numVerticel = 0;
// foreach (ColladaVisualSceneNodeGeometry item in nodeGeometries)
// {
// numberFace += item.GeometryInfo.Indices.Length / 3;
// numVerticel += item.GeometryInfo.Vertices.Length;
// }
// Mesh mesh = new Mesh(numberFace, numVerticel, MeshFlags.Managed, CustomVertex.PositionNormalTextured.Format, device);
// CustomVertex.PositionNormalTextured[] vertices =
// new CustomVertex.PositionNormalTextured[numVerticel];
// int index = 0;
// foreach (ColladaVisualSceneNodeGeometry item in nodeGeometries)
// {
// for (int j = 0; j < item.GeometryInfo.Vertices.Length; j++)
// {
// Vector3 vertex = item.GeometryInfo.Vertices[j];
// if (upAixs == UpAxisEnum.Z_UP)
// vertex = new Vector3(item.GeometryInfo.Vertices[j].X,
// item.GeometryInfo.Vertices[j].Z,
// item.GeometryInfo.Vertices[j].Y);
// vertices[index] = new CustomVertex.PositionNormalTextured(
// vertex,
// item.GeometryInfo.Normals[j],
// item.GeometryInfo.Texcoords[j].X,
// 1-item.GeometryInfo.Texcoords[j].Y);
// index++;
// }
// }
// int[] indices;
// int maxIndicesValue;
// GetIndices(nodeGeometries, numberFace, out indices, out maxIndicesValue);
// AttributeRange[] attrRange = new AttributeRange[nodeGeometries.Count];
// index = 0;
// int sumFace = 0;
// int sumVerticel = 0;
// foreach (ColladaVisualSceneNodeGeometry item in nodeGeometries)
// {
// attrRange[index] = new AttributeRange();
// attrRange[index].AttributeId = index;
// attrRange[index].FaceCount = item.GeometryInfo.Indices.Length / 3;
// attrRange[index].FaceStart = sumFace;
// attrRange[index].VertexCount = item.GeometryInfo.Vertices.Length;
// attrRange[index].VertexStart = sumVerticel;
// sumFace += attrRange[index].FaceCount;
// sumVerticel += attrRange[index].VertexCount;
// index++;
// }
// mesh.SetVertexBufferData(vertices, LockFlags.None);
// if (maxIndicesValue > short.MaxValue)
// {
// mesh.SetIndexBufferData(indices, LockFlags.None);
// }
// else
// {
// short[] sIndices = new short[indices.Length];
// for (int i = 0; i < indices.Length; i++)
// {
// sIndices[i] =(short)indices[i];
// }
// mesh.SetIndexBufferData(sIndices, LockFlags.None);
// }
// int[] adjacency = new int[mesh.NumberFaces * 3];
// mesh.GenerateAdjacency(0f, adjacency);
// mesh.OptimizeInPlace(MeshFlags.OptimizeAttributeSort, adjacency);
// mesh.ComputeNormals();
// mesh.SetAttributeTable(attrRange);
// m_meshObject= mesh;
// m_extentdMatrials = new ExtendedMaterial[nodeGeometries.Count];
// index = 0;
// foreach (ColladaVisualSceneNodeGeometry item in nodeGeometries)
// {
// ExtentdMatrials[index] = new ExtendedMaterial();
// ExtentdMatrials[index].TextureFilename =
// item.MatrialInfo.EffectInfo.Profile_COMMON.ImageInfo.TextureFileName_Init_from;
// index++;
// }
//}
private void BildMesh(ColladaVisualSceneNodeGeometry nodeGeometry, Device device,
UpAxisEnum upAixs, out Mesh mesh, out ExtendedMaterial[] matrials)
{
int numberFace = 0;
int numVerticel = 0;
numberFace = nodeGeometry.GeometryInfo.Indices.Length / 3;
numVerticel = nodeGeometry.GeometryInfo.Vertices.Length;
mesh = new Mesh(numberFace, numVerticel, MeshFlags.Managed, CustomVertex.PositionNormalTextured.Format, device);
CustomVertex.PositionNormalTextured[] vertices =
new CustomVertex.PositionNormalTextured[numVerticel];
for (int j = 0; j < nodeGeometry.GeometryInfo.Vertices.Length; j++)
{
Vector3 vertex = nodeGeometry.GeometryInfo.Vertices[j];
if (upAixs == UpAxisEnum.Z_UP)
vertex = new Vector3(nodeGeometry.GeometryInfo.Vertices[j].X,
nodeGeometry.GeometryInfo.Vertices[j].Z,
nodeGeometry.GeometryInfo.Vertices[j].Y);
vertices[j] = new CustomVertex.PositionNormalTextured(
vertex,
nodeGeometry.GeometryInfo.Normals[j],
nodeGeometry.GeometryInfo.Texcoords[j].X,
1 - nodeGeometry.GeometryInfo.Texcoords[j].Y);
}
short[] indices = new short[numberFace * 3];
for (int j = 0; j < nodeGeometry.GeometryInfo.Indices.Length; j++)
{
indices[j] = (short)nodeGeometry.GeometryInfo.Indices[j];
}
AttributeRange[] attrRange = new AttributeRange[1];
attrRange[0] = new AttributeRange();
attrRange[0].AttributeId = 0;
attrRange[0].FaceCount = nodeGeometry.GeometryInfo.Indices.Length / 3;
attrRange[0].FaceStart = 0;
attrRange[0].VertexCount = nodeGeometry.GeometryInfo.Vertices.Length;
attrRange[0].VertexStart = 0;
mesh.SetVertexBufferData(vertices, LockFlags.None);
mesh.SetIndexBufferData(indices, LockFlags.None);
int[] adjacency = new int[mesh.NumberFaces * 3];
mesh.GenerateAdjacency(0f, adjacency);
mesh.OptimizeInPlace(MeshFlags.OptimizeAttributeSort, adjacency);
mesh.ComputeNormals();
mesh.SetAttributeTable(attrRange);
matrials = new ExtendedMaterial[1];
matrials[0] = new ExtendedMaterial();
matrials[0].TextureFilename =
nodeGeometry.MatrialInfo.EffectInfo.Profile_COMMON.ImageInfo.TextureFileName_Init_from;
}
/// <summary>
/// 獲得軸信息
/// </summary>
/// <param name="colladaNode"></param>
/// <returns></returns>
private UpAxisEnum GetUpAxis(XmlNode colladaNode)
{
string upAxisStr = colladaNode["asset"]["up_axis"].InnerText.ToUpper();
switch (upAxisStr)
{
case "Z_UP":
return UpAxisEnum.Z_UP;
case "Y_UP":
return UpAxisEnum.Y_UP;
default:
throw new Exception("未知的向上軸方向");
}
}
/// <summary>
/// 獲得軸信息
/// </summary>
/// <param name="colladaNode"></param>
/// <returns></returns>
private UpAxisEnum GetUpAxis(XPathNodeIterator colladaNode)
{
string upAxisStr = WorldWind.Aide.XmlGetHelper.GetInnerText(colladaNode, new string[] { "asset", "up_axis" });
switch (upAxisStr)
{
case "Z_UP":
return UpAxisEnum.Z_UP;
case "Y_UP":
return UpAxisEnum.Y_UP;
default:
throw new Exception("未知的向上軸方向");
}
}
/// <summary>
/// 獲得最大的模型Index
/// </summary>
/// <param name="nodeGeometries"></param>
/// <returns></returns>
private void GetIndices(List<ColladaVisualSceneNodeGeometry> nodeGeometries,int numberFace,out int[] indices,out int maxIndicesValue)
{
maxIndicesValue = 0;
indices = new int[numberFace * 3];
int index = 0;
int sumIndiceCount = 0;
foreach (ColladaVisualSceneNodeGeometry item in nodeGeometries)
{
for (int j = 0; j < item.GeometryInfo.Indices.Length; j++)
{
indices[index] = item.GeometryInfo.Indices[j] + sumIndiceCount;
if (indices[index] > maxIndicesValue)
maxIndicesValue = indices[index];
index++;
}
sumIndiceCount += item.GeometryInfo.Indices.Length;
}
}
#endregion
#region 軸信息
enum UpAxisEnum
{
Z_UP,
Y_UP
}
#endregion
#region 卸載
/// <summary>
/// 卸載
/// </summary>
public void Dispose()
{
if (Disposed)
return;
if (MeshObject != null)
{
MeshObject.Dispose();
}
m_disposed = true;
}
#endregion
}
/// <summary>
/// 一個場景模式
/// <para>它包含一個場景節點(ColladaVisualSceneNode)</para>
/// </summary>
public class ColladaVisualScene : IDisposable
{
#region 屬性
private bool m_disposed = false;
private ColladaVisualSceneNode m_sceneNode;
#endregion
#region 對外屬性
public string ID;
/// <summary>
/// 是否被卸載了
/// </summary>
public bool Disposed
{
get { return m_disposed; }
}
/// <summary>
/// 場景節點
/// </summary>
public ColladaVisualSceneNode SceneNode
{
get { return m_sceneNode; }
}
#endregion
#region 構造函數
public ColladaVisualScene(XmlNode colladaNode, XmlNode visualSceneNode, Device device)
{
ID = visualSceneNode.Attributes["id"].Value;
m_sceneNode = new ColladaVisualSceneNode(colladaNode, visualSceneNode["node"], device);
}
public ColladaVisualScene(XPathNodeIterator colladaNode, XPathNodeIterator visualSceneNode, Device device)
{
ID = visualSceneNode.Current.GetAttribute("id", "");
XPathNodeIterator nodeIter = visualSceneNode.Current.SelectChildren("node", visualSceneNode.Current.NamespaceURI);
if (nodeIter.MoveNext() == false)
throw new Exception("無法展開visualSceneNode/Node節點");
m_sceneNode = new ColladaVisualSceneNode(colladaNode, nodeIter, device);
}
#endregion
#region 卸載
/// <summary>
/// 卸載
/// </summary>
public void Dispose()
{
if (Disposed)
return;
SceneNode.Dispose();
m_disposed = true;
}
#endregion
}
/// <summary>
/// 當前場景
/// <para>它選擇一個場景模式(ColladaVisualScene)</para>
/// </summary>
public class ColladaScene:IDisposable
{
#region 屬性
private bool m_disposed = false;
private string m_url;
private ColladaVisualScene m_visualScene;
#endregion
#region 對外屬性
public ColladaVisualScene VisualScene
{
get { return m_visualScene; }
}
/// <summary>
/// 是否被卸載了
/// </summary>
public bool Disposed
{
get { return m_disposed; }
}
#endregion
#region 構造函數
public ColladaScene(XmlNode colladaNode, Device device)
{
m_url = colladaNode["scene"]["instance_visual_scene"].Attributes["url"].Value;
XmlNode visualSceneNode = colladaNode["library_visual_scenes"];
foreach (XmlNode node in visualSceneNode.ChildNodes)
{
if ("#" + node.Attributes["id"].Value == m_url)
{
m_visualScene = new ColladaVisualScene(colladaNode, node, device);
break;
}
}
}
/// <summary>
/// 從XMl中加載
/// </summary>
/// <param name="colladaItor"></param>
public ColladaScene(XPathNodeIterator colladaItor, Device device)
{
XPathNodeIterator instance_visual_sceneNode =
WorldWind.Aide.XmlGetHelper.MoveToChild(colladaItor, new string[] { "scene", "instance_visual_scene" });
if (instance_visual_sceneNode == null)
throw new Exception("無法獲得scene/instance_visual_scene節點");
m_url = instance_visual_sceneNode.Current.GetAttribute("url", "");
XPathNodeIterator visual_sceneNode =
WorldWind.Aide.XmlGetHelper.MoveToChild(colladaItor, new string[] { "library_visual_scenes", "visual_scene" });
if (visual_sceneNode == null)
throw new Exception("無法獲得library_visual_scenes/visual_scene節點");
while (true)
{
string idStr = visual_sceneNode.Current.GetAttribute("id", "");
if ("#" + idStr == m_url)
{
m_visualScene = new ColladaVisualScene(colladaItor, visual_sceneNode, device);
break;
}
if (visual_sceneNode.MoveNext() == false)
break;
}
if (m_visualScene == null)
throw new Exception("無法生成ColladaVisualScene數據");
}
#endregion
#region 卸載
/// <summary>
/// 卸載
/// </summary>
public void Dispose()
{
if (Disposed)
return;
m_visualScene.Dispose();
m_disposed = true;
}
#endregion
}
#endregion
}
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.DirectX.Direct3D;
using System.IO;
using System.Xml;
using Microsoft.DirectX;
using System.Xml.XPath;
namespace WorldWind.Renderable.Model
{
/// <summary>
/// DAE模型讀取器
/// </summary>
public class ColladaLoader
{
#region 主加載
/// <summary>
/// 從文件中加載模型
/// </summary>
/// <param name="device"></param>
/// <param name="fileName"></param>
/// <returns></returns>
/// <exception cref="FileNotFoundException">文件不存在或者文件名錯誤</exception>
/// <exception cref="FormatException">格式不正確,讀取不了</exception>
public static ColladaScene FromFile(Device device, string fileName)
{
//初始化判斷
if (string.IsNullOrEmpty(fileName))
throw new FileNotFoundException("FileName Is Null Or Empty");
if (File.Exists(fileName) == false)
throw new FileNotFoundException("DAE File Not Found");
#region 通過XMLNode的方式
//打開文件
//XmlDocument doc = new XmlDocument();
//try
//{
// doc.Load(fileName);
//}
//catch
//{
// throw new FormatException("DAE Format Is Not Sopport");
//}
//XmlNode element = doc["COLLADA"];
//if (element == null)
//{
// throw new FormatException("DAE Format Is Not Sopport");
//}
//創建模型
//ColladaScene scene = new ColladaScene(element, device);
//return scene;
#endregion
#region 通過Reader的方式
string leadingNodeName = "COLLADA";
XmlReaderSettings readerSettings = new XmlReaderSettings();
XmlReader docReader = null;
try
{
docReader = XmlReader.Create(fileName, readerSettings);
XPathDocument docNav = new XPathDocument(docReader);
XPathNavigator nav = docNav.CreateNavigator();
XPathNodeIterator colladaNode = nav.SelectChildren(XPathNodeType.Element);
if (colladaNode.Count > 0)
{
colladaNode.MoveNext();
ColladaScene scene = new ColladaScene(colladaNode, device);
return scene;
}
else
{
throw new Exception("找不到[" + leadingNodeName + "]這個節點");
}
}
catch
{
throw;
}
finally
{
if (docReader != null)
{
docReader.Close();
}
}
#endregion
}
#endregion
#region 只獲得材質的節點
/// <summary>
/// 只獲得材質的節點
/// </summary>
/// <param name="daeFileXmlDoc">輸入模型的XmlDoc</param>
/// <returns></returns>
public static List<XmlNode> GetDaeTextureNodes(XmlDocument daeFileXmlDoc)
{
XmlNode element = daeFileXmlDoc["COLLADA"];
List<XmlNode> nodes = new List<XmlNode>();
XmlNode effectLibNode = element["library_effects"];
nodes.AddRange(GetDaeTextureNodesFromEffectLibNode(effectLibNode).ToArray());
nodes.AddRange(GetDaeTextureNodesFromImageLibNode(effectLibNode).ToArray());
return nodes;
}
/// <summary>
/// 獲得來自EffectLibrary節點的材質節點
/// </summary>
/// <param name="effectLibNode"></param>
/// <returns></returns>
private static List<XmlNode> GetDaeTextureNodesFromEffectLibNode(XmlNode effectLibNode)
{
List<XmlNode> nodes = new List<XmlNode>();
if (effectLibNode == null)
return nodes;
foreach (XmlNode effectNode in effectLibNode.ChildNodes)
{
if (effectNode.Name == "effect")
{
XmlNode profile_COMMON = effectNode["profile_COMMON"];
if (profile_COMMON == null)
continue;
XmlNode image = profile_COMMON["image"];
if (image == null)
continue;
XmlNode init_from = image["init_from"];
if (init_from == null)
continue;
nodes.Add(init_from);
}
}
return nodes;
}
/// <summary>
/// 獲得來自ImageLibrary節點的材質節點
/// </summary>
/// <param name="imageLibNode"></param>
/// <returns></returns>
private static List<XmlNode> GetDaeTextureNodesFromImageLibNode(XmlNode imageLibNode)
{
List<XmlNode> nodes = new List<XmlNode>();
if (imageLibNode == null)
return nodes;
foreach (XmlNode imageNode in imageLibNode.ChildNodes)
{
if (imageNode.Name == "image")
{
XmlNode init_from = imageNode["init_from"];
if (init_from == null)
continue;
nodes.Add(init_from);
}
}
return nodes;
}
#endregion
}
#region 子集信息
/// <summary>
/// 材質
/// </summary>
public class ColladaImage
{
public string TextureFileName_Init_from;
#region 構造函數
public ColladaImage(XmlNode imageNode)
{
TextureFileName_Init_from = imageNode.InnerText;
}
public ColladaImage(XPathNodeIterator imageNode)
{
TextureFileName_Init_from = imageNode.Current.Value;
}
#endregion
}
/// <summary>
/// 其他信息
/// </summary>
public class ColladaEffectProfileInfo
{
public string Surface;
public ColladaImage ImageInfo;
#region 構造函數
public ColladaEffectProfileInfo(XmlNode colladaNode, XmlNode profileNode)
{
XmlNode surfaceNode = profileNode["newparam"]["surface"];
if (surfaceNode != null)
Surface = surfaceNode.InnerText;
LoadImage(colladaNode, profileNode, Surface);
}
public ColladaEffectProfileInfo(XPathNodeIterator colladaNode, XPathNodeIterator profileNode)
{
XPathNodeIterator surfaceNode =WorldWind.Aide.XmlGetHelper.MoveToChild(profileNode,new string[]{"newparam","surface"});
if (surfaceNode != null)
Surface = surfaceNode.Current.Value;
LoadImage(colladaNode, profileNode, Surface);
}
#endregion
#region 獲得材質的信息
private void LoadImage(XmlNode colladaNode, XmlNode profileNode, string surface)
{
if (profileNode["image"] != null)
{
ImageInfo = new ColladaImage(profileNode["image"]);
}
else
{
XmlNode imageNodes = colladaNode["library_images"];
if (imageNodes == null)
return;
foreach (XmlNode imageNode in imageNodes.ChildNodes)
{
if (imageNode.Attributes["id"].Value == surface)
{
ImageInfo = new ColladaImage(imageNode);
break;
}
}
}
}
private void LoadImage(XPathNodeIterator colladaNode, XPathNodeIterator profileNode, string surface)
{
XPathNodeIterator imageIter = WorldWind.Aide.XmlGetHelper.MoveToChild(profileNode, new string[] { "image"});
if (imageIter != null)
{
ImageInfo = new ColladaImage(imageIter);
}
else
{
XPathNodeIterator imageNodes = WorldWind.Aide.XmlGetHelper.MoveToChild(colladaNode, new string[] { "library_images" });
if (imageNodes == null)
return;
XPathNodeIterator imageNode = imageNodes.Current.SelectChildren("image", imageNodes.Current.NamespaceURI);
if (imageNode.Count == 0)
throw new Exception("無法獲得材質library_images/image");
while(imageNode.MoveNext())
{
string idStr = imageNode.Current.GetAttribute("id", "");
if (idStr == surface)
{
ImageInfo = new ColladaImage(imageNode);
break;
}
}
}
}
#endregion
}
/// <summary>
/// 效果
/// </summary>
public class ColladaEffect
{
public ColladaEffectProfileInfo Profile_COMMON;
#region 構造函數
public ColladaEffect(XmlNode colladaNode, XmlNode effectNode)
{
Profile_COMMON = new ColladaEffectProfileInfo(colladaNode, effectNode["profile_COMMON"]);
}
public ColladaEffect(XPathNodeIterator colladaNode, XPathNodeIterator effectNode)
{
XPathNodeIterator profile_COMMONNode = WorldWind.Aide.XmlGetHelper.MoveToChild(effectNode, new string[] { "profile_COMMON" });
if (profile_COMMONNode == null)
throw new Exception("不含有library_effects/effect/profile_COMMON節點");
Profile_COMMON = new ColladaEffectProfileInfo(colladaNode, profile_COMMONNode);
}
#endregion
}
/// <summary>
/// 材質
/// </summary>
public class ColladaMatrial
{
public ColladaEffect EffectInfo;
#region 構造函數
public ColladaMatrial(XmlNode colladaNode, XmlNode matrialNode)
{
string m_url = matrialNode["instance_effect"].Attributes["url"].Value;
LoadEffectInfo(colladaNode, m_url);
}
public ColladaMatrial(XPathNodeIterator colladaNode, XPathNodeIterator matrialNode)
{
XPathNodeIterator instance_effectNode = WorldWind.Aide.XmlGetHelper.MoveToChild(matrialNode, new string[] { "instance_effect" });
if (instance_effectNode == null)
throw new Exception("不能訪問library_materials/material/instance_effect節點");
string m_url = instance_effectNode.Current.GetAttribute("url", "");
LoadEffectInfo(colladaNode, m_url);
}
#endregion
#region 加載效果信息
private void LoadEffectInfo(XmlNode colladaNode, string url)
{
XmlNode effectNodes = colladaNode["library_effects"];
foreach (XmlNode effectNode in effectNodes)
{
if ("#" + effectNode.Attributes["id"].Value == url)
{
EffectInfo = new ColladaEffect(colladaNode, effectNode);
break;
}
}
}
private void LoadEffectInfo(XPathNodeIterator colladaNode, string url)
{
XPathNodeIterator effectNode = WorldWind.Aide.XmlGetHelper.MoveToChild(colladaNode, new string[] { "library_effects", "effect" });
if (effectNode == null)
throw new Exception("無法獲得Collada/library_effects節點");
while(true)
{
string idStr = effectNode.Current.GetAttribute("id", "");
if ("#" + idStr == url)
{
EffectInfo = new ColladaEffect(colladaNode, effectNode);
break;
}
if (effectNode.MoveNext() == false)
break;
}
}
#endregion
}
/// <summary>
/// 一個空間對象的信息
/// </summary>
public class ColladaGeometry
{
public string ID;
public Vector3[] Vertices;
public Vector3[] Normals;
public Vector3[] Texcoords;
public int[] Indices;
#region 構造函數
public ColladaGeometry(XmlNode geometryNode,Matrix matrix)
{
XmlNode sourceElement = geometryNode["mesh"];
ID = geometryNode.Attributes["id"].Value;
Vertices = LoadColladaGeometrySource(sourceElement, "POSITION");
Normals = LoadColladaGeometrySource(sourceElement, "NORMAL");
Texcoords = LoadColladaGeometrySource(sourceElement, "TEXCOORD");
if (sourceElement["polylist"] != null)
{
//polylist類型的
Indices = LoadColladaGeometryPolylist(sourceElement, "polylist");
}
else if (sourceElement["triangles"] != null)
{
LoadColladaTriangles(sourceElement["triangles"]);
}
if (Normals == null)
{
Normals = new Vector3[Vertices.Length];
for (int i = 0; i < Vertices.Length; i++)
{
Normals[i] = new Vector3(0, 0, 1);
}
}
TransformVertical(matrix);
}
public ColladaGeometry(XPathNodeIterator geometryNode, Matrix matrix)
{
XPathNodeIterator sourceElement = WorldWind.Aide.XmlGetHelper.MoveToChild(geometryNode, "mesh");
ID = WorldWind.Aide.XmlGetHelper.GetAttribute(geometryNode, "id");
Vertices = LoadColladaGeometrySource(sourceElement, "POSITION");
Normals = LoadColladaGeometrySource(sourceElement, "NORMAL");
Texcoords = LoadColladaGeometrySource(sourceElement, "TEXCOORD");
XPathNodeIterator polylistNode = WorldWind.Aide.XmlGetHelper.MoveToChild(sourceElement, "polylist");
XPathNodeIterator trianglesNode = WorldWind.Aide.XmlGetHelper.MoveToChild(sourceElement, "triangles");
if (polylistNode != null)
{
//polylist類型的
Indices = LoadColladaGeometryPolylist(sourceElement, "polylist");
}
else if (trianglesNode != null)
{
LoadColladaTriangles(trianglesNode);
}
if (Normals == null)
{
Normals = new Vector3[Vertices.Length];
for (int i = 0; i < Vertices.Length; i++)
{
Normals[i] = new Vector3(0, 0, 1);
}
}
TransformVertical(matrix);
}
#endregion
#region 獲得source源
private string GetSourceNodeID(XmlNode meshNode, string semantic)
{
foreach (XmlNode desNode in meshNode.ChildNodes)
{
if (desNode.Name == "source")
continue;
foreach (XmlNode inputNode in desNode.ChildNodes)
{
if (inputNode.Name == "input")
{
string inputNodeSemantic = inputNode.Attributes["semantic"].Value;
if (inputNodeSemantic == semantic)
{
return inputNode.Attributes["source"].Value;
}
}
}
}
return null;
}
private string GetSourceNodeID(XPathNodeIterator meshNode, string semantic)
{
XPathNodeIterator sourceNode = meshNode.Current.SelectChildren( XPathNodeType.Element);
if (sourceNode.Count == 0)
throw new Exception("無法獲得節點library_geometries/geometry/mesh/source節點");
while(sourceNode.MoveNext())
{
if (sourceNode.Current.Name == "source")
continue;
XPathNodeIterator inputNode = sourceNode.Current.SelectChildren("input", sourceNode.Current.NamespaceURI);
if (inputNode.Count == 0)
throw new Exception("無法獲得節點library_geometries/geometry/mesh/source/input節點");
while (inputNode.MoveNext())
{
string inputNodeSemantic = inputNode.Current.GetAttribute("semantic", "");
if (inputNodeSemantic == semantic)
{
return inputNode.Current.GetAttribute("source", "");
}
}
}
return null;
}
private void TransformVertical(Matrix matrix)
{
for (int i = 0; i < Vertices.Length; i++)
{
Vector4 v = new Vector4(Vertices[i].X, Vertices[i].Y, Vertices[i].Z, 1);
float x = matrix.M11 * v.X + matrix.M12 * v.Y + matrix.M13 * v.Z + matrix.M14 * v.W;
float y = matrix.M21 * v.X + matrix.M22 * v.Y + matrix.M23 * v.Z + matrix.M24 * v.W;
float z = matrix.M31 * v.X + matrix.M32 * v.Y + matrix.M33 * v.Z + matrix.M34 * v.W;
Vertices[i] = new Vector3(x, y, z);
}
}
#endregion
#region 加載模型頂點序列
/// <summary>
/// 加載地理源數據
/// </summary>
/// <param name="meshNode"></param>
/// <param name="sourceName"></param>
/// <returns></returns>
private Vector3[] LoadColladaGeometrySource(XmlNode meshNode, string semantic)
{
XmlNode sourceItemElement = null;
string sourceID = GetSourceNodeID(meshNode, semantic);
if (sourceID == null)
return null;
foreach (XmlNode sourceNode in meshNode.ChildNodes)
{
if (sourceNode.Name == "source"
&& "#" + sourceNode.Attributes["id"].Value == sourceID)
{
sourceItemElement = sourceNode;
break;
}
}
if (sourceItemElement == null)
return null;
int vertCount = int.Parse(sourceItemElement["float_array"].Attributes["count"].Value);
int demPerVertex = int.Parse(sourceItemElement["technique_common"]["accessor"].Attributes["stride"].Value);
//navigate to vertex
XmlNode vertexArrayElement = sourceItemElement["float_array"];
string tStr = vertexArrayElement.InnerText.Trim();
return ParseVector3(tStr, vertCount, demPerVertex);
}
/// <summary>
/// 加載地理源數據
/// </summary>
/// <param name="meshNode"></param>
/// <param name="sourceName"></param>
/// <returns></returns>
private Vector3[] LoadColladaGeometrySource(XPathNodeIterator meshNode, string semantic)
{
XPathNodeIterator sourceItemElement = meshNode.Current.SelectChildren("source", meshNode.Current.NamespaceURI);
string sourceID = GetSourceNodeID(meshNode, semantic);
if (sourceID == null)
return null;
while(sourceItemElement.MoveNext())
{
string idStr = sourceItemElement.Current.GetAttribute("id", "");
if( "#" + idStr == sourceID)
{
break;
}
}
if (sourceItemElement == null)
return null;
int vertCount = int.Parse(
WorldWind.Aide.XmlGetHelper.GetAttribute(sourceItemElement,
new string[] { "float_array" }, "count"));
int demPerVertex = int.Parse(
WorldWind.Aide.XmlGetHelper.GetAttribute(sourceItemElement,
new string[] { "technique_common","accessor" }, "stride"));
string vertStr = WorldWind.Aide.XmlGetHelper.GetInnerText(sourceItemElement, new string[] { "float_array" }).Trim();
return ParseVector3(vertStr, vertCount, demPerVertex);
}
/// <summary>
/// 解析字符串到Vector3
/// </summary>
/// <param name="vertStr"></param>
/// <param name="vertCount"></param>
/// <param name="demPerVertex"></param>
/// <returns></returns>
private Vector3[] ParseVector3(string vertStr, int vertCount, int demPerVertex)
{
//navigate to vertex
Vector3[] vert = new Vector3[vertCount / demPerVertex];
string[] texCoordPart = vertStr.Split(' ');
int count = vertCount / demPerVertex;
int numPartPerItem = demPerVertex;
for (int i = 0; i < count; i++)
{
vert[i].X = float.Parse(texCoordPart[i * numPartPerItem + 0]);
vert[i].Y = float.Parse(texCoordPart[i * numPartPerItem + 1]);
//support 3 texCoords per vertex
if (numPartPerItem > 2)
{
vert[i].Z = float.Parse(texCoordPart[i * numPartPerItem + 2]);
}
else
vert[i].Z = 0;
}
return vert;
}
/// <summary>
/// 加載索引表
/// </summary>
/// <param name="meshNode"></param>
/// <param name="nodeName">默認爲Polylist</param>
/// <returns></returns>
private int[] LoadColladaGeometryPolylist(XmlNode meshNode, string nodeName)
{
XmlNode polylistNode = meshNode[nodeName];
XmlNode dataElement = polylistNode["p"];
int verticesPerFace = 3;
int referenceCount = int.Parse(polylistNode.Attributes["count"].Value);
string rStr = dataElement.InnerText.Trim();
return ParseIntArray(rStr, referenceCount, verticesPerFace);
}
/// <summary>
/// 加載索引表
/// </summary>
/// <param name="meshNode"></param>
/// <param name="nodeName">默認爲Polylist</param>
/// <returns></returns>
private int[] LoadColladaGeometryPolylist(XPathNodeIterator meshNode, string nodeName)
{
XPathNodeIterator polylistNode = WorldWind.Aide.XmlGetHelper.MoveToChild(meshNode, new string[] { nodeName });
XPathNodeIterator dataElement = WorldWind.Aide.XmlGetHelper.MoveToChild(polylistNode, new string[] {"p" });
string rStr = dataElement.Current.Value;
int verticesPerFace = 3;
int referenceCount = int.Parse(polylistNode.Current.GetAttribute("count", ""));
return ParseIntArray(rStr, referenceCount, verticesPerFace);
}
private int[] ParseIntArray(string rStr, int referenceCount, int verticesPerFace)
{
string[] refPart = rStr.Split(' '); // Splits spaces between words in st
int[] vertexReferenceArray = new int[referenceCount * verticesPerFace];
for (int i = 0; i < vertexReferenceArray.Length; i++)
{
vertexReferenceArray[i] = int.Parse(refPart[i]); //for vertices
}
return vertexReferenceArray;
}
#endregion
#region 獲得基於triangles類型的頂點索引
private void LoadColladaTriangles(XmlNode trianglesNode)
{
int count = int.Parse(trianglesNode.Attributes["count"].Value);
int inputCount = trianglesNode.ChildNodes.Count - 1;//input的個數
string rStr = trianglesNode.InnerText.Trim();
string[] refPart = rStr.Split(' ');
int[] vertexReferenceArray = new int[refPart.Length];
if (refPart.Length != count * inputCount * 3)
throw new Exception("LoadColladaTriangles計算錯誤");
for (int i = 0; i < refPart.Length; i++)
vertexReferenceArray[i] = int.Parse(refPart[i]);
foreach (XmlNode inputNode in trianglesNode.ChildNodes)
{
if (inputNode.Name != "input")
continue;
string semantic = inputNode.Attributes["semantic"].Value;
int offset = int.Parse(inputNode.Attributes["offset"].Value);
switch (semantic)
{
case "VERTEX":
LoadColladaTriangleIndices(vertexReferenceArray, offset, inputCount);
break;
case "TEXCOORD":
AdjuestColladaTriangleTexcoordValue(vertexReferenceArray, offset, inputCount);
break;
}
}
}
private void LoadColladaTriangles(XPathNodeIterator trianglesNode)
{
int count = int.Parse(trianglesNode.Current.GetAttribute("count", ""));
XPathNodeIterator inputNode = trianglesNode.Current.SelectChildren("input", trianglesNode.Current.NamespaceURI);
int inputCount = inputNode.Count;//input的個數
string rStr = trianglesNode.Current.Value.Trim();
string[] refPart = rStr.Split(' ');
int[] vertexReferenceArray = new int[refPart.Length];
if (refPart.Length != count * inputCount * 3)
throw new Exception("LoadColladaTriangles計算錯誤");
for (int i = 0; i < refPart.Length; i++)
vertexReferenceArray[i] = int.Parse(refPart[i]);
while(inputNode.MoveNext())
{
string semantic = inputNode.Current.GetAttribute("semantic", "");
int offset = int.Parse(inputNode.Current.GetAttribute("offset", ""));
switch (semantic)
{
case "VERTEX":
LoadColladaTriangleIndices(vertexReferenceArray, offset, inputCount);
break;
case "TEXCOORD":
AdjuestColladaTriangleTexcoordValue(vertexReferenceArray, offset, inputCount);
break;
}
}
}
/// <summary>
/// 加載基於Triangle的索引
/// </summary>
/// <param name="vertexReferenceArray"></param>
/// <param name="offset"></param>
/// <param name="numPerSeg"></param>
private void LoadColladaTriangleIndices(int[] vertexReferenceArray,int offset,int numPerSeg)
{
Indices = new int[vertexReferenceArray.Length/numPerSeg];
for (int i = 0; i < Indices.Length; i++)
{
Indices[i] = vertexReferenceArray[numPerSeg * i + offset];
}
}
/// <summary>
/// 調整Textcoord的位置
/// </summary>
/// <param name="vertexReferenceArray"></param>
/// <param name="offset"></param>
/// <param name="numPerSeg"></param>
private void AdjuestColladaTriangleTexcoordValue(int[] vertexReferenceArray, int offset, int numPerSeg)
{
//不能理解
}
#endregion
}
/// <summary>
/// 場景空間信息
/// </summary>
public class ColladaVisualSceneNodeGeometry
{
#region 屬性
private string m_matrial;
private string m_url;
#endregion
#region 對外屬性
public ColladaGeometry GeometryInfo;
public ColladaMatrial MatrialInfo;
#endregion
#region 構造函數
public ColladaVisualSceneNodeGeometry(XmlNode colladaNode, XmlNode instanceGeometryNode,Matrix matrix)
{
m_url = instanceGeometryNode.Attributes["url"].Value;
m_matrial = instanceGeometryNode["bind_material"]["technique_common"]["instance_material"].Attributes["target"].Value;
LoadGeometryInfo(colladaNode["library_geometries"], matrix);
LoadMatrialInfo(colladaNode, colladaNode["library_materials"]);
}
public ColladaVisualSceneNodeGeometry(XPathNodeIterator colladaNode, XPathNodeIterator instanceGeometryNode, Matrix matrix)
{
m_url = instanceGeometryNode.Current.GetAttribute("url", "");
m_matrial=WorldWind.Aide.XmlGetHelper.GetAttribute(instanceGeometryNode,new string[]{
"bind_material","technique_common","instance_material"},"target");
//XPathNodeIterator matrialNode = WorldWind.Aide.XmlGetHelper.MoveToChild(instanceGeometryNode,
// new string[] { "bind_material", "technique_common", "instance_material" });
//if (matrialNode == null)
// throw new Exception("不能獲得instanceGeometry/bind_material/technique_common/instance_material節點的數據");
XPathNodeIterator geometryNodes = WorldWind.Aide.XmlGetHelper.MoveToChild(colladaNode, new string[] { "library_geometries" });
if (geometryNodes==null)
throw new Exception("無法獲得collada/library_geometries的節點");
LoadGeometryInfo(geometryNodes, matrix);
XPathNodeIterator materialNodes = WorldWind.Aide.XmlGetHelper.MoveToChild(colladaNode, new string[] { "library_materials" });
if(materialNodes==null)
throw new Exception("無法獲得collada/library_materials的節點");
LoadMatrialInfo(colladaNode, materialNodes);
}
#endregion
#region 加載其他信息
private void LoadGeometryInfo(XmlNode geometryNodes, Matrix matrix)
{
foreach (XmlNode geometryNode in geometryNodes)
{
if ("#" + geometryNode.Attributes["id"].Value == m_url)
{
GeometryInfo = new ColladaGeometry(geometryNode, matrix);
break;
}
}
}
private void LoadGeometryInfo(XPathNodeIterator geometryNodes, Matrix matrix)
{
XPathNodeIterator geometryNode = geometryNodes.Current.SelectChildren("geometry", geometryNodes.Current.NamespaceURI);
if (geometryNode.Count == 0)
throw new Exception("無法獲得library_geometries/geometry節點");
while (geometryNode.MoveNext())
{
string idStr = geometryNode.Current.GetAttribute("id", "");
if ("#" + idStr == m_url)
{
GeometryInfo = new ColladaGeometry(geometryNode, matrix);
break;
}
}
}
private void LoadMatrialInfo(XmlNode colladaNode, XmlNode materialNodes)
{
foreach (XmlNode materialNode in materialNodes)
{
if ("#" + materialNode.Attributes["id"].Value == m_matrial)
{
MatrialInfo = new ColladaMatrial(colladaNode, materialNode);
break;
}
}
}
private void LoadMatrialInfo(XPathNodeIterator colladaNode, XPathNodeIterator materialNodes)
{
XPathNodeIterator materialNode = materialNodes.Current.SelectChildren("material", materialNodes.Current.NamespaceURI);
if (materialNode.Count == 0)
throw new Exception("無法獲得library_materials/material節點");
while (materialNode.MoveNext())
{
string idStr = materialNode.Current.GetAttribute("id", "");
if ("#" + idStr == m_matrial)
{
MatrialInfo = new ColladaMatrial(colladaNode, materialNode);
break;
}
}
}
#endregion
}
/// <summary>
/// 場景節點
/// </summary>
public class ColladaVisualSceneNode:IDisposable
{
#region 屬性
private bool m_disposed = false;
private SupperMesh m_meshObject;
#endregion
#region 對外屬性
public string ID;
/// <summary>
/// 模型對象
/// </summary>
public SupperMesh MeshObject
{
get { return m_meshObject; }
}
///// <summary>
///// 當前節點的模型
///// </summary>
//public Mesh MeshObject
//{
// get
// {
// return m_meshObject;
// }
//}
///// <summary>
///// 當前節點的材質信息
///// </summary>
//public ExtendedMaterial[] ExtentdMatrials
//{
// get { return m_extentdMatrials; }
//}
/// <summary>
/// 是否被卸載了
/// </summary>
public bool Disposed
{
get { return m_disposed; }
}
#endregion
#region 構造函數
public ColladaVisualSceneNode(XPathNodeIterator colladaNode, XPathNodeIterator sceneNodeNode, Device device)
{
ID = sceneNodeNode.Current.GetAttribute("id", "");
List<ColladaVisualSceneNodeGeometry> nodeGeometries = new List<ColladaVisualSceneNodeGeometry>();
LoadColladaSubsitMesh(colladaNode, sceneNodeNode, device, nodeGeometries, Matrix.Identity);
UpAxisEnum upAxis = GetUpAxis(colladaNode);
//BuildMesh(nodeGeometries, device, upAxis);
GenerateMeshObject(nodeGeometries, upAxis, device);
}
public ColladaVisualSceneNode(XmlNode colladaNode, XmlNode sceneNodeNode, Device device)
{
ID = sceneNodeNode.Attributes["id"].Value;
List<ColladaVisualSceneNodeGeometry> nodeGeometries = new List<ColladaVisualSceneNodeGeometry>();
LoadColladaSubsitMesh(colladaNode, sceneNodeNode, device, nodeGeometries, Matrix.Identity);
UpAxisEnum upAxis = GetUpAxis(colladaNode);
GenerateMeshObject(nodeGeometries, upAxis, device);
}
/// <summary>
/// 生成模型
/// </summary>
/// <param name="nodeGeometries"></param>
/// <param name="upAxis"></param>
/// <param name="device"></param>
private void GenerateMeshObject(List<ColladaVisualSceneNodeGeometry> nodeGeometries, UpAxisEnum upAxis, Device device)
{
//BuildMesh(nodeGeometries, device, upAxis);
Mesh[] meshes = new Mesh[nodeGeometries.Count];
ExtendedMatrialArray[] matrials = new ExtendedMatrialArray[nodeGeometries.Count];
for (int i = 0; i < nodeGeometries.Count; i++)
{
ExtendedMaterial[] matrial;
BildMesh(nodeGeometries[i], device, upAxis, out meshes[i], out matrial);
matrials[i] = new ExtendedMatrialArray(matrial);
}
m_meshObject = new SupperMesh(meshes, matrials);
}
#endregion
#region 獲得模型子集
private void LoadColladaSubsitMesh(XmlNode colladaNode,
XmlNode sceneNodeNode,
Device device,
List<ColladaVisualSceneNodeGeometry> nodeGeometries,
Matrix matrix)
{
//這裏
if (sceneNodeNode["instance_geometry"] != null &&
sceneNodeNode["node"] != null)
{
throw new Exception("系統暫不能理解既存在instance_geometry又存在node的場景節點");
}
if (sceneNodeNode["instance_geometry"] != null)
{
//Node下面多個instance_geometry
foreach (XmlNode geometryNode in sceneNodeNode.ChildNodes)
{
if (geometryNode.Name == "instance_geometry")
{
nodeGeometries.Add(new ColladaVisualSceneNodeGeometry(colladaNode, geometryNode, matrix));
}
}
}
else if (sceneNodeNode["node"] != null)
{
//Node下面有Matrix
Matrix m = LoadColladaNodeMatrix(sceneNodeNode["node"]["matrix"]);
m = m * matrix;
//Node下面有很多個Node
foreach (XmlNode childNode in sceneNodeNode.ChildNodes)
{
if (childNode.Name == "node")
{
LoadColladaSubsitMesh(colladaNode, childNode, device, nodeGeometries, m);
}
}
}
else
{
throw new Exception("系統暫不能理解場景節點既不存在instance_geometry又不存在node的場景節點");
}
}
private void LoadColladaSubsitMesh(
XPathNodeIterator colladaNode,
XPathNodeIterator sceneNodeNode,
Device device,
List<ColladaVisualSceneNodeGeometry> nodeGeometries,
Matrix matrix)
{
//這裏
XPathNodeIterator instance_geometryNode = sceneNodeNode.Current.SelectChildren("instance_geometry", sceneNodeNode.Current.NamespaceURI);
XPathNodeIterator nodeNode = sceneNodeNode.Current.SelectChildren("node", sceneNodeNode.Current.NamespaceURI);
if (instance_geometryNode.Count==0 &&
nodeNode.Count==0)
{
//throw new Exception("系統暫不能理解既存在instance_geometry又存在node的場景節點");
}
if (instance_geometryNode.Count != 0)
{
//Node下面多個instance_geometry
while (instance_geometryNode.MoveNext())
{
nodeGeometries.Add(new ColladaVisualSceneNodeGeometry(colladaNode, instance_geometryNode, matrix));
}
}
else if (nodeNode.Count != 0)
{
//Node下面有Matrix
XPathNodeIterator matrixIter = WorldWind.Aide.XmlGetHelper.MoveToChild(sceneNodeNode, new string[] { "node", "matrix" });
Matrix m = LoadColladaNodeMatrix(matrixIter);
m = m * matrix;
//Node下面有很多個Node
XPathNodeIterator nodeIter = sceneNodeNode.Current.SelectChildren("node", sceneNodeNode.Current.NamespaceURI);
if (nodeIter.Count == 0)
throw new Exception("無法獲得visual_scene/node/node節點");
while (nodeIter.MoveNext())
{
LoadColladaSubsitMesh(colladaNode, nodeIter, device, nodeGeometries, m);
}
}
else
{
throw new Exception("系統暫不能理解場景節點既存在instance_geometry又存在node的場景節點");
}
}
#endregion
#region 矩陣
private Matrix LoadColladaNodeMatrix(XmlNode matrixNode)
{
if (matrixNode == null)
return Matrix.Identity;
string matrixStr = matrixNode.InnerText;
return LoadColladaNodeMatrix(matrixStr);
}
private Matrix LoadColladaNodeMatrix(XPathNodeIterator matrixNode)
{
if (matrixNode == null)
return Matrix.Identity;
string matrixStr = matrixNode.Current.Value;
return LoadColladaNodeMatrix(matrixStr);
}
private Matrix LoadColladaNodeMatrix(string matrixStr)
{
string[] mValues = matrixStr.Trim().Split(' ');
if (mValues.Length != 16)
throw new Exception("COLLADA 矩陣不爲16個子");
float[] mValueFs = new float[16];
for (int i = 0; i < 16; i++)
{
mValueFs[i] = float.Parse(mValues[i]);
}
Matrix m = new Matrix();
m.M11 = mValueFs[0]; m.M12 = mValueFs[1]; m.M13 = mValueFs[2]; m.M14 = mValueFs[3];
m.M21 = mValueFs[0 + 4]; m.M22 = mValueFs[1 + 4]; m.M23 = mValueFs[2 + 4]; m.M24 = mValueFs[3 + 4];
m.M31 = mValueFs[0 + 8]; m.M32 = mValueFs[1 + 8]; m.M33 = mValueFs[2 + 8]; m.M34 = mValueFs[3 + 8];
m.M41 = mValueFs[0 + 12]; m.M42 = mValueFs[1 + 12]; m.M43 = mValueFs[2 + 12]; m.M44 = mValueFs[3 + 12];
return m;
}
#endregion
#region 構建模型
/// <summary>
/// 構建模型
/// </summary>
/// <param name="nodeGeometries"></param>
/// <param name="device"></param>
/// <param name="upAixs"></param>
//private void BuildMesh(List<ColladaVisualSceneNodeGeometry> nodeGeometries, Device device,UpAxisEnum upAixs)
//{
// int numberFace = 0;
// int numVerticel = 0;
// foreach (ColladaVisualSceneNodeGeometry item in nodeGeometries)
// {
// numberFace += item.GeometryInfo.Indices.Length / 3;
// numVerticel += item.GeometryInfo.Vertices.Length;
// }
// Mesh mesh = new Mesh(numberFace, numVerticel, MeshFlags.Managed, CustomVertex.PositionNormalTextured.Format, device);
// CustomVertex.PositionNormalTextured[] vertices =
// new CustomVertex.PositionNormalTextured[numVerticel];
// int index = 0;
// foreach (ColladaVisualSceneNodeGeometry item in nodeGeometries)
// {
// for (int j = 0; j < item.GeometryInfo.Vertices.Length; j++)
// {
// Vector3 vertex = item.GeometryInfo.Vertices[j];
// if (upAixs == UpAxisEnum.Z_UP)
// vertex = new Vector3(item.GeometryInfo.Vertices[j].X,
// item.GeometryInfo.Vertices[j].Z,
// item.GeometryInfo.Vertices[j].Y);
// vertices[index] = new CustomVertex.PositionNormalTextured(
// vertex,
// item.GeometryInfo.Normals[j],
// item.GeometryInfo.Texcoords[j].X,
// 1-item.GeometryInfo.Texcoords[j].Y);
// index++;
// }
// }
// int[] indices;
// int maxIndicesValue;
// GetIndices(nodeGeometries, numberFace, out indices, out maxIndicesValue);
// AttributeRange[] attrRange = new AttributeRange[nodeGeometries.Count];
// index = 0;
// int sumFace = 0;
// int sumVerticel = 0;
// foreach (ColladaVisualSceneNodeGeometry item in nodeGeometries)
// {
// attrRange[index] = new AttributeRange();
// attrRange[index].AttributeId = index;
// attrRange[index].FaceCount = item.GeometryInfo.Indices.Length / 3;
// attrRange[index].FaceStart = sumFace;
// attrRange[index].VertexCount = item.GeometryInfo.Vertices.Length;
// attrRange[index].VertexStart = sumVerticel;
// sumFace += attrRange[index].FaceCount;
// sumVerticel += attrRange[index].VertexCount;
// index++;
// }
// mesh.SetVertexBufferData(vertices, LockFlags.None);
// if (maxIndicesValue > short.MaxValue)
// {
// mesh.SetIndexBufferData(indices, LockFlags.None);
// }
// else
// {
// short[] sIndices = new short[indices.Length];
// for (int i = 0; i < indices.Length; i++)
// {
// sIndices[i] =(short)indices[i];
// }
// mesh.SetIndexBufferData(sIndices, LockFlags.None);
// }
// int[] adjacency = new int[mesh.NumberFaces * 3];
// mesh.GenerateAdjacency(0f, adjacency);
// mesh.OptimizeInPlace(MeshFlags.OptimizeAttributeSort, adjacency);
// mesh.ComputeNormals();
// mesh.SetAttributeTable(attrRange);
// m_meshObject= mesh;
// m_extentdMatrials = new ExtendedMaterial[nodeGeometries.Count];
// index = 0;
// foreach (ColladaVisualSceneNodeGeometry item in nodeGeometries)
// {
// ExtentdMatrials[index] = new ExtendedMaterial();
// ExtentdMatrials[index].TextureFilename =
// item.MatrialInfo.EffectInfo.Profile_COMMON.ImageInfo.TextureFileName_Init_from;
// index++;
// }
//}
private void BildMesh(ColladaVisualSceneNodeGeometry nodeGeometry, Device device,
UpAxisEnum upAixs, out Mesh mesh, out ExtendedMaterial[] matrials)
{
int numberFace = 0;
int numVerticel = 0;
numberFace = nodeGeometry.GeometryInfo.Indices.Length / 3;
numVerticel = nodeGeometry.GeometryInfo.Vertices.Length;
mesh = new Mesh(numberFace, numVerticel, MeshFlags.Managed, CustomVertex.PositionNormalTextured.Format, device);
CustomVertex.PositionNormalTextured[] vertices =
new CustomVertex.PositionNormalTextured[numVerticel];
for (int j = 0; j < nodeGeometry.GeometryInfo.Vertices.Length; j++)
{
Vector3 vertex = nodeGeometry.GeometryInfo.Vertices[j];
if (upAixs == UpAxisEnum.Z_UP)
vertex = new Vector3(nodeGeometry.GeometryInfo.Vertices[j].X,
nodeGeometry.GeometryInfo.Vertices[j].Z,
nodeGeometry.GeometryInfo.Vertices[j].Y);
vertices[j] = new CustomVertex.PositionNormalTextured(
vertex,
nodeGeometry.GeometryInfo.Normals[j],
nodeGeometry.GeometryInfo.Texcoords[j].X,
1 - nodeGeometry.GeometryInfo.Texcoords[j].Y);
}
short[] indices = new short[numberFace * 3];
for (int j = 0; j < nodeGeometry.GeometryInfo.Indices.Length; j++)
{
indices[j] = (short)nodeGeometry.GeometryInfo.Indices[j];
}
AttributeRange[] attrRange = new AttributeRange[1];
attrRange[0] = new AttributeRange();
attrRange[0].AttributeId = 0;
attrRange[0].FaceCount = nodeGeometry.GeometryInfo.Indices.Length / 3;
attrRange[0].FaceStart = 0;
attrRange[0].VertexCount = nodeGeometry.GeometryInfo.Vertices.Length;
attrRange[0].VertexStart = 0;
mesh.SetVertexBufferData(vertices, LockFlags.None);
mesh.SetIndexBufferData(indices, LockFlags.None);
int[] adjacency = new int[mesh.NumberFaces * 3];
mesh.GenerateAdjacency(0f, adjacency);
mesh.OptimizeInPlace(MeshFlags.OptimizeAttributeSort, adjacency);
mesh.ComputeNormals();
mesh.SetAttributeTable(attrRange);
matrials = new ExtendedMaterial[1];
matrials[0] = new ExtendedMaterial();
matrials[0].TextureFilename =
nodeGeometry.MatrialInfo.EffectInfo.Profile_COMMON.ImageInfo.TextureFileName_Init_from;
}
/// <summary>
/// 獲得軸信息
/// </summary>
/// <param name="colladaNode"></param>
/// <returns></returns>
private UpAxisEnum GetUpAxis(XmlNode colladaNode)
{
string upAxisStr = colladaNode["asset"]["up_axis"].InnerText.ToUpper();
switch (upAxisStr)
{
case "Z_UP":
return UpAxisEnum.Z_UP;
case "Y_UP":
return UpAxisEnum.Y_UP;
default:
throw new Exception("未知的向上軸方向");
}
}
/// <summary>
/// 獲得軸信息
/// </summary>
/// <param name="colladaNode"></param>
/// <returns></returns>
private UpAxisEnum GetUpAxis(XPathNodeIterator colladaNode)
{
string upAxisStr = WorldWind.Aide.XmlGetHelper.GetInnerText(colladaNode, new string[] { "asset", "up_axis" });
switch (upAxisStr)
{
case "Z_UP":
return UpAxisEnum.Z_UP;
case "Y_UP":
return UpAxisEnum.Y_UP;
default:
throw new Exception("未知的向上軸方向");
}
}
/// <summary>
/// 獲得最大的模型Index
/// </summary>
/// <param name="nodeGeometries"></param>
/// <returns></returns>
private void GetIndices(List<ColladaVisualSceneNodeGeometry> nodeGeometries,int numberFace,out int[] indices,out int maxIndicesValue)
{
maxIndicesValue = 0;
indices = new int[numberFace * 3];
int index = 0;
int sumIndiceCount = 0;
foreach (ColladaVisualSceneNodeGeometry item in nodeGeometries)
{
for (int j = 0; j < item.GeometryInfo.Indices.Length; j++)
{
indices[index] = item.GeometryInfo.Indices[j] + sumIndiceCount;
if (indices[index] > maxIndicesValue)
maxIndicesValue = indices[index];
index++;
}
sumIndiceCount += item.GeometryInfo.Indices.Length;
}
}
#endregion
#region 軸信息
enum UpAxisEnum
{
Z_UP,
Y_UP
}
#endregion
#region 卸載
/// <summary>
/// 卸載
/// </summary>
public void Dispose()
{
if (Disposed)
return;
if (MeshObject != null)
{
MeshObject.Dispose();
}
m_disposed = true;
}
#endregion
}
/// <summary>
/// 一個場景模式
/// <para>它包含一個場景節點(ColladaVisualSceneNode)</para>
/// </summary>
public class ColladaVisualScene : IDisposable
{
#region 屬性
private bool m_disposed = false;
private ColladaVisualSceneNode m_sceneNode;
#endregion
#region 對外屬性
public string ID;
/// <summary>
/// 是否被卸載了
/// </summary>
public bool Disposed
{
get { return m_disposed; }
}
/// <summary>
/// 場景節點
/// </summary>
public ColladaVisualSceneNode SceneNode
{
get { return m_sceneNode; }
}
#endregion
#region 構造函數
public ColladaVisualScene(XmlNode colladaNode, XmlNode visualSceneNode, Device device)
{
ID = visualSceneNode.Attributes["id"].Value;
m_sceneNode = new ColladaVisualSceneNode(colladaNode, visualSceneNode["node"], device);
}
public ColladaVisualScene(XPathNodeIterator colladaNode, XPathNodeIterator visualSceneNode, Device device)
{
ID = visualSceneNode.Current.GetAttribute("id", "");
XPathNodeIterator nodeIter = visualSceneNode.Current.SelectChildren("node", visualSceneNode.Current.NamespaceURI);
if (nodeIter.MoveNext() == false)
throw new Exception("無法展開visualSceneNode/Node節點");
m_sceneNode = new ColladaVisualSceneNode(colladaNode, nodeIter, device);
}
#endregion
#region 卸載
/// <summary>
/// 卸載
/// </summary>
public void Dispose()
{
if (Disposed)
return;
SceneNode.Dispose();
m_disposed = true;
}
#endregion
}
/// <summary>
/// 當前場景
/// <para>它選擇一個場景模式(ColladaVisualScene)</para>
/// </summary>
public class ColladaScene:IDisposable
{
#region 屬性
private bool m_disposed = false;
private string m_url;
private ColladaVisualScene m_visualScene;
#endregion
#region 對外屬性
public ColladaVisualScene VisualScene
{
get { return m_visualScene; }
}
/// <summary>
/// 是否被卸載了
/// </summary>
public bool Disposed
{
get { return m_disposed; }
}
#endregion
#region 構造函數
public ColladaScene(XmlNode colladaNode, Device device)
{
m_url = colladaNode["scene"]["instance_visual_scene"].Attributes["url"].Value;
XmlNode visualSceneNode = colladaNode["library_visual_scenes"];
foreach (XmlNode node in visualSceneNode.ChildNodes)
{
if ("#" + node.Attributes["id"].Value == m_url)
{
m_visualScene = new ColladaVisualScene(colladaNode, node, device);
break;
}
}
}
/// <summary>
/// 從XMl中加載
/// </summary>
/// <param name="colladaItor"></param>
public ColladaScene(XPathNodeIterator colladaItor, Device device)
{
XPathNodeIterator instance_visual_sceneNode =
WorldWind.Aide.XmlGetHelper.MoveToChild(colladaItor, new string[] { "scene", "instance_visual_scene" });
if (instance_visual_sceneNode == null)
throw new Exception("無法獲得scene/instance_visual_scene節點");
m_url = instance_visual_sceneNode.Current.GetAttribute("url", "");
XPathNodeIterator visual_sceneNode =
WorldWind.Aide.XmlGetHelper.MoveToChild(colladaItor, new string[] { "library_visual_scenes", "visual_scene" });
if (visual_sceneNode == null)
throw new Exception("無法獲得library_visual_scenes/visual_scene節點");
while (true)
{
string idStr = visual_sceneNode.Current.GetAttribute("id", "");
if ("#" + idStr == m_url)
{
m_visualScene = new ColladaVisualScene(colladaItor, visual_sceneNode, device);
break;
}
if (visual_sceneNode.MoveNext() == false)
break;
}
if (m_visualScene == null)
throw new Exception("無法生成ColladaVisualScene數據");
}
#endregion
#region 卸載
/// <summary>
/// 卸載
/// </summary>
public void Dispose()
{
if (Disposed)
return;
m_visualScene.Dispose();
m_disposed = true;
}
#endregion
}
#endregion
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.