11using System.Collections.Generic;
15 [AddComponentMenu(
"UI/Effects/Extensions/Gradient2")]
25 [Tooltip(
"Add vertices to display complex gradients. Turn off if your shape is already very complex, like text.")]
26 bool _modifyVertices =
true;
37 UnityEngine.Gradient _effectGradient =
new UnityEngine.Gradient() { colorKeys =
new GradientColorKey[] {
new GradientColorKey(
Color.black, 0),
new GradientColorKey(
Color.white, 1) } };
42 get {
return _blendMode; }
46 graphic.SetVerticesDirty();
52 get {
return _effectGradient; }
55 _effectGradient = value;
56 graphic.SetVerticesDirty();
62 get {
return _gradientType; }
65 _gradientType = value;
66 graphic.SetVerticesDirty();
72 get {
return _modifyVertices; }
75 _modifyVertices = value;
76 graphic.SetVerticesDirty();
82 get {
return _offset; }
85 _offset = Mathf.Clamp(value, -1f, 1f);
86 graphic.SetVerticesDirty();
95 _zoom = Mathf.Clamp(value, 0.1f, 10f);
96 graphic.SetVerticesDirty();
103 if (!IsActive() || helper.currentVertCount == 0)
106 List<UIVertex> _vertexList =
new List<UIVertex>();
108 helper.GetUIVertexStream(_vertexList);
110 int nCount = _vertexList.Count;
113 case Type.Horizontal:
116 Rect bounds = GetBounds(_vertexList);
117 float min = bounds.xMin;
118 float w = bounds.width;
119 Func<UIVertex, float> GetPosition = v => v.position.x;
125 GetPosition = v => v.position.y;
128 float width = w == 0f ? 0f : 1f / w /
Zoom;
129 float zoomOffset = (1 - (1 /
Zoom)) * 0.5f;
130 float offset = (
Offset * (1 - zoomOffset)) - zoomOffset;
134 SplitTrianglesAtGradientStops(_vertexList, bounds, zoomOffset, helper);
137 UIVertex vertex =
new UIVertex();
138 for (
int i = 0; i < helper.currentVertCount; i++)
140 helper.PopulateUIVertex(ref vertex, i);
141 vertex.color = BlendColor(vertex.color,
EffectGradient.Evaluate((GetPosition(vertex) - min) * width - offset));
142 helper.SetUIVertex(vertex, i);
149 Rect bounds = GetBounds(_vertexList);
151 float height = bounds.height == 0f ? 0f : 1f / bounds.height /
Zoom;
152 float radius = bounds.center.y / 2f;
153 Vector3 center = (Vector3.right + Vector3.up) * radius + Vector3.forward * _vertexList[0].position.z;
158 for (
int i = 0; i < nCount; i++) helper.AddVert(_vertexList[i]);
160 UIVertex centralVertex =
new UIVertex();
161 centralVertex.position = center;
162 centralVertex.normal = _vertexList[0].normal;
163 centralVertex.uv0 =
new Vector2(0.5f, 0.5f);
164 centralVertex.color =
Color.white;
165 helper.AddVert(centralVertex);
167 for (
int i = 1; i < nCount; i++) helper.AddTriangle(i - 1, i, nCount);
168 helper.AddTriangle(0, nCount - 1, nCount);
171 UIVertex vertex =
new UIVertex();
173 for (
int i = 0; i < helper.currentVertCount; i++)
175 helper.PopulateUIVertex(ref vertex, i);
178 Vector3.Distance(vertex.position, center) * height -
Offset));
180 helper.SetUIVertex(vertex, i);
187 Rect bounds = GetBounds(_vertexList);
189 float width = bounds.width == 0f ? 0f : 1f / bounds.width /
Zoom;
190 float height = bounds.height == 0f ? 0f : 1f / bounds.height /
Zoom;
196 float radiusX = bounds.width / 2f;
197 float radiusY = bounds.height / 2f;
198 UIVertex centralVertex =
new UIVertex();
199 centralVertex.position = Vector3.right * bounds.center.x + Vector3.up * bounds.center.y + Vector3.forward * _vertexList[0].position.z;
200 centralVertex.normal = _vertexList[0].normal;
201 centralVertex.uv0 =
new Vector2(0.5f, 0.5f);
202 centralVertex.color =
Color.white;
205 for (
int i = 0; i < steps; i++)
207 UIVertex curVertex =
new UIVertex();
208 float angle = (float)i * 360f / (
float)steps;
209 float cosX = Mathf.Cos(Mathf.Deg2Rad * angle);
210 float cosY = Mathf.Sin(Mathf.Deg2Rad * angle);
212 curVertex.position = Vector3.right * cosX * radiusX + Vector3.up * cosY * radiusY + Vector3.forward * _vertexList[0].position.z;
213 curVertex.normal = _vertexList[0].normal;
214 curVertex.uv0 =
new Vector2((cosX + 1) * 0.5f, (cosY + 1) * 0.5f);
215 curVertex.color =
Color.white;
216 helper.AddVert(curVertex);
219 helper.AddVert(centralVertex);
221 for (
int i = 1; i < steps; i++) helper.AddTriangle(i - 1, i, steps);
222 helper.AddTriangle(0, steps - 1, steps);
225 UIVertex vertex =
new UIVertex();
227 for (
int i = 0; i < helper.currentVertCount; i++)
229 helper.PopulateUIVertex(ref vertex, i);
233 Mathf.Pow(Mathf.Abs(vertex.position.x - bounds.center.x) * width, 2f) +
234 Mathf.Pow(Mathf.Abs(vertex.position.y - bounds.center.y) * height, 2f)) * 2f -
Offset));
236 helper.SetUIVertex(vertex, i);
243 Rect GetBounds(List<UIVertex> vertices)
245 float left = vertices[0].position.x;
247 float bottom = vertices[0].position.y;
250 for (
int i = vertices.Count - 1; i >= 1; --i)
252 float x = vertices[i].position.x;
253 float y = vertices[i].position.y;
255 if (x > right) right = x;
256 else if (x < left) left = x;
258 if (y > top) top = y;
259 else if (y < bottom) bottom = y;
262 return new Rect(left, bottom, right - left, top - bottom);
265 void SplitTrianglesAtGradientStops(List<UIVertex> _vertexList, Rect bounds,
float zoomOffset, VertexHelper helper)
267 List<float> stops = FindStops(zoomOffset, bounds);
272 int nCount = _vertexList.Count;
273 for (
int i = 0; i < nCount; i += 3)
275 float[] positions = GetPositions(_vertexList, i);
276 List<int> originIndices =
new List<int>(3);
277 List<UIVertex> starts =
new List<UIVertex>(3);
278 List<UIVertex> ends =
new List<UIVertex>(2);
280 for (
int s = 0; s < stops.Count; s++)
282 int initialCount = helper.currentVertCount;
283 bool hadEnds = ends.Count > 0;
284 bool earlyStart =
false;
287 for (
int p = 0; p < 3; p++)
289 if (!originIndices.Contains(p) && positions[p] < stops[s])
292 int p1 = (p + 1) % 3;
293 var start = _vertexList[p + i];
294 if (positions[p1] > stops[s])
296 originIndices.Insert(0, p);
297 starts.Insert(0, start);
302 originIndices.Add(p);
309 if (originIndices.Count == 0)
311 if (originIndices.Count == 3)
315 foreach (var start
in starts)
316 helper.AddVert(start);
320 foreach (
int index
in originIndices)
322 int oppositeIndex = (index + 1) % 3;
323 if (positions[oppositeIndex] < stops[s])
324 oppositeIndex = (oppositeIndex + 1) % 3;
325 ends.Add(CreateSplitVertex(_vertexList[index + i], _vertexList[oppositeIndex + i], stops[s]));
329 int oppositeIndex = (originIndices[0] + 2) % 3;
330 ends.Add(CreateSplitVertex(_vertexList[originIndices[0] + i], _vertexList[oppositeIndex + i], stops[s]));
334 foreach (var end
in ends)
340 helper.AddTriangle(initialCount - 2, initialCount, initialCount + 1);
341 helper.AddTriangle(initialCount - 2, initialCount + 1, initialCount - 1);
342 if (starts.Count > 0)
345 helper.AddTriangle(initialCount - 2, initialCount + 3, initialCount);
347 helper.AddTriangle(initialCount + 1, initialCount + 3, initialCount - 1);
352 int vertexCount = helper.currentVertCount;
353 helper.AddTriangle(initialCount, vertexCount - 2, vertexCount - 1);
354 if (starts.Count > 1)
355 helper.AddTriangle(initialCount, vertexCount - 1, initialCount + 1);
365 if (starts.Count == 0)
367 for (
int p = 0; p < 3; p++)
369 if (!originIndices.Contains(p) && positions[p] > stops[stops.Count - 1])
371 int p1 = (p + 1) % 3;
372 UIVertex end = _vertexList[p + i];
373 if (positions[p1] > stops[stops.Count - 1])
374 starts.Insert(0, end);
382 foreach (var start
in starts)
383 helper.AddVert(start);
386 int vertexCount = helper.currentVertCount;
387 if (starts.Count > 1)
389 helper.AddTriangle(vertexCount - 4, vertexCount - 2, vertexCount - 1);
390 helper.AddTriangle(vertexCount - 4, vertexCount - 1, vertexCount - 3);
392 else if (starts.Count > 0)
394 helper.AddTriangle(vertexCount - 3, vertexCount - 1, vertexCount - 2);
400 helper.AddVert(_vertexList[i]);
401 helper.AddVert(_vertexList[i + 1]);
402 helper.AddVert(_vertexList[i + 2]);
403 int vertexCount = helper.currentVertCount;
404 helper.AddTriangle(vertexCount - 3, vertexCount - 2, vertexCount - 1);
410 float[] GetPositions(List<UIVertex> _vertexList,
int index)
412 float[] positions =
new float[3];
415 positions[0] = _vertexList[index].position.x;
416 positions[1] = _vertexList[index + 1].position.x;
417 positions[2] = _vertexList[index + 2].position.x;
421 positions[0] = _vertexList[index].position.y;
422 positions[1] = _vertexList[index + 1].position.y;
423 positions[2] = _vertexList[index + 2].position.y;
428 List<float> FindStops(
float zoomOffset, Rect bounds)
430 List<float> stops =
new List<float>();
431 var offset =
Offset * (1 - zoomOffset);
432 var startBoundary = zoomOffset - offset;
433 var endBoundary = (1 - zoomOffset) - offset;
437 if (color.time >= endBoundary)
439 if (color.time > startBoundary)
440 stops.Add((color.time - startBoundary) *
Zoom);
444 if (alpha.time >= endBoundary)
446 if (alpha.time > startBoundary)
447 stops.Add((alpha.time - startBoundary) *
Zoom);
450 float min = bounds.xMin;
451 float size = bounds.width;
455 size = bounds.height;
459 for (
int i = 0; i < stops.Count; i++)
461 stops[i] = (stops[i] * size) + min;
463 if (i > 0 &&
Math.Abs(stops[i] - stops[i - 1]) < 2)
473 UIVertex CreateSplitVertex(UIVertex vertex1, UIVertex vertex2,
float stop)
477 float sx = vertex1.position.x - stop;
478 float dx = vertex1.position.x - vertex2.position.x;
479 float dy = vertex1.position.y - vertex2.position.y;
480 float uvx = vertex1.uv0.x - vertex2.uv0.x;
481 float uvy = vertex1.uv0.y - vertex2.uv0.y;
482 float ratio = sx / dx;
483 float splitY = vertex1.position.y - (dy * ratio);
485 UIVertex splitVertex =
new UIVertex();
486 splitVertex.position =
new Vector3(stop, splitY, vertex1.position.z);
487 splitVertex.normal = vertex1.normal;
488 splitVertex.uv0 =
new Vector2(vertex1.uv0.x - (uvx * ratio), vertex1.uv0.y - (uvy * ratio));
489 splitVertex.color =
Color.white;
494 float sy = vertex1.position.y - stop;
495 float dy = vertex1.position.y - vertex2.position.y;
496 float dx = vertex1.position.x - vertex2.position.x;
497 float uvx = vertex1.uv0.x - vertex2.uv0.x;
498 float uvy = vertex1.uv0.y - vertex2.uv0.y;
499 float ratio = sy / dy;
500 float splitX = vertex1.position.x - (dx * ratio);
502 UIVertex splitVertex =
new UIVertex();
503 splitVertex.position =
new Vector3(splitX, stop, vertex1.position.z);
504 splitVertex.normal = vertex1.normal;
505 splitVertex.uv0 =
new Vector2(vertex1.uv0.x - (uvx * ratio), vertex1.uv0.y - (uvy * ratio));
506 splitVertex.color =
Color.white;
515 default:
return colorB;
516 case Blend.Add:
return colorA + colorB;
517 case Blend.Multiply:
return colorA * colorB;
override void ModifyMesh(VertexHelper helper)
UnityEngine.Gradient EffectGradient
Credit Erdener Gonenc - @PixelEnvision.