internal static Texture2D RenderVectorImageToTexture2D(UnityEngine.Object o, int width, int height, Material mat, int antiAliasing = 1) { var vi = o as VectorImage; if (o == null) { return(null); } if (width <= 0 || height <= 0) { return(null); } RenderTexture rt = null; var oldActive = RenderTexture.active; var desc = new RenderTextureDescriptor(width, height, RenderTextureFormat.ARGB32, 0) { msaaSamples = antiAliasing, sRGB = QualitySettings.activeColorSpace == ColorSpace.Linear }; rt = RenderTexture.GetTemporary(desc); RenderTexture.active = rt; Vector2[] vertices = null; UInt16[] indices = null; Vector2[] uvs = null; Color[] colors = null; Vector2[] settingIndices = null; Texture2D atlas = null; Vector2 size = Vector2.zero; if (InternalBridge.GetDataFromVectorImage(o, ref vertices, ref indices, ref uvs, ref colors, ref settingIndices, ref atlas, ref size)) { vertices = vertices.Select(v => new Vector2(v.x / size.x, 1.0f - v.y / size.y)).ToArray(); var atlasWithEncodedSettings = vi.atlas != null?BuildAtlasWithEncodedSettings(vi.settings, vi.atlas) : null; VectorUtils.RenderFromArrays(vertices, indices, uvs, colors, settingIndices, atlasWithEncodedSettings, mat); Texture2D.DestroyImmediate(atlasWithEncodedSettings); } else { RenderTexture.active = oldActive; RenderTexture.ReleaseTemporary(rt); return(null); } Texture2D copy = new Texture2D(width, height, TextureFormat.RGBA32, false); copy.hideFlags = HideFlags.HideAndDontSave; copy.ReadPixels(new Rect(0, 0, width, height), 0, 0); copy.Apply(); RenderTexture.active = oldActive; RenderTexture.ReleaseTemporary(rt); return(copy); }
/// <summary>Builds a sprite asset from a scene tessellation.</summary> /// <param name="geoms">The list of tessellated Geometry instances</param> /// <param name="rect">The position and size of the sprite geometry</param> /// <param name="svgPixelsPerUnit">How many SVG "pixels" map into a Unity unit</param> /// <param name="alignment">The position of the sprite origin</param> /// <param name="customPivot">If alignment is <see cref="Alignment.Custom"/>, customPivot is used to compute the sprite origin</param> /// <param name="gradientResolution">The maximum size of the texture holding gradient data</param> /// <param name="flipYAxis">True to have the positive Y axis to go downward.</param> /// <returns>A new Sprite containing the provided geometry. The Sprite may have a texture if the geometry has any texture and/or gradients</returns> public static Sprite BuildSprite(List <Geometry> geoms, Rect rect, float svgPixelsPerUnit, Alignment alignment, Vector2 customPivot, UInt16 gradientResolution, bool flipYAxis = false) { // Generate atlas var texAtlas = GenerateAtlasAndFillUVs(geoms, gradientResolution); List <Vector2> vertices; List <UInt16> indices; List <Color> colors; List <Vector2> uvs; List <Vector2> settingIndices; FillVertexChannels(geoms, 1.0f, texAtlas != null, out vertices, out indices, out colors, out uvs, out settingIndices, flipYAxis); Texture2D texture = texAtlas != null ? texAtlas.Texture : null; if (rect == Rect.zero) { rect = VectorUtils.Bounds(vertices); VectorUtils.RealignVerticesInBounds(vertices, rect, flipYAxis); } else if (flipYAxis) { VectorUtils.FlipVerticesInBounds(vertices, rect); // The provided rect should normally contain the whole geometry, but since VectorUtils.SceneNodeBounds doesn't // take the strokes into account, some triangles may appear outside the rect. We clamp the vertices as a workaround for now. VectorUtils.ClampVerticesInBounds(vertices, rect); } var pivot = GetPivot(alignment, customPivot, rect, flipYAxis); var sprite = InternalBridge.CreateSprite(rect, pivot, svgPixelsPerUnit, texture); sprite.OverrideGeometry(vertices.ToArray(), indices.ToArray()); if (colors != null) { var colors32 = colors.Select(c => (Color32)c); using (var nativeColors = new NativeArray <Color32>(colors32.ToArray(), Allocator.Temp)) sprite.SetVertexAttribute <Color32>(VertexAttribute.Color, nativeColors); } if (uvs != null) { using (var nativeUVs = new NativeArray <Vector2>(uvs.ToArray(), Allocator.Temp)) sprite.SetVertexAttribute <Vector2>(VertexAttribute.TexCoord0, nativeUVs); using (var nativeSettingIndices = new NativeArray <Vector2>(settingIndices.ToArray(), Allocator.Temp)) sprite.SetVertexAttribute <Vector2>(VertexAttribute.TexCoord2, nativeSettingIndices); } return(sprite); }
internal static void MakeVectorImageAsset(IEnumerable <VectorUtils.Geometry> geoms, uint rasterSize, out UnityEngine.Object outAsset, out Texture2D outTexAtlas) { var atlas = VectorUtils.GenerateAtlas(geoms, rasterSize, false, false); if (atlas != null) { VectorUtils.FillUVs(geoms, atlas); } bool hasTexture = atlas != null && atlas.Texture != null; outTexAtlas = hasTexture ? atlas.Texture : null; var vertices = new List <InternalBridge.VectorImageVertexBridge>(100); var indices = new List <UInt16>(300); var settings = new List <InternalBridge.GradientSettingsBridge>(); var min = new Vector2(float.MaxValue, float.MaxValue); var max = new Vector2(float.MinValue, float.MinValue); foreach (var geom in geoms) { if (geom.Vertices.Length == 0) { continue; } var b = VectorUtils.Bounds(geom.Vertices.Select(v => geom.WorldTransform.MultiplyPoint(v))); min = Vector2.Min(min, b.min); max = Vector2.Max(max, b.max); } var bounds = Rect.zero; if (min.x != float.MaxValue) { bounds = new Rect(min, max - min); } // Save written settings to avoid duplicates var writtenSettings = new HashSet <int>(); writtenSettings.Add(0); // Create a map of filling -> atlas entry var fillEntries = new Dictionary <IFill, VectorUtils.PackRectItem>(); if (atlas != null && atlas.Entries != null) { foreach (var entry in atlas.Entries) { if (entry.Fill != null) { fillEntries[entry.Fill] = entry; } } } if (hasTexture && atlas != null && atlas.Entries != null && atlas.Entries.Count > 0) { // Write the 'white' texel info var entry = atlas.Entries[atlas.Entries.Count - 1]; settings.Add(new InternalBridge.GradientSettingsBridge() { gradientType = InternalBridge.GradientTypeBridge.Linear, addressMode = InternalBridge.AddressModeBridge.Wrap, radialFocus = Vector2.zero, location = new RectInt((int)entry.Position.x, (int)entry.Position.y, (int)entry.Size.x, (int)entry.Size.y) }); } foreach (var geom in geoms) { for (int i = 0; i < geom.Vertices.Length; ++i) { var v = geom.WorldTransform.MultiplyPoint(geom.Vertices[i]); v -= bounds.position; geom.Vertices[i] = v; } VectorUtils.AdjustWinding(geom.Vertices, geom.Indices, VectorUtils.WindingDir.CCW); var count = vertices.Count; for (int i = 0; i < geom.Vertices.Length; ++i) { Vector3 p = (Vector3)geom.Vertices[i]; p.z = Vertex.nearZ; vertices.Add(new InternalBridge.VectorImageVertexBridge() { position = p, uv = hasTexture ? geom.UVs[i] : Vector2.zero, tint = geom.Color, settingIndex = (uint)geom.SettingIndex }); } indices.AddRange(geom.Indices.Select(i => (UInt16)(i + count))); if (atlas != null && atlas.Entries != null && atlas.Entries.Count > 0) { VectorUtils.PackRectItem entry; if (geom.Fill == null || !fillEntries.TryGetValue(geom.Fill, out entry) || writtenSettings.Contains(entry.SettingIndex)) { continue; } writtenSettings.Add(entry.SettingIndex); var gradientType = GradientFillType.Linear; var radialFocus = Vector2.zero; var addressMode = AddressMode.Wrap; var gradientFill = geom.Fill as GradientFill; if (gradientFill != null) { gradientType = gradientFill.Type; radialFocus = gradientFill.RadialFocus; addressMode = gradientFill.Addressing; } var textureFill = geom.Fill as TextureFill; if (textureFill != null) { addressMode = textureFill.Addressing; } settings.Add(new InternalBridge.GradientSettingsBridge() { gradientType = (InternalBridge.GradientTypeBridge)gradientType, addressMode = (InternalBridge.AddressModeBridge)addressMode, radialFocus = radialFocus, location = new RectInt((int)entry.Position.x, (int)entry.Position.y, (int)entry.Size.x, (int)entry.Size.y) }); } } outAsset = InternalBridge.MakeVectorImageAsset(vertices, indices, outTexAtlas, settings, bounds.size); }