dev-LayerStyle
yang.yongquan 2023-03-15 11:25:14 +08:00
commit 73e63f3817
10 changed files with 1253 additions and 1003 deletions

View File

@ -893,7 +893,7 @@ bool angleLargeThanPi(vec2 a, vec2 b)
/************************************************************************************/ /************************************************************************************/
void drawLine(in float d, inout uint styleIndex, out vec4 elementColor, out vec2 metallicRoughness) void drawLine(in float d, uint styleIndex, out vec4 elementColor, out vec2 metallicRoughness)
{ {
elementColor = vec4(1); elementColor = vec4(1);
metallicRoughness = vec2(0.8); metallicRoughness = vec2(0.8);
@ -969,14 +969,38 @@ void drawLine(in float d, inout uint styleIndex, out vec4 elementColor, out vec2
} }
} }
bool shouldFillBeginCap(vec2 localUV, bool onVeryBegin, int endType, vec2 p3, vec2 tangentBegin, vec2 tangentEndLast) void nextStyleIndex(inout uint styleIndex)
{
uint headUint = floatBitsToUint(style[styleIndex + 1]);
vec4 head = unpackUnorm4x8(headUint);
switch (int(head.a * 100) % 10)
{
/// Plain
case 0: {
styleIndex += 3;
break;
}
/// RadialGradient
case 1: {
uint size = headUint % (1 << 15);
styleIndex += 2 + size * 2;
break;
}
case 2: {
break;
}
}
}
bool shouldFillBeginCap(vec2 localUV, bool onVeryBegin, int endType, vec2 p0, vec2 tangentBegin, vec2 tangentEndLast)
{ {
vec2 normal; vec2 normal;
if (onVeryBegin) if (onVeryBegin)
{ {
if (endType == 0) if (endType%2 == 0)
return true; return true;
else if (endType == 1) else if (endType%2 == 1)
normal = normalize(mat2(0, 1, -1, 0) * (-tangentBegin)); normal = normalize(mat2(0, 1, -1, 0) * (-tangentBegin));
} }
else else
@ -985,17 +1009,26 @@ bool shouldFillBeginCap(vec2 localUV, bool onVeryBegin, int endType, vec2 p3, ve
vec2 normalNow = normalize(mat2(0, 1, -1, 0) * (-tangentBegin)); vec2 normalNow = normalize(mat2(0, 1, -1, 0) * (-tangentBegin));
normal = normalLast + normalNow; normal = normalLast + normalNow;
} }
return angleLargeThanPi(normal, localUV - p3); return angleLargeThanPi(normal, localUV - p0);
} }
bool shouldFillEndCap(vec2 localUV, int endType, vec2 p0, vec2 tangentEnd) bool shouldFillEndCap(vec2 localUV, bool onVeryEnd, int endType, vec2 p3, vec2 tangentEnd, vec2 tangentBeginNext)
{ {
vec2 normal; vec2 normal;
if (endType == 0) if (onVeryEnd)
{
if ((endType/2)%2 == 0)
return true; return true;
else if (endType == 1) else if ((endType/2)%2 == 1)
normal = normalize(mat2(0, 1, -1, 0) * tangentEnd); normal = normalize(mat2(0, 1, -1, 0) * tangentEnd);
return angleLargeThanPi(localUV - p0, normal); }
else
{
vec2 normalLast = normalize(mat2(0, 1, -1, 0) * tangentEnd);
vec2 normalNow = normalize(mat2(0, 1, -1, 0) * (-tangentBeginNext));
normal = normalLast + normalNow;
}
return angleLargeThanPi(localUV - p3, normal);
} }
void main() void main()
@ -1006,9 +1039,8 @@ void main()
vec4 color = vec4(0); vec4 color = vec4(0);
// if(isinf(path[0].x)) imageStore(gBaseColor, ivec2(pixelLocation), // if(isinf(path[0].x)) imageStore(gBaseColor, ivec2(pixelLocation),
// vec4(vec2(pixelLocation)/vec2(imageSize(gBaseColor)), 1,1)); return; // vec4(vec2(pixelLocation)/vec2(imageSize(gBaseColor)), 1,1)); return;
for (uint styleIndex = 0; styleIndex < styleSize; styleIndex++) for (uint styleIndex = 0; styleIndex < styleSize;)
{ {
styleIndex += 6; styleIndex += 6;
vec2 localUV = vec2(pixelLocation) / pixelRatio + leftTop; vec2 localUV = vec2(pixelLocation) / pixelRatio + leftTop;
@ -1047,6 +1079,7 @@ void main()
elementColor = vec4(unpackUnorm4x8(floatBitsToUint(style[++styleIndex])).rgb, 1); elementColor = vec4(unpackUnorm4x8(floatBitsToUint(style[++styleIndex])).rgb, 1);
} }
} }
} }
else // Stroke else // Stroke
{ {
@ -1058,18 +1091,19 @@ void main()
// endType = 1; // endType = 1;
int debugBegin = 0; int debugBegin = 0;
bool onVeryBegin = false; bool onVeryBegin = false;
bool onVeryEnd = false;
vec2 tangentEndLast; vec2 tangentEndLast;
uint lastHitIndex = 0;
bool lastHitElement = false;
hitElement = false;
for (uint pathIndex = 0; pathIndex < pathSize; pathIndex++) for (uint pathIndex = 0; pathIndex < pathSize; pathIndex++)
// for (uint pathIndex = 0; pathIndex < 4; pathIndex++) //for (uint pathIndex = 0; pathIndex < 46; pathIndex++)
{ {
vec2 pTemp = path[pathIndex]; vec2 pTemp = path[pathIndex];
if (isinf(pTemp.x)) if (isinf(pTemp.x))
{ {
// TODO: ¼ì²âÊÇ·ñ·â±Õ²¢´¦Àí // TODO: ¼ì²âÊÇ·ñ·â±Õ²¢´¦Àí
if (hitElement && distance(localUV, p3Last) <= strokeWidth)
{
hitElement = shouldFillEndCap(localUV, endType, p3Last, tangentEndLast);
}
pBegin = path[++pathIndex]; pBegin = path[++pathIndex];
p3Last = pBegin; p3Last = pBegin;
@ -1079,10 +1113,32 @@ void main()
} }
mat4x2 p = mat4x2(p3Last, pTemp, path[++pathIndex], path[++pathIndex]); mat4x2 p = mat4x2(p3Last, pTemp, path[++pathIndex], path[++pathIndex]);
vec2 tangentBeginNext;
if (pathIndex + 1 < pathSize)
{
vec2 pTemp = path[pathIndex + 1];
if (isinf(pTemp.x))
{
onVeryEnd = true;
}
else
{
onVeryEnd = false;
vec2 pNext[3] = {p[3], pTemp, path[pathIndex + 2]};
if (pNext[0] != pNext[1])
tangentBeginNext = normalize(pNext[0] - pNext[1]);
else
tangentBeginNext = normalize(pNext[0] - pNext[2]);
}
}
else
onVeryEnd = true;
float d = cubic_bezier_dis(localUV, p[0], p[1], p[2], p[3], true); float d = cubic_bezier_dis(localUV, p[0], p[1], p[2], p[3], true);
if (d <= strokeWidth) if (d <= strokeWidth)
{ {
bool onBegin = distance(localUV, p[0]) <= strokeWidth && p3Last == p[0]; bool onBegin = distance(localUV, p[0]) <= strokeWidth;
bool onEnd = distance(localUV, p[3]) <= strokeWidth;
vec2 tangentBegin; vec2 tangentBegin;
vec2 tangentEnd; vec2 tangentEnd;
if (p[0] != p[1]) if (p[0] != p[1])
@ -1094,11 +1150,14 @@ void main()
else else
tangentEnd = normalize(p[3] - p[1]); tangentEnd = normalize(p[3] - p[1]);
if (onBegin ? shouldFillBeginCap(localUV, onVeryBegin, endType, p[0], tangentBegin, p3Last - p2Last) bool hit = d < minDistance;
: d < minDistance) if (onBegin)
hit = hit &&
shouldFillBeginCap(localUV, onVeryBegin, endType, p[0], tangentBegin, tangentEndLast);
if (onEnd)
hit = hit && shouldFillEndCap(localUV, onVeryEnd, endType, p[3], tangentEnd, tangentBeginNext);
if (hit)
{ {
minDistance = min(minDistance, d);
bool reverse = p[3].y - p[0].y < 0.; bool reverse = p[3].y - p[0].y < 0.;
if (tangentBegin.y == 0.) if (tangentBegin.y == 0.)
@ -1111,13 +1170,14 @@ void main()
if (lineType == 2 || (intTest % 2 == int(lineType))) if (lineType == 2 || (intTest % 2 == int(lineType)))
{ {
minDistance = min(minDistance, d);
lastHitElement = hitElement;
lastHitIndex = pathIndex;
hitElement = true; hitElement = true;
// elementColor = vec4(1, 1, 0, 1); // elementColor = vec4(1, 1, 0, 1);
vec2 metallicRoughness; vec2 metallicRoughness;
drawLine(minDistance / strokeWidth, styleIndex, elementColor, metallicRoughness); drawLine(minDistance / strokeWidth, styleIndex, elementColor, metallicRoughness);
} }
else if (p3Last == p[0])
hitElement = false;
} }
tangentEndLast = tangentEnd; tangentEndLast = tangentEnd;
} }
@ -1125,14 +1185,11 @@ void main()
p2Last = p[2]; p2Last = p[2];
onVeryBegin = false; onVeryBegin = false;
} }
if (hitElement && distance(localUV, p3Last) <= strokeWidth) nextStyleIndex(styleIndex);
{
hitElement = shouldFillEndCap(localUV, endType, p3Last, tangentEndLast);
}
} }
if (hitElement) if (hitElement)
color = elementColor; color = elementColor;
styleIndex += 100;
} }
if (color.a != 0) if (color.a != 0)
imageStore(gBaseColor, ivec2(pixelLocation), color); imageStore(gBaseColor, ivec2(pixelLocation), color);

View File

@ -37,7 +37,6 @@ layout(std430, binding = 4) buffer elementDataBuffer
const float PI = 3.14159265358979; const float PI = 3.14159265358979;
const uint STACK_SIZE = 10; const uint STACK_SIZE = 10;
struct Stack struct Stack
@ -77,7 +76,6 @@ struct Stack
} }
} stack, elementStack; } stack, elementStack;
// Modified from http://tog.acm.org/resources/GraphicsGems/gems/Roots3And4.c // Modified from http://tog.acm.org/resources/GraphicsGems/gems/Roots3And4.c
// Credits to Doublefresh for hinting there // Credits to Doublefresh for hinting there
int solve_quadric(vec2 coeffs, inout vec2 roots) int solve_quadric(vec2 coeffs, inout vec2 roots)
@ -151,7 +149,6 @@ int solve_cubic(vec3 coeffs, inout vec3 r)
return 3; return 3;
} }
int segment_int_test(vec2 uv, vec2 p0, vec2 p1) int segment_int_test(vec2 uv, vec2 p0, vec2 p1)
{ {
p0 -= uv; p0 -= uv;
@ -299,15 +296,19 @@ bvec3 cubic_bezier_sign_test(vec2 uv, vec2 p0, vec2 p1, vec2 p2, vec2 p3)
// int n_ints = 0; // int n_ints = 0;
bvec3 result = bvec3(false); bvec3 result = bvec3(false);
for(int i=0;i<3;i++){ for (int i = 0; i < 3; i++)
if(i < n_roots){ {
if(roots[i] >= 0. && roots[i] <= 1.){ if (i < n_roots)
{
if (roots[i] >= 0. && roots[i] <= 1.)
{
float x_pos = -p0.x + 3. * p1.x - 3. * p2.x + p3.x; float x_pos = -p0.x + 3. * p1.x - 3. * p2.x + p3.x;
x_pos = x_pos * roots[i] + 3. * p0.x - 6. * p1.x + 3. * p2.x; x_pos = x_pos * roots[i] + 3. * p0.x - 6. * p1.x + 3. * p2.x;
x_pos = x_pos * roots[i] + -3. * p0.x + 3. * p1.x; x_pos = x_pos * roots[i] + -3. * p0.x + 3. * p1.x;
x_pos = x_pos * roots[i] + p0.x; x_pos = x_pos * roots[i] + p0.x;
if(x_pos > uv.x){ if (x_pos > uv.x)
{
result[1] = !result[1]; result[1] = !result[1];
} }
} }
@ -320,24 +321,32 @@ bvec3 cubic_bezier_sign_test(vec2 uv, vec2 p0, vec2 p1, vec2 p2, vec2 p3)
vec2 nor1 = vec2(tang1.y, -tang1.x); vec2 nor1 = vec2(tang1.y, -tang1.x);
vec2 nor2 = vec2(tang2.y, -tang2.x); vec2 nor2 = vec2(tang2.y, -tang2.x);
if(p0.y < p1.y){ if (p0.y < p1.y)
if((uv.y<=p0.y) && (dot(uv-p0.xy,nor1)>0.)){ {
if ((uv.y <= p0.y) && (dot(uv - p0.xy, nor1) > 0.))
{
result[0] = !result[0]; result[0] = !result[0];
} }
} }
else{ else
if(!(uv.y<=p0.y) && !(dot(uv-p0.xy,nor1)>0.)){ {
if (!(uv.y <= p0.y) && !(dot(uv - p0.xy, nor1) > 0.))
{
result[0] = !result[0]; result[0] = !result[0];
} }
} }
if(p2.y<p3.y){ if (p2.y < p3.y)
if(!(uv.y<=p3.y) && dot(uv-p3.xy,nor2)>0.){ {
if (!(uv.y <= p3.y) && dot(uv - p3.xy, nor2) > 0.)
{
result[2] = !result[2]; result[2] = !result[2];
} }
} }
else{ else
if((uv.y<=p3.y) && !(dot(uv-p3.xy,nor2)>0.)){ {
if ((uv.y <= p3.y) && !(dot(uv - p3.xy, nor2) > 0.))
{
result[2] = !result[2]; result[2] = !result[2];
} }
} }
@ -355,7 +364,8 @@ const float eps = .000005;
const int halley_iterations = 8; const int halley_iterations = 8;
// lagrange positive real root upper bound // lagrange positive real root upper bound
// see for example: https://doi.org/10.1016/j.jsc.2014.09.038 // see for example: https://doi.org/10.1016/j.jsc.2014.09.038
float upper_bound_lagrange5(float a0, float a1, float a2, float a3, float a4){ float upper_bound_lagrange5(float a0, float a1, float a2, float a3, float a4)
{
vec4 coeffs1 = vec4(a0, a1, a2, a3); vec4 coeffs1 = vec4(a0, a1, a2, a3);
@ -383,7 +393,8 @@ float upper_bound_lagrange5(float a0, float a1, float a2, float a3, float a4){
} }
// lagrange upper bound applied to f(-x) to get lower bound // lagrange upper bound applied to f(-x) to get lower bound
float lower_bound_lagrange5(float a0, float a1, float a2, float a3, float a4){ float lower_bound_lagrange5(float a0, float a1, float a2, float a3, float a4)
{
vec4 coeffs1 = vec4(-a0, a1, -a2, a3); vec4 coeffs1 = vec4(-a0, a1, -a2, a3);
@ -410,7 +421,8 @@ float lower_bound_lagrange5(float a0, float a1, float a2, float a3, float a4){
return -max_max - max_max2; return -max_max - max_max2;
} }
vec2 parametric_cub_bezier(float t, vec2 p0, vec2 p1, vec2 p2, vec2 p3){ vec2 parametric_cub_bezier(float t, vec2 p0, vec2 p1, vec2 p2, vec2 p3)
{
vec2 a0 = (-p0 + 3. * p1 - 3. * p2 + p3); vec2 a0 = (-p0 + 3. * p1 - 3. * p2 + p3);
vec2 a1 = (3. * p0 - 6. * p1 + 3. * p2); vec2 a1 = (3. * p0 - 6. * p1 + 3. * p2);
vec2 a2 = (-3. * p0 + 3. * p1); vec2 a2 = (-3. * p0 + 3. * p1);
@ -419,7 +431,8 @@ vec2 parametric_cub_bezier(float t, vec2 p0, vec2 p1, vec2 p2, vec2 p3){
return (((a0 * t) + a1) * t + a2) * t + a3; return (((a0 * t) + a1) * t + a2) * t + a3;
} }
void sort_roots3(inout vec3 roots){ void sort_roots3(inout vec3 roots)
{
vec3 tmp; vec3 tmp;
tmp[0] = min(roots[0], min(roots[1], roots[2])); tmp[0] = min(roots[0], min(roots[1], roots[2]));
@ -429,7 +442,8 @@ void sort_roots3(inout vec3 roots){
roots = tmp; roots = tmp;
} }
void sort_roots4(inout vec4 roots){ void sort_roots4(inout vec4 roots)
{
vec4 tmp; vec4 tmp;
vec2 min1_2 = min(roots.xz, roots.yw); vec2 min1_2 = min(roots.xz, roots.yw);
@ -446,7 +460,8 @@ void sort_roots4(inout vec4 roots){
roots = tmp; roots = tmp;
} }
float eval_poly5(float a0, float a1, float a2, float a3, float a4, float x){ float eval_poly5(float a0, float a1, float a2, float a3, float a4, float x)
{
float f = ((((x + a4) * x + a3) * x + a2) * x + a1) * x + a0; float f = ((((x + a4) * x + a3) * x + a2) * x + a1) * x + a0;
@ -457,7 +472,8 @@ float eval_poly5(float a0, float a1, float a2, float a3, float a4, float x){
// basically a variant of newton raphson which converges quicker and has bigger basins of convergence // basically a variant of newton raphson which converges quicker and has bigger basins of convergence
// see http://mathworld.wolfram.com/HalleysMethod.html // see http://mathworld.wolfram.com/HalleysMethod.html
// or https://en.wikipedia.org/wiki/Halley%27s_method // or https://en.wikipedia.org/wiki/Halley%27s_method
float halley_iteration5(float a0, float a1, float a2, float a3, float a4, float x){ float halley_iteration5(float a0, float a1, float a2, float a3, float a4, float x)
{
float f = ((((x + a4) * x + a3) * x + a2) * x + a1) * x + a0; float f = ((((x + a4) * x + a3) * x + a2) * x + a1) * x + a0;
float f1 = (((5. * x + 4. * a4) * x + 3. * a3) * x + 2. * a2) * x + a1; float f1 = (((5. * x + 4. * a4) * x + 3. * a3) * x + 2. * a2) * x + a1;
@ -466,7 +482,8 @@ float halley_iteration5(float a0, float a1, float a2, float a3, float a4, float
return x - (2. * f * f1) / (2. * f1 * f1 - f * f2); return x - (2. * f * f1) / (2. * f1 * f1 - f * f2);
} }
float halley_iteration4(vec4 coeffs, float x){ float halley_iteration4(vec4 coeffs, float x)
{
float f = (((x + coeffs[3]) * x + coeffs[2]) * x + coeffs[1]) * x + coeffs[0]; float f = (((x + coeffs[3]) * x + coeffs[2]) * x + coeffs[1]) * x + coeffs[0];
float f1 = ((4. * x + 3. * coeffs[3]) * x + 2. * coeffs[2]) * x + coeffs[1]; float f1 = ((4. * x + 3. * coeffs[3]) * x + 2. * coeffs[2]) * x + coeffs[1];
@ -477,7 +494,8 @@ float halley_iteration4(vec4 coeffs, float x){
// Modified from http://tog.acm.org/resources/GraphicsGems/gems/Roots3And4.c // Modified from http://tog.acm.org/resources/GraphicsGems/gems/Roots3And4.c
// Credits to Doublefresh for hinting there // Credits to Doublefresh for hinting there
int solve_quartic(vec4 coeffs, inout vec4 s){ int solve_quartic(vec4 coeffs, inout vec4 s)
{
float a = coeffs[3]; float a = coeffs[3];
float b = coeffs[2]; float b = coeffs[2];
@ -529,17 +547,21 @@ int solve_quartic(vec4 coeffs, inout vec4 s){
float u = z * z - r; float u = z * z - r;
float v = 2. * z - p; float v = 2. * z - p;
if(u > -eps){ if (u > -eps)
{
u = sqrt(abs(u)); u = sqrt(abs(u));
} }
else{ else
{
return 0; return 0;
} }
if(v > -eps){ if (v > -eps)
{
v = sqrt(abs(v)); v = sqrt(abs(v));
} }
else{ else
{
return 0; return 0;
} }
@ -557,12 +579,15 @@ int solve_quartic(vec4 coeffs, inout vec4 s){
int old_num = num; int old_num = num;
num += solve_quadric(quad_coeffs, tmp); num += solve_quadric(quad_coeffs, tmp);
if(old_num!=num){ if (old_num != num)
if(old_num == 0){ {
if (old_num == 0)
{
s[0] = tmp[0]; s[0] = tmp[0];
s[1] = tmp[1]; s[1] = tmp[1];
} }
else{//old_num == 2 else
{ // old_num == 2
s[2] = tmp[0]; s[2] = tmp[0];
s[3] = tmp[1]; s[3] = tmp[1];
} }
@ -574,8 +599,10 @@ int solve_quartic(vec4 coeffs, inout vec4 s){
float sub = 1. / 4. * a; float sub = 1. / 4. * a;
/* single halley iteration to fix cancellation */ /* single halley iteration to fix cancellation */
for(int i=0;i<4;i+=2){ for (int i = 0; i < 4; i += 2)
if(i < num){ {
if (i < num)
{
s[i] -= sub; s[i] -= sub;
s[i] = halley_iteration4(coeffs, s[i]); s[i] = halley_iteration4(coeffs, s[i]);
@ -586,7 +613,8 @@ int solve_quartic(vec4 coeffs, inout vec4 s){
return num; return num;
} }
float cubic_bezier_dis(vec2 uv, vec2 p0, vec2 p1, vec2 p2, vec2 p3, bool roundEnd){ float cubic_bezier_dis(vec2 uv, vec2 p0, vec2 p1, vec2 p2, vec2 p3, bool roundEnd)
{
// switch points when near to end point to minimize numerical error // switch points when near to end point to minimize numerical error
// only needed when control point(s) very far away // only needed when control point(s) very far away
@ -659,57 +687,71 @@ float cubic_bezier_dis(vec2 uv, vec2 p0, vec2 p1, vec2 p2, vec2 p3, bool roundEn
// compute root isolating intervals by roots of derivative and outer root bounds // compute root isolating intervals by roots of derivative and outer root bounds
// only roots going form - to + considered, because only those result in a minimum // only roots going form - to + considered, because only those result in a minimum
if(num_roots_drv==4){ if (num_roots_drv == 4)
if(eval_poly5(b0,b1,b2,b3,b4,roots_drv[0]) > 0.){ {
if (eval_poly5(b0, b1, b2, b3, b4, roots_drv[0]) > 0.)
{
a[0] = lb; a[0] = lb;
b[0] = roots_drv[0]; b[0] = roots_drv[0];
num_roots = 1; num_roots = 1;
} }
if(sign(eval_poly5(b0,b1,b2,b3,b4,roots_drv[1])) != sign(eval_poly5(b0,b1,b2,b3,b4,roots_drv[2]))){ if (sign(eval_poly5(b0, b1, b2, b3, b4, roots_drv[1])) != sign(eval_poly5(b0, b1, b2, b3, b4, roots_drv[2])))
if(num_roots == 0){ {
if (num_roots == 0)
{
a[0] = roots_drv[1]; a[0] = roots_drv[1];
b[0] = roots_drv[2]; b[0] = roots_drv[2];
num_roots = 1; num_roots = 1;
} }
else{ else
{
a[1] = roots_drv[1]; a[1] = roots_drv[1];
b[1] = roots_drv[2]; b[1] = roots_drv[2];
num_roots = 2; num_roots = 2;
} }
} }
if(eval_poly5(b0,b1,b2,b3,b4,roots_drv[3]) < 0.){ if (eval_poly5(b0, b1, b2, b3, b4, roots_drv[3]) < 0.)
if(num_roots == 0){ {
if (num_roots == 0)
{
a[0] = roots_drv[3]; a[0] = roots_drv[3];
b[0] = ub; b[0] = ub;
num_roots = 1; num_roots = 1;
} }
else if(num_roots == 1){ else if (num_roots == 1)
{
a[1] = roots_drv[3]; a[1] = roots_drv[3];
b[1] = ub; b[1] = ub;
num_roots = 2; num_roots = 2;
} }
else{ else
{
a[2] = roots_drv[3]; a[2] = roots_drv[3];
b[2] = ub; b[2] = ub;
num_roots = 3; num_roots = 3;
} }
} }
} }
else{ else
if(num_roots_drv==2){ {
if(eval_poly5(b0,b1,b2,b3,b4,roots_drv[0]) < 0.){ if (num_roots_drv == 2)
{
if (eval_poly5(b0, b1, b2, b3, b4, roots_drv[0]) < 0.)
{
num_roots = 1; num_roots = 1;
a[0] = roots_drv[1]; a[0] = roots_drv[1];
b[0] = ub; b[0] = ub;
} }
else if(eval_poly5(b0,b1,b2,b3,b4,roots_drv[1]) > 0.){ else if (eval_poly5(b0, b1, b2, b3, b4, roots_drv[1]) > 0.)
{
num_roots = 1; num_roots = 1;
a[0] = lb; a[0] = lb;
b[0] = roots_drv[0]; b[0] = roots_drv[0];
} }
else{ else
{
num_roots = 2; num_roots = 2;
a[0] = lb; a[0] = lb;
@ -718,9 +760,9 @@ float cubic_bezier_dis(vec2 uv, vec2 p0, vec2 p1, vec2 p2, vec2 p3, bool roundEn
a[1] = roots_drv[1]; a[1] = roots_drv[1];
b[1] = ub; b[1] = ub;
} }
} }
else{//num_roots_drv==0 else
{ // num_roots_drv==0
vec3 roots_snd_drv = vec3(1e38); vec3 roots_snd_drv = vec3(1e38);
int num_roots_snd_drv = solve_cubic(c2, roots_snd_drv); int num_roots_snd_drv = solve_cubic(c2, roots_snd_drv);
@ -741,31 +783,44 @@ float cubic_bezier_dis(vec2 uv, vec2 p0, vec2 p1, vec2 p2, vec2 p3, bool roundEn
int num_roots_trd_drv = 0; int num_roots_trd_drv = 0;
vec2 roots_trd_drv = vec2(1e38); vec2 roots_trd_drv = vec2(1e38);
if(num_roots_snd_drv!=3){ if (num_roots_snd_drv != 3)
{
num_roots_trd_drv = solve_quadric(c3, roots_trd_drv); num_roots_trd_drv = solve_quadric(c3, roots_trd_drv);
} }
for(int i=0;i<3;i++){ for (int i = 0; i < 3; i++)
if(i < num_roots){ {
for(int j=0;j<3;j+=2){ if (i < num_roots)
if(j < num_roots_snd_drv){ {
if(a[i] < roots_snd_drv[j] && b[i] > roots_snd_drv[j]){ for (int j = 0; j < 3; j += 2)
if(eval_poly5(b0,b1,b2,b3,b4,roots_snd_drv[j]) > 0.){ {
if (j < num_roots_snd_drv)
{
if (a[i] < roots_snd_drv[j] && b[i] > roots_snd_drv[j])
{
if (eval_poly5(b0, b1, b2, b3, b4, roots_snd_drv[j]) > 0.)
{
b[i] = roots_snd_drv[j]; b[i] = roots_snd_drv[j];
} }
else{ else
{
a[i] = roots_snd_drv[j]; a[i] = roots_snd_drv[j];
} }
} }
} }
} }
for(int j=0;j<2;j++){ for (int j = 0; j < 2; j++)
if(j < num_roots_trd_drv){ {
if(a[i] < roots_trd_drv[j] && b[i] > roots_trd_drv[j]){ if (j < num_roots_trd_drv)
if(eval_poly5(b0,b1,b2,b3,b4,roots_trd_drv[j]) > 0.){ {
if (a[i] < roots_trd_drv[j] && b[i] > roots_trd_drv[j])
{
if (eval_poly5(b0, b1, b2, b3, b4, roots_trd_drv[j]) > 0.)
{
b[i] = roots_trd_drv[j]; b[i] = roots_trd_drv[j];
} }
else{ else
{
a[i] = roots_trd_drv[j]; a[i] = roots_trd_drv[j];
} }
} }
@ -779,15 +834,17 @@ float cubic_bezier_dis(vec2 uv, vec2 p0, vec2 p1, vec2 p2, vec2 p3, bool roundEn
// compute roots with halley's method // compute roots with halley's method
for(int i=0;i<3;i++){ for (int i = 0; i < 3; i++)
if(i < num_roots){ {
if (i < num_roots)
{
roots[i] = .5 * (a[i] + b[i]); roots[i] = .5 * (a[i] + b[i]);
for(int j=0;j<halley_iterations;j++){ for (int j = 0; j < halley_iterations; j++)
{
roots[i] = halley_iteration5(b0, b1, b2, b3, b4, roots[i]); roots[i] = halley_iteration5(b0, b1, b2, b3, b4, roots[i]);
} }
// compute squared distance to nearest point on curve // compute squared distance to nearest point on curve
if (roundEnd) if (roundEnd)
{ {
@ -797,21 +854,20 @@ float cubic_bezier_dis(vec2 uv, vec2 p0, vec2 p1, vec2 p2, vec2 p3, bool roundEn
} }
else else
{ {
if(roots[i]<0.||roots[i]>1.) d0=min(d0,1e38); if (roots[i] < 0. || roots[i] > 1.)
d0 = min(d0, 1e38);
else else
{ {
vec2 to_curve = uv - parametric_cub_bezier(roots[i], p0, p1, p2, p3); vec2 to_curve = uv - parametric_cub_bezier(roots[i], p0, p1, p2, p3);
d0 = min(d0, dot(to_curve, to_curve)); d0 = min(d0, dot(to_curve, to_curve));
} }
} }
} }
} }
return sqrt(d0); return sqrt(d0);
} }
int cubic_bezier_int_test2(vec2 uv, vec2 p0, vec2 p1, vec2 p2, vec2 p3, bool reverse) int cubic_bezier_int_test2(vec2 uv, vec2 p0, vec2 p1, vec2 p2, vec2 p3, bool reverse)
{ {
float cu = (-p0.y + 3. * p1.y - 3. * p2.y + p3.y); float cu = (-p0.y + 3. * p1.y - 3. * p2.y + p3.y);
@ -831,8 +887,10 @@ int cubic_bezier_int_test2(vec2 uv, vec2 p0, vec2 p1, vec2 p2, vec2 p3, bool rev
} }
else else
{ {
if (abs(cu) < .0001) n_roots = solve_quadric(vec2(co / qu, li / qu), roots.xy); if (abs(cu) < .0001)
else n_roots = solve_cubic(vec3(co / cu, li / cu, qu / cu), roots); n_roots = solve_quadric(vec2(co / qu, li / qu), roots.xy);
else
n_roots = solve_cubic(vec3(co / cu, li / cu, qu / cu), roots);
for (int i = 0; i < n_roots; i++) for (int i = 0; i < n_roots; i++)
{ {
@ -843,7 +901,8 @@ int cubic_bezier_int_test2(vec2 uv, vec2 p0, vec2 p1, vec2 p2, vec2 p3, bool rev
x_pos = x_pos * roots[i] + -3. * p0.x + 3. * p1.x; x_pos = x_pos * roots[i] + -3. * p0.x + 3. * p1.x;
x_pos = x_pos * roots[i] + p0.x; x_pos = x_pos * roots[i] + p0.x;
if (reverse? x_pos < uv.x: x_pos > uv.x) n_ints++; if (reverse ? x_pos < uv.x : x_pos > uv.x)
n_ints++;
} }
} }
} }
@ -858,10 +917,12 @@ int ray_int_test(vec2 uv, vec2 p0, vec2 direction, bool reverse)
vec2 nor = -direction; vec2 nor = -direction;
nor = vec2(nor.y, -nor.x); nor = vec2(nor.y, -nor.x);
float sgn = p0.y > direction.y ? 1. : -1.; float sgn = p0.y > direction.y ? 1. : -1.;
if(reverse) sgn = -sgn; if (reverse)
sgn = -sgn;
return dot(nor, p0) * sgn < 0. ? 0 : 1; return dot(nor, p0) * sgn < 0. ? 0 : 1;
} }
else return 0; else
return 0;
} }
vec2 bezierTangent(float t, vec2 p0, vec2 p1, vec2 p2, vec2 p3) vec2 bezierTangent(float t, vec2 p0, vec2 p1, vec2 p2, vec2 p3)
@ -962,65 +1023,63 @@ void drawLine(in float d, in uint styleIndex, out vec4 elementColor, out vec2 me
} }
} }
bool drawElement(uint elementIndex, vec2 localUV, vec2 scale, out vec3 color, out vec2 metallicRoughness, inout vec3 debugBVH = vec3(0)) bool shouldFillBeginCap(vec2 localUV, bool onVeryBegin, int endType, vec2 p0, vec2 tangentBegin, vec2 tangentEndLast)
{
vec2 normal;
if (onVeryBegin)
{
if (endType % 2 == 0)
return true;
else if (endType % 2 == 1)
normal = normalize(mat2(0, 1, -1, 0) * (-tangentBegin));
}
else
{
vec2 normalLast = normalize(mat2(0, 1, -1, 0) * tangentEndLast);
vec2 normalNow = normalize(mat2(0, 1, -1, 0) * (-tangentBegin));
normal = normalLast + normalNow;
}
return angleLargeThanPi(normal, localUV - p0);
}
bool shouldFillEndCap(vec2 localUV, bool onVeryEnd, int endType, vec2 p3, vec2 tangentEnd, vec2 tangentBeginNext)
{
vec2 normal;
if (onVeryEnd)
{
if ((endType / 2) % 2 == 0)
return true;
else if ((endType / 2) % 2 == 1)
normal = normalize(mat2(0, 1, -1, 0) * tangentEnd);
}
else
{
vec2 normalLast = normalize(mat2(0, 1, -1, 0) * tangentEnd);
vec2 normalNow = normalize(mat2(0, 1, -1, 0) * (-tangentBeginNext));
normal = normalLast + normalNow;
}
return angleLargeThanPi(localUV - p3, normal);
}
bool fillElement(vec2 localUV, uint contourIndex, uint linesOffset, uint pointsOffset, uint styleIndex,
inout vec4 elementColor, inout vec2 metallicRoughness)
{ {
bool hitElement = false; bool hitElement = false;
vec4 elementColor = vec4(-1);
metallicRoughness = vec2(0, 0.8);
uint currentOffset[] = elementOffset[elementIndex];
uint elementBvhRoot = currentOffset[0];
uint styleIndex = currentOffset[1];
uint elementBvhLength = 0x80000000;
uint pointsOffset = currentOffset[2];
uint linesOffset = currentOffset[3];
elementStack.top = 0;
uint elementBvhIndex = 0;
while (elementBvhIndex < elementBvhLength || !elementStack.empty())
{
while (elementBvhIndex < elementBvhLength)
{
vec4 bound = bvhBound[elementBvhRoot + elementBvhIndex];
uint leftChild = bvhChildren[elementBvhRoot + elementBvhIndex].x;
if (all(lessThan(bound.xy, localUV)) && all(lessThan(localUV, bound.zw)))
{
if (leftChild >= elementBvhLength)
{
if (any(greaterThan(bound.xy+vec2(0.003), localUV)) || any(greaterThan(localUV, bound.zw-vec2(0.003))))
{
debugBVH.g = 0;
debugBVH.r += 1;
}
//uint styleIndex = bvhChildren[elementBvhRoot + elementBvhIndex].y;
//uint elementType = bvhChildren[elementBvhRoot + elementBvhIndex].y;
//float elementType = elementData[styleIndex];
bool isFillStyle = elementData[styleIndex]<=0;
// for(int i = 0; i<200;i++)
if (isFillStyle) //Ãæ
{
uint contourIndex = linesOffset + leftChild - 0x80000000;
uint num_its = 0; uint num_its = 0;
uint lineCount = elementIndexs[contourIndex]; uint lineCount = elementIndexs[contourIndex];
for (uint contourIterator = contourIndex + 1; contourIterator < contourIndex + 1 + lineCount; contourIterator++) for (uint contourIterator = contourIndex + 1; contourIterator < contourIndex + 1 + lineCount; contourIterator++)
{ {
uint lineIndex = elementIndexs[contourIterator]; uint lineIndex = elementIndexs[contourIterator];
uint pLocation = linesOffset + 2 * lineIndex; uint pLocation = linesOffset + 2 * lineIndex;
uvec4 pxIndex = uvec4(pointsOffset)+2*uvec4(elementIndexs[pLocation]>>16, elementIndexs[pLocation]&0xFFFF, elementIndexs[pLocation+1]>>16, elementIndexs[pLocation+1]&0xFFFF); uvec4 pxIndex =
uvec4(pointsOffset) + 2 * uvec4(elementIndexs[pLocation] >> 16, elementIndexs[pLocation] & 0xFFFF,
elementIndexs[pLocation + 1] >> 16, elementIndexs[pLocation + 1] & 0xFFFF);
uvec4 pyIndex = uvec4(1) + pxIndex; uvec4 pyIndex = uvec4(1) + pxIndex;
mat4x2 p = mat4x2(elementData[pxIndex[0]], elementData[pyIndex[0]], mat4x2 p =
elementData[pxIndex[1]], elementData[pyIndex[1]], mat4x2(elementData[pxIndex[0]], elementData[pyIndex[0]], elementData[pxIndex[1]], elementData[pyIndex[1]],
elementData[pxIndex[2]],elementData[pyIndex[2]], elementData[pxIndex[2]], elementData[pyIndex[2]], elementData[pxIndex[3]], elementData[pyIndex[3]]);
elementData[pxIndex[3]], elementData[pyIndex[3]]);
// vec2 p[4] = {vec2(elementData[pxIndex[0]], elementData[pyIndex[0]]),
// vec2(elementData[pxIndex[1]], elementData[pyIndex[1]]),
// vec2(elementData[pxIndex[2]],elementData[pyIndex[2]]),
// vec2(elementData[pxIndex[3]], elementData[pyIndex[3]])};
// if (bound.z == p[0].x && distance(localUV, p[3]) < 0.01) // if (bound.z == p[0].x && distance(localUV, p[3]) < 0.01)
// { // {
// debugBVH = vec3(0, 0, 1); // debugBVH = vec3(0, 0, 1);
@ -1031,7 +1090,6 @@ bool drawElement(uint elementIndex, vec2 localUV, vec2 scale, out vec3 color, ou
// { // {
// num_its += segment_int_test(localUV, p0, p3); // num_its += segment_int_test(localUV, p0, p3);
// } // }
//
// else // else
num_its += cubic_bezier_int_test(localUV, p[0], p[1], p[2], p[3]); num_its += cubic_bezier_int_test(localUV, p[0], p[1], p[2], p[3]);
} }
@ -1047,49 +1105,83 @@ bool drawElement(uint elementIndex, vec2 localUV, vec2 scale, out vec3 color, ou
elementColor = vec4(unpackUnorm4x8(floatBitsToUint(elementData[styleIndex + 1])).rgb, 0); elementColor = vec4(unpackUnorm4x8(floatBitsToUint(elementData[styleIndex + 1])).rgb, 0);
metallicRoughness = head.xy; metallicRoughness = head.xy;
} }
} }
return hitElement;
} }
else //Ïß
bool strokeElement(vec2 localUV, uint contourIndex, uint linesOffset, uint pointsOffset, uint styleIndex,
float widthHeightRatio, inout vec4 elementColor, inout vec2 metallicRoughness)
{ {
bool hitElement = false;
float strokeWidth = elementData[styleIndex]; float strokeWidth = elementData[styleIndex];
float widthHeightRatio = uintBitsToFloat(currentOffset[4]);
vec2 size = normalize(vec2(widthHeightRatio, 1)) + vec2(2 * strokeWidth); vec2 size = normalize(vec2(widthHeightRatio, 1)) + vec2(2 * strokeWidth);
vec2 ratio = widthHeightRatio < 1 ? vec2(widthHeightRatio, 1) : vec2(1, 1 / widthHeightRatio); vec2 ratio = widthHeightRatio < 1 ? vec2(widthHeightRatio, 1) : vec2(1, 1 / widthHeightRatio);
localUV *= ratio; localUV *= ratio;
uint contourIndex = linesOffset + leftChild - 0x80000000;
float minDistance = 1e38; float minDistance = 1e38;
uint lineCount = elementIndexs[contourIndex]; uint lineCount = elementIndexs[contourIndex];
vec4 styleHead = unpackUnorm4x8(floatBitsToUint(elementData[styleIndex + 1])); vec4 styleHead = unpackUnorm4x8(floatBitsToUint(elementData[styleIndex + 1]));
float lineType = floor(styleHead.b * 10); float lineType = floor(styleHead.b * 10);
//float lineType = 2; int endType = int(round(styleHead.b * 100)) % 10;
vec2 p3Last = vec2(1e38); vec2 p3Last = vec2(1e38);
vec2 p2Last = vec2(1e38); vec2 p2Last = vec2(1e38);
vec2 tangentEndLast;
int debugBegin = 0; int debugBegin = 0;
for ( uint contourIterator_ = contourIndex + 1;contourIterator_ <= contourIndex + 1 + lineCount; contourIterator_++) for (uint contourIterator_ = contourIndex + 1; contourIterator_ < contourIndex + 1 + lineCount; contourIterator_++)
{ {
uint contourIterator = contourIterator_; uint contourIterator = contourIterator_;
if (contourIterator_ == contourIndex + 1 + lineCount) if (contourIterator_ == contourIndex + 1 + lineCount)
contourIterator = contourIndex + 1; contourIterator = contourIndex + 1;
uint lineIndex = elementIndexs[contourIterator]; uint lineIndex = elementIndexs[contourIterator];
uint pLocation = linesOffset + 3 * lineIndex; uint pLocation = linesOffset + 3 * lineIndex;
uvec4 pxIndex = uvec4(pointsOffset)+2*uvec4(elementIndexs[pLocation]>>16, elementIndexs[pLocation]&0xFFFF, elementIndexs[pLocation+1]>>16, elementIndexs[pLocation+1]&0xFFFF); vec2 percent = unpackUnorm2x16(elementIndexs[pLocation + 2]);
uvec4 pxIndex =
uvec4(pointsOffset) + 2 * uvec4(elementIndexs[pLocation] >> 16, elementIndexs[pLocation] & 0xFFFF,
elementIndexs[pLocation + 1] >> 16, elementIndexs[pLocation + 1] & 0xFFFF);
uvec4 pyIndex = uvec4(1) + pxIndex; uvec4 pyIndex = uvec4(1) + pxIndex;
mat4x2 p = mat4x2(elementData[pxIndex[0]], elementData[pyIndex[0]], mat4x2 p =
elementData[pxIndex[1]], elementData[pyIndex[1]], mat4x2(elementData[pxIndex[0]], elementData[pyIndex[0]], elementData[pxIndex[1]], elementData[pyIndex[1]],
elementData[pxIndex[2]], elementData[pyIndex[2]], elementData[pxIndex[2]], elementData[pyIndex[2]], elementData[pxIndex[3]], elementData[pyIndex[3]]);
elementData[pxIndex[3]], elementData[pyIndex[3]]);
p[0] *= ratio; p[0] *= ratio;
p[1] *= ratio; p[1] *= ratio;
p[2] *= ratio; p[2] *= ratio;
p[3] *= ratio; p[3] *= ratio;
vec2 tangentBeginNext;
if (contourIterator + 1 < contourIndex + 1 + lineCount)
{
uint lineIndex = elementIndexs[contourIterator + 1];
uint pLocation = linesOffset + 3 * lineIndex;
//vec2 percent = unpackUnorm2x16(elementIndexs[pLocation + 2]);
uvec4 pxIndex = uvec4(pointsOffset) +
2 * uvec4(elementIndexs[pLocation] >> 16, elementIndexs[pLocation] & 0xFFFF,
elementIndexs[pLocation + 1] >> 16, elementIndexs[pLocation + 1] & 0xFFFF);
uvec4 pyIndex = uvec4(1) + pxIndex;
mat4x2 pNext = mat4x2(elementData[pxIndex[0]], elementData[pyIndex[0]], elementData[pxIndex[1]],
elementData[pyIndex[1]], elementData[pxIndex[2]], elementData[pyIndex[2]],
elementData[pxIndex[3]], elementData[pyIndex[3]]);
pNext[0] *= ratio;
pNext[1] *= ratio;
pNext[2] *= ratio;
pNext[3] *= ratio;
if (pNext[0] == pNext[1] && pNext[2] == pNext[3])
{
pNext[1] = (pNext[0] + pNext[3]) / 2;
pNext[2] = pNext[1];
}
//if(pNext[0]!=p[3])
// break;
if (pNext[0] != pNext[1])
tangentBeginNext = normalize(pNext[0] - pNext[1]);
else
tangentBeginNext = normalize(pNext[0] - pNext[2]);
}
if (p[0] == p[1] && p[2] == p[3]) if (p[0] == p[1] && p[2] == p[3])
{ {
p[1] = (p[0] + p[3]) / 2; p[1] = (p[0] + p[3]) / 2;
@ -1098,52 +1190,70 @@ bool drawElement(uint elementIndex, vec2 localUV, vec2 scale, out vec3 color, ou
if (distance(localUV, p[0]) <= 0.001) if (distance(localUV, p[0]) <= 0.001)
{ {
if(p3Last==p[0]) debugBegin = 2; if (p3Last == p[0])
else debugBegin = 1; debugBegin = 2;
else
debugBegin = 1;
} }
float d = cubic_bezier_dis(localUV, p[0], p[1], p[2], p[3], true); float d = cubic_bezier_dis(localUV, p[0], p[1], p[2], p[3], true);
if (d <= strokeWidth) if (d <= strokeWidth)
{ {
bool onBegin = distance(localUV,p[0])<=strokeWidth&&p3Last==p[0]; bool onBegin =
bool fill = true; distance(localUV, p[0]) <= strokeWidth; //&& (p3Last == p[0] || contourIterator == contourIndex + 1);
bool onEnd = distance(localUV, p[3]) <= strokeWidth;
vec2 tangentBegin;
vec2 tangentEnd;
if (p[0] != p[1])
tangentBegin = normalize(p[0] - p[1]);
else
tangentBegin = normalize(p[0] - p[2]);
if (p[3] != p[2])
tangentEnd = normalize(p[3] - p[2]);
else
tangentEnd = normalize(p[3] - p[1]);
bool hit = d < minDistance;
if (onBegin) if (onBegin)
hit =
hit && shouldFillBeginCap(localUV, percent[0] < 1e-5, endType, p[0], tangentBegin, p3Last - p2Last);
if (onEnd)
hit = hit &&
shouldFillEndCap(localUV, percent[1] > 1 - 1e-5, endType, p[3], tangentEnd, tangentBeginNext);
if (hit)
{ {
vec2 normalLast = normalize(mat2(0,1,-1,0)*(p3Last-p2Last));
vec2 normalNow = normalize(mat2(0,1,-1,0)*(p[1]-p[0]));
vec2 normal = normalLast+normalNow;
fill = angleLargeThanPi(normal, localUV-p[0]);
}
if(onBegin?fill:d<minDistance)
{
minDistance = min(minDistance, d);
bool reverse = p[3].y - p[0].y < 0.; bool reverse = p[3].y - p[0].y < 0.;
vec2 tangentBegin = normalize(p[0]-p[1]); // if (tangentBegin.y == 0.)
vec2 tangentEnd = normalize(p[3]-p[2]); // tangentBegin.y = reverse ? eps : -eps;
if(tangentBegin.y==0.) tangentBegin.y=reverse?eps:-eps; // if (tangentEnd.y == 0.)
if(tangentEnd.y==0.) tangentEnd.y=reverse?-eps:eps; // tangentEnd.y = reverse ? -eps : eps;
int intTest = cubic_bezier_int_test2(localUV, p[0], p[1], p[2], p[3], reverse) int intTest = cubic_bezier_int_test2(localUV, p[0], p[1], p[2], p[3], reverse) +
+ ray_int_test(localUV, p[0], tangentBegin, reverse) ray_int_test(localUV, p[0], tangentBegin, reverse) +
+ ray_int_test(localUV, p[3], tangentEnd, reverse); ray_int_test(localUV, p[3], tangentEnd, reverse);
if(lineType==2 || intTest%2==int(lineType))
if (lineType == 2 || (intTest % 2 == int(lineType)))
{ {
minDistance = min(minDistance, d);
hitElement = true; hitElement = true;
// elementColor = vec4(1, 1, 0, 1);
vec2 metallicRoughness;
drawLine(minDistance / strokeWidth, styleIndex, elementColor, metallicRoughness); drawLine(minDistance / strokeWidth, styleIndex, elementColor, metallicRoughness);
} }
else if(p3Last==p[0]) hitElement = false; // else if (p3Last == p[0])
// if(distance(localUV,p[0])<=strokeWidth&&p3Last==p[0]&&fill) // hitElement = false;
// {
// hitElement = true;
// elementColor = vec4(0,0,1,1);
// }
} }
tangentEndLast = tangentEnd;
} }
p3Last = p[3]; p3Last = p[3];
p2Last = p[2]; p2Last = p[2];
} }
if (hitElement && distance(localUV, p3Last) <= strokeWidth)
{
// hitElement = shouldFillEndCap(localUV, percent[1] > 1 - 1e-5, endType, p3Last, tangentEndLast, vec2(0));
}
// if (minDistance <= 0.001) // if (minDistance <= 0.001)
// { // {
@ -1154,7 +1264,55 @@ bool drawElement(uint elementIndex, vec2 localUV, vec2 scale, out vec3 color, ou
// else if (debugBegin == 2) // else if (debugBegin == 2)
// elementColor = vec4(0, 1, 0, 1); // elementColor = vec4(0, 1, 0, 1);
// } // }
return hitElement;
}
bool drawElement(uint elementIndex, vec2 localUV, vec2 scale, out vec3 color, out vec2 metallicRoughness,
inout vec3 debugBVH = vec3(0))
{
bool hitElement = false;
vec4 elementColor = vec4(-1);
metallicRoughness = vec2(0, 0.8);
uint currentOffset[] = elementOffset[elementIndex];
uint elementBvhRoot = currentOffset[0];
uint styleIndex = currentOffset[1];
uint pointsOffset = currentOffset[2];
uint linesOffset = currentOffset[3];
float widthHeightRatio = uintBitsToFloat(currentOffset[4]);
elementStack.top = 0;
uint elementBvhIndex = 0;
uint elementBvhLength = 0x80000000;
while (elementBvhIndex < elementBvhLength || !elementStack.empty())
{
while (elementBvhIndex < elementBvhLength)
{
vec4 bound = bvhBound[elementBvhRoot + elementBvhIndex];
uint leftChild = bvhChildren[elementBvhRoot + elementBvhIndex].x;
if (all(lessThan(bound.xy, localUV)) && all(lessThan(localUV, bound.zw)))
{
if (leftChild >= elementBvhLength)
{
if (any(greaterThan(bound.xy + vec2(0.003), localUV)) ||
any(greaterThan(localUV, bound.zw - vec2(0.003))))
{
debugBVH.g = 0;
debugBVH.r += 1;
}
uint contourIndex = linesOffset + leftChild - 0x80000000;
bool isFillStyle = elementData[styleIndex] <= 0;
if (isFillStyle) // Ãæ
{
hitElement = fillElement(localUV, contourIndex, linesOffset, pointsOffset, styleIndex,
elementColor, metallicRoughness);
}
else // Ïß
{
hitElement = strokeElement(localUV, contourIndex, linesOffset, pointsOffset, styleIndex,
widthHeightRatio, elementColor, metallicRoughness);
} }
elementBvhIndex = elementBvhLength; elementBvhIndex = elementBvhLength;
@ -1182,7 +1340,6 @@ bool drawElement(uint elementIndex, vec2 localUV, vec2 scale, out vec3 color, ou
return hitElement; return hitElement;
} }
void main() void main()
{ {
ivec2 pixelLocation = ivec2(pixelOffset + gl_GlobalInvocationID.xy); ivec2 pixelLocation = ivec2(pixelOffset + gl_GlobalInvocationID.xy);
@ -1195,7 +1352,8 @@ void main()
vec3 debugBVH = vec3(0); vec3 debugBVH = vec3(0);
// bool debugHit = false; // bool debugHit = false;
vec4 color = vec4(1,1,1,-1); vec4 color = vec4(0.76, 0.33, 0.15, -1);
// vec4 color = vec4(1,1,1, -1);
vec2 metallicRoughness = vec2(0, 0.8); vec2 metallicRoughness = vec2(0, 0.8);
stack.top = 0; stack.top = 0;
uint index = 0, visitTime = 0; uint index = 0, visitTime = 0;
@ -1221,22 +1379,25 @@ void main()
if (all(lessThan(vec2(-1), localUV)) && all(lessThan(localUV, vec2(1))) && zIndex > color.w) if (all(lessThan(vec2(-1), localUV)) && all(lessThan(localUV, vec2(1))) && zIndex > color.w)
{ {
// if (any(greaterThan(bound.xy+vec2(0.005), uv)) || any(greaterThan(uv, bound.zw-vec2(0.005)))) // if (any(greaterThan(bound.xy+vec2(0.005), uv)) || any(greaterThan(uv, bound.zw-vec2(0.005))))
if (any(greaterThan(vec2(-1)+vec2(0.005), localUV)) || any(greaterThan(localUV, vec2(1)-vec2(0.005)))) if (any(greaterThan(vec2(-1) + vec2(0.005), localUV)) ||
any(greaterThan(localUV, vec2(1) - vec2(0.005))))
debugBVH.g += 0.3; debugBVH.g += 0.3;
// uint elementIndex = leftChild - bvhLength; // uint elementIndex = leftChild - bvhLength;
// debugBVH.bg += 0.5 * (localUV + vec2(1)); // debugBVH.bg += 0.5 * (localUV + vec2(1));
// debugBVH = vec3(0); // debugBVH = vec3(0);
if(flip.x) localUV.x = -localUV.x; if (flip.x)
if(flip.y) localUV.y = -localUV.y; localUV.x = -localUV.x;
if (flip.y)
localUV.y = -localUV.y;
vec3 elementColor; vec3 elementColor;
vec2 elementMetallicRoughness; vec2 elementMetallicRoughness;
if(drawElement(leftChild - 0x80000000, localUV, scale, elementColor, elementMetallicRoughness, debugBVH)) if (drawElement(leftChild - 0x80000000, localUV, scale, elementColor, elementMetallicRoughness,
debugBVH))
{ {
color = vec4(elementColor, zIndex); color = vec4(elementColor, zIndex);
metallicRoughness = elementMetallicRoughness; metallicRoughness = elementMetallicRoughness;
} }
} }
index = bvhLength; index = bvhLength;
@ -1262,7 +1423,7 @@ void main()
imageStore(gBaseColor, pixelLocation, vec4(color.rgb, 1)); imageStore(gBaseColor, pixelLocation, vec4(color.rgb, 1));
imageStore(gMetallicRoughness, pixelLocation, vec4(metallicRoughness, 0, 1)); imageStore(gMetallicRoughness, pixelLocation, vec4(metallicRoughness, 0, 1));
return; //return;
if (/*color.a!=-1&&*/ debugBVH == vec3(0)) if (/*color.a!=-1&&*/ debugBVH == vec3(0))
{ {
// imageStore(gBaseColor, pixelLocation, vec4(vec3(1, 1, 0),1)); // imageStore(gBaseColor, pixelLocation, vec4(vec3(1, 1, 0),1));
@ -1272,5 +1433,4 @@ void main()
imageStore(gBaseColor, pixelLocation, vec4(debugBVH, 1)); imageStore(gBaseColor, pixelLocation, vec4(debugBVH, 1));
imageStore(gMetallicRoughness, pixelLocation, vec4(0, 0.8, 0, 1)); imageStore(gMetallicRoughness, pixelLocation, vec4(0, 0.8, 0, 1));
} }
} }

View File

@ -62,15 +62,15 @@ QPainterPath PainterPathUtil::monotonization(QPainterPath& painterPath) {
return resPath; return resPath;
} }
std::pair<QPainterPath, float> PainterPathUtil::normalized(const QPainterPath& path) std::pair<QPainterPath, float> PainterPathUtil::normalized(const QPainterPath& path, float width)
{ {
auto rect = path.boundingRect(); auto rect = path.boundingRect();
return { (QTransform::fromTranslate(-rect.center().x(), -rect.center().y()) * QTransform::fromScale(1 / (rect.width() / 1.999999), -1 / (rect.height() / 1.999999))).map(path), return { (QTransform::fromTranslate(-rect.center().x(), -rect.center().y()) * QTransform::fromScale(1 / (rect.width() / 1.999999), -1 / (rect.height() / 1.999999)) * QTransform::fromScale(1 / (1 + width),1 / (1 + width))).map(path),
rect.width() / rect.height() }; rect.width() / rect.height() };
} }
std::pair<std::vector<std::vector<Renderer::Point>>, float> PainterPathUtil::toNormalizedLines(const QPainterPath& path) std::pair<std::vector<std::vector<Renderer::Point>>, float> PainterPathUtil::toNormalizedLines(const QPainterPath& path, float width)
{ {
auto [p, ratio] = normalized(path); auto [p, ratio] = normalized(path, width);
return { transformToLines(p), ratio }; return { transformToLines(p), ratio };
} }

View File

@ -8,7 +8,7 @@ class PainterPathUtil
public: public:
static std::vector<std::vector<Renderer::Point>> transformToLines(const QPainterPath& painterPath); static std::vector<std::vector<Renderer::Point>> transformToLines(const QPainterPath& painterPath);
static QPainterPath monotonization(QPainterPath& painterPath); static QPainterPath monotonization(QPainterPath& painterPath);
static std::pair<QPainterPath, float> normalized(const QPainterPath& path); static std::pair<QPainterPath, float> normalized(const QPainterPath& path, float width = 0);
static std::pair<std::vector<std::vector<Renderer::Point>>, float> toNormalizedLines(const QPainterPath& path); static std::pair<std::vector<std::vector<Renderer::Point>>, float> toNormalizedLines(const QPainterPath& path, float width = 0);
}; };

View File

@ -15,6 +15,7 @@
#include "../Editor/util/SvgFileLoader.h" #include "../Editor/util/SvgFileLoader.h"
#include <ThirdPartyLib/qquick/qquicksvgparser_p.h> #include <ThirdPartyLib/qquick/qquicksvgparser_p.h>
#include <util/PaintingUtil.h> #include <util/PaintingUtil.h>
#include "Painting/MaterialStyleStroke.h"
using namespace Renderer; using namespace Renderer;
using std::vector; using std::vector;
@ -157,9 +158,8 @@ std::unique_ptr<Drawable> Model::processMesh(aiMesh* mesh, const aiScene* scene,
for (auto& v : vertices) for (auto& v : vertices)
{ {
//qDebug() << v.TexCoords.x << v.TexCoords.y;
v.TexCoords = (v.TexCoords - leftBottom) / (rightTop - leftBottom); v.TexCoords = (v.TexCoords - leftBottom) / (rightTop - leftBottom);
qDebug() << v.TexCoords.x << v.TexCoords.y; //qDebug() << v.TexCoords.x << v.TexCoords.y;
} }
mesh->vertices = vertices; mesh->vertices = vertices;

View File

@ -104,7 +104,11 @@ std::unique_ptr<MaterialStyle> Renderer::MaterialStyleStroke::clone() const
bool Renderer::MaterialStyleStroke::operator==(const MaterialStyle& m) const bool Renderer::MaterialStyleStroke::operator==(const MaterialStyle& m) const
{ {
return type() == m.type() && *materialStroke == *static_cast<const MaterialStyleStroke&>(m).materialStroke; return type() == m.type()
&& halfWidth == static_cast<const MaterialStyleStroke&>(m).halfWidth
&& strokeType == static_cast<const MaterialStyleStroke&>(m).strokeType
&& endType == static_cast<const MaterialStyleStroke&>(m).endType
&& *materialStroke == *static_cast<const MaterialStyleStroke&>(m).materialStroke;
} }
float Renderer::MaterialStyleStroke::getHalfWidth() const float Renderer::MaterialStyleStroke::getHalfWidth() const

View File

@ -43,7 +43,7 @@ namespace Renderer
}; };
enum class StrokeType { kBothSides = 2, kLeftSide = 1, kRightSide = 0 }; enum class StrokeType { kBothSides = 2, kLeftSide = 1, kRightSide = 0 };
enum class StrokeEndType { kRound = 0, kFlat = 1 }; enum class StrokeEndType { kRound = 0b00, kFlat = 0b11, kRoundFlat = 0b10, kFlatRound = 0b01 };
class MaterialStyleStroke : public MaterialStyle class MaterialStyleStroke : public MaterialStyle
{ {
@ -54,7 +54,7 @@ namespace Renderer
virtual std::unique_ptr<MaterialStyle> clone() const override; virtual std::unique_ptr<MaterialStyle> clone() const override;
virtual bool operator==(const MaterialStyle&) const override; virtual bool operator==(const MaterialStyle&) const override;
float getHalfWidth() const; float getHalfWidth() const;
//protected:
float halfWidth; float halfWidth;
StrokeType strokeType; StrokeType strokeType;
StrokeEndType endType; StrokeEndType endType;

View File

@ -77,6 +77,7 @@ std::vector<GLfloat> generateStyleBuffer(const std::vector<BaseStyle>& styles)
styleBuffer.push_back(glm::uintBitsToFloat(glm::packUnorm2x16(style.transform->flip))); styleBuffer.push_back(glm::uintBitsToFloat(glm::packUnorm2x16(style.transform->flip)));
auto encoded = style.material->encoded(); auto encoded = style.material->encoded();
styleBuffer.insert(styleBuffer.end(), encoded.begin(), encoded.end()); styleBuffer.insert(styleBuffer.end(), encoded.begin(), encoded.end());
qDebug() << "style size" << styleBuffer.size();
} }
return styleBuffer; return styleBuffer;
} }

View File

@ -12,9 +12,11 @@ Renderer::RendererWidget::RendererWidget(QWidget* parent)
auto openAction = new QAction(QStringLiteral("´ò¿ª"), menu); auto openAction = new QAction(QStringLiteral("´ò¿ª"), menu);
auto saveAction = new QAction(QStringLiteral("±£´æ"), menu); auto saveAction = new QAction(QStringLiteral("±£´æ"), menu);
auto testAction = new QAction(QStringLiteral("²âÊÔ"), menu); auto testAction = new QAction(QStringLiteral("²âÊÔ"), menu);
auto test2Action = new QAction(QStringLiteral("²âÊÔ2"), menu);
menu->addAction(openAction); menu->addAction(openAction);
menu->addAction(saveAction); menu->addAction(saveAction);
menu->addAction(testAction); menu->addAction(testAction);
menu->addAction(test2Action);
ui.openButton->setHaloVisible(false); ui.openButton->setHaloVisible(false);
ui.openButton->setOverlayStyle(::Material::TintedOverlay); ui.openButton->setOverlayStyle(::Material::TintedOverlay);
@ -47,7 +49,9 @@ Renderer::RendererWidget::RendererWidget(QWidget* parent)
QObject::connect(testAction, &QAction::triggered, [&] { QObject::connect(testAction, &QAction::triggered, [&] {
ui.openGLWidget->setModel("Models/Sponza/Sponza.gltf"); ui.openGLWidget->setModel("Models/Sponza/Sponza.gltf");
}); });
QObject::connect(test2Action, &QAction::triggered, [&] {
ui.openGLWidget->setModel("E:\\3D Objects\\Gate\\Gate.gltf");
});
ui.horizontalSlider->setValue(105); ui.horizontalSlider->setValue(105);
ui.horizontalSlider_2->setValue(80); ui.horizontalSlider_2->setValue(80);
ui.exposureSlider->setValue(60); ui.exposureSlider->setValue(60);

View File

@ -10,6 +10,8 @@ using namespace Renderer;
namespace UnitTest namespace UnitTest
{ {
void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg);
TEST_CLASS(ElementRendererStokeTypeTest) TEST_CLASS(ElementRendererStokeTypeTest)
{ {
private: private:
@ -20,6 +22,7 @@ namespace UnitTest
TEST_METHOD_INITIALIZE(initialize) TEST_METHOD_INITIALIZE(initialize)
{ {
qInstallMessageHandler(messageHandler);
QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
@ -108,6 +111,27 @@ namespace UnitTest
w.show(); w.show();
a.exec(); a.exec();
} }
TEST_METHOD(TestRightSideFlatRound)
{
QApplication a(argc, argv);
class StyleStrokeRadialGradient : public Renderer::ElementStyle
{
virtual std::vector<Renderer::BaseStyle> toBaseStyles() const override
{
std::map<float, Material> materialMap = {
{0.20, Material{QColor(255,255,255)}},
{0.60, Material{QColor(165,176,207)}},
{1.00, Material{QColor(58,64,151)}}
};
return { BaseStyle(std::make_shared<TransformStyle>(),
std::make_shared<MaterialStyleStroke>(160, StrokeType::kRightSide, StrokeEndType::kFlatRound,
std::make_shared<StrokeRadialGradient>(materialMap, false))) };
}
} style;
TestGLWidget w(style);
w.show();
a.exec();
}
}; };
TEST_CLASS(ElementRendererStokeMaterialTest) TEST_CLASS(ElementRendererStokeMaterialTest)