更新MaterialStyle::decoded

main
wuyize 2023-03-29 12:31:21 +08:00
parent 5013538e16
commit 38336aa944
3 changed files with 61 additions and 12 deletions

View File

@ -625,7 +625,7 @@ int solve_quartic(vec4 coeffs, inout vec4 s)
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, out float t)
{
// switch points when near to end point to minimize numerical error
@ -862,7 +862,13 @@ float cubic_bezier_dis(vec2 uv, vec2 p0, vec2 p1, vec2 p2, vec2 p3, bool roundEn
{
roots[i] = clamp(roots[i], 0., 1.);
vec2 to_curve = uv - parametric_cub_bezier(roots[i], p0, p1, p2, p3);
d0 = min(d0, dot(to_curve, to_curve));
float d = dot(to_curve, to_curve);
if (d < d0)
{
d0 = d;
t = roots[i];
}
// d0 = min(d0, dot(to_curve, to_curve));
}
else
{
@ -959,6 +965,37 @@ bool angleLargeThanPi(vec2 a, vec2 b)
return a.x * b.y - b.x * a.y < 0;
}
float getLocalWidth(float t, vec2 lengthRate, float originWidth, uint widthMapSize, uint widthMapIndex)
{
if (widthMapSize == 0)
return originWidth;
float width;
vec2 lastData = unpackUnorm2x16(floatBitsToUint(elementData[widthMapIndex]));
float lastLevel = 0;
float lastWidth = lastData.y;
float currentLengthRate = mix(lengthRate.x, lengthRate.y, t);
bool found = false;
for (uint i = 0; i < widthMapSize; i++)
{
vec2 data = unpackUnorm2x16(floatBitsToUint(elementData[widthMapIndex + i]));
float level = data.x;
float currentWidth = data.y;
if (currentLengthRate <= level)
{
float a = (currentLengthRate - lastLevel) / (level - lastLevel);
a = smoothstep(0, 1, a);
width = mix(lastWidth, currentWidth, a);
found = true;
break;
}
lastWidth = currentWidth;
lastLevel = level;
}
if (!found)
width = lastWidth;
return width * originWidth;
}
void drawLine(in float d, uint styleHeadIndex, out vec4 elementColor, out vec2 metallicRoughness)
{
elementColor = vec4(1);
@ -1156,11 +1193,11 @@ vec2 getLineTangentEnd(uint contourIterator, uint linesOffset, uint pointsOffset
return normalize(p[3] - p[1]);
}
mat4x2 getPointsByContourIterator(uint contourIterator, uint linesOffset, uint pointsOffset)
mat4x2 getPointsByContourIterator(uint contourIterator, uint linesOffset, uint pointsOffset, out vec2 lengthRate)
{
uint lineIndex = elementIndexs[contourIterator];
uint pLocation = linesOffset + 3 * lineIndex;
vec2 percent = unpackUnorm2x16(elementIndexs[pLocation + 2]);
lengthRate = unpackUnorm2x16(elementIndexs[pLocation + 2]);
uvec4 pxIndex =
uvec4(pointsOffset) + 2 * uvec4(elementIndexs[pLocation] >> 16, elementIndexs[pLocation] & 0xFFFF,
elementIndexs[pLocation + 1] >> 16, elementIndexs[pLocation + 1] & 0xFFFF);
@ -1186,6 +1223,7 @@ bool strokeElement(vec2 localUV, uint contourIndex, uint linesOffset, uint point
float minDistance = 1e38;
uint lineCount = elementIndexs[contourIndex];
uint widthMapSize = floatBitsToUint(elementData[styleIndex + 1]);
uint widthMapIndex = styleIndex + 2;
styleIndex += widthMapSize + 2;
vec4 styleHead = unpackUnorm4x8(floatBitsToUint(elementData[styleIndex]));
float lineType = floor(styleHead.b * 10);
@ -1202,7 +1240,8 @@ bool strokeElement(vec2 localUV, uint contourIndex, uint linesOffset, uint point
for (uint contourIterator_ = contourIndex + 1; contourIterator_ < contourIndex + 1 + lineCount; contourIterator_++)
{
uint contourIterator = contourIterator_;
mat4x2 p = getPointsByContourIterator(contourIterator, linesOffset, pointsOffset);
vec2 lengthRate;
mat4x2 p = getPointsByContourIterator(contourIterator, linesOffset, pointsOffset, lengthRate);
if ((contourIterator == contourIndex + 1))
{
@ -1235,7 +1274,8 @@ bool strokeElement(vec2 localUV, uint contourIndex, uint linesOffset, uint point
vec2 tangentBeginNext = vec2(0);
if (contourIterator + 1 < contourIndex + 1 + lineCount)
{
mat4x2 pNext = getPointsByContourIterator(contourIterator + 1, linesOffset, pointsOffset);
vec2 lengthRate;
mat4x2 pNext = getPointsByContourIterator(contourIterator + 1, linesOffset, pointsOffset, lengthRate);
if (pNext[0] == p[3])
{
@ -1267,13 +1307,15 @@ bool strokeElement(vec2 localUV, uint contourIndex, uint linesOffset, uint point
onVeryEnd = true;
}
float d = cubic_bezier_dis(localUV, p[0], p[1], p[2], p[3], true);
if (d <= strokeWidth)
float t;
float d = cubic_bezier_dis(localUV, p[0], p[1], p[2], p[3], true, t);
float localWidth = getLocalWidth(t, lengthRate, strokeWidth, widthMapSize, widthMapIndex);
if (d <= localWidth)
{
bool hit = d < minDistance;
hit = hit &&
shouldFillBeginCap(localUV, onVeryBegin, endType, p[0], tangentBegin, tangentEndLast, strokeWidth);
hit = hit && shouldFillEndCap(localUV, onVeryEnd, endType, p[3], tangentEnd, tangentBeginNext, strokeWidth);
shouldFillBeginCap(localUV, onVeryBegin, endType, p[0], tangentBegin, tangentEndLast, localWidth);
hit = hit && shouldFillEndCap(localUV, onVeryEnd, endType, p[3], tangentEnd, tangentBeginNext, localWidth);
if (hit)
{
bool reverse = p[3].y - p[0].y < 0.;
@ -1289,7 +1331,7 @@ bool strokeElement(vec2 localUV, uint contourIndex, uint linesOffset, uint point
{
minDistance = min(minDistance, d);
hitElement = true;
drawLine(minDistance / strokeWidth, styleIndex, elementColor, metallicRoughness);
drawLine(minDistance / localWidth, styleIndex, elementColor, metallicRoughness);
}
}
}

View File

@ -64,7 +64,13 @@ std::unique_ptr<MaterialStyle> Renderer::MaterialStyle::decoded(const std::vecto
else /// MaterialStyleStroke
{
std::unique_ptr<MaterialStroke> materialStroke;
std::map<float, float> widthMap;
uint widthMapSize = floatBitsToUint(encoded[1]);
for (int i = 0; i < widthMapSize; i++)
{
glm::vec2 v = glm::unpackUnorm2x16(glm::floatBitsToUint(encoded[2 + i]));
widthMap.emplace(v.x, v.y);
}
uint headIndex = widthMapSize + 2;
if (encoded[1] < 0)
headIndex = 1; /// 쇗휭앉경긍쯤
@ -96,6 +102,6 @@ std::unique_ptr<MaterialStyle> Renderer::MaterialStyle::decoded(const std::vecto
break;
}
}
return std::make_unique<MaterialStyleStroke>(encoded[0], strokeType, endType, std::move(materialStroke));
return std::make_unique<MaterialStyleStroke>(encoded[0], strokeType, endType, std::move(materialStroke), widthMap);
}
}

View File

@ -70,6 +70,7 @@ std::vector<glm::vec2> generatePathBuffer(const QPainterPath& path)
pathBuffer.emplace_back(element.x, element.y);
lastPoint = glm::vec2(element.x, element.y);
j++;
k = 0;
break;
case QPainterPath::LineToElement:
{