Fix:曲线锐角连接时渲染错误

main
wuyize 2023-03-24 13:42:16 +08:00
parent 7667525287
commit 2345cd6758
4 changed files with 68 additions and 52 deletions

View File

@ -1002,7 +1002,8 @@ void nextStyleIndex(inout uint styleIndex)
} }
} }
bool shouldFillBeginCap(vec2 localUV, bool onVeryBegin, int endType, vec2 p0, vec2 tangentBegin, vec2 tangentEndLast) bool shouldFillBeginCap(vec2 localUV, bool onVeryBegin, int endType, vec2 p0, vec2 tangentBegin, vec2 tangentEndLast,
float width)
{ {
vec2 normal; vec2 normal;
if (onVeryBegin) if (onVeryBegin)
@ -1018,10 +1019,16 @@ bool shouldFillBeginCap(vec2 localUV, bool onVeryBegin, int endType, vec2 p0, 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 - p0); normal = normalize(normal);
float cosine = dot(normal, -tangentBegin);
vec2 toBegin = localUV - p0;
if (/*cosine > 0 ||*/ dot(toBegin, toBegin) > (width * width / (1 - cosine * cosine)))
return true;
return angleLargeThanPi(normal, toBegin);
} }
bool shouldFillEndCap(vec2 localUV, bool onVeryEnd, int endType, vec2 p3, vec2 tangentEnd, vec2 tangentBeginNext) bool shouldFillEndCap(vec2 localUV, bool onVeryEnd, int endType, vec2 p3, vec2 tangentEnd, vec2 tangentBeginNext,
float width)
{ {
vec2 normal; vec2 normal;
if (onVeryEnd) if (onVeryEnd)
@ -1037,7 +1044,12 @@ bool shouldFillEndCap(vec2 localUV, bool onVeryEnd, int endType, vec2 p3, vec2 t
vec2 normalNow = normalize(mat2(0, 1, -1, 0) * (-tangentBeginNext)); vec2 normalNow = normalize(mat2(0, 1, -1, 0) * (-tangentBeginNext));
normal = normalLast + normalNow; normal = normalLast + normalNow;
} }
return angleLargeThanPi(localUV - p3, normal); normal = normalize(normal);
float cosine = dot(normal, tangentEnd);
vec2 toEnd = localUV - p3;
if (/*cosine < 0 ||*/ dot(toEnd, toEnd) > (width * width / (1 - cosine * cosine)))
return true;
return angleLargeThanPi(toEnd, normal);
} }
void main() void main()
@ -1097,7 +1109,7 @@ void main()
bool onVeryBegin = false; bool onVeryBegin = false;
bool onVeryEnd = false; bool onVeryEnd = false;
vec2 tangentEndLast = vec2(0); vec2 tangentEndLast = vec2(0);
vec2 tangentFirstBegin; vec2 tangentFirstBegin = vec2(0);
uint lastHitIndex = 0; uint lastHitIndex = 0;
bool lastHitElement = false; bool lastHitElement = false;
hitElement = false; hitElement = false;
@ -1154,7 +1166,11 @@ void main()
else else
onVeryEnd = true; onVeryEnd = true;
} }
vec2 tangentBegin;
if (p[0] != p[1])
tangentBegin = normalize(p[0] - p[1]);
else
tangentBegin = normalize(p[0] - p[2]);
vec2 tangentEnd; vec2 tangentEnd;
if (p[3] != p[2]) if (p[3] != p[2])
tangentEnd = normalize(p[3] - p[2]); tangentEnd = normalize(p[3] - p[2]);
@ -1166,22 +1182,14 @@ void main()
float localWidth = strokeWidth; // * mix(lengthRate.x, lengthRate.y, t); float localWidth = strokeWidth; // * mix(lengthRate.x, lengthRate.y, t);
if (d <= localWidth) if (d <= localWidth)
{ {
bool onBegin = t<1e-5; // bool onBegin = true;
bool onEnd = t>1-1e-5; // bool onEnd = true;
//bool onBegin = true;
//bool onEnd = true;
vec2 tangentBegin;
if (p[0] != p[1])
tangentBegin = normalize(p[0] - p[1]);
else
tangentBegin = normalize(p[0] - p[2]);
bool hit = d < minDistance; bool hit = d < minDistance;
if (onBegin) hit = hit && shouldFillBeginCap(localUV, onVeryBegin, endType, p[0], tangentBegin, tangentEndLast,
localWidth);
hit = hit && hit = hit &&
shouldFillBeginCap(localUV, onVeryBegin, endType, p[0], tangentBegin, tangentEndLast); shouldFillEndCap(localUV, onVeryEnd, endType, p[3], tangentEnd, tangentBeginNext, localWidth);
if (onEnd)
hit = hit && shouldFillEndCap(localUV, onVeryEnd, endType, p[3], tangentEnd, tangentBeginNext);
if (hit) if (hit)
{ {
bool reverse = p[3].y - p[0].y < 0.; bool reverse = p[3].y - p[0].y < 0.;
@ -1205,11 +1213,10 @@ void main()
drawLine(minDistance / localWidth, styleIndex, elementColor, metallicRoughness); drawLine(minDistance / localWidth, styleIndex, elementColor, metallicRoughness);
} }
} }
if (pathIndex == 5)
tangentFirstBegin = tangentBegin;
} }
tangentEndLast = tangentEnd; tangentEndLast = tangentEnd;
if (pathIndex == 5)
tangentFirstBegin = tangentBegin;
p3Last = p[3]; p3Last = p[3];
p2Last = p[2]; p2Last = p[2];
onVeryBegin = false; onVeryBegin = false;

View File

@ -1035,7 +1035,8 @@ void drawLine(in float d, uint styleHeadIndex, out vec4 elementColor, out vec2 m
} }
} }
bool shouldFillBeginCap(vec2 localUV, bool onVeryBegin, int endType, vec2 p0, vec2 tangentBegin, vec2 tangentEndLast) bool shouldFillBeginCap(vec2 localUV, bool onVeryBegin, int endType, vec2 p0, vec2 tangentBegin, vec2 tangentEndLast,
float width)
{ {
vec2 normal; vec2 normal;
if (onVeryBegin) if (onVeryBegin)
@ -1051,10 +1052,16 @@ bool shouldFillBeginCap(vec2 localUV, bool onVeryBegin, int endType, vec2 p0, 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 - p0); normal = normalize(normal);
float cosine = dot(normal, -tangentBegin);
vec2 toBegin = localUV - p0;
if (/*cosine > 0 ||*/ dot(toBegin, toBegin) > (width * width / (1 - cosine * cosine)))
return true;
return angleLargeThanPi(normal, toBegin);
} }
bool shouldFillEndCap(vec2 localUV, bool onVeryEnd, int endType, vec2 p3, vec2 tangentEnd, vec2 tangentBeginNext) bool shouldFillEndCap(vec2 localUV, bool onVeryEnd, int endType, vec2 p3, vec2 tangentEnd, vec2 tangentBeginNext,
float width)
{ {
vec2 normal; vec2 normal;
if (onVeryEnd) if (onVeryEnd)
@ -1070,7 +1077,12 @@ bool shouldFillEndCap(vec2 localUV, bool onVeryEnd, int endType, vec2 p3, vec2 t
vec2 normalNow = normalize(mat2(0, 1, -1, 0) * (-tangentBeginNext)); vec2 normalNow = normalize(mat2(0, 1, -1, 0) * (-tangentBeginNext));
normal = normalLast + normalNow; normal = normalLast + normalNow;
} }
return angleLargeThanPi(localUV - p3, normal); normal = normalize(normal);
float cosine = dot(normal, tangentEnd);
vec2 toEnd = localUV - p3;
if (/*cosine < 0 ||*/ dot(toEnd, toEnd) > (width * width / (1 - cosine * cosine)))
return true;
return angleLargeThanPi(toEnd, normal);
} }
bool fillElement(vec2 localUV, uint contourIndex, uint linesOffset, uint pointsOffset, uint styleIndex, bool fillElement(vec2 localUV, uint contourIndex, uint linesOffset, uint pointsOffset, uint styleIndex,
@ -1231,29 +1243,24 @@ bool strokeElement(vec2 localUV, uint contourIndex, uint linesOffset, uint point
debugBegin = 1; debugBegin = 1;
} }
float d = cubic_bezier_dis(localUV, p[0], p[1], p[2], p[3], true);
if (d <= strokeWidth)
{
bool onBegin =
distance(localUV, p[0]) <= strokeWidth; //&& (p3Last == p[0] || contourIterator == contourIndex + 1);
bool onEnd = distance(localUV, p[3]) <= strokeWidth;
vec2 tangentBegin; vec2 tangentBegin;
vec2 tangentEnd;
if (p[0] != p[1]) if (p[0] != p[1])
tangentBegin = normalize(p[0] - p[1]); tangentBegin = normalize(p[0] - p[1]);
else else
tangentBegin = normalize(p[0] - p[2]); tangentBegin = normalize(p[0] - p[2]);
vec2 tangentEnd;
if (p[3] != p[2]) if (p[3] != p[2])
tangentEnd = normalize(p[3] - p[2]); tangentEnd = normalize(p[3] - p[2]);
else else
tangentEnd = normalize(p[3] - p[1]); tangentEnd = normalize(p[3] - p[1]);
float d = cubic_bezier_dis(localUV, p[0], p[1], p[2], p[3], true);
if (d <= strokeWidth)
{
bool hit = d < minDistance; bool hit = d < minDistance;
if (onBegin) hit = hit &&
hit = hit && shouldFillBeginCap(localUV, onVeryBegin, endType, p[0], tangentBegin, tangentEndLast); shouldFillBeginCap(localUV, onVeryBegin, endType, p[0], tangentBegin, tangentEndLast, strokeWidth);
if (onEnd) hit = hit && shouldFillEndCap(localUV, onVeryEnd, endType, p[3], tangentEnd, tangentBeginNext, strokeWidth);
hit = hit && shouldFillEndCap(localUV, onVeryEnd, endType, p[3], tangentEnd, tangentBeginNext);
if (hit) if (hit)
{ {
@ -1269,10 +1276,10 @@ bool strokeElement(vec2 localUV, uint contourIndex, uint linesOffset, uint point
drawLine(minDistance / strokeWidth, styleIndex, elementColor, metallicRoughness); drawLine(minDistance / strokeWidth, styleIndex, elementColor, metallicRoughness);
} }
} }
}
tangentEndLast = tangentEnd; tangentEndLast = tangentEnd;
if (contourIterator == contourIndex + 1) if (contourIterator == contourIndex + 1)
tangentFirstBegin = tangentBegin; tangentFirstBegin = tangentBegin;
}
p3Last = p[3]; p3Last = p[3];
p2Last = p[2]; p2Last = p[2];
onVeryBegin = false; onVeryBegin = false;

View File

@ -46,7 +46,7 @@ bool Renderer::Material::operator==(const Material& m) const
std::pair<glm::vec4, glm::vec2> Renderer::Material::toVec() const std::pair<glm::vec4, glm::vec2> Renderer::Material::toVec() const
{ {
return { glm::vec4(color.redF(), color.greenF(), color.blueF(), color.alphaF()), glm::vec2(metallicF(), roughnessF())}; return { glm::vec4(color.redF(), color.greenF(), color.blueF(), color.alphaF()), glm::vec2(metallicF(), roughnessF()) };
} }
std::unique_ptr<MaterialStyle> Renderer::MaterialStyle::decoded(const std::vector<GLfloat>& encoded) std::unique_ptr<MaterialStyle> Renderer::MaterialStyle::decoded(const std::vector<GLfloat>& encoded)
@ -66,6 +66,8 @@ std::unique_ptr<MaterialStyle> Renderer::MaterialStyle::decoded(const std::vecto
std::unique_ptr<MaterialStroke> materialStroke; std::unique_ptr<MaterialStroke> materialStroke;
uint widthMapSize = floatBitsToUint(encoded[1]); uint widthMapSize = floatBitsToUint(encoded[1]);
uint headIndex = widthMapSize + 2; uint headIndex = widthMapSize + 2;
if (encoded[1] < 0)
headIndex = 1; /// 쇗휭앉경긍쯤
uint headUint = floatBitsToUint(encoded[headIndex]); uint headUint = floatBitsToUint(encoded[headIndex]);
vec4 head = unpackUnorm4x8(headUint); vec4 head = unpackUnorm4x8(headUint);
StrokeType strokeType = (StrokeType)floor(head.b * 10); StrokeType strokeType = (StrokeType)floor(head.b * 10);
@ -74,7 +76,7 @@ std::unique_ptr<MaterialStyle> Renderer::MaterialStyle::decoded(const std::vecto
{ {
/// Plain /// Plain
case 0: { case 0: {
materialStroke = std::make_unique<StrokePlain>(Material(glm::unpackUnorm4x8(glm::floatBitsToUint(encoded[headIndex+1])), glm::vec2(head.r, head.g))); materialStroke = std::make_unique<StrokePlain>(Material(glm::unpackUnorm4x8(glm::floatBitsToUint(encoded[headIndex + 1])), glm::vec2(head.r, head.g)));
break; break;
} }
/// RadialGradient /// RadialGradient

View File

@ -220,7 +220,7 @@ namespace UnitTest
{1.00, Material{QColor(58,64,151)}} {1.00, Material{QColor(58,64,151)}}
}; };
return { BaseStyle(std::make_shared<TransformStyle>(), return { BaseStyle(std::make_shared<TransformStyle>(),
std::make_shared<MaterialStyleStroke>(10, StrokeType::kBothSides, StrokeEndType::kClosed, std::make_shared<MaterialStyleStroke>(10, StrokeType::kLeftSide, StrokeEndType::kClosed,
std::make_shared<StrokeRadialGradient>(materialMap, false))) }; std::make_shared<StrokeRadialGradient>(materialMap, false))) };
} }
} style; } style;