diff --git a/common/rhi/shaders/flow.frag b/common/rhi/shaders/flow.frag index 5e6f6c40..411204f4 100644 --- a/common/rhi/shaders/flow.frag +++ b/common/rhi/shaders/flow.frag @@ -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 + ); } diff --git a/common/rhi/shaders/flow.frag.qsb b/common/rhi/shaders/flow.frag.qsb index 02f9d8a6..cf44ec8e 100644 Binary files a/common/rhi/shaders/flow.frag.qsb and b/common/rhi/shaders/flow.frag.qsb differ diff --git a/common/rhi/yacreader_comic_flow_rhi.cpp b/common/rhi/yacreader_comic_flow_rhi.cpp index 6117114e..a5ec18fe 100644 --- a/common/rhi/yacreader_comic_flow_rhi.cpp +++ b/common/rhi/yacreader_comic_flow_rhi.cpp @@ -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) diff --git a/common/rhi/yacreader_flow_rhi.cpp b/common/rhi/yacreader_flow_rhi.cpp index d3b7b715..f3c0a33c 100644 --- a/common/rhi/yacreader_flow_rhi.cpp +++ b/common/rhi/yacreader_flow_rhi.cpp @@ -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, diff --git a/common/rhi/yacreader_flow_rhi.h b/common/rhi/yacreader_flow_rhi.h index 7c02b8f8..44e5e60d 100644 --- a/common/rhi/yacreader_flow_rhi.h +++ b/common/rhi/yacreader_flow_rhi.h @@ -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; }; diff --git a/common/rhi/yacreader_page_flow_rhi.cpp b/common/rhi/yacreader_page_flow_rhi.cpp index f2e9b398..d3220071 100644 --- a/common/rhi/yacreader_page_flow_rhi.cpp +++ b/common/rhi/yacreader_page_flow_rhi.cpp @@ -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)