mirror of
https://github.com/YACReader/yacreader
synced 2026-04-12 15:49:53 -04:00
Use the fragment shader to calculate the shading effect for a more uniform shading than the one based on vertex
This commit is contained in:
@ -157,7 +157,10 @@ SOURCES += ../common/comic.cpp \
|
|||||||
SOURCES += ../common/rhi/yacreader_flow_rhi.cpp
|
SOURCES += ../common/rhi/yacreader_flow_rhi.cpp
|
||||||
SOURCES += ../common/rhi/yacreader_comic_flow_rhi.cpp \
|
SOURCES += ../common/rhi/yacreader_comic_flow_rhi.cpp \
|
||||||
../common/rhi/yacreader_page_flow_rhi.cpp
|
../common/rhi/yacreader_page_flow_rhi.cpp
|
||||||
RESOURCES += ../common/rhi/shaders/shaders.qrc
|
RESOURCES += ../common/rhi/shaders/shaders.qrc
|
||||||
|
# Make raw GLSL shader sources editable in Qt Creator
|
||||||
|
OTHER_FILES += ../common/rhi/shaders/flow.vert \
|
||||||
|
../common/rhi/shaders/flow.frag
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -253,7 +253,10 @@ SOURCES += comic_flow.cpp \
|
|||||||
SOURCES += ../common/rhi/yacreader_flow_rhi.cpp
|
SOURCES += ../common/rhi/yacreader_flow_rhi.cpp
|
||||||
SOURCES += ../common/rhi/yacreader_comic_flow_rhi.cpp \
|
SOURCES += ../common/rhi/yacreader_comic_flow_rhi.cpp \
|
||||||
../common/rhi/yacreader_page_flow_rhi.cpp
|
../common/rhi/yacreader_page_flow_rhi.cpp
|
||||||
RESOURCES += ../common/rhi/shaders/shaders.qrc
|
RESOURCES += ../common/rhi/shaders/shaders.qrc
|
||||||
|
# Make raw GLSL shader sources editable in Qt Creator
|
||||||
|
OTHER_FILES += ../common/rhi/shaders/flow.vert \
|
||||||
|
../common/rhi/shaders/flow.frag
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,8 +2,11 @@
|
|||||||
|
|
||||||
// Inputs from vertex shader
|
// Inputs from vertex shader
|
||||||
layout(location = 0) in vec2 vTexCoord;
|
layout(location = 0) in vec2 vTexCoord;
|
||||||
layout(location = 1) in vec4 vColor;
|
layout(location = 1) in flat vec4 vInstanceShading;
|
||||||
layout(location = 2) in float vIsReflection;
|
layout(location = 2) in flat float vInstanceOpacity;
|
||||||
|
layout(location = 3) in flat float vIsReflection;
|
||||||
|
layout(location = 4) in flat float vInstanceRotation;
|
||||||
|
layout(location = 5) in vec2 vLocalPos;
|
||||||
|
|
||||||
// Output
|
// Output
|
||||||
layout(location = 0) out vec4 fragColor;
|
layout(location = 0) out vec4 fragColor;
|
||||||
@ -29,16 +32,30 @@ void main()
|
|||||||
{
|
{
|
||||||
vec4 texColor = texture(coverTexture, vTexCoord);
|
vec4 texColor = texture(coverTexture, vTexCoord);
|
||||||
|
|
||||||
// Apply shading: multiply texture by vColor.r to darken
|
// Compute per-pixel shading using per-instance corner shading values
|
||||||
float shadingAmount = vColor.r;
|
float leftUp = vInstanceShading.x;
|
||||||
|
float leftDown = vInstanceShading.y;
|
||||||
|
float rightUp = vInstanceShading.z;
|
||||||
|
float rightDown = vInstanceShading.w;
|
||||||
|
|
||||||
// For reflections, apply gradient fade (darker at bottom, fading to black)
|
// Use interpolated local vertex position to match original vertex-based shading.
|
||||||
|
// position.y in vertex ranges [-0.5..0.5], so map to [0..1] with +0.5
|
||||||
|
float y = clamp(vLocalPos.y + 0.5, 0.0, 1.0);
|
||||||
|
float x = clamp(vLocalPos.x + 0.5, 0.0, 1.0);
|
||||||
|
float leftShading = mix(leftDown, leftUp, y);
|
||||||
|
float rightShading = mix(rightDown, rightUp, y);
|
||||||
|
float shading = mix(leftShading, rightShading, x);
|
||||||
|
|
||||||
|
// Combine with per-instance opacity (opacity only darkens RGB, alpha preserved)
|
||||||
|
float shadingAmount = shading * vInstanceOpacity;
|
||||||
|
|
||||||
|
// For reflections, apply a gradient fade using reflection uniforms (darker further away)
|
||||||
if (vIsReflection > 0.5) {
|
if (vIsReflection > 0.5) {
|
||||||
// vTexCoord.y goes from 1 (top of reflection, near cover) to 0 (bottom, far from cover)
|
// Legacy reflection fade: ramp from 0.0 to 0.33 using texture V coordinate
|
||||||
// We want it brightest near the cover and fading away
|
|
||||||
float gradientFade = mix(0.0, 0.33, vTexCoord.y);
|
float gradientFade = mix(0.0, 0.33, vTexCoord.y);
|
||||||
shadingAmount *= gradientFade;
|
shadingAmount *= gradientFade;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Final color: shaded RGB, keep source alpha
|
||||||
fragColor = vec4(texColor.rgb * shadingAmount, texColor.a);
|
fragColor = vec4(texColor.rgb * shadingAmount, texColor.a);
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
@ -12,11 +12,15 @@ layout(location = 5) in vec4 instanceModel_row3;
|
|||||||
layout(location = 6) in vec4 instanceShading1;
|
layout(location = 6) in vec4 instanceShading1;
|
||||||
layout(location = 7) in float instanceOpacity;
|
layout(location = 7) in float instanceOpacity;
|
||||||
layout(location = 8) in float instanceFlip;
|
layout(location = 8) in float instanceFlip;
|
||||||
|
layout(location = 9) in float instanceRotation;
|
||||||
|
|
||||||
// Outputs to fragment shader
|
// Outputs to fragment shader
|
||||||
layout(location = 0) out vec2 vTexCoord;
|
layout(location = 0) out vec2 vTexCoord;
|
||||||
layout(location = 1) out vec4 vColor;
|
layout(location = 1) out flat vec4 vInstanceShading;
|
||||||
layout(location = 2) out float vIsReflection;
|
layout(location = 2) out flat float vInstanceOpacity;
|
||||||
|
layout(location = 3) out flat float vIsReflection;
|
||||||
|
layout(location = 4) out flat float vInstanceRotation;
|
||||||
|
layout(location = 5) out vec2 vLocalPos;
|
||||||
|
|
||||||
// Uniform buffer
|
// Uniform buffer
|
||||||
layout(std140, binding = 0) uniform UniformBuffer
|
layout(std140, binding = 0) uniform UniformBuffer
|
||||||
@ -39,21 +43,16 @@ void main()
|
|||||||
|
|
||||||
gl_Position = viewProjectionMatrix * instanceModel * vec4(position, 1.0);
|
gl_Position = viewProjectionMatrix * instanceModel * vec4(position, 1.0);
|
||||||
vTexCoord = texCoord;
|
vTexCoord = texCoord;
|
||||||
|
vLocalPos = position.xy;
|
||||||
|
|
||||||
// Flip texture vertically per-instance when requested (reflection)
|
// Flip texture vertically per-instance when requested (reflection)
|
||||||
if (instanceFlip != 0.0) {
|
if (instanceFlip != 0.0) {
|
||||||
vTexCoord.y = 1.0 - texCoord.y;
|
vTexCoord.y = 1.0 - vTexCoord.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
float leftUpShading = instanceShading1.x;
|
// Pass per-instance values to fragment shader as flat (no interpolation)
|
||||||
float leftDownShading = instanceShading1.y;
|
vInstanceShading = instanceShading1;
|
||||||
float rightUpShading = instanceShading1.z;
|
vInstanceOpacity = instanceOpacity;
|
||||||
float rightDownShading = instanceShading1.w;
|
|
||||||
|
|
||||||
float leftShading = mix(leftDownShading, leftUpShading, (position.y + 0.5));
|
|
||||||
float rightShading = mix(rightDownShading, rightUpShading, (position.y + 0.5));
|
|
||||||
float shading = mix(leftShading, rightShading, (position.x + 0.5));
|
|
||||||
|
|
||||||
vColor = vec4(shading * instanceOpacity);
|
|
||||||
vIsReflection = instanceFlip;
|
vIsReflection = instanceFlip;
|
||||||
|
vInstanceRotation = instanceRotation;
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
@ -194,9 +194,9 @@ void YACReaderFlow3D::initialize(QRhiCommandBuffer *cb)
|
|||||||
|
|
||||||
// Create instance buffer for per-draw instance data
|
// Create instance buffer for per-draw instance data
|
||||||
if (!scene.instanceBuffer) {
|
if (!scene.instanceBuffer) {
|
||||||
// Allocate buffer for per-instance data (model matrix + shading + opacity + flipFlag)
|
// Allocate buffer for per-instance data (model matrix + shading + opacity + flipFlag + rotation)
|
||||||
// mat4 (16 floats) + vec4 (4 floats) + float (1 float) + float (1 float) = 22 floats
|
// mat4 (16 floats) + vec4 (4 floats) + float (opacity) + float (flipFlag) + float (rotation) = 23 floats
|
||||||
scene.instanceBuffer.reset(m_rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::VertexBuffer, 22 * sizeof(float)));
|
scene.instanceBuffer.reset(m_rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::VertexBuffer, 23 * sizeof(float)));
|
||||||
scene.instanceBuffer->create();
|
scene.instanceBuffer->create();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -333,7 +333,7 @@ void YACReaderFlow3D::ensurePipeline()
|
|||||||
QRhiVertexInputLayout inputLayout;
|
QRhiVertexInputLayout inputLayout;
|
||||||
inputLayout.setBindings({
|
inputLayout.setBindings({
|
||||||
{ 5 * sizeof(float) }, // Per-vertex data (position + texCoord)
|
{ 5 * sizeof(float) }, // Per-vertex data (position + texCoord)
|
||||||
{ 22 * sizeof(float), QRhiVertexInputBinding::PerInstance } // Per-instance data
|
{ 23 * sizeof(float), QRhiVertexInputBinding::PerInstance } // Per-instance data
|
||||||
});
|
});
|
||||||
inputLayout.setAttributes({
|
inputLayout.setAttributes({
|
||||||
// Per-vertex attributes
|
// Per-vertex attributes
|
||||||
@ -347,7 +347,8 @@ void YACReaderFlow3D::ensurePipeline()
|
|||||||
{ 1, 5, QRhiVertexInputAttribute::Float4, 12 * sizeof(float) }, // row 3
|
{ 1, 5, QRhiVertexInputAttribute::Float4, 12 * sizeof(float) }, // row 3
|
||||||
{ 1, 6, QRhiVertexInputAttribute::Float4, 16 * sizeof(float) }, // shading vec4
|
{ 1, 6, QRhiVertexInputAttribute::Float4, 16 * sizeof(float) }, // shading vec4
|
||||||
{ 1, 7, QRhiVertexInputAttribute::Float, 20 * sizeof(float) }, // opacity
|
{ 1, 7, QRhiVertexInputAttribute::Float, 20 * sizeof(float) }, // opacity
|
||||||
{ 1, 8, QRhiVertexInputAttribute::Float, 21 * sizeof(float) } // flipFlag (1.0 = reflection)
|
{ 1, 8, QRhiVertexInputAttribute::Float, 21 * sizeof(float) }, // flipFlag (1.0 = reflection)
|
||||||
|
{ 1, 9, QRhiVertexInputAttribute::Float, 22 * sizeof(float) } // rotation
|
||||||
});
|
});
|
||||||
scene.pipeline->setVertexInputLayout(inputLayout);
|
scene.pipeline->setVertexInputLayout(inputLayout);
|
||||||
|
|
||||||
@ -408,7 +409,7 @@ void YACReaderFlow3D::render(QRhiCommandBuffer *cb)
|
|||||||
bool isReflection;
|
bool isReflection;
|
||||||
bool isMark;
|
bool isMark;
|
||||||
QRhiTexture *texture;
|
QRhiTexture *texture;
|
||||||
float instanceData[22];
|
float instanceData[23];
|
||||||
UniformData uniformData;
|
UniformData uniformData;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -482,7 +483,7 @@ void YACReaderFlow3D::render(QRhiCommandBuffer *cb)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Ensure instance buffer is large enough for all draws
|
// Ensure instance buffer is large enough for all draws
|
||||||
auto requiredInstanceSize = static_cast<quint32>(draws.size() * 22 * sizeof(float));
|
auto requiredInstanceSize = static_cast<quint32>(draws.size() * 23 * sizeof(float));
|
||||||
if (!scene.instanceBuffer || scene.instanceBuffer->size() < requiredInstanceSize) {
|
if (!scene.instanceBuffer || scene.instanceBuffer->size() < requiredInstanceSize) {
|
||||||
scene.instanceBuffer.reset(m_rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::VertexBuffer, requiredInstanceSize));
|
scene.instanceBuffer.reset(m_rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::VertexBuffer, requiredInstanceSize));
|
||||||
if (!scene.instanceBuffer->create()) {
|
if (!scene.instanceBuffer->create()) {
|
||||||
@ -514,8 +515,8 @@ void YACReaderFlow3D::render(QRhiCommandBuffer *cb)
|
|||||||
|
|
||||||
// Update instance buffer with all instance data
|
// Update instance buffer with all instance data
|
||||||
for (int i = 0; i < draws.size(); ++i) {
|
for (int i = 0; i < draws.size(); ++i) {
|
||||||
int offset = i * 22 * sizeof(float);
|
int offset = i * 23 * sizeof(float);
|
||||||
batch->updateDynamicBuffer(scene.instanceBuffer.get(), offset, 22 * sizeof(float), draws[i].instanceData);
|
batch->updateDynamicBuffer(scene.instanceBuffer.get(), offset, 23 * sizeof(float), draws[i].instanceData);
|
||||||
}
|
}
|
||||||
|
|
||||||
// === PHASE 2: RENDER (DURING PASS) ===
|
// === PHASE 2: RENDER (DURING PASS) ===
|
||||||
@ -601,6 +602,9 @@ void YACReaderFlow3D::prepareDrawData(const YACReader3DImageRHI &image, bool isR
|
|||||||
outInstanceData[i] = matData[i];
|
outInstanceData[i] = matData[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Store per-instance rotation in the instance data (new slot at index 22)
|
||||||
|
outInstanceData[22] = image.current.rot;
|
||||||
|
|
||||||
// Prepare uniform data
|
// Prepare uniform data
|
||||||
outUniformData.viewProjectionMatrix = viewProjectionMatrix;
|
outUniformData.viewProjectionMatrix = viewProjectionMatrix;
|
||||||
outUniformData.backgroundColor = QVector3D(backgroundColor.redF(), backgroundColor.greenF(), backgroundColor.blueF());
|
outUniformData.backgroundColor = QVector3D(backgroundColor.redF(), backgroundColor.greenF(), backgroundColor.blueF());
|
||||||
@ -637,7 +641,7 @@ void YACReaderFlow3D::executeDrawWithOffset(QRhiCommandBuffer *cb, QRhiTexture *
|
|||||||
// Bind vertex buffers with offset into instance buffer
|
// Bind vertex buffers with offset into instance buffer
|
||||||
const QRhiCommandBuffer::VertexInput vbufBindings[] = {
|
const QRhiCommandBuffer::VertexInput vbufBindings[] = {
|
||||||
{ scene.vertexBuffer.get(), 0 },
|
{ scene.vertexBuffer.get(), 0 },
|
||||||
{ scene.instanceBuffer.get(), quint32(uniformSlot * 22 * sizeof(float)) }
|
{ scene.instanceBuffer.get(), quint32(uniformSlot * 23 * sizeof(float)) }
|
||||||
};
|
};
|
||||||
cb->setVertexInput(0, 2, vbufBindings);
|
cb->setVertexInput(0, 2, vbufBindings);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user