浏览代码

Complete C# part of antialiasing, with temporary shader.

/main
Yuncong Zhang 5 年前
当前提交
da75b829
共有 9 个文件被更改,包括 437 次插入194 次删除
  1. 8
      Runtime/Resources/UIWidgets_canvas.cginc
  2. 3
      Runtime/ui/renderer/cmdbufferCanvas/rendering/canvas_clip.cs
  3. 52
      Runtime/ui/renderer/cmdbufferCanvas/rendering/canvas_impl.cs
  4. 19
      Runtime/ui/renderer/cmdbufferCanvas/rendering/canvas_shader.cs
  5. 418
      Runtime/ui/renderer/common/geometry/path/path_cache.cs
  6. 84
      Runtime/ui/renderer/common/geometry/path/path_utils.cs
  7. 9
      Runtime/ui/renderer/common/picture.cs
  8. 29
      Runtime/Resources/UIWidgets_canvas_strokeAlpha.shader
  9. 9
      Runtime/Resources/UIWidgets_canvas_strokeAlpha.shader.meta

8
Runtime/Resources/UIWidgets_canvas.cginc


return color;
}
float strokeMask(float u, float v) {
return min(1.0, (1.0 - abs(u * 2.0 - 1.0)) * _alpha) * min(1.0, v);
}
fixed4 frag_stroke_alpha(v2f i) : SV_Target {
return _color * strokeMask(i.ftcoord.x, i.ftcoord.y);
}

3
Runtime/ui/renderer/cmdbufferCanvas/rendering/canvas_clip.cs


newElement.saveCount = saveCount;
var pathCache = uiPath.flatten(scale);
var fillMesh = pathCache.getFillMesh(out newElement.convex);
pathCache.computeFillMesh(0.0f, out newElement.convex);
var fillMesh = pathCache.fillMesh;
newElement.mesh = fillMesh.transform(matrix);
var vertices = newElement.mesh.vertices;

52
Runtime/ui/renderer/cmdbufferCanvas/rendering/canvas_impl.cs


var maskState = maskLayer.states[maskLayer.states.Count - 1];
maskState.matrix = parentState.matrix;
drawCallback.Invoke(uiPaint.shapeOnly(paint), mesh, convex, alpha, tex, texBound, textMesh, notEmoji);
drawCallback.Invoke(uiPaint.shapeOnly(paint), mesh, null, convex, alpha, tex, texBound, textMesh, notEmoji);
var removed = this._layers.removeLast();
D.assert(removed == maskLayer);

layer.draws.Add(CanvasShader.texRT(layer, paint, blurMesh, blurLayer));
}
delegate void _drawPathDrawMeshCallbackDelegate(uiPaint p, uiMeshMesh mesh, bool convex, float alpha,
delegate void _drawPathDrawMeshCallbackDelegate(uiPaint p, uiMeshMesh fillMesh, uiMeshMesh strokeMesh, bool convex, float alpha,
void _drawPathDrawMeshCallback(uiPaint p, uiMeshMesh mesh, bool convex, float alpha, Texture tex,
void _drawPathDrawMeshCallback(uiPaint p, uiMeshMesh fillMesh, uiMeshMesh strokeMesh, bool convex, float alpha, Texture tex,
if (!this._applyClip(mesh.bounds)) {
ObjectPool<uiMeshMesh>.release(mesh);
if (!this._applyClip(fillMesh.bounds)) {
ObjectPool<uiMeshMesh>.release(fillMesh);
layer.draws.Add(CanvasShader.convexFill(layer, p, mesh));
layer.draws.Add(CanvasShader.convexFill(layer, p, fillMesh));
layer.draws.Add(CanvasShader.fill0(layer, mesh));
layer.draws.Add(CanvasShader.fill1(layer, p, mesh.boundsMesh));
layer.draws.Add(CanvasShader.fill0(layer, fillMesh));
layer.draws.Add(CanvasShader.fill1(layer, p, fillMesh.boundsMesh));
}
if (strokeMesh != null) {
layer.draws.Add(CanvasShader.strokeAlpha(layer, p, 1.0f, strokeMesh));
void _drawPathDrawMeshCallback2(uiPaint p, uiMeshMesh mesh, bool convex, float alpha, Texture tex,
void _drawPathDrawMeshCallback2(uiPaint p, uiMeshMesh fillMesh, uiMeshMesh strokeMesh, bool convex, float alpha, Texture tex,
if (!this._applyClip(mesh.bounds)) {
ObjectPool<uiMeshMesh>.release(mesh);
if (!this._applyClip(strokeMesh.bounds)) {
ObjectPool<uiMeshMesh>.release(strokeMesh);
layer.draws.Add(CanvasShader.stroke0(layer, p, alpha, mesh));
layer.draws.Add(CanvasShader.stroke1(layer, mesh.duplicate()));
layer.draws.Add(CanvasShader.strokeAlpha(layer, p, alpha, strokeMesh));
layer.draws.Add(CanvasShader.stroke1(layer, strokeMesh.duplicate()));
void _drawTextDrawMeshCallback(uiPaint p, uiMeshMesh mesh, bool convex, float alpha, Texture tex,
void _drawTextDrawMeshCallback(uiPaint p, uiMeshMesh fillMesh, uiMeshMesh strokeMesh, bool convex, float alpha, Texture tex,
uiRect textBlobBounds, TextBlobMesh textMesh, bool notEmoji) {
if (!this._applyClip(textBlobBounds)) {
ObjectPool<TextBlobMesh>.release(textMesh);

var cache = path.flatten(state.scale * this._devicePixelRatio);
bool convex;
var fillMesh = cache.getFillMesh(out convex);
var mesh = fillMesh.transform(state.matrix);
cache.computeFillMesh(this._fringeWidth, out convex);
var fillMesh = cache.fillMesh;
var strokeMesh = cache.strokeMesh;
var fmesh = fillMesh.transform(state.matrix);
var smesh = strokeMesh?.transform(state.matrix);
this._drawWithMaskFilter(mesh.bounds, paint, paint.maskFilter.Value, mesh, convex, 0, null,
this._drawWithMaskFilter(fmesh.bounds, paint, paint.maskFilter.Value, fmesh, convex, 0, null,
this._drawPathDrawMeshCallback(paint, mesh, convex, 0, null, uiRectHelper.zero, null, false);
this._drawPathDrawMeshCallback(paint, fmesh, smesh, convex, 0, null, uiRectHelper.zero, null, false);
}
else {
var state = this._currentLayer.currentState;

var cache = path.flatten(state.scale * this._devicePixelRatio);
var strokenMesh = cache.getStrokeMesh(
var strokeMesh = cache.computeStrokeMesh(
this._fringeWidth,
var mesh = strokenMesh.transform(state.matrix);
var mesh = strokeMesh.transform(state.matrix);
if (paint.maskFilter != null && paint.maskFilter.Value.sigma != 0) {
this._drawWithMaskFilter(mesh.bounds, paint, paint.maskFilter.Value, mesh, false, alpha, null,

this._drawPathDrawMeshCallback2(paint, mesh, false, alpha, null, uiRectHelper.zero, null, false);
this._drawPathDrawMeshCallback2(paint, null, mesh, false, alpha, null, uiRectHelper.zero, null, false);
}
}

return;
}
this._drawTextDrawMeshCallback(paint, null, false, 0, tex, textBlobBounds, mesh, notEmoji);
this._drawTextDrawMeshCallback(paint, null, null, false, 0, tex, textBlobBounds, mesh, notEmoji);
}
public void flush(uiPicture picture) {

19
Runtime/ui/renderer/cmdbufferCanvas/rendering/canvas_shader.cs


static readonly MaterialByBlendModeStencilComp _texMat;
static readonly Material _stencilMat;
static readonly Material _filterMat;
static readonly MaterialByBlendModeStencilComp _strokeAlphaMat;
static CanvasShader() {
var convexFillShader = Shader.Find("UIWidgets/canvas_convexFill");

throw new Exception("UIWidgets/canvas_stroke1 not found");
}
var strokeAlphaShader = Shader.Find("UIWidgets/canvas_strokeAlpha");
if (strokeAlphaShader == null) {
throw new Exception("UIWidgets/canvas_strokeAlpha not found");
}
var texShader = Shader.Find("UIWidgets/canvas_tex");
if (texShader == null) {
throw new Exception("UIWidgets/canvas_tex not found");

_fill1Mat = new MaterialByBlendMode(fill1Shader);
_stroke0Mat = new MaterialByBlendModeStencilComp(stroke0Shader);
_stroke1Mat = new Material(stroke1Shader) {hideFlags = HideFlags.HideAndDontSave};
_strokeAlphaMat = new MaterialByBlendModeStencilComp(strokeAlphaShader);
_texMat = new MaterialByBlendModeStencilComp(texShader);
_stencilMat = new Material(stencilShader) {hideFlags = HideFlags.HideAndDontSave};
_filterMat = new Material(filterShader) {hideFlags = HideFlags.HideAndDontSave};

return PictureFlusher.CmdDraw.create(
mesh: mesh,
pass: pass,
material: mat,
properties: props
);
}
public static PictureFlusher.CmdDraw strokeAlpha(PictureFlusher.RenderLayer layer, uiPaint paint, float alpha, uiMeshMesh mesh) {
var mat = _strokeAlphaMat.getMaterial(paint.blendMode, layer.ignoreClip);
_getShaderPassAndProps(layer, paint, mesh.matrix, alpha, out var pass, out var props);
return PictureFlusher.CmdDraw.create(
mesh: mesh,
pass: 0,
material: mat,
properties: props
);

418
Runtime/ui/renderer/common/geometry/path/path_cache.cs


//mesh cache
uiMeshMesh _fillMesh;
public uiMeshMesh fillMesh {
get { return this._fillMesh; }
}
public uiMeshMesh strokeMesh {
get { return this._strokeMesh; }
}
float _strokeWidth;
StrokeCap _lineCap;
StrokeJoin _lineJoin;

}
}
uiList<Vector3> _expandFill() {
var points = this._points;
var paths = this._paths;
for (var j = 0; j < paths.Count; j++) {
var path = paths[j];
if (path.count <= 2) {
continue;
}
var ip0 = path.first + path.count - 1;
var ip1 = path.first;
for (var i = 0; i < path.count; i++) {
var p0 = points[ip0];
var p1 = points[ip1];
p0.dx = p1.x - p0.x; // no need to normalize
p0.dy = p1.y - p0.y;
points[ip0] = p0;
ip0 = ip1++;
}
path.convex = true;
ip0 = path.first + path.count - 1;
ip1 = path.first;
for (var i = 0; i < path.count; i++) {
var p0 = points[ip0];
var p1 = points[ip1];
float cross = p1.dx * p0.dy - p0.dx * p1.dy;
if (cross < 0.0f) {
path.convex = false;
}
ip0 = ip1++;
}
paths[j] = path;
}
var cvertices = 0;
for (var i = 0; i < paths.Count; i++) {
var path = paths[i];
if (path.count <= 2) {
continue;
}
cvertices += path.count;
}
var _vertices = ObjectPool<uiList<Vector3>>.alloc();
_vertices.SetCapacity(cvertices);
for (var i = 0; i < paths.Count; i++) {
var path = paths[i];
if (path.count <= 2) {
continue;
}
path.ifill = _vertices.Count;
for (var j = 0; j < path.count; j++) {
var p = points[path.first + j];
_vertices.Add(new Vector2(p.x, p.y));
}
path.nfill = _vertices.Count - path.ifill;
paths[i] = path;
}
return _vertices;
}
public uiMeshMesh getFillMesh(out bool convex) {
if (this._fillMesh != null) {
convex = this._fillConvex;
return this._fillMesh;
}
var vertices = this._expandFill();
var paths = this._paths;
var cindices = 0;
for (var i = 0; i < paths.Count; i++) {
var path = paths[i];
if (path.count <= 2) {
continue;
}
if (path.nfill > 0) {
D.assert(path.nfill >= 2);
cindices += (path.nfill - 2) * 3;
}
}
var indices = ObjectPool<uiList<int>>.alloc();
indices.SetCapacity(cindices);
for (var i = 0; i < paths.Count; i++) {
var path = paths[i];
if (path.count <= 2) {
continue;
}
if (path.nfill > 0) {
for (var j = 2; j < path.nfill; j++) {
indices.Add(path.ifill);
indices.Add(path.ifill + j);
indices.Add(path.ifill + j - 1);
}
}
}
D.assert(indices.Count == cindices);
var mesh = uiMeshMesh.create(null, vertices, indices);
this._fillMesh = mesh;
this._fillConvex = false;
for (var i = 0; i < paths.Count; i++) {
var path = paths[i];
if (path.count <= 2) {
continue;
}
if (this._fillConvex) {
// if more than two paths, convex is false.
this._fillConvex = false;
break;
}
if (!path.convex) {
// if not convex, convex is false.
break;
}
this._fillConvex = true;
}
convex = this._fillConvex;
return this._fillMesh;
}
void _calculateJoins(float w, StrokeJoin lineJoin, float miterLimit) {
float iw = w > 0.0f ? 1.0f / w : 0.0f;

ip0 = path.first + path.count - 1;
ip1 = path.first;
path.convex = true;
for (var j = 0; j < path.count; j++) {
var p0 = points[ip0];
var p1 = points[ip1];

// Keep track of left turns.
float cross = p1.dx * p0.dy - p0.dx * p1.dy;
} else if (cross < 0.0f) {
path.convex = false;
}
// Calculate if we should use bevel or miter for inner join.

ip0 = ip1++;
}
paths[i] = path;
uiList<Vector3> _expandStroke(float w, StrokeCap lineCap, StrokeJoin lineJoin, float miterLimit) {
this._calculateJoins(w, lineJoin, miterLimit);
struct VertexUV {
public uiList<Vector3> fillVertices;
public uiList<Vector2> fillUV;
public uiList<Vector3> strokeVertices;
public uiList<Vector2> strokeUV;
}
VertexUV _expandStroke(float w, float fringe, StrokeCap lineCap, StrokeJoin lineJoin, float miterLimit) {
float aa = fringe;
float u0 = 0.0f, u1 = 1.0f;
w += aa * 0.5f;
if (aa == 0.0f) {
u0 = 0.5f;
u1 = 0.5f;
}
this._calculateJoins(w, lineJoin, miterLimit);
var points = this._points;
var paths = this._paths;

}
cvertices += path.count * 2;
cvertices += 4;
cvertices += 8;
var _uv = ObjectPool<uiList<Vector2>>.alloc();
_uv.SetCapacity(cvertices);
for (var i = 0; i < paths.Count; i++) {
var path = paths[i];
if (path.count <= 1) {

if (!path.closed) {
if (lineCap == StrokeCap.butt) {
_vertices.buttCapStart(p0, p0.dx, p0.dy, w, 0.0f);
_vertices.buttCapStart(_uv, p0, p0.dx, p0.dy, w, 0.0f, aa, u0, u1);
_vertices.buttCapStart(p0, p0.dx, p0.dy, w, w);
_vertices.buttCapStart(_uv, p0, p0.dx, p0.dy, w, w, aa, u0, u1);
_vertices.roundCapStart(p0, p0.dx, p0.dy, w, ncap);
_vertices.roundCapStart(_uv, p0, p0.dx, p0.dy, w, ncap, u0, u1);
}
}

if ((p1.flags & (uiPointFlags.bevel | uiPointFlags.innerBevel)) != 0) {
if (lineJoin == StrokeJoin.round) {
_vertices.roundJoin(p0, p1, w, w, ncap);
_vertices.roundJoin(_uv, p0, p1, w, w, ncap, u0, u1, aa);
_vertices.bevelJoin(p0, p1, w, w);
_vertices.bevelJoin(_uv, p0, p1, w, w, u0, u1, aa);
_uv.Add(new Vector2(u0, 1));
_uv.Add(new Vector2(u1, 1));
}
ip0 = ip1++;

p0 = points[ip0];
p1 = points[ip1];
if (lineCap == StrokeCap.butt) {
_vertices.buttCapEnd(p1, p0.dx, p0.dy, w, 0.0f);
_vertices.buttCapEnd(_uv, p1, p0.dx, p0.dy, w, 0.0f, aa, u0, u1);
_vertices.buttCapEnd(p1, p0.dx, p0.dy, w, w);
_vertices.buttCapEnd(_uv, p1, p0.dx, p0.dy, w, w, aa, u0, u1);
_vertices.roundCapEnd(p1, p0.dx, p0.dy, w, ncap);
_vertices.roundCapEnd(_uv, p1, p0.dx, p0.dy, w, ncap, u0, u1);
_uv.Add(new Vector2(u0, 1));
_uv.Add(new Vector2(u1, 1));
D.assert(_uv.Count == _vertices.Count);
return _vertices;
return new VertexUV {
strokeVertices = _vertices,
strokeUV = _uv,
};
public uiMeshMesh getStrokeMesh(float strokeWidth, StrokeCap lineCap, StrokeJoin lineJoin, float miterLimit) {
VertexUV _expandFill(float fringe) {
float aa = fringe;
var points = this._points;
var paths = this._paths;
this._calculateJoins(fringe, StrokeJoin.miter, 4.0f);
var cvertices = 0;
for (var i = 0; i < paths.Count; i++) {
var path = paths[i];
if (path.count <= 2) {
continue;
}
cvertices += path.count;
}
this._fillConvex = false;
for (var i = 0; i < paths.Count; i++) {
var path = paths[i];
if (path.count <= 2) {
continue;
}
if (this._fillConvex) {
// if more than two paths, convex is false.
this._fillConvex = false;
break;
}
if (!path.convex) {
// if not convex, convex is false.
break;
}
this._fillConvex = true;
}
var _vertices = ObjectPool<uiList<Vector3>>.alloc();
_vertices.SetCapacity(cvertices);
var _uv = ObjectPool<uiList<Vector2>>.alloc();
_uv.SetCapacity(cvertices);
for (var i = 0; i < paths.Count; i++) {
var path = paths[i];
if (path.count <= 2) {
continue;
}
path.ifill = _vertices.Count;
for (var j = 0; j < path.count; j++) {
var p = points[path.first + j];
_vertices.Add(new Vector2(p.x, p.y));
_uv.Add(new Vector2(0.5f, 1.0f));
}
path.nfill = _vertices.Count - path.ifill;
paths[i] = path;
}
uiList<Vector3> _strokeVertices = null;
uiList<Vector2> _strokeUV = null;
if (aa > 0.0f) {
_strokeVertices = ObjectPool<uiList<Vector3>>.alloc();
_strokeUV = ObjectPool<uiList<Vector2>>.alloc();
cvertices = 0;
for (var i = 0; i < paths.Count; i++) {
var path = paths[i];
if (path.count <= 2) {
continue;
}
cvertices += path.count * 2;
}
_strokeVertices.SetCapacity(cvertices);
_strokeUV.SetCapacity(cvertices);
float woff = aa * 0.5f;
float lw = this._fillConvex ? woff : aa + woff;
float rw = aa - woff;
float lu = this._fillConvex ? 0.5f : 0.0f;
float ru = 1.0f;
for (var i = 0; i < paths.Count; i++) {
var path = paths[i];
if (path.count <= 2) {
continue;
}
path.istroke = _strokeVertices.Count;
for (var j = 0; j < path.count; j++) {
var p = points[path.first + j];
_strokeVertices.Add(new Vector2(p.x + p.dmx * lw, p.y + p.dmy * lw));
_strokeUV.Add(new Vector2(lu, 1.0f));
_strokeVertices.Add(new Vector2(p.x - p.dmx * rw, p.y - p.dmy * rw));
_strokeUV.Add(new Vector2(ru, 1.0f));
}
path.nstroke = _strokeVertices.Count - path.istroke;
paths[i] = path;
}
}
return new VertexUV {
fillVertices = _vertices,
fillUV = _uv,
strokeVertices = _strokeVertices,
strokeUV = _strokeUV,
};
}
public uiMeshMesh computeStrokeMesh(float strokeWidth, float fringe, StrokeCap lineCap, StrokeJoin lineJoin, float miterLimit) {
if (this._strokeMesh != null &&
this._strokeWidth == strokeWidth &&
this._lineCap == lineCap &&

}
var vertices = this._expandStroke(strokeWidth, lineCap, lineJoin, miterLimit);
var verticesUV = this._expandStroke(strokeWidth, fringe, lineCap, lineJoin, miterLimit);
var paths = this._paths;

D.assert(indices.Count == cindices);
ObjectPool<uiMeshMesh>.release(this._strokeMesh);
this._strokeMesh = uiMeshMesh.create(null, vertices, indices);
this._strokeMesh = uiMeshMesh.create(null, verticesUV.strokeVertices, indices, verticesUV.strokeUV);
}
public void computeFillMesh(float fringe, out bool convex) {
if (this._fillMesh != null && (fringe != 0.0f || this._strokeMesh != null)) {
convex = this._fillConvex;
return;
}
var verticesUV = this._expandFill(fringe);
convex = this._fillConvex;
var paths = this._paths;
var cindices = 0;
for (var i = 0; i < paths.Count; i++) {
var path = paths[i];
if (path.count <= 2) {
continue;
}
if (path.nfill > 0) {
D.assert(path.nfill >= 2);
cindices += (path.nfill - 2) * 3;
}
}
var indices = ObjectPool<uiList<int>>.alloc();
indices.SetCapacity(cindices);
for (var i = 0; i < paths.Count; i++) {
var path = paths[i];
if (path.count <= 2) {
continue;
}
if (path.nfill > 0) {
for (var j = 2; j < path.nfill; j++) {
indices.Add(path.ifill);
indices.Add(path.ifill + j);
indices.Add(path.ifill + j - 1);
}
}
}
D.assert(indices.Count == cindices);
if (verticesUV.strokeVertices != null) {
cindices = 0;
for (var i = 0; i < paths.Count; i++) {
var path = paths[i];
if (path.count <= 2) {
continue;
}
if (path.nstroke > 0) {
D.assert(path.nstroke >= 6);
cindices += path.nstroke * 3;
}
}
var strokeIndices = ObjectPool<uiList<int>>.alloc();
strokeIndices.SetCapacity(cindices);
for (var i = 0; i < paths.Count; i++) {
var path = paths[i];
if (path.count <= 2) {
continue;
}
if (path.nstroke > 0) {
strokeIndices.Add(path.nstroke - 1);
strokeIndices.Add(path.nstroke - 2);
strokeIndices.Add(path.istroke);
strokeIndices.Add(path.nstroke - 1);
strokeIndices.Add(path.istroke);
strokeIndices.Add(path.istroke + 1);
for (var j = 2; j < path.nstroke; j++) {
if ((j & 1) == 0) {
strokeIndices.Add(path.istroke + j - 1);
strokeIndices.Add(path.istroke + j - 2);
strokeIndices.Add(path.istroke + j);
}
else {
strokeIndices.Add(path.istroke + j - 2);
strokeIndices.Add(path.istroke + j - 1);
strokeIndices.Add(path.istroke + j);
}
}
}
}
D.assert(strokeIndices.Count == cindices);
ObjectPool<uiMeshMesh>.release(this._strokeMesh);
this._strokeMesh = uiMeshMesh.create(null, verticesUV.strokeVertices, strokeIndices, verticesUV.strokeUV);
}
var mesh = uiMeshMesh.create(null, verticesUV.fillVertices, indices, verticesUV.fillUV);
this._fillMesh = mesh;
}
}
}

84
Runtime/ui/renderer/common/geometry/path/path_utils.cs


return d;
}
public static void buttCapStart(this uiList<Vector3> dst, uiPathPoint p,
float dx, float dy, float w, float d) {
public static void buttCapStart(this uiList<Vector3> dst, uiList<Vector2> uv, uiPathPoint p,
float dx, float dy, float w, float d, float aa, float u0, float u1) {
dst.Add(new Vector2(px + dlx * w - dx * aa, py + dly * w - dy * aa));
dst.Add(new Vector2(px - dlx * w - dx * aa, py - dly * w - dy * aa));
uv.Add(new Vector2(u0, 0));
uv.Add(new Vector2(u1, 0));
uv.Add(new Vector2(u0, 1));
uv.Add(new Vector2(u1, 1));
public static void buttCapEnd(this uiList<Vector3> dst, uiPathPoint p,
float dx, float dy, float w, float d) {
public static void buttCapEnd(this uiList<Vector3> dst, uiList<Vector2> uv, uiPathPoint p,
float dx, float dy, float w, float d, float aa, float u0, float u1) {
float px = p.x + dx * d;
float py = p.y + dy * d;
float dlx = dy;

dst.Add(new Vector2(px - dlx * w, py - dly * w));
dst.Add(new Vector2(px + dlx * w + dx * aa, py + dly * w + dy * aa));
dst.Add(new Vector2(px - dlx * w + dx * aa, py - dly * w + dy * aa));
uv.Add(new Vector2(u0, 1));
uv.Add(new Vector2(u1, 1));
uv.Add(new Vector2(u0, 0));
uv.Add(new Vector2(u1, 0));
public static void roundCapStart(this uiList<Vector3> dst, uiPathPoint p,
float dx, float dy, float w, int ncap) {
public static void roundCapStart(this uiList<Vector3> dst, uiList<Vector2> uv, uiPathPoint p,
float dx, float dy, float w, int ncap, float u0, float u1) {
float px = p.x;
float py = p.y;
float dlx = dy;

float ax = Mathf.Cos(a) * w, ay = Mathf.Sin(a) * w;
dst.Add(new Vector2(px - dlx * ax - dx * ay, py - dly * ax - dy * ay));
dst.Add(new Vector2(px, py));
uv.Add(new Vector2(u0, 1));
uv.Add(new Vector2(0.5f, 1));
uv.Add(new Vector2(u0, 1));
uv.Add(new Vector2(u1, 1));
public static void roundCapEnd(this uiList<Vector3> dst, uiPathPoint p,
float dx, float dy, float w, int ncap) {
public static void roundCapEnd(this uiList<Vector3> dst, uiList<Vector2> uv, uiPathPoint p,
float dx, float dy, float w, int ncap, float u0, float u1) {
float px = p.x;
float py = p.y;
float dlx = dy;

dst.Add(new Vector2(px - dlx * w, py - dly * w));
uv.Add(new Vector2(u0, 1));
uv.Add(new Vector2(u1, 1));
for (var i = 0; i < ncap; i++) {
float a = (float) i / (ncap - 1) * Mathf.PI;

uv.Add(new Vector2(0.5f, 1));
uv.Add(new Vector2(u0, 1));
}
}

return Mathf.Max(2, Mathf.CeilToInt(arc / da));
}
public static void roundJoin(this uiList<Vector3> dst, uiPathPoint p0, uiPathPoint p1,
float lw, float rw, int ncap) {
public static void roundJoin(this uiList<Vector3> dst, uiList<Vector2> uv, uiPathPoint p0, uiPathPoint p1,
float lw, float rw, int ncap, float lu, float ru, float fringe) {
float dlx0 = p0.dy;
float dly0 = -p0.dx;
float dlx1 = p1.dy;

dst.Add(new Vector2(lx0, ly0));
dst.Add(new Vector2(p1.x - dlx0 * rw, p1.y - dly0 * rw));
uv.Add(new Vector2(lu, 1));
uv.Add(new Vector2(ru, 1));
var n = Mathf.CeilToInt((a0 - a1) / Mathf.PI * ncap).clamp(2, ncap);
for (var i = 0; i < n; i++) {

dst.Add(new Vector2(p1.x, p1.y));
dst.Add(new Vector2(rx, ry));
uv.Add(new Vector2(0.5f, 1));
uv.Add(new Vector2(ru, 1));
uv.Add(new Vector2(lu, 1));
uv.Add(new Vector2(ru, 1));
}
else {
float rx0, ry0, rx1, ry1;

dst.Add(new Vector2(p1.x + dlx0 * lw, p1.y + dly0 * lw));
dst.Add(new Vector2(rx0, ry0));
uv.Add(new Vector2(lu, 1));
uv.Add(new Vector2(ru, 1));
var n = Mathf.CeilToInt((a1 - a0) / Mathf.PI * ncap).clamp(2, ncap);
for (var i = 0; i < n; i++) {

dst.Add(new Vector2(lx, ly));
dst.Add(new Vector2(p1.x, p1.y));
uv.Add(new Vector2(lu, 1));
uv.Add(new Vector2(0.5f, 1));
uv.Add(new Vector2(lu, 1));
uv.Add(new Vector2(ru, 1));
public static void bevelJoin(this uiList<Vector3> dst, uiPathPoint p0, uiPathPoint p1,
float lw, float rw) {
public static void bevelJoin(this uiList<Vector3> dst, uiList<Vector2> uv, uiPathPoint p0, uiPathPoint p1,
float lw, float rw, float lu, float ru, float fringe) {
float rx0, ry0, rx1, ry1;
float lx0, ly0, lx1, ly1;

dst.Add(new Vector2 {x = lx0, y = ly0});
dst.Add(new Vector2 {x = p1.x - dlx0 * rw, y = p1.y - dly0 * rw});
uv.Add(new Vector2(lu, 1));
uv.Add(new Vector2(ru, 1));
if ((p1.flags & uiPointFlags.bevel) != 0) {
dst.Add(new Vector2(lx0, ly0));

uv.Add(new Vector2(lu, 1));
uv.Add(new Vector2(ru, 1));
uv.Add(new Vector2(lu, 1));
uv.Add(new Vector2(ru, 1));
}
else {
rx0 = p1.x - p1.dmx * rw;

dst.Add(new Vector2(rx0, ry0));
dst.Add(new Vector2(p1.x, p1.y));
dst.Add(new Vector2(p1.x - dlx1 * rw, p1.y - dly1 * rw));
uv.Add(new Vector2(0.5f, 1));
uv.Add(new Vector2(ru, 1));
uv.Add(new Vector2(ru, 1));
uv.Add(new Vector2(ru, 1));
uv.Add(new Vector2(0.5f, 1));
uv.Add(new Vector2(ru, 1));
uv.Add(new Vector2(lu, 1));
uv.Add(new Vector2(ru, 1));
}
else {
chooseBevel((p1.flags & uiPointFlags.innerBevel) != 0, p0, p1, -rw,

dst.Add(new Vector2(rx0, ry0));
uv.Add(new Vector2(lu, 1));
uv.Add(new Vector2(ru, 1));
if ((p1.flags & uiPointFlags.bevel) != 0) {
dst.Add(new Vector2(p1.x + dlx0 * lw, p1.y + dly0 * lw));

uv.Add(new Vector2(lu, 1));
uv.Add(new Vector2(ru, 1));
uv.Add(new Vector2(lu, 1));
uv.Add(new Vector2(ru, 1));
}
else {
lx0 = p1.x + p1.dmx * lw;

dst.Add(new Vector2(lx0, ly0));
dst.Add(new Vector2(p1.x + dlx1 * lw, p1.y + dly1 * lw));
dst.Add(new Vector2(p1.x, p1.y));
uv.Add(new Vector2(lu, 1));
uv.Add(new Vector2(0.5f, 1));
uv.Add(new Vector2(lu, 1));
uv.Add(new Vector2(lu, 1));
uv.Add(new Vector2(lu, 1));
uv.Add(new Vector2(0.5f, 1));
uv.Add(new Vector2(lu, 1));
uv.Add(new Vector2(ru, 1));
}
}
}

9
Runtime/ui/renderer/common/picture.cs


var rectPathCache = cmd.path.flatten(
scale * Window.instance.devicePixelRatio);
var rectMesh = rectPathCache.getFillMesh(out _);
rectPathCache.computeFillMesh(0.0f, out _);
var rectMesh = rectPathCache.fillMesh;
var transformedMesh = rectMesh.transform(state.xform);
var rect = transformedMesh.bounds;
state.scissor = state.scissor == null ? rect : state.scissor.Value.intersect(rect);

uiMeshMesh mesh;
if (paint.style == PaintingStyle.fill) {
var cache = path.flatten(scale * devicePixelRatio);
var fillMesh = cache.getFillMesh(out _);
cache.computeFillMesh(0.0f, out _);
var fillMesh = cache.fillMesh;
mesh = fillMesh.transform(state.xform);
}
else {

}
var cache = path.flatten(scale * devicePixelRatio);
var strokenMesh = cache.getStrokeMesh(
var strokenMesh = cache.computeStrokeMesh(
0.0f,
paint.strokeCap,
paint.strokeJoin,
paint.strokeMiterLimit);

29
Runtime/Resources/UIWidgets_canvas_strokeAlpha.shader


Shader "UIWidgets/canvas_strokeAlpha"
{
Properties {
_SrcBlend("_SrcBlend", Int) = 1 // One
_DstBlend("_DstBlend", Int) = 10 // OneMinusSrcAlpha
_StencilComp("_StencilComp", Float) = 3 // - Equal, 8 - Always
}
SubShader {
ZTest Always
ZWrite Off
Blend [_SrcBlend] [_DstBlend]
Stencil {
Ref 128
Comp [_StencilComp]
Pass IncrSat
}
Pass { // 0, color
CGPROGRAM
#define UIWIDGETS_COLOR
#include "UIWidgets_canvas.cginc"
#pragma vertex vert
#pragma fragment frag_stroke_alpha
ENDCG
}
}
}

9
Runtime/Resources/UIWidgets_canvas_strokeAlpha.shader.meta


fileFormatVersion: 2
guid: c57ed8e638931f946a7b5e26a54725d8
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:
正在加载...
取消
保存