private static void GetValues(this HoudiniGeoAttribute attr, out string[] values) { if (!attr.ValidateForGetValues <string>(HoudiniGeoAttributeType.String, 1)) { values = new string[0]; return; } values = attr.stringValues; }
private static void GetValues(this HoudiniGeoAttribute attr, out float[] values) { if (!attr.ValidateForGetValues <float>(HoudiniGeoAttributeType.Float, 1)) { values = new float[0]; return; } values = attr.floatValues; }
private static void GetValues(this HoudiniGeoAttribute attr, out int[] values) { if (!attr.ValidateForGetValues <int>(HoudiniGeoAttributeType.Integer, 1)) { values = new int[0]; return; } values = attr.intValues; }
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 AddSingleAttributeToDictionary(List <object> attributes, HoudiniGeoAttribute attribute) { string typeString = HoudiniGeoFileParser.AttributeTypeEnumValueToCategoryString(attribute.type); // Each attribute has a list with two dictionaries: a header and a body. List <object> attributeDictionaries = new List <object>(); attributes.Add(attributeDictionaries); // Header dictionary. Dictionary <string, object> header = new Dictionary <string, object>() { { "scope", "public" }, // TODO: Does this ever vary?
private static void GetValues(this HoudiniGeoAttribute attr, out Vector2[] values) { if (!attr.ValidateForGetValues <Vector2>(HoudiniGeoAttributeType.Float, 2)) { values = new Vector2[0]; return; } // Convert to Vector2 float[] rawValues = attr.floatValues; values = new Vector2[rawValues.Length / attr.tupleSize]; for (int i = 0; i < values.Length; i++) { values[i].x = rawValues[i * attr.tupleSize]; values[i].y = rawValues[i * attr.tupleSize + 1]; } }
private static bool ValidateForGetValues <T>(this HoudiniGeoAttribute attr, HoudiniGeoAttributeType expectedType, int expectedMinTupleSize) { if (attr.type != expectedType) { Debug.LogError(string.Format("Cannot convert raw values of {0} attribute '{1}' to {2} (type: {3})", attr.owner, attr.name, typeof(T).Name, attr.type)); return(false); } if (attr.tupleSize < expectedMinTupleSize) { Debug.LogError(string.Format("The tuple size of {0} attribute '{1}' too small for conversion to {2}", attr.owner, attr.name, typeof(T).Name)); return(false); } return(true); }
private static object GetAttributeValue(Type type, HoudiniGeoAttribute attribute, int index) { if (type == typeof(float)) { return(attribute.floatValues[index]); } if (type == typeof(int)) { return(attribute.intValues[index]); } if (type == typeof(string)) { return(attribute.stringValues[index]); } if (type == typeof(Vector2)) { return(new Vector2(attribute.floatValues[index * 2], attribute.floatValues[index * 2 + 1])); } if (type == typeof(Vector3)) { return(new Vector3(attribute.floatValues[index * 3], attribute.floatValues[index * 3 + 1], attribute.floatValues[index * 3 + 2])); } if (type == typeof(Vector4)) { return(new Vector4(attribute.floatValues[index * 4], attribute.floatValues[index * 4 + 1], attribute.floatValues[index * 4 + 2], attribute.floatValues[index * 4 + 3])); } if (type == typeof(Vector2Int)) { return(new Vector2Int(attribute.intValues[index * 2], attribute.intValues[index * 2 + 1])); } if (type == typeof(Vector3Int)) { return(new Vector3Int(attribute.intValues[index * 3], attribute.intValues[index * 3 + 1], attribute.intValues[index * 3 + 2])); } if (type == typeof(Color)) { return(new Color(attribute.floatValues[index * 3], attribute.floatValues[index * 3 + 1], attribute.floatValues[index * 3 + 2])); } Debug.LogWarning($"Tried to get value of unrecognized type '{type.Name}'"); return(null); }
private static void GetValues(this HoudiniGeoAttribute attr, out Color[] values) { if (!attr.ValidateForGetValues <Color>(HoudiniGeoAttributeType.Float, 3)) { values = new Color[0]; return; } // Convert to Color float[] rawValues = attr.floatValues; values = new Color[rawValues.Length / attr.tupleSize]; for (int i = 0; i < values.Length; i++) { values[i].r = rawValues[i * attr.tupleSize]; values[i].g = rawValues[i * attr.tupleSize + 1]; values[i].b = rawValues[i * attr.tupleSize + 2]; values[i].a = 1; if (attr.tupleSize == 4) { values[i].a = rawValues[i * attr.tupleSize + 3]; } } }
private static bool TryCreateAttribute(FieldInfo fieldInfo, out HoudiniGeoAttribute attribute) { attribute = null; Type type = fieldInfo.FieldType; if (type == typeof(float)) { attribute = new HoudiniGeoAttribute { type = HoudiniGeoAttributeType.Float, tupleSize = 1 } } ; else if (type == typeof(int)) { attribute = new HoudiniGeoAttribute { type = HoudiniGeoAttributeType.Integer, tupleSize = 1 } } ; else if (type == typeof(string)) { attribute = new HoudiniGeoAttribute { type = HoudiniGeoAttributeType.String, tupleSize = 1 } } ; if (type == typeof(Vector2)) { attribute = new HoudiniGeoAttribute { type = HoudiniGeoAttributeType.Float, tupleSize = 2 } } ; else if (type == typeof(Vector3)) { attribute = new HoudiniGeoAttribute { type = HoudiniGeoAttributeType.Float, tupleSize = 3 } } ; else if (type == typeof(Vector4)) { attribute = new HoudiniGeoAttribute { type = HoudiniGeoAttributeType.Float, tupleSize = 4 } } ; else if (type == typeof(Vector2Int)) { attribute = new HoudiniGeoAttribute { type = HoudiniGeoAttributeType.Integer, tupleSize = 2 } } ; else if (type == typeof(Vector3Int)) { attribute = new HoudiniGeoAttribute { type = HoudiniGeoAttributeType.Integer, tupleSize = 3 } } ; else if (type == typeof(Color)) { attribute = new HoudiniGeoAttribute { type = HoudiniGeoAttributeType.Float, tupleSize = 3 } } ; if (attribute == null) { return(false); } attribute.name = fieldInfo.Name; return(true); }
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); }
private static HoudiniGeoAttribute ParseSingleAttribute(JToken attrToken, HoudiniGeoAttributeOwner owner) { // NUMERIC // [ // [ // "scope","public", // "type","numeric", // "name","P", <- Extract This // "options",{ // "type":{ // "type":"string", // "value":"hpoint" // } // } // ], // [ // "size",4, <- Extract This // "storage","fpreal32", <- Extract This // "defaults",[ // "size",4, // "storage","fpreal64", // "values",[0,0,0,1] // ], // "values",[ // "size",4, // "storage","fpreal32", // "tuples",[[-0.5,-0.5,-0.5,1],[0.5,-0.5,-0.5,1],...] <- Extract This // ] // ] // ] // STRING // [ // [ // "scope","public", // "type","string", // "name","varmap", // "options",{ // } // ], // [ // "size",1, // "storage","int32", // "strings",["SHIT_INT -> SHIT_INT"], // "indices",[ // "size",1, // "storage","int32", // "arrays",[[0]] // ] // ] // ] JToken[] childBlockTokens = attrToken.Children().ToArray(); JToken headerToken = childBlockTokens[0]; JToken bodyToken = childBlockTokens[1]; var geoAttribute = new HoudiniGeoAttribute(); geoAttribute.owner = owner; // Parse header block Dictionary <string, JToken> headerBlockDict = ArrayKeyValueToDictionary(headerToken.Children().ToArray()); geoAttribute.name = headerBlockDict["name"].Value <string>(); string valueType = headerBlockDict["type"].Value <string>(); // Parse body block Dictionary <string, JToken> valuesBlockDict = ArrayKeyValueToDictionary(bodyToken.Children().ToArray()); geoAttribute.tupleSize = valuesBlockDict["size"].Value <int>(); // Parse Numeric types if (valueType == "numeric") { // Get storage type (float, int) string storageType = valuesBlockDict["storage"].Value <string>(); geoAttribute.type = AttributeTypeStrToEnumValue(storageType); if (geoAttribute.type == HoudiniGeoAttributeType.Invalid) { Debug.LogWarning("HoudiniGeoFileParser: unsuppored numeric storage type " + valueType); return(null); } // Get all values Dictionary <string, JToken> valuesDict = ArrayKeyValueToDictionary(valuesBlockDict["values"].Children().ToArray()); if (geoAttribute.type == HoudiniGeoAttributeType.Float) { int tupleSize = valuesDict["size"].Value <int>(); string valuesKey = (tupleSize == 1) ? "arrays" : "tuples"; geoAttribute.floatValues = valuesDict[valuesKey].Children().SelectMany(t => t.Values <float>()).ToArray(); } else if (geoAttribute.type == HoudiniGeoAttributeType.Integer) { geoAttribute.intValues = valuesDict["arrays"].Children().SelectMany(t => t.Values <int>()).ToArray(); } } // Parse String types else if (valueType == "string") { geoAttribute.type = HoudiniGeoAttributeType.String; Dictionary <string, JToken> indicesDict = ArrayKeyValueToDictionary(valuesBlockDict["indices"].Children().ToArray()); string[] stringValues = valuesBlockDict["strings"].Values <string>().ToArray(); int[] indices = indicesDict["arrays"].Children().SelectMany(t => t.Values <int>()).ToArray(); geoAttribute.stringValues = indices.Select(i => (i >= 0 && i < stringValues.Length) ? stringValues[i] : "").ToArray(); } // Unexpected type? else { Debug.LogWarning("HoudiniGeoFileParser: unsuppored attribute valueType " + valueType); return(null); } return(geoAttribute); }