- Home /
Saving/Loading Vertices Efficiently
First, my problem.
Short story: I'm trying to efficiently save and load vertex positions of my mesh.
Long story: I would first like to state I know nothing about serialization even though I've tried to understand it. From what I have read and researched, it saves variables in methods/functions which does absolutely nothing for me (I think). I am currently using (many) loops to go through and get every x,y,and z position of each vertex in my meshes and store them in xml.
My game has a terrain system hopefully like Wurm Online (currently minus the caves), and so I have about 10,000 tiles (100 tiles per chunk, 100 chunks in the level) and 5 vertices per tile, in short, 50,000 variables.
Saving this all at once would be a massive burden on my multiplayer online game since it takes about 5-15 seconds to save (freezing unity editor). I haven't tested the loading method yet, but I'm sure it would burden my computer even more, as the save function is rough enough.
I'm looking for a much more efficient method to save this. If there isn't one, I understand, since I currently only have a Phenom II x2 560 Processor 3.30Ghz, that my computer just isn't powerful enough.
public void loadTerrainDatabase()
{
XmlDocument xmlDoc = fm.useXmlFile("Database","Terrain","xml",isDataEncrypted);
XmlNodeList chunkXmlList = xmlDoc.GetElementsByTagName("chunk");
Vector3 tempPos = Vector3.zero;
float adjustAmount = 0.0f;
foreach(XmlNode chunk in chunkXmlList)//for every chunk in the list
{
for(int i = 0; i < 100; i++)
{
if(chunk.Attributes["index"].Value == i.ToString()) //if found chunk i
{
XmlNodeList chunkInfoList = chunk.ChildNodes; //put chunk tiles in a list
foreach(XmlNode tile in chunkInfoList)//for every tile in the chunk
{
for(int j = 0; j < 100; j++) //used to go through each tile index value
{
if(tile.Attributes["index"].Value == j.ToString())//if the index's match
{
XmlNodeList tilePos = tile.ChildNodes;//put the tile position into a list
for(int k = 0; k < 5; k++)//goes through every vertex in the mesh
{
foreach(XmlNode axis in tilePos)
{
if(axis.Name == "x")//gets the x position
tempPos.x = int.Parse(axis.InnerText);
if(axis.Name == "y")//gets the y position
adjustAmount = int.Parse(axis.InnerText);
if(axis.Name == "z")//gets the z position
tempPos.z = int.Parse(axis.InnerText);
}
tm (i,j).changeMesh(tempPos, adjustAmount);//gets the vertex and changes the y pos only
}}}}}}}
}
public void saveTerrainDatabase()
{
XmlDocument xml = new XmlDocument();
XmlDeclaration xmlDecl;
xmlDecl = xml.CreateXmlDeclaration("1.0","UTF-8","yes");
xml.AppendChild(xmlDecl);
XmlElement rootElement = fm.createXmlElement(xml, "TerrainDatabase");
xml.AppendChild(rootElement);
for (int i = 0; i < 100; i++) //chunk loop
{
XmlElement chunkElement = fm.createXmlElement(xml, "chunk", null, "index", i.ToString());
Transform tempChunk = chunks[i];
for(int j = 0; j < 100; j++)
{
XmlElement tileElement = fm.createXmlElement(xml, "tile", null, "index", j.ToString());
Transform tempTile = tempChunk.GetComponent<chunkManager>().tiles[j];
for(int k = 0; k < 5; k++)
{
tileElement.AppendChild(fm.createXmlElement(xml, "x",getVertX(tempTile, k)));
tileElement.AppendChild(fm.createXmlElement(xml, "y",getVertY(tempTile, k)));
tileElement.AppendChild(fm.createXmlElement(xml, "z",getVertZ(tempTile, k)));
}
chunkElement.AppendChild(tileElement);
}
rootElement.AppendChild(chunkElement);
}
fm.updateFile("Database","Terrain","xml",xml.OuterXml,isDataEncrypted,true);
}
string getVertX(Transform tempTile, int k)
{
return tempTile.GetComponent<tileManager>().verts[k].x.ToString();
}
string getVertY(Transform tempTile, int k)
{
return tempTile.GetComponent<tileManager>().verts[k].y.ToString();
}
string getVertZ(Transform tempTile, int k)
{
return tempTile.GetComponent<tileManager>().verts[k].z.ToString();
}
tileManager tm(int i, int j)
{
return chunks[i].GetComponent<chunkManager>().tiles[j].GetComponent<tileManager>();
}
Answer by whydoidoit · Feb 24, 2014 at 05:05 AM
Ok first let me recommend you read these two articles - first for XML http://unitygems.com/xml and then also this: http://unitygems.com/saving-data-1 which cover some easy ways of integrating .NET serialization.
Then given that - you just need a file naming convention and a series of chunks that you write out after they have been modified. You can probably do this on a second thread without too much of a problem (presuming that you record that something has changed even though it is currently being serialized). Presuming the data is in your own structure you could use the class from here: http://unitygems.com/threads (called Loom) to have the saving moved away from the main thread.
So if I wanted to save the xml class system, based on the http://unitygems.com/xml link, I would simply put the root class into this function
public static string SerializeXml (this object item)
{
var s = new XmlSerializer (item.GetType ());
using (var m = new $$anonymous$$emoryStream())
{
s.Serialize (m, item);
m.Flush ();
return Encoding.UTF8.GetString (m.GetBuffer ());
}
}
and save that string into the xml file? If I were to implement it using the function above and my update method, fm.updateFile("Database","Terrain","xml",SerializeXml(Library),isDataEncrypted,true);
Is this correct?
And to save Vector3 positions of the vertices looks like it might be a problem since xmlserialized doesn't support saving vector3's.
Answer by Simeon · Feb 25, 2014 at 01:10 AM
One of the best and fastest serialization methods is ProtoBuf-Net. It works with .Net 3.5 so it works with Unity. The best solution to send a whole mesh with information to triangles, vertices and normals would be to make yourself a custom container and a custom struct for Vector3 position. You can use System.Linq for fast casting to a custom Vector3 array, or just use a loop.
Your answer
Follow this Question
Related Questions
Saving Game Problem 1 Answer
Save/Load system is saving but not loading. 1 Answer
Editing an XML File 1 Answer
Save and Load from XML U3 Collections Problem 1 Answer
Save/Load XML crashing? 1 Answer