public static PCache FromFile(string filename) { PCache data = new PCache(); List <string> header; long offset; using (var stream = File.OpenRead(filename)) { GetHeader(stream, out offset, out header); } if (header == null || header[0] != "pcache") { throw new Exception("Invalid header : missing magic number"); } Format format = (Format)int.MaxValue; data.elementCount = 0; data.properties = new List <PropertyDesc>(); foreach (string line in header) { var words = line.Split(' '); switch (words[0].ToLower()) { case "comment": //do nothing break; case "format": if (words.Length != 3) { throw new Exception("Invalid format description :" + line); } switch (words[1]) { case "ascii": format = Format.Ascii; break; case "binary": format = Format.Binary; break; default: throw new Exception("Invalid Format :" + words[1]); } break; case "elements": if (words.Length != 2) { throw new Exception("Invalid element description :" + line); } if (!int.TryParse(words[1], out data.elementCount)) { throw new Exception("Invalid element count :" + words[1]); } break; case "property": if (words.Length != 3) { throw new Exception("Invalid property description :" + line); } string property = words[2]; string component = GetComponentName(property); int idx = GetComponentIndex(property); string type = words[1]; int stride = GetPropertySize(type); if (stride == 0) { throw new Exception("Invalid Type for " + property + " property : " + type); } PropertyDesc prop = new PropertyDesc() { Name = property, Type = type, ComponentName = component, ComponentIndex = idx, Stride = stride }; data.properties.Add(prop); break; case "end_header": if (words.Length != 1) { throw new Exception("Invalid end_header description :" + line); } break; } } data.buckets = new List <List <object> >(); foreach (var property in data.properties) { data.buckets.Add(new List <object>(data.elementCount)); } if (format == Format.Binary) { using (var binaryReader = new BinaryReader(File.OpenRead(filename))) { binaryReader.BaseStream.Seek(offset, SeekOrigin.Begin); for (int i = 0; i < data.elementCount; i++) { for (int j = 0; j < data.properties.Count; j++) { var prop = data.properties[j]; switch (prop.Type) { case "short": data.buckets[j].Add(binaryReader.ReadInt16()); break; case "ushort": data.buckets[j].Add(binaryReader.ReadUInt16()); break; case "int": data.buckets[j].Add(binaryReader.ReadInt32()); break; case "uint": data.buckets[j].Add(binaryReader.ReadUInt32()); break; case "char": data.buckets[j].Add(binaryReader.ReadSByte()); break; case "uchar": data.buckets[j].Add(binaryReader.ReadByte()); break; case "float": data.buckets[j].Add(binaryReader.ReadSingle()); break; case "double": data.buckets[j].Add(binaryReader.ReadDouble()); break; } } } } } else if (format == Format.Ascii) { string[] lines = null; using (var reader = new StreamReader(File.OpenRead(filename))) { reader.BaseStream.Seek(offset, SeekOrigin.Begin); lines = reader.ReadToEnd().Replace("\r", "").Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries); } if (lines.Length != data.elementCount) { throw new InvalidOperationException(string.Format("Bad item amount, {0} expected in header, found {1}", data.elementCount, lines.Length)); } for (int i = 0; i < data.elementCount; i++) { string line = lines[i]; string[] elements = line.Split(' '); for (int j = 0; j < data.properties.Count; j++) { var prop = data.properties[j]; switch (prop.Type) { case "short": data.buckets[j].Add(short.Parse(elements[j], CultureInfo.InvariantCulture)); break; case "ushort": data.buckets[j].Add(ushort.Parse(elements[j], CultureInfo.InvariantCulture)); break; case "int": data.buckets[j].Add(int.Parse(elements[j], CultureInfo.InvariantCulture)); break; case "uint": data.buckets[j].Add(uint.Parse(elements[j], CultureInfo.InvariantCulture)); break; case "char": data.buckets[j].Add(sbyte.Parse(elements[j], CultureInfo.InvariantCulture)); break; case "uchar": data.buckets[j].Add(byte.Parse(elements[j], CultureInfo.InvariantCulture)); break; case "float": data.buckets[j].Add(float.Parse(elements[j], CultureInfo.InvariantCulture)); break; case "double": data.buckets[j].Add(double.Parse(elements[j], CultureInfo.InvariantCulture)); break; } } } } return(data); }
void OnGUI_Texture() { GUILayout.Label("Texture baking", EditorStyles.boldLabel); m_Texture = (Texture2D)EditorGUILayout.ObjectField("Texture", m_Texture, typeof(Texture2D), false); m_DecimationThresholdMode = (DecimationThresholdMode)EditorGUILayout.EnumPopup("Decimation Threshold", m_DecimationThresholdMode); if (m_DecimationThresholdMode != DecimationThresholdMode.None) { m_Threshold = EditorGUILayout.Slider("Threshold", m_Threshold, 0.0f, 1.0f); } m_RandomizePixels = EditorGUILayout.Toggle("Randomize Pixels Order", m_RandomizePixels); if (m_RandomizePixels) { m_SeedPixels = EditorGUILayout.IntField("Seed", m_SeedPixels); } m_ExportColors = EditorGUILayout.Toggle("Export Colors", m_ExportColors); m_OutputFormat = (PCache.Format)EditorGUILayout.EnumPopup("File Format", m_OutputFormat); if (m_Texture != null) { if (GUILayout.Button("Save to pCache file...")) { string fileName = EditorUtility.SaveFilePanelInProject("pCacheFile", m_Texture.name, "pcache", "Save PCache"); if (fileName != null) { PCache file = new PCache(); file.AddVector3Property("position"); if (m_ExportColors) { file.AddColorProperty("color"); } List <Vector3> positions = new List <Vector3>(); List <Vector4> colors = null; if (m_ExportColors) { colors = new List <Vector4>(); } ComputeTextureData(positions, colors); file.SetVector3Data("position", positions); if (m_ExportColors) { file.SetColorData("color", colors); } file.SaveToFile(fileName, m_OutputFormat); } } using (new GUILayout.VerticalScope(EditorStyles.helpBox)) { EditorGUILayout.LabelField("Texture Statistics", EditorStyles.boldLabel); EditorGUI.indentLevel++; EditorGUILayout.IntField("Width", m_Texture.width); EditorGUILayout.IntField("Height", m_Texture.height); EditorGUILayout.IntField("Pixels count", m_Texture.width * m_Texture.height); EditorGUI.indentLevel--; } } }
PCache ComputePCacheFromMesh() { var meshCache = ComputeDataCache(m_Mesh); Picker picker = null; if (m_Distribution == Distribution.Sequential) { if (m_MeshBakeMode == MeshBakeMode.Vertex) { picker = new SequentialPickerVertex(meshCache); } else if (m_MeshBakeMode == MeshBakeMode.Triangle) { picker = new SequentialPickerTriangle(meshCache); } } else if (m_Distribution == Distribution.Random) { if (m_MeshBakeMode == MeshBakeMode.Vertex) { picker = new RandomPickerVertex(meshCache, m_SeedMesh); } else if (m_MeshBakeMode == MeshBakeMode.Triangle) { picker = new RandomPickerTriangle(meshCache, m_SeedMesh); } } else if (m_Distribution == Distribution.RandomUniformArea) { picker = new RandomPickerUniformArea(meshCache, m_SeedMesh); } if (picker == null) { throw new InvalidOperationException("Unable to find picker"); } var positions = new List <Vector3>(); var normals = m_ExportNormals ? new List <Vector3>() : null; var colors = m_ExportColors ? new List <Vector4>() : null; var uvs = m_ExportUV ? new List <Vector4>() : null; for (int i = 0; i < m_OutputPointCount; ++i) { if (i % 64 == 0) { var cancel = EditorUtility.DisplayCancelableProgressBar("pCache bake tool", string.Format("Sampling data... {0}/{1}", i, m_OutputPointCount), (float)i / (float)m_OutputPointCount); if (cancel) { return(null); } } var vertex = picker.GetNext(); positions.Add(vertex.position); if (m_ExportNormals) { normals.Add(vertex.normal); } if (m_ExportColors) { colors.Add(vertex.color); } if (m_ExportUV) { uvs.Add(vertex.uvs.Any() ? vertex.uvs[0] : Vector4.zero); } } var file = new PCache(); file.AddVector3Property("position"); if (m_ExportNormals) { file.AddVector3Property("normal"); } if (m_ExportColors) { file.AddColorProperty("color"); } if (m_ExportUV) { file.AddVector4Property("uv"); } EditorUtility.DisplayProgressBar("pCache bake tool", "Generating pCache...", 0.0f); file.SetVector3Data("position", positions); if (m_ExportNormals) { file.SetVector3Data("normal", normals); } if (m_ExportColors) { file.SetColorData("color", colors); } if (m_ExportUV) { file.SetVector4Data("uv", uvs); } EditorUtility.ClearProgressBar(); return(file); }
public override void OnImportAsset(AssetImportContext ctx) { try { PCache pcache = PCache.FromFile(ctx.assetPath); PointCacheAsset cache = ScriptableObject.CreateInstance <PointCacheAsset>(); cache.name = "PointCache"; ctx.AddObjectToAsset("PointCache", cache); ctx.SetMainObject(cache); List <InProperty> inProperties = new List <InProperty>(); Dictionary <string, OutProperty> outProperties = new Dictionary <string, OutProperty>(); Dictionary <OutProperty, Texture2D> surfaces = new Dictionary <OutProperty, Texture2D>(); foreach (var prop in pcache.properties) { OutProperty p_out; if (outProperties.ContainsKey(prop.ComponentName)) { p_out = outProperties[prop.ComponentName]; p_out.Size = Math.Max(p_out.Size, prop.ComponentIndex + 1); } else { p_out = new OutProperty(prop.Type, prop.ComponentName, prop.ComponentIndex + 1); outProperties.Add(prop.ComponentName, p_out); } inProperties.Add(new InProperty(prop.Type, prop.Name, prop.ComponentIndex, p_out)); } int width, height; FindBestSize(pcache.elementCount, out width, out height); // Output Surface Creation foreach (var kvp in outProperties) { TextureFormat surfaceFormat = TextureFormat.Alpha8; switch (kvp.Value.PropertyType) { case "byte": if (kvp.Value.Size == 1) { surfaceFormat = TextureFormat.Alpha8; } else { surfaceFormat = TextureFormat.RGBA32; } break; case "float": if (kvp.Value.Size == 1) { surfaceFormat = TextureFormat.RHalf; } else { surfaceFormat = TextureFormat.RGBAHalf; } break; default: throw new NotImplementedException("Types other than byte/float are not supported yet"); } Texture2D surface = new Texture2D(width, height, surfaceFormat, false); surface.name = kvp.Key; surfaces.Add(kvp.Value, surface); } cache.PointCount = pcache.elementCount; cache.surfaces = new Texture2D[surfaces.Count]; Dictionary <OutProperty, Color> outValues = new Dictionary <OutProperty, Color>(); foreach (var kvp in outProperties) { outValues.Add(kvp.Value, new Color()); } for (int i = 0; i < pcache.elementCount; i++) { int idx = 0; foreach (var prop in inProperties) { float val = 0.0f; switch (prop.PropertyType) { case "byte": val = Mathf.Clamp01(((int)pcache.buckets[idx][i]) / 256.0f); break; case "float": val = ((float)pcache.buckets[idx][i]); break; default: throw new NotImplementedException("Types other than byte/float are not supported yet"); } SetPropValue(prop.Index, outValues, prop.OutProperty, val); idx++; } foreach (var kvp in outProperties) { surfaces[kvp.Value].SetPixel(i % width, i / width, outValues[kvp.Value]); } } int k = 0; foreach (var kvp in surfaces) { kvp.Value.Apply(); kvp.Value.hideFlags = HideFlags.HideInHierarchy; ctx.AddObjectToAsset(kvp.Key.Name, kvp.Value); cache.surfaces[k] = kvp.Value; k++; } } catch (System.Exception e) { Debug.LogException(e); } }