private AABB_s GetAABB2(YmapEntityDef ent) { var arch = ent.Archetype; var ori = ent.Orientation; var pos = ent.Position; var sca = ent.Scale; var mat = Matrix.Transformation(Vector3.Zero, Quaternion.Identity, sca, Vector3.Zero, ori, pos); var matabs = mat; matabs.Column1 = mat.Column1.Abs(); matabs.Column2 = mat.Column2.Abs(); matabs.Column3 = mat.Column3.Abs(); matabs.Column4 = mat.Column4.Abs(); Vector3 bbmin = pos - ent.BSRadius; //sphere Vector3 bbmax = pos + ent.BSRadius; if (arch != null) { var bbcenter = (arch.BBMax + arch.BBMin) * 0.5f; var bbextent = (arch.BBMax - arch.BBMin) * 0.5f; var ncenter = Vector3.TransformCoordinate(bbcenter, mat); var nextent = Vector3.TransformNormal(bbextent, matabs); bbmin = ncenter - nextent; bbmax = ncenter + nextent; } AABB_s b = new AABB_s(); b.Min = new Vector4(bbmin, 0f); b.Max = new Vector4(bbmax, 0f); return(b); }
private AABB_s GetAABB(YmapEntityDef ent) { var arch = ent.Archetype; var ori = ent.Orientation; Vector3 bbmin = ent.Position - ent.BSRadius; //sphere Vector3 bbmax = ent.Position + ent.BSRadius; if (arch != null) { Vector3[] c = new Vector3[8]; Vector3 abmin = arch.BBMin * ent.Scale; //entity box Vector3 abmax = arch.BBMax * ent.Scale; c[0] = abmin; c[1] = new Vector3(abmin.X, abmin.Y, abmax.Z); c[2] = new Vector3(abmin.X, abmax.Y, abmin.Z); c[3] = new Vector3(abmin.X, abmax.Y, abmax.Z); c[4] = new Vector3(abmax.X, abmin.Y, abmin.Z); c[5] = new Vector3(abmax.X, abmin.Y, abmax.Z); c[6] = new Vector3(abmax.X, abmax.Y, abmin.Z); c[7] = abmax; bbmin = new Vector3(float.MaxValue); bbmax = new Vector3(float.MinValue); for (int j = 0; j < 8; j++) { Vector3 corn = ori.Multiply(c[j]) + ent.Position; bbmin = Vector3.Min(bbmin, corn); bbmax = Vector3.Max(bbmax, corn); } } AABB_s b = new AABB_s(); b.Min = new Vector4(bbmin, 0f); b.Max = new Vector4(bbmax, 0f); return(b); }
private DrawableGeometry TryConvertGeometry(List <FbxPolygon> fPolys, FbxNode matNode, out AABB_s aabb) { aabb = new AABB_s(); if (matNode == null) { return(null); } if (fPolys == null) { return(null); } if (fPolys.Count == 0) { return(null); } var dShader = TryConvertMaterial(matNode); var dVertDecl = GetVertexDeclaration(dShader); var vDict = new Dictionary <FbxVertex, ushort>(); var vList = new List <FbxVertex>(); var iList = new List <ushort>(); foreach (var fPoly in fPolys) { if (fPoly.Vertices == null) { continue; } if (vList.Count >= 65535) { break; //too many vertices in this geometry!! } ushort i0 = 0; //first generated index ushort iP = 0; //previous generated index ushort iN = 0; //current index for (int v = 0; v < fPoly.Vertices.Length; v++) { var vert = fPoly.Vertices[v]; vert.GenVertexBytes(dVertDecl); if (!vDict.TryGetValue(vert, out iN)) { iN = (ushort)vList.Count; vDict[vert] = iN; vList.Add(vert); } else { } //found identical vertex, use its index if (v == 0) { i0 = iN; } if (v < 3) //first triangle { iList.Add(iN); } else //for each extra vertex, make triangle from v0, vN-1, vN - assumes convex polygon!! { iList.Add(i0); iList.Add(iP); iList.Add(iN); } iP = iN; } } var vStride = dVertDecl.Stride; var vBytes = new byte[vList.Count * vStride]; for (int i = 0; i < vList.Count; i++) { var v = vList[i].Bytes; var o = i * vStride; for (int j = 0; j < vStride; j++) { vBytes[o + j] = v[j]; } } if (vList.Count > 0) { aabb.Min = new Vector4(float.MaxValue); aabb.Max = new Vector4(float.MinValue); foreach (var vert in vList) { var v = new Vector4(vert.Position, vert.Position.X); aabb.Min = Vector4.Min(aabb.Min, v); aabb.Max = Vector4.Max(aabb.Max, v); } } var vData = new VertexData(); vData.Info = dVertDecl; vData.VertexType = (VertexType)dVertDecl.Flags; vData.VertexStride = dVertDecl.Stride; vData.VertexCount = vList.Count; vData.VertexBytes = vBytes; var vBuff = new VertexBuffer(); vBuff.Data1 = vData; vBuff.Data2 = vData; vBuff.Info = dVertDecl; vBuff.VertexCount = (uint)vList.Count; vBuff.VertexStride = vStride; vBuff.VFT = 1080153064;//is this needed? vBuff.Unknown_4h = 1; var iBuff = new IndexBuffer(); iBuff.IndicesCount = (uint)iList.Count; iBuff.Indices = iList.ToArray(); iBuff.VFT = 1080111576;//is this needed? iBuff.Unknown_4h = 1; var dGeom = new DrawableGeometry(); dGeom.Shader = dShader; dGeom.VertexData = vData; dGeom.VertexBuffer = vBuff; dGeom.IndexBuffer = iBuff; dGeom.VFT = 1080133736;//is this needed? dGeom.Unknown_4h = 1; dGeom.IndicesCount = (uint)iList.Count; dGeom.TrianglesCount = (uint)iList.Count / 3; dGeom.VerticesCount = (ushort)vList.Count; dGeom.Unknown_62h = 3; //indices per triangle..? dGeom.VertexStride = vStride; dGeom.BoneIdsCount = 0; //todo: bones return(dGeom); }
private FbxModel TryConvertModel(FbxNode mnode) { FbxNode geonode = null; var matnodes = new List <FbxNode>(); foreach (var cnode in mnode.Connections) { if (cnode == null) { continue; } switch (cnode.Name) { case "Geometry": geonode = cnode; break; case "Material": matnodes.Add(cnode); break; } } if (geonode == null) { return(null); } if (matnodes.Count == 0) { return(null); //need atleast one material... } var fnEdges = geonode["Edges"]?.Value as int[]; //do we need this? maybe for collision/navmesh var fnVerts = geonode["Vertices"]?.Value as double[]; var fnIndices = geonode["PolygonVertexIndex"]?.Value as int[]; if ((fnVerts == null) || (fnIndices == null)) { return(null); } //no mesh data.. abort! var fnNormals = new List <FbxNode>(); var fnBinormals = new List <FbxNode>(); var fnTangents = new List <FbxNode>(); var fnTexcoords = new List <FbxNode>(); var fnColours = new List <FbxNode>(); var fnMaterials = new List <FbxNode>(); foreach (var cnode in geonode.Nodes) { if (cnode == null) { continue; } switch (cnode.Name) { case "LayerElementNormal": fnNormals.Add(cnode); break; case "LayerElementBinormal": fnBinormals.Add(cnode); break; case "LayerElementTangent": fnTangents.Add(cnode); break; case "LayerElementUV": fnTexcoords.Add(cnode); break; case "LayerElementColor": fnColours.Add(cnode); break; case "LayerElementMaterial": fnMaterials.Add(cnode); break; case "LayerElementSmoothing": break; //ignore currently case "Layer": break; //ignore- merge all layers data instead } } var nNormals = fnNormals.Count; var nBinormals = fnBinormals.Count; var nTangents = fnTangents.Count; var nTexcoords = fnTexcoords.Count; var nColours = fnColours.Count; var nMaterials = fnMaterials.Count; var fPolys = new List <FbxPolygon>(); var fPolyVerts = new List <FbxVertex>(); var fPolysByMat = new List <FbxPolygon> [matnodes.Count]; foreach (var fnIndex in fnIndices) //build the polygons. { var pVert = new FbxVertex(); pVert.Position = GetVector3FromDoubleArray(fnVerts, (fnIndex < 0) ? (-fnIndex - 1) : fnIndex); pVert.Normals = nNormals > 0 ? new Vector3[nNormals] : null; pVert.Binormals = nBinormals > 0 ? new Vector3[nBinormals] : null; pVert.Tangents = nTangents > 0 ? new Vector3[nTangents] : null; pVert.Texcoords = nTexcoords > 0 ? new Vector2[nTexcoords] : null; pVert.Colours = nColours > 0 ? new Vector4[nColours] : null; fPolyVerts.Add(pVert); if (fnIndex < 0) //yeah because negative index means end of polygon... { var fPoly = new FbxPolygon(); fPoly.Vertices = fPolyVerts.ToArray(); fPoly.Materials = nMaterials > 0 ? new FbxNode[nMaterials] : null; fPolyVerts.Clear(); fPolys.Add(fPoly); if (fPoly.Vertices.Length > 3) { } //more than 3 vertices in this poly! will need to split it into triangles!! but do it later since all poly verts are needed for next steps } } for (int i = 0; i < nNormals; i++) { var fnNorms = fnNormals[i]; var arNorms = fnNorms["Normals"]?.Value as double[]; var aiNorms = fnNorms["NormalIndex"]?.Value as int[]; if (!IsByPolygonVertexMapType(fnNorms)) { continue; } var indexed = IsIndexToDirectRefType(fnNorms); if (indexed && (aiNorms == null)) { continue; } //need the index array if it's IndexToDirect! int j = 0; foreach (var fPoly in fPolys) { foreach (var fVert in fPoly.Vertices) { var ai = indexed ? aiNorms[j] : j; fVert.Normals[i] = GetVector3FromDoubleArray(arNorms, ai); j++; } } } for (int i = 0; i < nBinormals; i++) { var fnBinorms = fnBinormals[i]; var arBinorms = fnBinorms["Binormals"]?.Value as double[]; var aiBinorms = fnBinorms["BinormalIndex"]?.Value as int[]; if (!IsByPolygonVertexMapType(fnBinorms)) { continue; } var indexed = IsIndexToDirectRefType(fnBinorms); if (indexed && (aiBinorms == null)) { continue; } //need the index array if it's IndexToDirect! int j = 0; foreach (var fPoly in fPolys) { foreach (var fVert in fPoly.Vertices) { var ai = indexed ? aiBinorms[j] : j; fVert.Binormals[i] = GetVector3FromDoubleArray(arBinorms, ai); j++; } } } for (int i = 0; i < nTangents; i++) { var fnTangs = fnTangents[i]; var arTangs = fnTangs["Tangents"]?.Value as double[]; var aiTangs = fnTangs["TangentIndex"]?.Value as int[]; if (!IsByPolygonVertexMapType(fnTangs)) { continue; } var indexed = IsIndexToDirectRefType(fnTangs); if (indexed && (aiTangs == null)) { continue; } //need the index array if it's IndexToDirect! int j = 0; foreach (var fPoly in fPolys) { foreach (var fVert in fPoly.Vertices) { var ai = indexed ? aiTangs[j] : j; fVert.Tangents[i] = GetVector3FromDoubleArray(arTangs, ai); j++; } } } for (int i = 0; i < nTexcoords; i++) { var fnTexcs = fnTexcoords[i]; var arTexcs = fnTexcs["UV"]?.Value as double[]; var aiTexcs = fnTexcs["UVIndex"]?.Value as int[]; if (!IsByPolygonVertexMapType(fnTexcs)) { continue; } var indexed = IsIndexToDirectRefType(fnTexcs); if (indexed && (aiTexcs == null)) { continue; } //need the index array if it's IndexToDirect! int j = 0; foreach (var fPoly in fPolys) { foreach (var fVert in fPoly.Vertices) { var ai = indexed ? aiTexcs[j] : j; var tc = GetVector2FromDoubleArray(arTexcs, ai); fVert.Texcoords[i] = InvertTexcoordV ? new Vector2(tc.X, -tc.Y) : tc;//whyyyy j++; } } } for (int i = 0; i < nColours; i++) { var fnCols = fnColours[i]; var arCols = fnCols["Colors"]?.Value as double[]; var aiCols = fnCols["ColorIndex"]?.Value as int[]; if (!IsByPolygonVertexMapType(fnCols)) { continue; } var indexed = IsIndexToDirectRefType(fnCols); if (indexed && (aiCols == null)) { continue; } //need the index array if it's IndexToDirect! int j = 0; foreach (var fPoly in fPolys) { foreach (var fVert in fPoly.Vertices) { var ai = indexed ? aiCols[j] : j; fVert.Colours[i] = GetVector4FromDoubleArray(arCols, ai); j++; } } } for (int i = 0; i < nMaterials; i++) { var fnMats = fnMaterials[i]; var arMats = fnMats["Materials"]?.Value as int[]; var mapType = fnMats["MappingInformationType"]?.Value as string; var refType = fnMats["ReferenceInformationType"]?.Value as string; var allSame = false; switch (mapType) { case "ByPolygon": break; case "AllSame": allSame = true; break; default: continue; } switch (refType) { case "IndexToDirect": break; default: continue; } for (int j = 0; j < fPolys.Count; j++) { var fPoly = fPolys[j]; var iMat = allSame ? arMats[0] : arMats[j]; fPoly.Materials[i] = matnodes[iMat]; //group all the polygons by material... var matPolys = fPolysByMat[iMat]; if (matPolys == null) { matPolys = new List <FbxPolygon>(); fPolysByMat[iMat] = matPolys; } matPolys.Add(fPoly); } } var dModel = new DrawableModel(); var dGeoms = new List <DrawableGeometry>(); var dGeomAABBs = new List <AABB_s>(); var dModelAABB = new AABB_s(); for (int i = 0; i < fPolysByMat.Length; i++) { AABB_s dGeomAABB; var dGeom = TryConvertGeometry(fPolysByMat[i], matnodes[i], out dGeomAABB); if (dGeom != null) { dGeoms.Add(dGeom); dGeomAABBs.Add(dGeomAABB); } } if (dGeomAABBs.Count > 1)//need to include whole model AABB first, if more than one geometry.. { var dGeomAABBs2 = new List <AABB_s>(); dModelAABB.Min = new Vector4(float.MaxValue); dModelAABB.Max = new Vector4(float.MinValue); foreach (var aabb in dGeomAABBs) { dModelAABB.Min = Vector4.Min(dModelAABB.Min, aabb.Min); dModelAABB.Max = Vector4.Max(dModelAABB.Max, aabb.Max); } dGeomAABBs2.Add(dModelAABB); dGeomAABBs2.AddRange(dGeomAABBs); dGeomAABBs = dGeomAABBs2; } dModel.VFT = 1080101496; //is this needed? dModel.Unknown_4h = 1; dModel.RenderMaskFlags = 0x00FF; //GIMS "Mask" dModel.Geometries = dGeoms.ToArray(); dModel.GeometriesCount1 = (ushort)dGeoms.Count; dModel.GeometriesCount2 = (ushort)dGeoms.Count; dModel.GeometriesCount3 = (ushort)dGeoms.Count; dModel.BoundsData = dGeomAABBs.ToArray(); //shader mappings array will be added when adding models to drawable. var fModel = new FbxModel(); fModel.Name = (mnode.Properties.Count > 1) ? (mnode.Properties[1] as string)?.Replace("Model::", "") : null; fModel.Node = mnode; fModel.Model = dModel; return(fModel); }