Fix the fragment shader to work with any background color

There now some dither to avoid banding in the gradients.
This commit is contained in:
luisangelsm
2026-01-19 19:23:57 +01:00
parent 41b02725d7
commit 720d58533c
6 changed files with 47 additions and 27 deletions

View File

@ -51,11 +51,19 @@ void main()
// For reflections, apply a gradient fade using reflection uniforms (darker further away)
if (vIsReflection > 0.5) {
// Legacy reflection fade: ramp from 0.0 to 0.33 using texture V coordinate
float gradientFade = mix(0.0, 0.33, vTexCoord.y);
float gradientFade = mix(reflectionUp, reflectionDown, vTexCoord.y);
shadingAmount *= gradientFade;
}
// Final color: shaded RGB, keep source alpha
fragColor = vec4(texColor.rgb * shadingAmount, texColor.a);
// Subtle dithering to break up bands (very low amplitude, within 8-bit quantization)
float rnd = fract(sin(dot(gl_FragCoord.xy, vec2(12.9898,78.233))) * 43758.5453);
// scale to roughly +/- 0.5/255 range (adjust strength if needed)
float dither = (rnd - 0.5) / 255.0;
float shadedAmountDithered = clamp(shadingAmount + dither, 0.0, 1.0);
fragColor = vec4(
mix(backgroundColor, texColor.rgb, shadedAmountDithered),
texColor.a
);
}

Binary file not shown.

View File

@ -37,7 +37,7 @@ void YACReaderComicFlow3D::updateImageData()
// Create QRhiTexture from the loaded image
if (m_rhi) {
QRhiTexture *texture = m_rhi->newTexture(QRhiTexture::BGRA8, img.size(), 1, QRhiTexture::MipMapped | QRhiTexture::UsedWithGenerateMips);
QRhiTexture *texture = m_rhi->newTexture(QRhiTexture::RGBA8, img.size(), 1, QRhiTexture::MipMapped | QRhiTexture::UsedWithGenerateMips);
if (texture->create()) {
PendingTextureUpload upload;
@ -168,7 +168,7 @@ QImage ImageLoader3D::loadImage(const QString &fileName)
break;
}
return image;
return image.convertToFormat(QImage::Format_RGBA8888);
}
ImageLoader3D::ImageLoader3D(YACReaderFlow3D *flow)

View File

@ -37,8 +37,8 @@ YACReaderFlow3D::YACReaderFlow3D(QWidget *parent, struct Preset p)
shadingTop = 0.8f;
shadingBottom = 0.02f;
reflectionUp = 0.f;
reflectionBottom = 0.6f;
reflectionUp = 0.0f;
reflectionBottom = 0.33f;
setBackgroundColor(Qt::black);
@ -119,9 +119,9 @@ void YACReaderFlow3D::initialize(QRhiCommandBuffer *cb)
// Initialize default texture from image
if (!scene.defaultTexture) {
QImage defaultImage(":/images/defaultCover.png");
QImage defaultImage = QImage(":/images/defaultCover.png").convertToFormat(QImage::Format_RGBA8888);
scene.defaultTexture.reset(m_rhi->newTexture(QRhiTexture::BGRA8, defaultImage.size(), 1, QRhiTexture::MipMapped | QRhiTexture::UsedWithGenerateMips));
scene.defaultTexture.reset(m_rhi->newTexture(QRhiTexture::RGBA8, defaultImage.size(), 1, QRhiTexture::MipMapped | QRhiTexture::UsedWithGenerateMips));
scene.defaultTexture->create();
getResourceBatch()->uploadTexture(scene.defaultTexture.get(), defaultImage);
getResourceBatch()->generateMips(scene.defaultTexture.get());
@ -131,9 +131,9 @@ void YACReaderFlow3D::initialize(QRhiCommandBuffer *cb)
#ifdef YACREADER_LIBRARY
// Initialize mark textures
if (!scene.markTexture) {
QImage markImage(":/images/readRibbon.png");
QImage markImage = QImage(":/images/readRibbon.png").convertToFormat(QImage::Format_RGBA8888);
if (!markImage.isNull()) {
scene.markTexture.reset(m_rhi->newTexture(QRhiTexture::BGRA8, markImage.size(), 1, QRhiTexture::MipMapped | QRhiTexture::UsedWithGenerateMips));
scene.markTexture.reset(m_rhi->newTexture(QRhiTexture::RGBA8, markImage.size(), 1, QRhiTexture::MipMapped | QRhiTexture::UsedWithGenerateMips));
scene.markTexture->create();
getResourceBatch()->uploadTexture(scene.markTexture.get(), markImage);
getResourceBatch()->generateMips(scene.markTexture.get());
@ -141,9 +141,9 @@ void YACReaderFlow3D::initialize(QRhiCommandBuffer *cb)
}
if (!scene.readingTexture) {
QImage readingImage(":/images/readingRibbon.png");
QImage readingImage = QImage(":/images/readingRibbon.png").convertToFormat(QImage::Format_RGBA8888);
if (!readingImage.isNull()) {
scene.readingTexture.reset(m_rhi->newTexture(QRhiTexture::BGRA8, readingImage.size(), 1, QRhiTexture::MipMapped | QRhiTexture::UsedWithGenerateMips));
scene.readingTexture.reset(m_rhi->newTexture(QRhiTexture::RGBA8, readingImage.size(), 1, QRhiTexture::MipMapped | QRhiTexture::UsedWithGenerateMips));
scene.readingTexture->create();
getResourceBatch()->uploadTexture(scene.readingTexture.get(), readingImage);
getResourceBatch()->generateMips(scene.readingTexture.get());
@ -605,13 +605,25 @@ void YACReaderFlow3D::prepareDrawData(const YACReader3DImageRHI &image, bool isR
// Store per-instance rotation in the instance data (new slot at index 22)
outInstanceData[22] = image.current.rot;
// Prepare uniform data
outUniformData.viewProjectionMatrix = viewProjectionMatrix;
outUniformData.backgroundColor = QVector3D(backgroundColor.redF(), backgroundColor.greenF(), backgroundColor.blueF());
outUniformData.shadingColor = QVector3D(shadingColor.redF(), shadingColor.greenF(), shadingColor.blueF());
// Prepare uniform data (copy float data into POD arrays)
const float *vp = viewProjectionMatrix.constData();
for (int m = 0; m < 16; ++m)
outUniformData.viewProjectionMatrix[m] = vp[m];
outUniformData.backgroundColor[0] = backgroundColor.redF();
outUniformData.backgroundColor[1] = backgroundColor.greenF();
outUniformData.backgroundColor[2] = backgroundColor.blueF();
outUniformData._pad0 = 0.0f;
outUniformData.shadingColor[0] = shadingColor.redF();
outUniformData.shadingColor[1] = shadingColor.greenF();
outUniformData.shadingColor[2] = shadingColor.blueF();
outUniformData._pad1 = 0.0f;
outUniformData.reflectionUp = reflectionUp;
outUniformData.reflectionDown = reflectionBottom;
outUniformData.isReflection = isReflection ? 1 : 0;
outUniformData.isReflection = isReflection ? 1.0f : 0.0f;
outUniformData._pad2 = 0.0f;
}
void YACReaderFlow3D::executeDrawWithOffset(QRhiCommandBuffer *cb, QRhiTexture *texture,

View File

@ -112,14 +112,14 @@ protected:
// Uniform buffer data structure (must match shader layout)
struct UniformData {
QMatrix4x4 viewProjectionMatrix;
QVector3D backgroundColor;
float _pad0;
QVector3D shadingColor;
float _pad1;
float viewProjectionMatrix[16]; // column-major 4x4
float backgroundColor[3];
float _pad0; // pad to vec4
float shadingColor[3];
float _pad1; // pad to vec4
float reflectionUp;
float reflectionDown;
int isReflection;
float isReflection;
float _pad2;
};

View File

@ -40,7 +40,7 @@ void YACReaderPageFlow3D::updateImageData()
// Create QRhiTexture from the loaded image and queue the pixel upload
if (m_rhi) {
QRhiTexture *texture = m_rhi->newTexture(QRhiTexture::BGRA8, img.size(), 1, QRhiTexture::MipMapped | QRhiTexture::UsedWithGenerateMips);
QRhiTexture *texture = m_rhi->newTexture(QRhiTexture::RGBA8, img.size(), 1, QRhiTexture::MipMapped | QRhiTexture::UsedWithGenerateMips);
if (texture->create()) {
// Queue the image upload so it happens together with other resource updates
@ -136,7 +136,7 @@ QImage ImageLoaderByteArray3D::loadImage(const QByteArray &raw)
break;
}
return image;
return image.convertToFormat(QImage::Format_RGBA8888);
}
ImageLoaderByteArray3D::ImageLoaderByteArray3D(YACReaderFlow3D *flow)