gl_engine: fix gradient rendering error

* Fix error when handle GradientTransform calculation. And move the inv
calculation into gradient vertex shader.
* Fix cubic tessellation not close the last point
This commit is contained in:
RuiwenTang 2024-04-19 17:29:45 +08:00 committed by Hermet Park
parent d55b8afd6a
commit 25d43ddacf
3 changed files with 74 additions and 38 deletions

View file

@ -20,6 +20,7 @@
* SOFTWARE.
*/
#include "tvgMath.h"
#include "tvgGlRenderer.h"
#include "tvgGlGpuBuffer.h"
#include "tvgGlGeometry.h"
@ -600,6 +601,22 @@ void GlRenderer::drawPrimitive(GlShape& sdata, const Fill* fill, RenderUpdateFla
// matrix buffer
{
auto matrix = sdata.geometry->getTransforMatrix();
auto gradientTransform = fill->transform();
float invMat4[16];
if (!mathIdentity(const_cast<const Matrix*>(&gradientTransform))) {
Matrix inv{};
mathInverse(&gradientTransform , &inv);
GET_MATRIX44(inv, invMat4);
} else {
memset(invMat4, 0, 16 * sizeof(float));
invMat4[0] = 1.f;
invMat4[5] = 1.f;
invMat4[10] = 1.f;
invMat4[15] = 1.f;
}
uint32_t loc = task->getProgram()->getUniformBlockIndex("Matrix");
uint32_t viewOffset = mGpuBuffer->push(matrix, 16 * sizeof(float), true);
@ -621,6 +638,17 @@ void GlRenderer::drawPrimitive(GlShape& sdata, const Fill* fill, RenderUpdateFla
16 * sizeof(float),
});
}
loc = task->getProgram()->getUniformBlockIndex("InvMatrix");
viewOffset = mGpuBuffer->push(invMat4, 16 * sizeof(float), true);
task->addBindResource(GlBindingResource{
1,
loc,
mGpuBuffer->getBufferId(),
viewOffset,
16 * sizeof(float),
});
}
// gradient block
@ -633,29 +661,31 @@ void GlRenderer::drawPrimitive(GlShape& sdata, const Fill* fill, RenderUpdateFla
GlLinearGradientBlock gradientBlock;
gradientBlock.nStops[0] = stopCnt * 1.f;
gradientBlock.nStops[1] = NOISE_LEVEL;
gradientBlock.nStops[2] = static_cast<int32_t>(fill->spread()) * 1.f;
uint32_t nStops = 0;
for (uint32_t i = 0; i < stopCnt; ++i) {
if (i > 0 && gradientBlock.stopPoints[nStops - 1] > stops[i].offset) continue;
gradientBlock.stopPoints[i] = stops[i].offset;
gradientBlock.stopColors[i * 4 + 0] = stops[i].r / 255.f;
gradientBlock.stopColors[i * 4 + 1] = stops[i].g / 255.f;
gradientBlock.stopColors[i * 4 + 2] = stops[i].b / 255.f;
gradientBlock.stopColors[i * 4 + 3] = stops[i].a / 255.f;
nStops++;
}
gradientBlock.nStops[0] = nStops * 1.f;
float x1, x2, y1, y2;
linearFill->linear(&x1, &y1, &x2, &y2);
auto transform = linearFill->transform();
gradientBlock.startPos[0] = x1 * transform.e11 + transform.e13;
gradientBlock.startPos[1] = y1 * transform.e22 + transform.e23;
gradientBlock.stopPos[0] = x2 * transform.e11 + transform.e13;
gradientBlock.stopPos[1] = y2 * transform.e22 + transform.e23;
gradientBlock.startPos[0] = x1;
gradientBlock.startPos[1] = y1;
gradientBlock.stopPos[0] = x2;
gradientBlock.stopPos[1] = y2;
gradientBinding = GlBindingResource{
1,
2,
loc,
mGpuBuffer->getBufferId(),
mGpuBuffer->push(&gradientBlock, sizeof(GlLinearGradientBlock), true),
@ -666,28 +696,31 @@ void GlRenderer::drawPrimitive(GlShape& sdata, const Fill* fill, RenderUpdateFla
GlRadialGradientBlock gradientBlock;
gradientBlock.nStops[0] = stopCnt * 1.f;
gradientBlock.nStops[1] = NOISE_LEVEL;
gradientBlock.nStops[2] = static_cast<int32_t>(fill->spread()) * 1.f;
uint32_t nStops = 0;
for (uint32_t i = 0; i < stopCnt; ++i) {
if (i > 0 && gradientBlock.stopPoints[nStops - 1] > stops[i].offset) continue;
gradientBlock.stopPoints[i] = stops[i].offset;
gradientBlock.stopColors[i * 4 + 0] = stops[i].r / 255.f;
gradientBlock.stopColors[i * 4 + 1] = stops[i].g / 255.f;
gradientBlock.stopColors[i * 4 + 2] = stops[i].b / 255.f;
gradientBlock.stopColors[i * 4 + 3] = stops[i].a / 255.f;
nStops++;
}
gradientBlock.nStops[0] = nStops * 1.f;
float x, y, r;
radialFill->radial(&x, &y, &r);
auto transform = radialFill->transform();
gradientBlock.centerPos[0] = x * transform.e11 + transform.e13;
gradientBlock.centerPos[1] = y * transform.e22 + transform.e23;
gradientBlock.radius[0] = r * transform.e11;
gradientBlock.centerPos[0] = x;
gradientBlock.centerPos[1] = y;
gradientBlock.radius[0] = r;
gradientBinding = GlBindingResource{
1,
2,
loc,
mGpuBuffer->getBufferId(),
mGpuBuffer->push(&gradientBlock, sizeof(GlRadialGradientBlock), true),

View file

@ -52,11 +52,15 @@ out vec2 vPos;
layout(std140) uniform Matrix { \n
mat4 transform; \n
} uMatrix; \n
layout(std140) uniform InvMatrix { \n
mat4 transform; \n
} uInvMatrix; \n
\n
void main() \n
{ \n
gl_Position = uMatrix.transform * vec4(aLocation, 0.0, 1.0); \n
vPos = aLocation; \n
vec4 pos = uInvMatrix.transform * vec4(aLocation, 0.0, 1.0); \n
vPos = pos.xy / pos.w; \n
});
@ -89,20 +93,23 @@ float gradientWrap(float d)
return clamp(d, 0.0, 1.0); \n
} \n
\n
int i = 1; \n
while (d > 1.0) { \n
d = d - 1.0; \n
i *= -1; \n
if (spread == 1) { /* Reflect */ \n
float n = mod(d, 2.0); \n
if (n > 1.0) \n
{ \n
n = 2.0 - n; \n
} \n
return n; \n
} \n
\n
if (spread == 2) { /* Reflect */ \n
return smoothstep(0.0, 1.0, d); \n
if (spread == 2) { /* Repeat */ \n
float n = mod(d, 1.0); \n
if (n < 0.0) \n
{ \n
n += 1.0 + n; \n
} \n
return n; \n
} \n
\n
if (i == 1) \n
return smoothstep(0.0, 1.0, d); \n
else \n
return smoothstep(1.0, 0.0, d); \n
} \n
\n
vec4 gradient(float t) \n
@ -112,11 +119,11 @@ vec4 gradient(float t)
int count = int(uGradientInfo.nStops[0]); \n
if (t <= gradientStop(0)) \n
{ \n
col += uGradientInfo.stopColors[0]; \n
col = uGradientInfo.stopColors[0]; \n
} \n
else if (t >= gradientStop(count - 1)) \n
{ \n
col += uGradientInfo.stopColors[count - 1]; \n
col = uGradientInfo.stopColors[count - 1]; \n
} \n
else \n
{ \n
@ -126,7 +133,7 @@ vec4 gradient(float t)
float stopi1 = gradientStop(i + 1); \n
if (t > stopi && t <stopi1) \n
{ \n
col += (uGradientInfo.stopColors[i] * (1. - gradientStep(stopi, stopi1, t))); \n
col = (uGradientInfo.stopColors[i] * (1. - gradientStep(stopi, stopi1, t))); \n
col += (uGradientInfo.stopColors[i + 1] * gradientStep(stopi, stopi1, t)); \n
break; \n
} \n
@ -163,15 +170,13 @@ void main()
\n
vec2 ba = ed - st; \n
\n
float t = dot(pos - st, ba) / dot(ba, ba); \n
float t = abs(dot(pos - st, ba) / dot(ba, ba)); \n
\n
t = gradientWrap(t); \n
\n
vec4 color = gradient(t); \n
\n
vec3 noise = 8.0 * uGradientInfo.nStops[1] * ScreenSpaceDither(pos); \n
vec4 finalCol = vec4(color.xyz + noise, color.w); \n
FragColor = vec4(finalCol.rgb * finalCol.a, finalCol.a); \n
FragColor = vec4(color.rgb * color.a, color.a); \n
});
std::string STR_RADIAL_GRADIENT_VARIABLES = TVG_COMPOSE_SHADER(
@ -198,9 +203,7 @@ void main()
\n
vec4 color = gradient(t); \n
\n
vec3 noise = 8.0 * uGradientInfo.nStops[1] * ScreenSpaceDither(pos); \n
vec4 finalCol = vec4(color.xyz + noise, color.w); \n
FragColor = vec4(finalCol.rgb * finalCol.a, finalCol.a); \n
FragColor = vec4(color.rgb * color.a, color.a); \n
});
std::string STR_LINEAR_GRADIENT_FRAG_SHADER =

View file

@ -2154,7 +2154,7 @@ void BWTessellator::tessellate(const RenderShape *rshape)
float step = 1.f / stepCount;
for (uint32_t s = 1; s < static_cast<uint32_t>(stepCount); s++) {
for (uint32_t s = 1; s <= static_cast<uint32_t>(stepCount); s++) {
auto pt = bezPointAt(curve, step * s);
auto currIndex = pushVertex(pt.x, pt.y);