/// Converts TiltBrush brush strokes into linear USD BasisCurves. static BrushCurvesSample GetCurvesSample(ExportUtils.SceneStatePayload payload, List <Stroke> strokes, Matrix4x4 mat44) { var sample = new BrushCurvesSample(); var times = new List <float>(); var pressures = new List <float>(); sample.doubleSided = true; sample.orientation = USD.NET.Orientation.LeftHanded; sample.basis = BasisCurvesSample.Basis.Bezier; sample.type = BasisCurvesSample.CurveType.Linear; sample.wrap = BasisCurvesSample.WrapMode.Nonperiodic; sample.curveVertexCounts = strokes.Select(x => x.m_ControlPoints.Length).ToArray(); sample.transform = mat44; int numCPs = sample.curveVertexCounts.Sum(); sample.points = new Vector3[numCPs]; sample.normals = new Vector3[numCPs]; sample.colors = new Color[numCPs]; int iKnot = 0; foreach (Stroke stroke in strokes) { foreach (var cp in stroke.m_ControlPoints) { times.Add(cp.m_TimestampMs / 1000.0f); pressures.Add(cp.m_Pressure); } foreach (var cp in stroke.m_ControlPoints) { // Normals in USD are stored in object/local space, just as points are. sample.normals[iKnot] = cp.m_Orient * Vector3.up; sample.points[iKnot] = cp.m_Pos; sample.colors[iKnot] = stroke.m_Color.linear; iKnot++; } } { Matrix4x4 basis = ExportUtils.GetFromUnity_Axes(payload); Matrix4x4 units = Matrix4x4.Scale(Vector3.one * payload.exportUnitsFromAppUnits); MathUtils.TransformVector3AsPoint(units * basis, 0, sample.points.Length, sample.points); MathUtils.TransformVector3AsVector(basis, 0, sample.normals.Length, sample.normals); } sample.extent = new Bounds(sample.points[0], Vector3.zero); for (int i = 0; i < sample.points.Length; i++) { sample.extent.Encapsulate(sample.points[i]); } sample.times = times.ToArray(); sample.pressures = pressures.ToArray(); return(sample); }
public static void Export(string outputFile) { float scale = 100f; ExportUtils.SceneStatePayload payload = ExportCollector.GetExportPayload(AxisConvention.kStl); var buffer = new StringBuilder(); foreach (var group in payload.groups) { foreach (var brushMeshPayload in group.brushMeshes) { var pool = brushMeshPayload.geometry; var xf = brushMeshPayload.xform; var name = brushMeshPayload.legacyUniqueName; buffer.AppendFormat("solid {0}\n", name); for (int i = 0; i < pool.NumTriIndices; i += 3) { Vector3 normal = (pool.m_Normals[pool.m_Tris[i]] + pool.m_Normals[pool.m_Tris[i + 1]] + pool.m_Normals[pool.m_Tris[i + 2]]) / 3f; normal.Normalize(); normal = xf.MultiplyVector(normal); Vector3 v1 = xf * pool.m_Vertices[pool.m_Tris[i]] * scale; Vector3 v2 = xf * pool.m_Vertices[pool.m_Tris[i + 1]] * scale; Vector3 v3 = xf * pool.m_Vertices[pool.m_Tris[i + 2]] * scale; buffer.AppendFormat(" facet normal {0} {1} {2}\n", normal.x, normal.y, normal.z); buffer.Append(" outer loop\n"); buffer.AppendFormat(" vertex {0} {1} {2}\n", v1.x, v1.y, v1.z); buffer.AppendFormat(" vertex {0} {1} {2}\n", v2.x, v2.y, v2.z); buffer.AppendFormat(" vertex {0} {1} {2}\n", v3.x, v3.y, v3.z); buffer.Append(" endloop\n"); buffer.Append(" endfacet\n"); } buffer.AppendFormat("endsolid {0}\n", name); } } System.IO.File.WriteAllText(outputFile, buffer.ToString()); }
// Populates glTF metadata and scene extras fields. private void SetExtras( GlTF_ScriptableExporter exporter, ExportUtils.SceneStatePayload payload) { Color skyColorA = payload.env.skyColorA; Color skyColorB = payload.env.skyColorB; Vector3 skyGradientDir = payload.env.skyGradientDir; // Scene-level extras: exporter.G.extras["TB_EnvironmentGuid"] = payload.env.guid.ToString("D"); exporter.G.extras["TB_Environment"] = payload.env.description; exporter.G.extras["TB_UseGradient"] = payload.env.useGradient ? "true" : "false"; exporter.G.extras["TB_SkyColorA"] = CommaFormattedFloatRGB(skyColorA); exporter.G.extras["TB_SkyColorB"] = CommaFormattedFloatRGB(skyColorB); Matrix4x4 exportFromUnity = AxisConvention.GetFromUnity(payload.axes); exporter.G.extras["TB_SkyGradientDirection"] = CommaFormattedVector3( exportFromUnity * skyGradientDir); exporter.G.extras["TB_FogColor"] = CommaFormattedFloatRGB(payload.env.fogColor); exporter.G.extras["TB_FogDensity"] = payload.env.fogDensity.ToString(); // TODO: remove when Poly starts using the new color data exporter.G.extras["TB_SkyColorHorizon"] = CommaFormattedFloatRGB(skyColorA); exporter.G.extras["TB_SkyColorZenith"] = CommaFormattedFloatRGB(skyColorB); }
public static bool Export(string outputFile) { ExportUtils.SceneStatePayload payload = ExportCollector.GetExportPayload(AxisConvention.kVrml); var buffer = new StringBuilder("#VRML V2.0 utf8\n"); AppendSceneHeader(ref buffer); foreach (var group in payload.groups) { foreach (var brushMeshPayload in group.brushMeshes) { var pool = brushMeshPayload.geometry; Color32 lastColor = pool.m_Colors[0]; // Set to color of first vert initially int j = 0; // An index marking current position in pool.m_Tris int numVerts = 0; // Number of verts appended int firstVertInchunk = 0; // So chunks starts triangle-indexing verts at 0 in the wrl AppendchunkHeader(ref buffer); AppendchunkVerticesHeader(ref buffer); // Iterate through the verts-array and append them to the wrl. // Upon hitting a vertex with a different color (a new chunk), backtrack and iterate // through the tris-array, appending all triangles that are in the current chunk. // Continue again with the new chunk, etc., until all vertices are appended. for (int i = 0; i < pool.NumVerts; i++) { Color32 curColor = pool.m_Colors[i]; if (curColor.Equals(lastColor)) { // In the same chunk AppendVertex(ref buffer, pool, i); numVerts += 1; if (i == pool.NumVerts - 1) { // last vertex AppendchunkVerticesFooter(ref buffer); AppendchunkTrianglesHeader(ref buffer); while (j < pool.NumTriIndices) { // Append all remaining triangles AppendTriangle(ref buffer, pool, j, firstVertInchunk); j += 3; } AppendchunkTrianglesFooter(ref buffer); AppendchunkAppearanceHeader(ref buffer); AppendColorRGB(ref buffer, lastColor); AppendColorA(ref buffer, lastColor); AppendchunkAppearanceFooter(ref buffer); AppendchunkFooter(ref buffer); } } else { // New color, so new chunk AppendchunkVerticesFooter(ref buffer); AppendchunkTrianglesHeader(ref buffer); // Vertex "i" is part of a new chunk, therefore only append // triangles that contain vertices up to and not including "i" while (j < pool.NumTriIndices) { // Only check first index in triangle because triangles cannot span across chunks. // Either all vertices of the triangle are in chunk_n or all are in chunk_n+1. if (pool.m_Tris[j] < i) { AppendTriangle(ref buffer, pool, j, firstVertInchunk); j += 3; } else { break; } } AppendchunkTrianglesFooter(ref buffer); AppendchunkAppearanceHeader(ref buffer); AppendColorRGB(ref buffer, lastColor); AppendColorA(ref buffer, lastColor); AppendchunkAppearanceFooter(ref buffer); AppendchunkFooter(ref buffer); AppendchunkHeader(ref buffer); // Starting the next chunk AppendchunkVerticesHeader(ref buffer); AppendVertex(ref buffer, pool, i); firstVertInchunk = numVerts; numVerts += 1; lastColor = curColor; } } } } AppendSceneFooter(ref buffer); System.IO.File.WriteAllText(outputFile, buffer.ToString()); return true; }