浏览代码

fast shadow

/main
xingwei.zhu 5 年前
当前提交
61a56230
共有 14 个文件被更改,包括 365 次插入65 次删除
  1. 2
      Runtime/engine/UIWidgetsPanel.cs
  2. 6
      Runtime/ui/painting/painting.cs
  3. 25
      Runtime/ui/painting/path.cs
  4. 6
      Runtime/ui/painting/shadow_utils.cs
  5. 8
      Runtime/ui/renderer/cmdbufferCanvas/rendering/canvas_impl.cs
  6. 86
      Runtime/ui/renderer/cmdbufferCanvas/rendering/canvas_shader.cs
  7. 32
      Runtime/ui/renderer/common/geometry/path/path.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. 100
      Runtime/Resources/UIWidgets_canvas_shadowRBox.shader
  12. 9
      Runtime/Resources/UIWidgets_canvas_shadowRBox.shader.meta
  13. 37
      Runtime/ui/renderer/cmdbufferCanvas/rendering/canvas_shadow_utils.cs
  14. 19
      Runtime/ui/renderer/common/geometry/path/path_extension.cs

2
Runtime/engine/UIWidgetsPanel.cs


this._needsPaint = true;
}
this._needsPaint = true;
if (evt.type == EventType.Repaint) {
if (!this._needsPaint) {
return;

6
Runtime/ui/painting/painting.cs


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

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

25
Runtime/ui/painting/path.cs


bool _isRRect = false;
public bool isRRect => this._isRRect;
PathShapeHint _shapeHint = PathShapeHint.Other;
public PathShapeHint shapeHint => this._shapeHint;
public uint pathKey {
get {

public List<float> commands => this._commands;
void _updateRRectFlag(bool isRRect) {
void _updateRRectFlag(bool isRRect, PathShapeHint shapeHint = PathShapeHint.Other) {
this._shapeHint = shapeHint;
}
bool _hasOnlyMoveTos() {

}
public void addRect(Rect rect) {
this._updateRRectFlag(true);
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(true);
this._updateRRectFlag(true, PathShapeHint.RRect);
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(true);
this._updateRRectFlag(true, PathShapeHint.Oval);
this._appendMoveTo(cx - rx, cy);
this._appendBezierTo(cx - rx, cy + ry * _KAPPA90,
cx - rx * _KAPPA90, cy + ry, cx, cy + ry);

}
public void addCircle(float cx, float cy, float r) {
this._updateRRectFlag(true);
this._updateRRectFlag(true, PathShapeHint.Oval);
this._updateRRectFlag(true);
this._updateRRectFlag(true, PathShapeHint.Oval);
var center = oval.center;
this.addEllipse(center.dx, center.dy, oval.width / 2, oval.height / 2);
}

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

w = newW,
};
}
}
public enum PathShapeHint {
Rect,
Oval,
RRect,
Other
}
enum PathCommand {

6
Runtime/ui/painting/shadow_utils.cs


_shadowMatrix.reset();
canvas.setMatrix(_shadowMatrix);
float sigma = convertRadiusToSigma(blurRadius);
_shadowPaint.maskFilter = MaskFilter.blur(BlurStyle.normal, sigma);
canvas.drawPath(_devSpacePath, _shadowPaint);
_shadowPaint.maskFilter = _devSpacePath.isRRect ? MaskFilter.fastShadow(sigma) : MaskFilter.blur(BlurStyle.normal, sigma);
//canvas.drawPath(_devSpacePath, _shadowPaint);
canvas.restore();
//spot light

_shadowPaint.strokeWidth = 0;
_shadowPaint.style = PaintingStyle.fill;
float sigma2 = convertRadiusToSigma(radius);
_shadowPaint.maskFilter = MaskFilter.blur(BlurStyle.normal, sigma2);
_shadowPaint.maskFilter = path.isRRect ? MaskFilter.fastShadow(sigma2) : MaskFilter.blur(BlurStyle.normal, sigma2);
canvas.drawPath(path, _shadowPaint);
canvas.restore();

8
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;

var fillMesh = cache.getFillMesh(out convex);
var mesh = fillMesh.transform(state.matrix);
if (paint.maskFilter != null && paint.maskFilter.Value.sigma != 0) {
this._drawWithMaskFilter(mesh.bounds, paint, paint.maskFilter.Value, mesh, convex, 0, null,
uiRectHelper.zero, null, false, this.___drawPathDrawMeshCallback);

paint.strokeMiterLimit);
var mesh = strokenMesh.transform(state.matrix);
if (paint.maskFilter != null && paint.maskFilter.Value.sigma != 0) {
this._drawWithMaskFilter(mesh.bounds, paint, paint.maskFilter.Value, mesh, false, alpha, null,
uiRectHelper.zero, null, false, this.___drawPathDrawMeshCallback2);

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


static readonly MaterialByBlendModeStencilComp _texMat;
static readonly Material _stencilMat;
static readonly Material _filterMat;
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");
static Shader GetShader(string shaderName) {
var shader = Shader.Find(shaderName);
if (shader == null) {
throw new Exception(shaderName + " not found");
var fill0Shader = Shader.Find("UIWidgets/canvas_fill0");
if (fill0Shader == null) {
throw new Exception("UIWidgets/canvas_fill0 not found");
}
return shader;
}
var fill1Shader = Shader.Find("UIWidgets/canvas_fill1");
if (fill1Shader == null) {
throw new Exception("UIWidgets/canvas_fill1 not found");
}
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 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};
}
static readonly int _viewportId = Shader.PropertyToID("_viewport");

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("box");
static readonly int _shadowSigma = Shader.PropertyToID("sigma");
static readonly int _shadowColor = Shader.PropertyToID("color");
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,
bool isRect, Vector4 bound) {
Vector4 viewport = layer.viewport;
var mat = _shadowBox;
//if (isRect) {
// mat = _shadowBox;
//}
//use props to set all the uniforms !!!!!
var props = ObjectPool<MaterialPropertyBlockWrapper>.alloc();
props.SetVector(_viewportId, viewport);
props.SetFloat(_shadowSigma, 3f);
props.SetVector(_shadowBoxId, bound);
props.SetVector(_shadowColor, new Vector4(0, 0, 0, 1));
return PictureFlusher.CmdDraw.create(
mesh: mesh,
pass: 0,
material: mat,
properties: props
);
}
}

32
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;

bool _isRRect = false;
public bool isRRect => this._isRRect;
void _updateRRectFlag(bool isRRect) {
uiPathShapeHint _shapeHint = uiPathShapeHint.Other;
public uiPathShapeHint shapeHint => this._shapeHint;
void _updateRRectFlag(bool isRRect, uiPathShapeHint shapeHint = uiPathShapeHint.Other) {
if (!this._isRRect) {
int s = 0;
if (this._isRRect) {
this._shapeHint = shapeHint;
}
}

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);
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);
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(true);
this._updateRRectFlag(true, uiPathShapeHint.RRect);
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(true);
this._updateRRectFlag(true, uiPathShapeHint.Oval);
this._appendMoveTo(cx - rx, cy);
this._appendBezierTo(cx - rx, cy + ry * _KAPPA90,
cx - rx * _KAPPA90, cy + ry, cx, cy + ry);

}
public void addCircle(float cx, float cy, float r) {
this._updateRRectFlag(true);
this._updateRRectFlag(true, uiPathShapeHint.Oval);
this.addEllipse(cx, cy, r, r);
}

return uipath;
}
uipath._updateRRectFlag(path.isRRect);
uipath._updateRRectFlag(path.isRRect, (uiPathShapeHint)path.shapeHint);
var i = 0;
var _commands = path.commands;

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 box;
float4 _viewport;
float sigma;
float4 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 * sigma;
o.coord = lerp(box.xy - padding, 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 = color;
fragColor.a = fragColor.a * boxShadow(box.xy, box.zw, i.coord, 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:

100
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
}
SubShader
{
Blend [_SrcBlend] [_DstBlend]
Pass {
CGPROGRAM
float4 box;
float2 window;
float sigma;
float4 color;
float corner;
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 * sigma;
o.coord = lerp(box.xy - padding, box.zw + padding, v.vertex.xy);
o.vertex = float4(o.coord.x * 2.0 /window.x - 1.0, o.coord.y * 2.0/window.y - 1.0, 0, 1);
return o;
}
float4 frag(v2f i) : SV_TARGET {
float4 fragColor = color;
fragColor.a = fragColor.a * roundedBoxShadow(box.xy, box.zw, i.coord, sigma, 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:

37
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.isRRect, () => "Cannot draw Shadow for non-RRect shapes");
D.assert(paint.style == PaintingStyle.fill, () => "Cannot draw Shadow for stroke lines");
var layer = this._currentLayer;
var state = layer.currentState;
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);
var bound = path.getBounds();
Debug.Log("Draw shadow>>> " + bound.top);
layer.draws.Add(CanvasShader.fastShadow(layer, mesh, path.isRect, new Vector4(bound.left, bound.top, bound.right, bound.bottom)));
}
}
}

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


namespace Unity.UIWidgets.ui {
public partial class uiPath {
public enum uiPathShapeHint {
Rect,
Oval,
RRect,
Other
}
public bool isRect {
get { return this._shapeHint == uiPathShapeHint.Rect; }
}
public bool isOval {
get { return this._shapeHint == uiPathShapeHint.Oval; }
}
}
}
正在加载...
取消
保存