浏览代码

Merge branch 'optmize_shadow' of github.com:UnityTech/UIWidgets into dev

# Conflicts:
#	Runtime/ui/painting/path.cs
#	Runtime/ui/renderer/cmdbufferCanvas/rendering/canvas_impl.cs
#	Runtime/ui/renderer/cmdbufferCanvas/rendering/canvas_shader.cs
/main
xingwei.zhu 5 年前
当前提交
57b9eec6
共有 16 个文件被更改,包括 556 次插入56 次删除
  1. 5
      Runtime/ui/painting/painting.cs
  2. 78
      Runtime/ui/painting/path.cs
  3. 50
      Runtime/ui/painting/shadow_utils.cs
  4. 6
      Runtime/ui/renderer/cmdbufferCanvas/rendering/canvas_impl.cs
  5. 96
      Runtime/ui/renderer/cmdbufferCanvas/rendering/canvas_shader.cs
  6. 68
      Runtime/ui/renderer/common/geometry/path/path.cs
  7. 2
      Runtime/ui/renderer/compositeCanvas/flow/physical_shape_layer.cs
  8. 6
      Samples/UIWidgetSample/MaterialSample.cs
  9. 85
      Runtime/Resources/UIWidgets_canvas_shadowBox.shader
  10. 9
      Runtime/Resources/UIWidgets_canvas_shadowBox.shader.meta
  11. 117
      Runtime/Resources/UIWidgets_canvas_shadowRBox.shader
  12. 9
      Runtime/Resources/UIWidgets_canvas_shadowRBox.shader.meta
  13. 40
      Runtime/ui/renderer/cmdbufferCanvas/rendering/canvas_shadow_utils.cs
  14. 11
      Runtime/ui/renderer/cmdbufferCanvas/rendering/canvas_shadow_utils.cs.meta
  15. 19
      Runtime/ui/renderer/common/geometry/path/path_extension.cs
  16. 11
      Runtime/ui/renderer/common/geometry/path/path_extension.cs.meta

5
Runtime/ui/painting/painting.cs


solid,
outer,
inner,
fast_shadow
}
public class MaskFilter : IEquatable<MaskFilter> {

public static MaskFilter blur(BlurStyle style, float sigma) {
return new MaskFilter(style, sigma);
}
public static MaskFilter fastShadow(float sigma) {
return new MaskFilter(BlurStyle.fast_shadow, sigma);
}
public readonly BlurStyle style;

78
Runtime/ui/painting/path.cs


uint _pathKey = 0;
//shadow speeder relevant
bool _isNaiveRRect = false;
public bool isNaiveRRect => this._isNaiveRRect;
PathShapeHint _shapeHint = PathShapeHint.Other;
public PathShapeHint shapeHint => this._shapeHint;
float _rRectCorner;
public float rRectCorner => this._rRectCorner;
public uint pathKey {
get { return this._pathKey; }
}

get { return this._commands; }
}
void _updateRRectFlag(bool isNaiveRRect, PathShapeHint shapeHint = PathShapeHint.Other, float corner = 0) {
if (this._commands.Count > 0 && !this._isNaiveRRect) {
return;
}
this._isNaiveRRect = isNaiveRRect && this._hasOnlyMoveTos();
if (this._isNaiveRRect) {
this._shapeHint = shapeHint;
this._rRectCorner = corner;
}
}
bool _hasOnlyMoveTos() {
var i = 0;
while (i < this._commands.Count) {
var cmd = (PathCommand) this._commands[i];
switch (cmd) {
case PathCommand.moveTo:
i += 3;
break;
case PathCommand.lineTo:
return false;
case PathCommand.bezierTo:
return false;
case PathCommand.close:
i++;
break;
case PathCommand.winding:
i += 2;
break;
default:
return false;
}
}
return true;
}
public override string ToString() {
var sb = new StringBuilder("Path: count = " + this._commands.Count);

this._pathKey = pathGlobalKey++;
this._cache = null;
this._isNaiveRRect = false;
}
internal PathCache flatten(float scale) {

var x0 = this._commandx;
var y0 = this._commandy;
this._updateRRectFlag(false);
this._updateRRectFlag(false);
this._updateRRectFlag(false);
this._appendBezierTo(c1x, c1y, c2x, c2y, x, y);
}

this._updateRRectFlag(false);
this.cubicTo(x0 + c1x, y0 + c1y, x0 + c2x, y0 + c2y, x0 + x, y0 + y);
}

const float twoThird = 2.0f / 3.0f;
this._updateRRectFlag(false);
this._appendBezierTo(
x0 + twoThird * (cx - x0), y0 + twoThird * (cy - y0),
x + twoThird * (cx - x), y + twoThird * (cy - y),

var x0 = this._commandx;
var y0 = this._commandy;
this._updateRRectFlag(false);
this._updateRRectFlag(false);
if (!(w > 0)) {
this.lineTo(x2, y2);
return;

public void relativeConicTo(float x1, float y1, float x2, float y2, float w) {
var x0 = this._commandx;
var y0 = this._commandy;
this._updateRRectFlag(false);
this.conicTo(x0 + x1, y0 + y1, x0 + x2, y0 + y2, w);
}

bool largeArc = false,
bool clockwise = false) {
radius = radius ?? Radius.zero;
this._updateRRectFlag(false);
D.assert(PaintingUtils._offsetIsValid(arcEnd));
D.assert(PaintingUtils._radiusIsValid(radius));

}
public void addRect(Rect rect) {
this._updateRRectFlag(true, PathShapeHint.Rect);
this._appendMoveTo(rect.left, rect.top);
this._appendLineTo(rect.left, rect.bottom);
this._appendLineTo(rect.right, rect.bottom);

public void addRRect(RRect rrect) {
this._updateRRectFlag(rrect.isNaiveRRect(), PathShapeHint.NaiveRRect, rrect.blRadiusX);
float w = rrect.width;
float h = rrect.height;
float halfw = Mathf.Abs(w) * 0.5f;

}
public void addEllipse(float cx, float cy, float rx, float ry) {
this._updateRRectFlag(rx == ry, PathShapeHint.Circle, rx);
this._appendMoveTo(cx - rx, cy);
this._appendBezierTo(cx - rx, cy + ry * _KAPPA90,
cx - rx * _KAPPA90, cy + ry, cx, cy + ry);

}
public void arcTo(float x1, float y1, float x2, float y2, float radius) {
this._updateRRectFlag(false);
var x0 = this._commandx;
var y0 = this._commandy;

}
public void arcTo(Rect rect, float startAngle, float sweepAngle, bool forceMoveTo = true) {
this._updateRRectFlag(false);
var mat = Matrix3.makeScale(rect.width / 2, rect.height / 2);
var center = rect.center;
mat.postTranslate(center.dx, center.dy);

}
public void addArc(Rect rect, float startAngle, float sweepAngle) {
this._updateRRectFlag(false);
this.arcTo(rect, startAngle, sweepAngle, true);
}

}
public void addArc(float cx, float cy, float r, float a0, float a1, PathWinding dir, bool forceMoveTo = true) {
this._updateRRectFlag(false);
this._updateRRectFlag(false);
D.assert(points != null);
if (points.Count == 0) {
return;

public void addPath(Path path, Matrix3 transform = null) {
D.assert(path != null);
this._updateRRectFlag(path.isNaiveRRect, path.shapeHint, path.rRectCorner);
var i = 0;
while (i < path._commands.Count) {
var cmd = (PathCommand) path._commands[i];

w = newW,
};
}
}
public enum PathShapeHint {
Rect,
Circle,
NaiveRRect,
Other
}
enum PathCommand {

50
Runtime/ui/painting/shadow_utils.cs


using Unity.UIWidgets.material;
public const bool kUseFastShadow = false;
public const bool kUseFastShadow = true;
const float kAmbientHeightFactor = 1.0f / 128.0f;
const float kAmbientGeomFactor = 64.0f;

const float kMaxAmbientRadius = 300 * kAmbientHeightFactor * kAmbientGeomFactor;
const bool debugShadow = false;
static float divideAndPin(float numer, float denom, float min, float max) {
return (numer / denom).clamp(min, max);

_shadowPaint.maskFilter = null;
}
//debug shadow
if (debugShadow) {
var isRRect = path.isNaiveRRect;
if (isRRect) {
ambientColor = uiColor.fromColor(Colors.red);
spotColor = uiColor.fromColor(Colors.red);
}
else {
ambientColor = uiColor.fromColor(Colors.green);
spotColor = uiColor.fromColor(Colors.green);
}
}
//ambient light
float devSpaceOutset = ambientBlurRadius(zPlaneParams.z);
float oneOverA = ambientRecipAlpha(zPlaneParams.z);

//Paint paint = new Paint {color = ambientColor, strokeWidth = strokeWidth, style = PaintingStyle.fill};
_shadowPaint.color = new Color(ambientColor.value);
_shadowPaint.strokeWidth = strokeWidth;
_shadowPaint.style = PaintingStyle.fill;

float radius = 0.0f;
if (!getSpotShadowTransform(devLightPos, lightRadius, viewMatrix, zPlaneParams, path.getBounds(),
_shadowMatrix, ref radius)) {
return;

canvas.setMatrix(_shadowMatrix);
//Paint paint2 = new Paint {color = spotColor};
float sigma2 = convertRadiusToSigma(radius);
_shadowPaint.maskFilter = path.isNaiveRRect ? MaskFilter.fastShadow(sigma2) : MaskFilter.blur(BlurStyle.normal, sigma2);
_shadowPaint.maskFilter = null;
}
/*
* Check whether the RRect is a naive Round-Rect, of which
* (1) all the corner radius are the same
* (2) the corner radius is not bigger than either half the width or the height of the Round Rect's bounding box
*
* Usage: The shadow of a naive Round-Rect can be easily drawn using a ShadowRBox shader, so we can use it to
* find all the situations that a fast shadow can be drawn to tackle the performance issue
*/
public static bool isNaiveRRect(this RRect rrect) {
var radius = rrect.tlRadiusX;
return rrect.tlRadiusY == radius &&
rrect.trRadiusX == radius &&
rrect.trRadiusY == radius &&
rrect.blRadiusX == radius &&
rrect.blRadiusY == radius &&
rrect.brRadiusX == radius &&
rrect.brRadiusY == radius &&
radius <= rrect.width / 2 &&
radius <= rrect.height / 2;
}
}
}

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


void _drawPath(uiPath path, uiPaint paint) {
D.assert(path != null);
//draw fast shadow
if (paint.maskFilter != null && paint.maskFilter.Value.style == BlurStyle.fast_shadow) {
this._drawRRectShadow(path, paint);
return;
}
if (paint.style == PaintingStyle.fill) {
var state = this._currentLayer.currentState;

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


static readonly Material _stencilMat;
static readonly Material _filterMat;
static readonly MaterialByBlendModeStencilComp _strokeAlphaMat;
static readonly Material _shadowBox;
static readonly Material _shadowRBox;
static CanvasShader() {
var convexFillShader = Shader.Find("UIWidgets/canvas_convexFill");
if (convexFillShader == null) {
throw new Exception("UIWidgets/canvas_convexFill not found");
}
var fill0Shader = Shader.Find("UIWidgets/canvas_fill0");
if (fill0Shader == null) {
throw new Exception("UIWidgets/canvas_fill0 not found");
static Shader GetShader(string shaderName) {
var shader = Shader.Find(shaderName);
if (shader == null) {
throw new Exception(shaderName + " not found");
var fill1Shader = Shader.Find("UIWidgets/canvas_fill1");
if (fill1Shader == null) {
throw new Exception("UIWidgets/canvas_fill1 not found");
}
return shader;
}
var stroke0Shader = Shader.Find("UIWidgets/canvas_stroke0");
if (stroke0Shader == null) {
throw new Exception("UIWidgets/canvas_stroke0 not found");
}
var stroke1Shader = Shader.Find("UIWidgets/canvas_stroke1");
if (stroke1Shader == null) {
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");
}
var stencilShader = Shader.Find("UIWidgets/canvas_stencil");
if (stencilShader == null) {
throw new Exception("UIWidgets/canvas_stencil not found");
}
var filterShader = Shader.Find("UIWidgets/canvas_filter");
if (filterShader == null) {
throw new Exception("UIWidgets/canvas_filter not found");
}
static CanvasShader() {
var convexFillShader = GetShader("UIWidgets/canvas_convexFill");
var fill0Shader = GetShader("UIWidgets/canvas_fill0");
var fill1Shader = GetShader("UIWidgets/canvas_fill1");
var stroke0Shader = GetShader("UIWidgets/canvas_stroke0");
var stroke1Shader = GetShader("UIWidgets/canvas_stroke1");
var texShader = GetShader("UIWidgets/canvas_tex");
var stencilShader = GetShader("UIWidgets/canvas_stencil");
var filterShader = GetShader("UIWidgets/canvas_filter");
var shadowBoxShader = GetShader("UIWidgets/ShadowBox");
var shadowRBoxShader = GetShader("UIWidgets/ShadowRBox");
_convexFillMat = new MaterialByBlendModeStencilComp(convexFillShader);
_fill0Mat = new MaterialByStencilComp(fill0Shader);

_texMat = new MaterialByBlendModeStencilComp(texShader);
_stencilMat = new Material(stencilShader) {hideFlags = HideFlags.HideAndDontSave};
_filterMat = new Material(filterShader) {hideFlags = HideFlags.HideAndDontSave};
_shadowBox = new Material(shadowBoxShader) {hideFlags = HideFlags.HideAndDontSave};
_shadowRBox = new Material(shadowRBoxShader) {hideFlags = HideFlags.HideAndDontSave};
public static Material shadowBox => _shadowBox;
static readonly int _viewportId = Shader.PropertyToID("_viewport");
static readonly int _alphaId = Shader.PropertyToID("_alpha");
static readonly int _strokeMultId = Shader.PropertyToID("_strokeMult");

static readonly int _mfRadiusId = Shader.PropertyToID("_mf_radius");
static readonly int _mfImgIncId = Shader.PropertyToID("_mf_imgInc");
static readonly int _mfKernelId = Shader.PropertyToID("_mf_kernel");
static readonly int _shadowBoxId = Shader.PropertyToID("_sb_box");
static readonly int _shadowSigmaId = Shader.PropertyToID("_sb_sigma");
static readonly int _shadowColorId = Shader.PropertyToID("_sb_color");
static readonly int _shadowCornerId = Shader.PropertyToID("_sb_corner");
static Vector4 _colorToVector4(uiColor c) {
return new Vector4(

material: mat,
properties: props,
layerId: renderLayer.rtID
);
}
public static PictureFlusher.CmdDraw fastShadow(PictureFlusher.RenderLayer layer, uiMeshMesh mesh, float sigma,
bool isRect, bool isCircle, float corner, Vector4 bound, uiColor color) {
Vector4 viewport = layer.viewport;
var mat = _shadowBox;
if (!isRect) {
mat = _shadowRBox;
}
var props = ObjectPool<MaterialPropertyBlockWrapper>.alloc();
props.SetVector(_viewportId, viewport);
props.SetFloat(_shadowSigmaId, sigma);
props.SetVector(_shadowBoxId, bound);
props.SetVector(_shadowColorId, _colorToVector4(color));
if (!isRect) {
props.SetFloat(_shadowCornerId, corner);
}
return PictureFlusher.CmdDraw.create(
mesh: mesh,
pass: 0,
material: mat,
properties: props
);
}
}

68
Runtime/ui/renderer/common/geometry/path/path.cs


using UnityEngine;
namespace Unity.UIWidgets.ui {
public class uiPath : PoolObject {
public partial class uiPath : PoolObject {
const float _KAPPA90 = 0.5522847493f;
uiList<float> _commands;

public uint pathKey = 0;
public bool needCache = false;
bool _isNaiveRRect = false;
public bool isNaiveRRect => this._isNaiveRRect;
uiPathShapeHint _shapeHint = uiPathShapeHint.Other;
public uiPathShapeHint shapeHint => this._shapeHint;
float _rRectCorner;
public float rRectCorner => this._rRectCorner;
void _updateRRectFlag(bool isNaiveRRect, uiPathShapeHint shapeHint = uiPathShapeHint.Other, float corner = 0) {
if (this._commands.Count > 0 && !this._isNaiveRRect) {
return;
}
this._isNaiveRRect = isNaiveRRect && this._hasOnlyMoveTos();
if (this._isNaiveRRect) {
this._shapeHint = shapeHint;
this._rRectCorner = corner;
}
}
bool _hasOnlyMoveTos() {
var i = 0;
while (i < this._commands.Count) {
var cmd = (PathCommand) this._commands[i];
switch (cmd) {
case PathCommand.moveTo:
i += 3;
break;
case PathCommand.lineTo:
return false;
case PathCommand.bezierTo:
return false;
case PathCommand.close:
i++;
break;
case PathCommand.winding:
i += 2;
break;
default:
return false;
}
}
return true;
}
public static uiPath create(int capacity = 128) {
uiPath newPath = ObjectPool<uiPath>.alloc();

this.needCache = false;
this.pathKey = 0;
this._isNaiveRRect = false;
}
void _reset() {

this._maxY = float.MinValue;
ObjectPool<uiPathCache>.release(this._cache);
this._cache = null;
this._isNaiveRRect = false;
}
internal uiPathCache flatten(float scale) {

this._maxY = y;
}
}
public uiRect getBounds() {
if (this._minX >= this._maxX || this._minY >= this._maxY) {
return uiRectHelper.zero;
}
return uiRectHelper.fromLTRB(this._minX, this._minY, this._maxX, this._maxY);
}
void _appendMoveTo(float x, float y) {
this._commands.Add((float) uiPathCommand.moveTo);

}
public void addRect(uiRect rect) {
this._updateRRectFlag(true, uiPathShapeHint.Rect);
this._appendMoveTo(rect.left, rect.top);
this._appendLineTo(rect.left, rect.bottom);
this._appendLineTo(rect.right, rect.bottom);

public void addRect(Rect rect) {
this._updateRRectFlag(true, uiPathShapeHint.Rect);
this._appendMoveTo(rect.left, rect.top);
this._appendLineTo(rect.left, rect.bottom);
this._appendLineTo(rect.right, rect.bottom);

public void addRRect(RRect rrect) {
this._updateRRectFlag(rrect.isNaiveRRect(), uiPathShapeHint.NaiveRRect, rrect.blRadiusX);
float w = rrect.width;
float h = rrect.height;
float halfw = Mathf.Abs(w) * 0.5f;

}
public void lineTo(float x, float y) {
this._updateRRectFlag(false);
this._appendLineTo(x, y);
}

public void addEllipse(float cx, float cy, float rx, float ry) {
this._updateRRectFlag(rx == ry, uiPathShapeHint.Circle, rx);
this._appendMoveTo(cx - rx, cy);
this._appendBezierTo(cx - rx, cy + ry * _KAPPA90,
cx - rx * _KAPPA90, cy + ry, cx, cy + ry);

}
public void arcTo(Rect rect, float startAngle, float sweepAngle, bool forceMoveTo = true) {
this._updateRRectFlag(false);
var mat = Matrix3.makeScale(rect.width / 2, rect.height / 2);
var center = rect.center;
mat.postTranslate(center.dx, center.dy);

if (exists) {
return uipath;
}
uipath._updateRRectFlag(path.isNaiveRRect, (uiPathShapeHint)path.shapeHint, path.rRectCorner);
var i = 0;
var _commands = path.commands;
while (i < _commands.Count) {

2
Runtime/ui/renderer/compositeCanvas/flow/physical_shape_layer.cs


const float kAmbientAlpha = 0.039f;
const float kLightHeight = 600f;
const float kLightRadius = 800f;
const float kSpotAlpha = ShadowUtils.kUseFastShadow ? 0.1f : 0.25f;
const float kSpotAlpha = 0.25f;
public static void drawShadow(Canvas canvas, Path path, Color color, float elevation, bool transparentOccluder,
float dpr) {

6
Samples/UIWidgetSample/MaterialSample.cs


child: new Center(
child: new Column(
children: new List<Widget> {
new FlatButton(
new Padding(padding: EdgeInsets.only(top: 30f)),
new MaterialButton(
shape: new RoundedRectangleBorder(borderRadius: BorderRadius.all(20.0f)),
color: new Color(0xFF00FF00),
splashColor: new Color(0xFFFF0011),

),
new RaisedButton(
new Padding(padding: EdgeInsets.only(top: 30f)),
new MaterialButton(
shape: new RoundedRectangleBorder(borderRadius: BorderRadius.all(20.0f)),
color: new Color(0xFFFF00FF),
splashColor: new Color(0xFFFF0011),

85
Runtime/Resources/UIWidgets_canvas_shadowBox.shader


Shader "UIWidgets/ShadowBox"
{
//originally from http://madebyevan.com/shaders/fast-rounded-rectangle-shadows/
Properties
{
_SrcBlend("_SrcBlend", Int) = 1 // One
_DstBlend("_DstBlend", Int) = 10 // OneMinusSrcAlpha
_StencilComp("_StencilComp", Float) = 8 // - Equal, 8 - Always
}
SubShader
{
ZTest Always
ZWrite Off
Blend [_SrcBlend] [_DstBlend]
Stencil {
Ref 128
Comp [_StencilComp]
}
Pass {
CGPROGRAM
float4 _sb_box;
float4 _viewport;
float _sb_sigma;
float4 _sb_color;
float _mat[9];
struct appdata
{
float4 vertex : POSITION;
};
struct v2f
{
float4 vertex : SV_POSITION;
float2 coord : TEXCOORD0;
};
float4 erf(float4 x)
{
float4 s = sign(x);
float4 a = abs(x);
x = 1.0 + (0.278393 + (0.230389 + 0.078108 * (a * a)) * a) * a;
x = x * x;
return s - s / (x * x);
return s;
}
float boxShadow(float2 lower, float2 upper, float2 pnt, float sigma)
{
float4 query = float4(pnt - lower, pnt - upper);
float4 integral = 0.5 + 0.5 * erf(query * (sqrt(0.5) / sigma));
return (integral.z - integral.x) * (integral.w - integral.y);
}
v2f vert(appdata v){
v2f o;
float padding = 3.0 * _sb_sigma;
o.coord = lerp(_sb_box.xy - padding, _sb_box.zw + padding, v.vertex.xy);
float3x3 mat = float3x3(_mat[0], _mat[1], _mat[2], _mat[3], _mat[4], _mat[5], 0, 0, 1);
float2 p = mul(mat, float3(o.coord.xy, 1.0)).xy - _viewport.xy;
#if UNITY_UV_STARTS_AT_TOP
o.vertex = float4(2.0 * p.x / _viewport.z - 1.0, 2.0 * p.y / _viewport.w - 1.0, 0, 1);
#else
o.vertex = float4(2.0 * p.x / _viewport.z - 1.0, 1.0 - 2.0 * p.y / _viewport.w, 0, 1);
#endif
return o;
}
float4 frag(v2f i) : SV_TARGET {
float4 fragColor = _sb_color;
fragColor.a = fragColor.a * boxShadow(_sb_box.xy, _sb_box.zw, i.coord, _sb_sigma);
return fragColor;
}
#pragma vertex vert
#pragma fragment frag
ENDCG
}
}
}

9
Runtime/Resources/UIWidgets_canvas_shadowBox.shader.meta


fileFormatVersion: 2
guid: 105f52491741049d88708e718c749e34
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:

117
Runtime/Resources/UIWidgets_canvas_shadowRBox.shader


Shader "UIWidgets/ShadowRBox"
{
//originally from http://madebyevan.com/shaders/fast-rounded-rectangle-shadows/
Properties
{
_SrcBlend("_SrcBlend", Int) = 1 // One
_DstBlend("_DstBlend", Int) = 10 // OneMinusSrcAlpha
_StencilComp("_StencilComp", Float) = 8 // - Equal, 8 - Always
}
SubShader
{
ZTest Always
ZWrite Off
Blend [_SrcBlend] [_DstBlend]
Stencil {
Ref 128
Comp [_StencilComp]
}
Pass {
CGPROGRAM
float4 _sb_box;
float4 _viewport;
float _sb_sigma;
float4 _sb_color;
float _sb_corner;
float _mat[9];
struct appdata
{
float4 vertex : POSITION;
};
struct v2f
{
float4 vertex : SV_POSITION;
float2 coord : TEXCOORD0;
};
float gaussian(float x, float sigma)
{
float pi = 3.141592653589793;
return exp(-(x*x) / (2.0 * sigma * sigma)) / (sqrt(2.0 * pi) * sigma);
}
float2 erf(float2 x)
{
float2 s = sign(x);
float2 a = abs(x);
x = 1.0 + (0.278393 + (0.230389 + 0.078108 * (a * a)) * a) * a;
x = x * x;
return s - s / (x * x);
return s;
}
float roundedBoxShadowX(float x, float y, float sigma, float corner, float2 halfSize)
{
float delta = min(halfSize.y - corner - abs(y), 0.0);
float curved = halfSize.x - corner + sqrt(max(0.0, corner * corner - delta * delta));
float2 integral = 0.5 + 0.5 * erf((x + float2(-curved, curved)) * (sqrt(0.5)/sigma));
return integral.y - integral.x;
}
float roundedBoxShadow(float2 lower, float2 upper, float2 pnt, float sigma, float corner)
{
float2 center = (lower + upper) * 0.5;
float2 halfSize = (upper - lower) * 0.5;
pnt -= center;
float low = pnt.y - halfSize.y;
float high = pnt.y + halfSize.y;
float start = clamp(-3.0 * sigma, low, high);
float end = clamp(3.0 * sigma, low, high);
float step = (end - start) / 4.0;
float y = start + step * 0.5;
float value = 0.0;
for(int i=0; i<4;i++)
{
value += roundedBoxShadowX(pnt.x, pnt.y - y, sigma, corner, halfSize) * gaussian(y, sigma) * step;
y += step;
}
return value;
}
v2f vert(appdata v){
v2f o;
float padding = 3.0 * _sb_sigma;
o.coord = lerp(_sb_box.xy - padding, _sb_box.zw + padding, v.vertex.xy);
float3x3 mat = float3x3(_mat[0], _mat[1], _mat[2], _mat[3], _mat[4], _mat[5], 0, 0, 1);
float2 p = mul(mat, float3(o.coord.xy, 1.0)).xy - _viewport.xy;
#if UNITY_UV_STARTS_AT_TOP
o.vertex = float4(2.0 * p.x / _viewport.z - 1.0, 2.0 * p.y / _viewport.w - 1.0, 0, 1);
#else
o.vertex = float4(2.0 * p.x / _viewport.z - 1.0, 1.0 - 2.0 * p.y / _viewport.w, 0, 1);
#endif
return o;
}
float4 frag(v2f i) : SV_TARGET {
float4 fragColor = _sb_color;
fragColor.a = fragColor.a * roundedBoxShadow(_sb_box.xy, _sb_box.zw, i.coord, _sb_sigma, _sb_corner);
return fragColor;
}
#pragma vertex vert
#pragma fragment frag
ENDCG
}
}
}

9
Runtime/Resources/UIWidgets_canvas_shadowRBox.shader.meta


fileFormatVersion: 2
guid: 77c8565b9b449434490473ef8f7f0e91
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:

40
Runtime/ui/renderer/cmdbufferCanvas/rendering/canvas_shadow_utils.cs


using Unity.UIWidgets.foundation;
using UnityEngine;
namespace Unity.UIWidgets.ui {
public partial class PictureFlusher {
void _drawRRectShadow(uiPath path, uiPaint paint) {
D.assert(path.isNaiveRRect, () => "Cannot draw fast Shadow for non-NaiveRRect shapes");
D.assert(paint.style == PaintingStyle.fill, () => "Cannot draw fast Shadow for stroke lines");
var bound = path.getBounds();
if (!this._applyClip(bound)) {
return;
}
var layer = this._currentLayer;
var state = layer.currentState;
float sigma = state.scale * paint.maskFilter.Value.sigma;
var vertices = ObjectPool<uiList<Vector3>>.alloc();
vertices.SetCapacity(4);
vertices.Add(new Vector2(0, 0));
vertices.Add(new Vector2(1, 0));
vertices.Add(new Vector2(0, 1));
vertices.Add(new Vector2(1, 1));
var _triangles = ObjectPool<uiList<int>>.alloc();
_triangles.SetCapacity(6);
_triangles.Add(0);
_triangles.Add(1);
_triangles.Add(2);
_triangles.Add(2);
_triangles.Add(1);
_triangles.Add(3);
var mesh = uiMeshMesh.create(state.matrix, vertices, _triangles);
layer.draws.Add(CanvasShader.fastShadow(layer, mesh, sigma, path.isRect, path.isCircle, path.rRectCorner, new Vector4(bound.left, bound.top, bound.right, bound.bottom), paint.color));
}
}
}

11
Runtime/ui/renderer/cmdbufferCanvas/rendering/canvas_shadow_utils.cs.meta


fileFormatVersion: 2
guid: fbf14696e076b4453a580e27ad682959
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

19
Runtime/ui/renderer/common/geometry/path/path_extension.cs


namespace Unity.UIWidgets.ui {
public partial class uiPath {
public enum uiPathShapeHint {
Rect,
Circle,
NaiveRRect,
Other
}
public bool isRect {
get { return this._shapeHint == uiPathShapeHint.Rect; }
}
public bool isCircle {
get { return this._shapeHint == uiPathShapeHint.Circle; }
}
}
}

11
Runtime/ui/renderer/common/geometry/path/path_extension.cs.meta


fileFormatVersion: 2
guid: 41c5cc4750b044c49b1089ec86ffe415
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
正在加载...
取消
保存