public override void OnInspectorGUI() { if (!isHoudiniGeoFile && !fileCheckPerformed) { string assetPath = AssetDatabase.GetAssetPath(target); isHoudiniGeoFile = (assetPath.EndsWith(".geo")); fileCheckPerformed = true; } else if (!isHoudiniGeoFile) { return; } if (houdiniGeo == null) { string assetPath = AssetDatabase.GetAssetPath(target); string outDir = Path.GetDirectoryName(assetPath); string assetName = Path.GetFileNameWithoutExtension(assetPath); // Parse geo string geoOutputPath = string.Format("{0}/{1}.asset", outDir, assetName); houdiniGeo = AssetDatabase.LoadAllAssetsAtPath(geoOutputPath).Where(a => a is HoudiniGeo).FirstOrDefault() as HoudiniGeo; houdiniGeoInspector = Editor.CreateEditor(houdiniGeo); } if (houdiniGeoInspector != null) { GUI.enabled = true; houdiniGeoInspector.DrawDefaultInspector(); } }
public static bool HasAttribute(this HoudiniGeo geo, string attrName, HoudiniGeoAttributeOwner owner) { if (owner == HoudiniGeoAttributeOwner.Any) { return(geo.attributes.Any(a => a.name == attrName)); } return(geo.attributes.Any(a => a.owner == owner && a.name == attrName)); }
private static void ParseAttributes(HoudiniGeo geo, JToken attributesValueToken) { // "attributes",[ // "vertexattributes",[ // [(attribute obj)], // [(attribute obj)], // ... // ], // "pointattributes",[ // [(attribute obj)], // [(attribute obj)], // ... // ], // ... // ], if (ATTRIBUTES_TO_PARSE == null) { ATTRIBUTES_TO_PARSE = new Dictionary <string, HoudiniGeoAttributeOwner>(); ATTRIBUTES_TO_PARSE.Add("vertexattributes", HoudiniGeoAttributeOwner.Vertex); ATTRIBUTES_TO_PARSE.Add("pointattributes", HoudiniGeoAttributeOwner.Point); ATTRIBUTES_TO_PARSE.Add("primitiveattributes", HoudiniGeoAttributeOwner.Primitive); ATTRIBUTES_TO_PARSE.Add("globalattributes", HoudiniGeoAttributeOwner.Detail); } Dictionary <string, JToken> attributeTokensDict = ArrayKeyValueToDictionary(attributesValueToken.Children().ToArray()); // Parse each attribute group var geoAttributes = new List <HoudiniGeoAttribute>(); foreach (var attrKeyVal in ATTRIBUTES_TO_PARSE) { string attrGroupKey = attrKeyVal.Key; HoudiniGeoAttributeOwner attrOwner = attrKeyVal.Value; JToken groupValueToken; if (attributeTokensDict.TryGetValue(attrGroupKey, out groupValueToken)) { // Parse each attribute in group foreach (var attributeToken in groupValueToken.Children()) { var attribute = ParseSingleAttribute(attributeToken, attrOwner); if (attribute != null) { geoAttributes.Add(attribute); } } } } geo.attributes = geoAttributes.ToArray(); }
public static bool TryGetAttribute(this HoudiniGeo geo, string attrName, HoudiniGeoAttributeType type, HoudiniGeoAttributeOwner owner, out HoudiniGeoAttribute attr) { if (owner == HoudiniGeoAttributeOwner.Any) { attr = geo.attributes.FirstOrDefault(a => a.type == type && a.name == attrName); } else { attr = geo.attributes.FirstOrDefault(a => a.owner == owner && a.type == type && a.name == attrName); } return(attr != null); }
private static void ParseTopology(HoudiniGeo geo, JToken topologyValueToken) { //"topology",[ // "pointref",[ // "indices",[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18] // ] //], Dictionary <string, JToken> topologyDict = ArrayKeyValueToDictionary(topologyValueToken.Children().ToArray()); Dictionary <string, JToken> pointRefDict = ArrayKeyValueToDictionary(topologyDict["pointref"].Children().ToArray()); geo.pointRefs = pointRefDict["indices"].Values <int>().ToArray(); }
private static HoudiniGeo ParseInternal(string assetPath, HoudiniGeo existingGeo = null) { if (!File.Exists(assetPath)) { throw new FileNotFoundException("File not found: " + assetPath); } // Parse the json JToken mainToken = null; try { mainToken = JToken.Parse(File.ReadAllText(assetPath)); } catch (System.Exception e) { Debug.LogError(string.Format("HoudiniGeoParseError: JSON in file '{0}' could not be parsed", assetPath)); throw e; } // The houdini geo format expects the main element to be an array if (mainToken.Type != JTokenType.Array) { throw new HoudiniGeoParseException("Unexpected type in geo json."); } // The main element is an array that actually functions as a dictionary! Dictionary <string, JToken> geoDataDict = ArrayKeyValueToDictionary(mainToken.Children().ToArray()); HoudiniGeo houdiniGeo = existingGeo; if (houdiniGeo == null) { houdiniGeo = ScriptableObject.CreateInstance <HoudiniGeo>(); } houdiniGeo.sourceAsset = AssetDatabase.LoadMainAssetAtPath(assetPath); houdiniGeo.fileVersion = geoDataDict["fileversion"].ValueSafe <string>(); houdiniGeo.pointCount = geoDataDict["pointcount"].ValueSafe <int>(); houdiniGeo.vertexCount = geoDataDict["vertexcount"].ValueSafe <int>(); houdiniGeo.primCount = geoDataDict["primitivecount"].ValueSafe <int>(); houdiniGeo.fileInfo = ParseFileInfo(geoDataDict["info"] as JObject); ParseTopology(houdiniGeo, geoDataDict["topology"]); ParseAttributes(houdiniGeo, geoDataDict["attributes"]); ParsePrimitives(houdiniGeo, geoDataDict["primitives"]); return(houdiniGeo); }
internal static void ImportAllMeshes(this HoudiniGeo geo) { string geoAssetPath = AssetDatabase.GetAssetPath(geo); if (!File.Exists(geoAssetPath)) { return; } // Convert to unity mesh and store mesh as sub asset if (geo.polyPrimitives.Length > 0) { var mesh = AssetDatabase.LoadAllAssetsAtPath(geoAssetPath).Where(a => a is Mesh).FirstOrDefault() as Mesh; if (mesh == null) { mesh = new Mesh(); AssetDatabase.AddObjectToAsset(mesh, geoAssetPath); } geo.ToUnityMesh(mesh); EditorUtility.SetDirty(mesh); } }
public static void ToUnityMesh(this HoudiniGeo geo, Mesh mesh) { if (geo.polyPrimitives.Length == 0) { Debug.LogError("Cannot convert HoudiniGeo to Mesh because geo has no PolyPrimitives"); return; } mesh.name = geo.name; int[] indices = geo.polyPrimitives.SelectMany(p => p.indices).ToArray(); int vertexCount = indices.Length; if (vertexCount > 65000) { throw new Exception(string.Format("Vertex count ({0}) exceeds limit of {1}!", geo.vertexCount, 65000)); } // Check if position attribute P exists HoudiniGeoAttribute posAttr = null; if (!geo.TryGetAttribute(HoudiniGeo.POS_ATTR_NAME, HoudiniGeoAttributeType.Float, out posAttr)) { Debug.LogWarning("HoudiniGEO has no Position attribute on points or vertices"); } // Get Vertex/Point positions Vector3[] posAttrValues = null; posAttr.GetValues(out posAttrValues); // Get uv attribute values HoudiniGeoAttribute uvAttr = null; Vector2[] uvAttrValues = null; if (geo.TryGetAttribute(HoudiniGeo.UV_ATTR_NAME, HoudiniGeoAttributeType.Float, out uvAttr)) { uvAttr.GetValues(out uvAttrValues); } // Get uv2 attribute values HoudiniGeoAttribute uv2Attr = null; Vector2[] uv2AttrValues = null; if (geo.TryGetAttribute(HoudiniGeo.UV2_ATTR_NAME, HoudiniGeoAttributeType.Float, out uv2Attr)) { uv2Attr.GetValues(out uv2AttrValues); } // Get normal attribute values HoudiniGeoAttribute normalAttr = null; Vector3[] normalAttrValues = null; if (geo.TryGetAttribute(HoudiniGeo.NORMAL_ATTR_NAME, HoudiniGeoAttributeType.Float, out normalAttr)) { normalAttr.GetValues(out normalAttrValues); } // Get color attribute values HoudiniGeoAttribute colorAttr = null; Color[] colorAttrValues = null; if (geo.TryGetAttribute(HoudiniGeo.COLOR_ATTR_NAME, HoudiniGeoAttributeType.Float, out colorAttr)) { colorAttr.GetValues(out colorAttrValues); // Get alpha color values HoudiniGeoAttribute alphaAttr = null; float[] alphaAttrValues = null; if (geo.TryGetAttribute(HoudiniGeo.ALPHA_ATTR_NAME, HoudiniGeoAttributeType.Float, colorAttr.owner, out alphaAttr)) { alphaAttr.GetValues(out alphaAttrValues); if (colorAttrValues.Length == alphaAttrValues.Length) { for (int i = 0; i < colorAttrValues.Length; i++) { colorAttrValues[i].a = alphaAttrValues[i]; } } } } // Get tangent attribute values HoudiniGeoAttribute tangentAttr = null; Vector3[] tangentAttrValues = null; if (geo.TryGetAttribute(HoudiniGeo.TANGENT_ATTR_NAME, HoudiniGeoAttributeType.Float, out tangentAttr)) { tangentAttr.GetValues(out tangentAttrValues); } // Get material primitive attribute (Multiple materials result in multiple submeshes) HoudiniGeoAttribute materialAttr = null; string[] materialAttributeValues = null; if (geo.TryGetAttribute(HoudiniGeo.MATERIAL_ATTR_NAME, HoudiniGeoAttributeType.String, HoudiniGeoAttributeOwner.Primitive, out materialAttr)) { materialAttr.GetValues(out materialAttributeValues); } // Create our mesh attribute buffers var submeshInfo = new Dictionary <string, List <int> >(); var positions = new Vector3[vertexCount]; var uvs = new Vector2[vertexCount]; // unity doesn't like it when meshes have no uvs var uvs2 = (uv2Attr != null) ? new Vector2[vertexCount] : null; var normals = (normalAttr != null) ? new Vector3[vertexCount] : null; var colors = (colorAttr != null) ? new Color[vertexCount] : null; var tangents = (tangentAttr != null) ? new Vector4[vertexCount] : null; // Fill the mesh buffers int[] vertToPoint = geo.pointRefs; Dictionary <int, int> vertIndexGlobalToLocal = new Dictionary <int, int>(); for (int i = 0; i < vertexCount; ++i) { int vertIndex = indices[i]; int pointIndex = vertToPoint[vertIndex]; vertIndexGlobalToLocal.Add(vertIndex, i); // Position switch (posAttr.owner) { case HoudiniGeoAttributeOwner.Vertex: positions[i] = posAttrValues[vertIndex]; break; case HoudiniGeoAttributeOwner.Point: positions[i] = posAttrValues[pointIndex]; break; } // UV1 if (uvAttr != null) { switch (uvAttr.owner) { case HoudiniGeoAttributeOwner.Vertex: uvs[i] = uvAttrValues[vertIndex]; break; case HoudiniGeoAttributeOwner.Point: uvs[i] = uvAttrValues[pointIndex]; break; } } else { // Unity likes to complain when a mesh doesn't have any UVs so we'll just add a default uvs[i] = Vector2.zero; } // UV2 if (uv2Attr != null) { switch (uv2Attr.owner) { case HoudiniGeoAttributeOwner.Vertex: uvs2[i] = uv2AttrValues[vertIndex]; break; case HoudiniGeoAttributeOwner.Point: uvs2[i] = uv2AttrValues[pointIndex]; break; } } // Normals if (normalAttr != null) { switch (normalAttr.owner) { case HoudiniGeoAttributeOwner.Vertex: normals[i] = normalAttrValues[vertIndex]; break; case HoudiniGeoAttributeOwner.Point: normals[i] = normalAttrValues[pointIndex]; break; } } // Colors if (colorAttr != null) { switch (colorAttr.owner) { case HoudiniGeoAttributeOwner.Vertex: colors[i] = colorAttrValues[vertIndex]; break; case HoudiniGeoAttributeOwner.Point: colors[i] = colorAttrValues[pointIndex]; break; } } // Fill tangents info if (tangentAttr != null) { switch (tangentAttr.owner) { case HoudiniGeoAttributeOwner.Vertex: tangents[i] = tangentAttrValues[vertIndex]; break; case HoudiniGeoAttributeOwner.Point: tangents[i] = tangentAttrValues[pointIndex]; break; } } } // Get primitive attribute values and created submeshes foreach (var polyPrim in geo.polyPrimitives) { // Normals if (normalAttr != null && normalAttr.owner == HoudiniGeoAttributeOwner.Primitive) { foreach (var vertIndex in polyPrim.indices) { int localVertIndex = vertIndexGlobalToLocal[vertIndex]; normals[localVertIndex] = normalAttrValues[polyPrim.id]; } } // Colors if (colorAttr != null && colorAttr.owner == HoudiniGeoAttributeOwner.Primitive) { foreach (var vertIndex in polyPrim.indices) { int localVertIndex = vertIndexGlobalToLocal[vertIndex]; colors[localVertIndex] = colorAttrValues[polyPrim.id]; } } // Add face to submesh based on material attribute var materialName = (materialAttr == null) ? HoudiniGeo.DEFAULT_MATERIAL_NAME : materialAttributeValues[polyPrim.id]; if (!submeshInfo.ContainsKey(materialName)) { submeshInfo.Add(materialName, new List <int>()); } submeshInfo[materialName].AddRange(polyPrim.triangles); } // Assign buffers to mesh mesh.vertices = positions; mesh.subMeshCount = submeshInfo.Count; mesh.uv = uvs; mesh.uv2 = uvs2; mesh.normals = normals; mesh.colors = colors; mesh.tangents = tangents; // Set submesh indexbuffers int submeshIndex = 0; foreach (var item in submeshInfo) { // Skip empty submeshes if (item.Value.Count == 0) { continue; } // Set the indices for the submesh (Reversed by default because axis coordinates Z flipped) IEnumerable <int> submeshIndices = item.Value; if (!geo.importSettings.reverseWinding) { submeshIndices = submeshIndices.Reverse(); } mesh.SetIndices(submeshIndices.ToArray(), MeshTopology.Triangles, submeshIndex); submeshIndex++; } // Calculate any missing buffers mesh.ConvertToUnityCoordinates(); mesh.RecalculateBounds(); if (normalAttr == null) { mesh.RecalculateNormals(); } }
public static bool TryGetAttribute(this HoudiniGeo geo, string attrName, HoudiniGeoAttributeType type, out HoudiniGeoAttribute attr) { attr = geo.attributes.FirstOrDefault(a => a.type == type && a.name == attrName); return(attr != null); }
public static void ParseInto(string assetPath, HoudiniGeo existingGeo) { ParseInternal(assetPath, existingGeo); }
private static void ParsePrimitives(HoudiniGeo geo, JToken primitivesValueToken) { // Polygon Mesh // Only type: "run", runtiype: "Poly" supported for now. // // "primitives",[ // [ // [Header], // [Body] // ], // [ // [Header], // [Body] // ], // ... // ], int primIdCounter = 0; var polyPrimitives = new List <PolyPrimitive>(); var bezierCurvePrimitives = new List <BezierCurvePrimitive>(); var nurbCurvePrimitives = new List <NURBCurvePrimitive>(); foreach (var primitiveToken in primitivesValueToken.Children()) { // Primitive [[Header], [Body]] //[ // [ // "type","run", // "runtype","Poly", // "varyingfields",["vertex"], // "uniformfields",{ // "closed":true // } // ], // [ // [[0,1,2,3]], // [[4,5,6,7]], // [[8,9,10,11]], // [[12,13,14,15]], // ... // ] //] JToken[] childBlockTokens = primitiveToken.Children().ToArray(); JToken headerToken = childBlockTokens[0]; JToken bodyToken = childBlockTokens[1]; // Parse header Dictionary <string, JToken> headerDict = ArrayKeyValueToDictionary(headerToken.Children().ToArray()); string type = headerDict["type"].Value <string>(); // Parse RunType primitives if (type == "run") { string runType = headerDict["runtype"].Value <string>(); switch (runType) { case "Poly": polyPrimitives.AddRange(ParsePolyPrimitiveGroup(headerDict, bodyToken, primIdCounter)); break; case "BezierCurve": //bezierCurvePrimitives.AddRange(primitives); break; case "NURBCurve": //nurbCurvePrimitives.AddRange(primitives); break; } } } geo.polyPrimitives = polyPrimitives.ToArray(); geo.bezierCurvePrimitives = bezierCurvePrimitives.ToArray(); geo.nurbCurvePrimitives = nurbCurvePrimitives.ToArray(); }